Noel Rappin, Friday, August 15, 2008 @ 3:32 pm
(Image comes from the Rails Envy MVC public service announcements -- and I hope they don't mind)
Here's the question:
Describe the MVC design pattern as it is implemented in Ruby on Rails.
And the followup:
In an MVC design, where would you place complex business logic?
This is part of the standard phone screen we give to potential Rails developers. The expected answer goes something like this:
MVC stands for Model, View, Controller, each of which represents a section of the application. The model manages data and often persistence, the view manages presentation, and the controller mediates between user actions and associated models and views. Each of these three subsystems should have as little interaction with the others as possible. Complex business logic should go in the model, since that is the section that deals with business objects.
If your doing a phone screen with us after this, at least have the decency to phrase that in your own words...
I don't think of that as particularly controversial, although I suppose you could pick at the wording and details to taste. Interestingly, or oddly, or something, the recent stretch of phone interviews has had a nearly unanimous answer to the followup question: Controller (sometimes, to be fair, the answer would be controller and model, but with controller as the primary answer).
After a brief time-out to check my sanity and calibrate with some other people (like the video with guys from the picture), I came out of the process with the following few thoughts:
- I have no doubt, from my phone calls, and from some Rails code I've seen in the wild, that it's very common to put complicated logic in the controller.
- I still think that's a bad idea, at least in Rails.
- Why #1: That's where the data is. Putting logic about which find methods to use and so on in the controller makes the controller too knowledgeable about the details of the model. This makes you vulnerable to changes in the model later on, and makes the controller more brittle.
- Why #2: It's easier to keep code from repeating itself if the logic is in the model -- that is, it's more likely that multiple controllers or controller actions will need the same set of logic from the model. From a maintenance standpoint, it's best to have that in one place. The logical place for that is the model.
- Why #3: In Rails, is significantly easier to unit test models than it is to test controllers.
- In my own coding, I try to limit controller code to an assignment statement that calls a model method, a single line action on a model (such as save), and logic to determine which view to call. The right hand side of the assignments goes in the model, and as much of the other logic as possible goes in helpers.
- The main exceptions to the rule is that I'll put some parameter parsing logic and the like in controller private methods, and also I'll include simple RJS stuff in an
update :page in the controller.
- It's kind of a small sample size, but I think that the tendency to put logic in the controller corresponds with a lack of test-driven development. The theory goes like this: if you are doing a reasonably strict TDD process in Rails, you tend to start in the model because that's the easiest part to test. As such, your business logic tends to wind up in the model. If you aren't using TDD, you tend to start off coding in the controller, because that's the first point of contact for the request. If you also aren't refactoring much, then your complicated winds up in the controller. Anyway, it's a theory.
Related posts:
- Rails Worst Practices: 13 Coding Nightmares You Should Avoid
- From JSP to Ruby on Rails: First thoughts on front-end coding conventions
- The Testing Interviews
- DRYing up Rails Controllers: Polymorphic and Super Controllers
- Rails Test Prescriptions is now on sale