Rails Pacific 2014

Trailblazer A New Architecture For Rails

Trailblazer A New Architecture For Rails

by Nick Sutterer

In his talk "Trailblazer: A New Architecture for Rails" at Rails Pacific 2014, Nick Sutterer discusses innovations brought to the Ruby on Rails framework through the Trailblazer architecture. He emphasizes that Rails has maintained a monolithic MVC architecture for a long time, which can lead to complexity in larger applications. The main focus of Trailblazer is to introduce additional abstraction layers that simplify the organization and structure of Rails applications. Key points covered in the talk include:

  • Rails Architecture: Sutterer critiques the traditional monolithic architecture, stating that it often leads to complex dependencies in large applications, making maintenance difficult.
  • Trailblazer's Role: He presents Trailblazer as a solution that provides a thin layer over Rails, aiming to reduce complexities through the introduction of new abstraction layers. This change is designed to make development easier and less cumbersome.
  • Concept of Operations: Sutterer elaborates on the concept of operations, which manage high-level actions within an application. Operations encapsulate the logic needed for certain tasks, consequently promoting a cleaner separation of concerns between models and controllers.
  • Form Objects: The talk details how form objects in Trailblazer simplify parameter handling and validation, allowing for cleaner and more maintainable code compared to traditional Rails approaches.
  • Use of Cells: Sutterer introduces cells, which are designed to manage view fragments. By encapsulating view logic, cells help reduce the clutter often found in Rails helpers, creating a more organized and manageable way to render views.
  • Integration with Testing: The ease of testing operations and form objects is highlighted, demonstrating how operations can closely mimic the real application logic, providing better interfaces for testing.

In conclusion, Sutterer urges developers to consider Trailblazer as an effective framework that adds needed abstraction layers to Rails development. He believes that while Rails is robust, the addition of tools like Trailblazer, Reform, and Cells will help modernize application structures, making software development more enjoyable and efficient.

