Test-Driven Development

Properly Factored MVC

Properly Factored MVC

by Katrina Owen and Jeff Casimir

The video 'Properly Factored MVC' presented by Jeff Casimir and Katrina Owen at RailsConf 2013 explores the principles of the Model-View-Controller (MVC) architecture as applied in Ruby on Rails. The session addresses the evolution of Rails applications and emphasizes the importance of maintaining clean, modular, and maintainable code as projects grow. The presenters acknowledge the challenges encountered in long-lived software development, highlighting common pitfalls and best practices in refactoring.

Key Points Discussed:
- Effective Communication: Challenges in software projects often stem from communication issues that create mismatches between expectations and reality.
- Understanding MVC: The ideal flow of MVC is explained, emphasizing the roles of the router, controller, model, and view. In reality, the responsibilities can become tangled and chaotic, especially in controller and view interactions.
- Refactoring Importance: Refactoring is framed not just as code alteration but as a process for improving the quality and adaptability of the code. Best practices encourage starting with a simple version of the code and iteratively enhancing it.
- Testing Foundation: Establishing tests around the initial code ensures that functionality is preserved while improvements are made.
- Iterative Improvement: Refactoring should focus on maintaining functionality while simplifying the code structure and isolating logic within classes. This is facilitated through clear and concise naming conventions to enhance readability.
- Tutorial Resource: The presenters provide a tutorial for attendees aimed at applying these principles post-conference, promoting active discussion and community learning.
- Heroku Workshop Reminder: The video concludes with an invitation to a performance workshop covering optimization strategies for Rails applications, emphasizing real-world application of the discussed principles.

Overall, the presenters encourage developers to critically analyze their code and aim for a modular, adaptable structure that enhances both understandability and maintainability, stressing the continuous nature of the refactoring process to achieve effective software design.

