Take the 2-minute tour ×
Programmers Stack Exchange is a question and answer site for professional programmers interested in conceptual questions about software development. It's 100% free, no registration required.

During development process, things are constantly changing (especially in early phases). Requirements change, UI changes, everything changes. Pages that clearly belonged to specific controller, mutated to something completely different in the future.

For example. Lets say that we have website for managing Projects. One page of the website was dedicated to managing existing, and inviting new members of specific project. Naturally, I created members controller nested under projects which had proper responsibility.

Later in the development, it turned out that it was the only page that was "configuring the project" in some way, so additional functionalities were added to it:

  • editing project description
  • setting project as a default
  • ...

In other words, this page changed its primary responsibility from managing project members to managing project itself. Ideally, this page should be moved to "edit" action of "projects" controller. That would mean that all request and controller specs need to refactored too. Is it worth the effort? Should it be done?

Personally, I am really starting to dislike the 1-1 relationship between views and controllers. Its common situation that we have 1 page (view) that handles 2 or more different resources. I think we should have views completely decoupled from controllers, but rails is giving us hard time to achieve this.

I know that AJAX can be used to solve this issue, but I consider it an improvisation. Is there some other kind of architecture (other than MVC) that decouples views from controllers?

share|improve this question
add comment

migrated from stackoverflow.com Nov 17 '11 at 16:33

This question came from our site for professional and enthusiast programmers.

3 Answers

up vote 1 down vote accepted

Applying composition over inheritance to controllers is one of those approaches with which you just can't go wrong.

The idea is to have as thin of a controller as possible. The controller should just define the request/response processes, but anything substantial happening in between is going to be defined outside of the class.

For instance, if you had a controller that filtered a collection of Product instances by a certain criteria, apply the VAT to the base price and then produce a tabular representation, CSV or JSON response, you'd end up with the following classes:

  1. A class that takes the request object and returns an appropriate collection of Product instances; this class is concerned with knowing how to construct an appropriate query based on the incoming request (like querying products based on a mix of attribute values).
  2. A class that takes a Product collection, processes each entry and returns the resulting collection; this class is concerned with taking a product's specified VAT and applying it on the base price.
  3. A class that takes the incoming request object and a Product collection and produces an appropriate response; this class is concerned with figuring out whether to produce an HTML, CSV or JSON response of the collection.
  4. Your actual controller that simply creates a network of communication between the three classes; this class finally specifies the notion of collecting, processing and displaying the Product model appropriately.

The thing is that controllers often end up exhibiting a lot of complex behavior, but this way that behavior is factored into several different components that are defined and tested independently. By simply mixing in different classes and changing a few lines of code, your controller's behavior changes dramatically. I don't really have any experience with Ruby, but from what I know this can be achieved by including and mixing different modules and perhaps even a macro or two for seasoning.

One good example of this approach are Django's generic controllers. They're just types composed of different mixins where each mixin defines certain behavior and exposes class attributes and instance methods that can be specified/overriden to configure their behavior. The generic controllers provided are just a particular combination of existing mixins that are suited for a particular problem.

Another good example is Android with it's controllers. An Acitivty is called by the instrumentation framework whenever the activity needs to respond to a certain kind of request (create yourself, start yourself, destroy yourself) with certain input, but it's all happening on a UI thread that expects these methods to be snappy. Anything substantial, such as number crunching, retrieving data over HTTP, collecting data from the DB, so forth, is actually managed by objects of some external types that communicate some data back to the calling controller. Sometimes, this communication is generic enough that it can structured by implementing interfaces and the behavior pertaining to each is specified in an anonymous class. Again, you end up with a simple controller that only wires a network of communication between different objects to define some complex behavior, but the behavior is defined in a compact form from which you can readily figure out what's going on.

This is the code reuse promised by the composition principle: if your controller's behavior needs to be migrated to a different controller or if a certain kind of behavior needs to be shared between multiple controllers, composition over inheritance provides you with the ability to do so. And what's best, by applying Liskov substitution principle, the possibilities become endless!

share|improve this answer
    
Thumbs up Filip for great answer! Extracting controller behavior into module(s) that could be tested in isolation and reused or migrated to other controllers with ease sounds really like the way to go. –  Milovan Zogovic Apr 18 '12 at 8:16
add comment

Well, to keep my code organized, I often:

  • decide to extract some controller logic to a superclass and make controller inherit from it. This way, controllers end up calling method from it and remain clean, avoiding duplication

  • same thing could be done by including modules in your controllers

  • an alternative solution would be to use a third part component such as Cells.

share|improve this answer
    
Hmm.. interesting points. Are you suggesting that "duplicate controllers" are OK as long as their implementations are not duplicate (achieved through inheritance or modules)? I've looked into Cells, still trying to fall in love with that concept :) –  Milovan Zogovic Nov 20 '11 at 8:14
    
there is no duplication when you use inheritance or module, unless ou want to override. –  apneadiving Nov 20 '11 at 10:05
add comment

I often find this problem too. I do a couple of things to fix it;

I stuff as much as i can into the models so i dont clutter my controllers and I usually make it so when you click on a project in /projects (projects#index) it will go straight to /projects/:project_id/members (members#index) instead of the default /projects/:id (projects#show). Reason for this being that the members are the main resource on the page.

share|improve this answer
    
Yes, I completely agree with that. But what if the main responsibility of the page changes over time, causing main resource to be no longer main? Should I migrate all the code to the other controller, or leave it as is? Leaving it as is can make it feel not natural as the time passes. Migrating it would require rewriting lots of specs.. –  Milovan Zogovic Nov 20 '11 at 8:11
    
If the design has changed then of course there will be rewrites to match. You must decide whether making the code maintainable over time is worth the work of those rewrites, or if time is better spent elsewhere. –  Patrick Hughes Feb 15 '12 at 18:56
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.