It all began in 1979 when Trygve Reenskaug outlined the Model-View-Controller (MVC) pattern for a Smalltalk application at Xerox research labs. The initial implementation was designed to allow users to both control and interact with a large and complex set of data. Big deal, right? Well, before MVC, a reoccurring problem with many applications surfaced when business logic, presentation, and functionality were intermixed. As project requirements changed, such as a new graphical interface or a new data source, the application structure became more difficult to maintain. This, in turn, weakened the stability of the system and could eventually lead to a complete rewrite. The Model-View-Controller pattern, or MVC, broke business logic, presentation, and functionality into separate, self-contained pieces. Now, that is a big deal. MVC set a new standard for application development and was readily embraced by the development community.
In the next twenty years, numerous emerging technologies were developed using the MVC architecture pattern. NextSTEP, Java Swing, and Microsoft Foundation Classes (MFC) are just a few notable examples. With the rapid expansion of the World Wide Web and growing demand for web-based applications, the MVC pattern found itself in such well-known web frameworks as Jakarta Struts and WebObjects. While these frameworks were based on a clean pattern, the obscure configurations and slow development cycles have driven some developers to build a framework that embraced the MVC pattern in a clean and simple manner. Thus, the Ruby on Rails framework was born. Let's take a deeper look at the pattern itself.
The primary functions of the model are to access and modify data, all the while maintaining the current state and of an application.
Imagine that you’ve built a payroll application. In the database, you store the hourly rate and number of hours worked per week for each employee. If Cliff worked 50 hours last week, 10 hours of overtime pay would need to be calculated, assuming overtime is any time worked beyond 40 hours in a single week. In order for the application to return the proper amount to pay Cliff, it would need to run through a series of calculations. It is the model that this business logic would be stored and executed.
When thinking about models in relation to data, it is important to understand that any unrelated groups of data should become separate models. Each group of data is self-contained, this means that you can, in theory, add and modify models without affecting other sets of data.
The model presents data but is not responsible for displaying it.
The primary function of the view is to render how the data from an application is displayed.
Let’s come back to Cliff’s paycheck for a moment. In order to generate a properly formatted check, we would need to display all the pertinent information—name, address, amount, and date. How this information is displayed on a screen and then printed onto the check is handled by the view.
The view allows an application to display multiple representations of the same data, such as Cliff’s individual paychecks, a list of all his paychecks, or his check amount in a list of all employee paychecks for last week. Each of these instances relies on the same models to provide the data, but use separate views to render it.
The view renders data but does not communicate directly with the models.
If the application were a symphony orchestra, the controller would be the conductor. A controller is what coordinates the flow of an application by handling user input and then responds with the proper view to the client.
After printing Cliff’s paycheck you might reflect on the quality of his work and decide to give him a raise. You fill out the form to modify employee wages and hit the save button. The controller accepts your input and notifies the model to do something with it, in this case, give Cliff his well-deserved raise.
It is within a controller that one would program the logic for handling user interaction. In our example, when you post the form, your controller would determine what sequence of events should occur after you hit submit. If you were saving a record to the database, the controller could call the save or update method in the corresponding model. After your data has been saved, the controller would determine which view to render to the client next.
The controller communicates with both the model and the view, as they should not directly talk to each other when following the MVC pattern.
Putting it All Together
The model, the view, and the controller are independent of each other. Future changes to any of these three components should have little to no impact on the other two components.
Let’s suppose that our payroll application has been picked up by another company and they want to redesign the look to match their corporate branding. With MVC, all they should need to do is modify the views. The company is also planning on moving to another country, which would mean a change in their payroll requirements. Again, with MVC, all they should need to do is update the corresponding models where this business logic is located. MVC allows you to make adjustments in one area without sacrificing or interrupting functionality in another.
Many web applications use themes to easily switch between any number of designs and layouts by using different stylesheets and template files. Take your average weblog application or your favorite media player with its numerous skins. Both of these take full advantage of the how the MVC pattern separates the user interface from the logic and functionality of the application. Likewise, Ruby on Rails takes full advantage of the MVC pattern by providing you with a pre-defined structure that not only makes it easy to follow MVC but also encourages you to build applications with unknown future changes in mind.
Speaking from experience, following MVC can save you a lot of headaches when unexpected modifications must be made.