00:00:16.800 Please don’t take anything that I or we say today to mean that whoever wrote this is an idiot. They clearly focused on the goal of delivering the features they wanted to implement, and they succeeded at that goal. Today, we can use their success to help us pursue a second goal: to improve the quality of the code, making it cleaner and more resilient to change.
00:00:36.640 This software project started in 2006. At that time, as a community—particularly the Ruby on Rails community—we did not know which choices would eventually hurt us. We were making a lot of decisions with no clear idea about their future implications. This project has not only solved the problem it set out to address, but it has also survived, with 200 forks and active development. They keep releasing new versions, and many people are using it. In many ways, it is a success story, despite some of the growing pains inherent in long-lived projects.
00:01:02.879 When people new to the community think about open source, they often feel they should contribute right away. They imagine new features that Rails needs, and when they can’t come up with those ideas, they might decide to build something themselves and contribute it back to Rails. However, that’s a significant jump to make. It is much more practical to find an existing open source project, possibly one you’re already familiar with, and experiment with it. This way, you can benefit from trying it out, downloading the app, and making improvements before contributing back.
00:01:28.239 I’m Jeff Casimir, and this is Katrina Owen. We run a company called Jumpstart Lab, which provides technical training for companies. Our time is currently spent on a six-month developer training program in Denver called G-School. Previously, we ran Hungry Academy at LivingSocial.
00:01:48.000 So why do Rails projects go wrong? Generally, the chorus on why software projects fail is that it's due to communication issues. For projects to face significant challenges, communication problems must create mismatches between expectations and reality. But even with clear expectations and good communication, Rails can set projects up for trouble. Let’s start by discussing MVC theory and how it should ideally work. The process works like this: the application receives a request, which goes to the router, then to the controller, then to the model, across to the database, and back to the model, the controller, and finally to the view, which returns a response.
00:03:11.920 An HTTP request arrives, hits the router, which determines who the request belongs to and what the user intends to do with it. The router passes that information to the controller, which ideally acts as a middleman with minimal responsibility, merely receiving and dispatching information to other components in the system. It takes necessary information from the router, passes it to the model, which performs the essential processing. The model retrieves data from the database, formats it, and sends it back to the controller.
00:04:02.880 This idealized flow illustrates how it works, though reality is often messier. Despite clear agreements on how it should function, the code has significantly changed over time, especially within Rails' Active Record. Many understand what an Object-Relational Mapping (ORM) tool should accomplish, which has allowed for extensive improvements. However, if you were to examine a Rails 1.0 app from 2006, its controllers and views would still work right out of the box. There have been additions, but the fundamental approach hasn't evolved significantly.
00:05:30.680 In a realistic scenario, however, each component has numerous responsibilities. The controller must process incoming requests, pull parameters, and determine what actions to take before passing these down to the model. The model, in turn, communicates with the database and needs to perform business logic as it processes the data. After working with the database, the model returns data to the controller, which then prepares the results for the view.
00:06:30.640 Explaining data transfer from controller to view often becomes complex. In Rails, you simply define an instance variable in the controller to make data available in the view. However, this creates a complicated system where the controller generates a view context, an anonymous class created on the fly, which pulls instance variables and supplies them to the view. A good way to explore this complexity is by inspecting a view template, returning thousands of lines with various repeated parameters.
00:07:35.680 It's a chaotic situation that begs for a better solution, and perhaps someday, a fix for Action View can be realized. But the complexity of what the controller does is worrisome. A controller handling numerous responsibilities can quickly become unmanageable. While we often talk about a 'fat model, skinny controller' approach, promoting concise controllers remains a constant goal to strive for. If a controller method exceeds about seven lines of code, it’s time to reconsider your approach. Some controller methods can grow to dozens or even hundreds of lines, especially when multiple parameters need to interact in different ways.
00:08:24.320 Let's discuss refactoring—specifically, how it relates to what Katrina excels in. Refactoring is often misinterpreted, sometimes used to critique others' codes, including one's past self. The critical aspect of refactoring isn't simply changing code—it needs to follow a structured process, and that’s where tools like Tracks help.
00:09:30.640 Refactoring should not produce external changes in the application. It’s only feasible if the existing code functions correctly. Therefore, we often advise students to write the simplest working version first and improve it later. Focusing on the implementation’s initial crudity allows them to build tests around it, establishing expectations and ensuring the desired outcomes. Once tests are in place, it's easier to enhance the code incrementally.
00:10:37.920 Our goal is to increase the code's adaptability—mostly accomplished by breaking it into manageable chunks that can be recombined in interesting ways. Katrina has created a detailed tutorial for attendees. Given it's the third conference day, remember to connect to the alternate Wi-Fi network named on_rails to access the necessary tutorial files at RailsConfTutorials.com.
00:11:41.520 The tutorial is extensive, likely taking learners several days to explore completely, but it offers a valuable basis for applying these principles in your own work post-conference. We're available to answer questions intermittently, encouraging everyone to participate in discussions.
00:13:01.600 Please share your questions with one another before reaching out to us; this often leads to clearer comprehension and deeper understanding of the concepts at hand. Feel free to utilize the chat room so everyone can benefit from shared queries, allowing us to better address common challenges when breaking into groups later on.
00:14:09.920 Tonight, there will be a Heroku performance workshop that promises to be engaging. Join us as we cover strategies on optimizing applications, particularly for Rails apps, with food provided. We will explore topics such as using threaded forking web servers, cashing for improved performance, and optimizing database queries. Participants will have the chance to apply what they've learned to a sample app for hands-on experience.
00:15:50.640 The coding process for refactoring is often tedious, involving the incremental renaming of variables and methods. However, each minor improvement compounds, leading to a significantly clearer codebase. The primary goal here is to maintain functionality while simplifying by isolating the logic within classes. Therefore, our efforts will continually aim to minimize the code's complexity while refactoring.
00:16:45.440 Refactoring proceeds through careful examination to remove redundancies and ensure each method name and variable serves a clear purpose. In discussions about naming, clarity becomes important: the aim is to ensure that every word in a variable or method name adds value. Long complex names often detract from readability; clear, succinct names help foster better understanding and maintenance.
00:18:17.280 In summary, the process is an iterative journey. Each step toward improvement moves the code closer to a healthier state, helped by a solid testing foundation. We hope you found this discussion helpful, and we encourage you to apply these thoughts to your own code for improved modularity.
00:19:37.760 Let’s review how this tutorial can help you navigate these challenges. During your exploration, reflect on both the successes and the pitfalls of previous versions of applications to critically analyze the choices made. The combination of conscientious refactoring with solid testing practices helps build code that remains flexible and easy to understand.