00:00:15.200 By the way, my name is Nick Sutterer—not Stutterer. Where's my beer, actually?
00:00:21.760 So, I get extremely excited. Can I walk, by the way? I don't want to just stand here.
00:00:27.439 I have extremely good news: I'm probably not going to leave Taiwan at all! It's not only the beautiful people here, but also the extremely well-brewed and high-quality beers from Taiwan.
00:00:39.520 What really impresses me is the fact that I can find two of my favorite German beers in a random supermarket in Taiwan. I've been living in Australia for about a year and a half, and they only import a select few from Germany.
00:00:51.600 You guys have all that awesome stuff! Additionally, I admire the effort that you all put into returning the empty containers to Germany, as it is required by German law.
00:01:01.920 Okay, let's talk about Trailblazer. I want to discuss Rails first because Trailblazer is a thin layer that sits on top of Rails.
00:01:10.799 Rails is quite proud of its monolithic MVC architecture. So, what Rails is famous for is its really simple setup: UI elements go into the view, persistence logic goes into the model, and everything else typically stays in the controller.
00:01:21.600 The issue I've seen with Rails over the last 10 years is that applications often end up too complex. An app might only use three abstraction layers for handling complex domain logic.
00:01:39.520 When you suggest additional abstraction layers, you're often criticized for being too enterprise-focused or for over-abstracting. People tend to react strongly to new class additions; it's seen as something that diverges from MVC principles—like something Martin Fowler would propose.
00:02:20.959 This reaction makes me a bit sad. Trailblazer actively introduces these additional abstraction layers into Rails to help you escape from the misery of complex Rails applications.
00:02:28.959 Trailblazer aims to provide a more elegant architecture that makes developers happy. It allows you to go home feeling proud of the awesome component you created—a component that's not going to break regardless of what else changes in your application.
00:02:40.239 Trailblazer is here to simplify your life, not to overcomplicate it. A friend of mine once tweeted that 'Rails is so 2005.' While I think the innovation level in Rails back then was amazing—introducing concepts like test-driven development and generators—the architectural innovations have stagnated.
00:03:23.680 In the last ten years, the architectural components of Rails have seen little change. We still largely rely on the MVC framework. While I think Active Record is still a fantastic component of Rails, it isn't the entire framework.
00:04:07.360 This is why I feel a bit disappointed about the lack of innovation—despite positive additions like template lookup context and Active Job, which decouples background jobs. However, many changes seem more like fixes for existing issues rather than true innovations.
00:04:35.199 For instance, improvements like nested attributes often complicate things further and stem from earlier design flaws. The concept of MVC has been deemed sufficient for application architecture, but thankfully, we have Trailblazer.
00:05:04.960 Trailblazer brings new abstraction layers, classes, and concepts into the Rails architecture. In this talk, I will specifically discuss operations and how form objects work with operations, as well as the view layer and cells.
00:05:31.360 The first thing I love about Trailblazer is the new file structure. Instead of the traditional app controller and app view, we now have app concepts, which contain the actual components we're working on.
00:06:05.280 This way, all assets and classes reside in a single directory, promoting organization. Another goal of Trailblazer is to create logic-less models, so your model classes ideally only contain associations.
00:06:21.120 You won't directly interact with models anymore; instead, you'll be working with the persistence layer through operations.
00:06:46.560 To explain operations, I want to touch on high-level domains. Every application has a high-level domain—in my example, a coffee shop rating application.
00:07:02.320 This application allows users to search for coffee shops, view their details, add comments, and follow their favorite shops for notifications.
00:07:15.360 Typically, when we talk about an application, we focus on high-level domains instead of implementation details. For example, we say, 'My application allows you to add a comment to a coffee shop' without discussing how the comment is saved.
00:07:30.880 Users interact with the application through these high-level domains just like a machine would use your API. These points are essential as they define your application. When explaining your app to someone else, like your mom, you highlight these high-level concepts rather than the technical implementation.
00:08:07.920 What I wanted in Trailblazer with Rails was to have those high-level endpoints clearly defined in separate classes or files. This way, I can map my domain effectively and ensure that implementation details are accessible for both user interfaces and API endpoints.
00:08:49.920 When setting up a high-level domain in Trailblazer, we organize our public API steps in operations—like creating, commenting, showing, and following a shop. Namespacing is crucial to avoid clutter and confusion as we define these operations.
00:10:04.320 To trigger an operation, you use square brackets and pass the necessary parameters, which returns the operation instance. You can also run the operation with a block that executes only if the operation is valid.
00:10:46.840 An operation can also be passed to a responder, making it functionally similar to an Active Model, allowing the appropriate view to render or error messages to display.
00:11:14.080 The operation concept enables us to change the application state using a well-defined interface that's usable in various environments. However, it's important to note that operations are not simply calls to models.
00:11:47.440 In Active Record, the problem is every different step—creating, deleting, updating—resides in a single model class. There are callbacks for default behaviors, which can lead to complexities if you need different validations for create and update scenarios.
00:12:56.960 The operation concept allows us to encapsulate these requirements cleanly without convoluted logic.
00:13:17.840 By defining an operation for each high-level step, we maintain clarity and cohesion in our code structure. The process method in an operation receives parameters from the application.
00:13:38.080 An automatic feature of the operation is its capability to find the appropriate models, although this behavior can be customized. Validations happen by utilizing a block where logic can be implemented if the operation evaluates as valid.
00:14:06.560 This approach greatly simplifies the process of distinguishing between valid and invalid operations. The operation's internal structure remains hidden, leading to a clean and understandable interface.
00:14:38.360 Every operation has a form object that defines properties for incoming parameters and any related validations. Should an operation fail its validation, the execution of the validation block does not occur.
00:15:06.720 The validation encapsulated in the form object enables a cleaner structure compared to traditional Rails methods that often intertwine controller and model logic.
00:15:27.360 Operations are designed to handle about 75% of typical application logic without excessive if and else conditions, making error handling and logic extension straightforward.
00:15:49.440 However, operations also allow for flexibility outside the typical validation block. You can implement custom logic directly in the process method as needed.
00:16:13.520 Reform is an additional gem that makes using form objects in Rails easy. Unlike traditional Rails, which combines multiple layers of logic in models, form objects provide explicit management for parameters.
00:16:38.960 With Reform, you define properties and validations for each field, allowing for a nested structure that represents complex relationships cleanly.
00:17:04.080 Testing form objects is also straightforward, as you simply instantiate the form, pass in the model you wish to represent, and invoke the validate method.
00:17:31.440 Form objects in Trailblazer help to ensure that incoming data is validated before it interacts with a model. This also means that only valid data will influence your application state.
00:17:51.680 In Reform, the validate method returns true or false based on the validation state, and you can inquire about errors directly.
00:18:11.760 This allows more extensive control over your forms without directly touching underlying models until you're ready to save.
00:18:27.920 You can render forms easily using helpers from Rails. In contrast to the conventional Rails model, Trailblazer maintains a greater separation of concerns.
00:19:06.560 Multiple forms can be created for a single model, or one form can manage multiple models efficiently, by passing relevant objects into the constructor.
00:19:39.280 As a consequence, each form object is also capable of processing JSON and XML formats due to its reliance on the Representable gem.
00:20:08.000 Although my talk is limited to thirty minutes, I recommend looking into Representable for further reading.
00:20:30.400 Reform is versatile, capable of adapting to incoming data formats without diminishing the validation integrity.
00:20:55.680 In conclusion, Reform provides a way to manage forms smoothly within a broad spectrum of data sources, ensuring that your Rails applications remain resilient.
00:21:22.800 I'd like to wrap up by discussing Cells, which are useful for managing fragments or components within a Rails page.
00:21:52.320 Using Cells, we can avoid excessively complex helper methods while also maintaining structured, testable components.
00:22:33.440 Cells can encapsulate their rendering logic while remaining contextually aware of the data they require.
00:23:15.600 Finally, I just want to emphasize that Trailblazer encourages you to enhance the way you architect your applications without imposing unnecessary complexities. Thank you for your attention!