Jim Gay

Panel: Rails vs. OOP

This video was recorded on http://wrocloverb.com. You should follow us at https://twitter.com/wrocloverb. See you next year!

A lot has been said recently about the topic of Rails and OOP. We consider this issue very important in our community. This fight is all about the recent OOP movements in the Rails world. There are quite a few problems that people focus on and quite a few proposed solutions.

wroc_love.rb 2012

00:00:11.920 Hi, my name is Nick. I was very drunk yesterday. Don't tell my mother about it! How are you all doing? It's still about 80% of the crowd from yesterday, so that's pretty good. So, this keynote is about monolithic applications.
00:00:31.519 Rails is a web framework that's quite popular for building monolithic applications. But what is a monolithic application? Essentially, it’s a large piece of software that can be difficult to maintain; a lot of people find it a challenge. Why is it hard to maintain? The problem is that there are many dependencies within the application. If you change a dependency in a monolithic system, it can break other parts without you even noticing. Rails is a great framework; it introduced testing and made it quite popular in software development.
00:01:14.880 However, it often encourages you to build monolithic applications. This means that all your models, all your business logic, and all your view logic are contained within one application, leading to the very dependencies I mentioned. My issue with Rails is that there isn’t really a good approach to building componentized applications. Rails 3.0 improved the internal architecture of the framework, but we still end up with a single, cumbersome application to manage everything.
00:01:43.920 One thing that Rails 3 did do to help is with the new router. You can mount any Rack application under any URL. For example, you could mount a Sinatra app inside of Rails. If you have an API at api.mydomain.com, you could write your API in Sinatra, put it in a class within your application, and then mount it to a specific route. This provides a slight modularization; although it's not the same as having completely separate apps and repositories, it still helps.
00:03:00.160 In Rails, there is a concept that your protocol is your database. Essentially, everything is interacting through the database level. Ideally, separate systems should communicate using protocols like REST or SOAP, not through the database directly. This is a significant issue in Rails: all communication is based on the database. Consequently, you have to access any part of the system through specific models, which is something I’m critical of. I prefer REST and similar approaches because they force you to think about interfaces and interactions at a protocol level rather than a database level.
00:03:54.000 There are cases where people attempt to use a database as a locking structure when they should be using job queues or similar mechanisms. Rails does not inherently present a problem; rather, it's the way we define a monolith. People often equate monolithic applications with poorly designed software. Just because an application is large doesn’t mean it is poorly designed; it could follow good encapsulation and the single responsibility principle. You can still practice object-oriented programming without having to shove all your models into the database.
00:05:05.760 The culture is shifting, but in the past, Rails generated scaffold-like commands brought a specific mindset. The solution could be similar to how GitHub operates: a collection of small applications that communicate with each other, allowing easy replacement. There's an idea thrown around that if a piece of code is more than 100 lines, it should probably be a separate application.
00:05:48.720 Is it more complicated to build small applications and connect them or is it actually simpler in the long run? DHH made a valuable point about Rails being perceived as no longer suitable for beginners, which actually isn't true. Rails might be easy to get started with, but when you want to build more advanced applications, you will find that the available resources and information on building well-designed applications are much improved now compared to the past.
00:06:59.600 We used to jam everything into Active Record models. If you wanted to store data, it had to go into Active Record. If you needed behavior, you also needed a database table. We've certainly evolved, and while you can start with Rails, I believe it’s important to understand that the learning curve is not necessarily as steep as some think.
00:08:08.560 Additionally, I wanted to share an experience I had with a REST project. We aimed for small systems rather than building a monolithic application. For example, we had individual projects for products and users. Instead of relying on Ruby API methods, we communicated using REST API documentation. When the product project encountered an issue, we could pinpoint responsibility, which is far more challenging in a monolithic app.
00:09:33.200 On a personal note, every time I try to build a Sinatra app, it fails, and I end up rewriting it in Rails anyway. Sinatra is appealing, but ultimately, I find that Rails never fails me, even if I have regrets from time to time.
00:10:00.160 There's also a connection to the idea of package content separation. Is the content a separate application, or is it just part of the main application? As for decorators, they are a specific type for presentational logic. A presenter is essentially a decorator designed for presentations.
00:11:00.800 I believe it ties into the idea of separation between domain objects and their responsibilities. Presenters can help you split domain objects from rendering logic, akin to how we often use helpers. One particular library I maintain is Draper, designed for Rails view integration because Rails views can be quite complicated.
00:12:10.399 Draper allows for complex objects to present statistics neatly, simplifying code and making it much more testable because it represents the actual domain of the view. Cells are another interesting approach for creating components that I have considered, but Draper serves my needs in managing Rails view complexity.
00:13:16.400 In terms of instance variables within views, I’ve found it beneficial to avoid using them. Instead, I prefer to use helper methods in my controllers to initialize necessary resources, maintaining cleanliness across my views and avoiding clutter with instance variable names.
00:16:05.120 Also, Uncle Bob touched on focusing on the behavior of objects rather than purely on data. Rails is often criticized for adding layers but, at its core, can be optimized by emphasizing behavior through plain Ruby objects rather than complex data models.
00:16:56.640 We should model our domain distinctly to ensure we don’t cling to outdated structures. Carefully designing how objects interrelate and their responsibilities lays a foundation that can easily adapt to future needs.
00:17:50.520 However, we do need to consolidate how we view application layers. Maintaining three levels (model, controller, view) can become cumbersome, mainly if one simply ends up passing messages back and forth without clear direction.
00:18:58.480 The idea of using a single API endpoint encapsulating complex service interactions can streamline communications, allowing for more straightforward designs. Focusing on defining workflows rather than raw data interactions makes for cleaner integrations.
00:20:23.760 I believe developing separate service applications should occur only after establishing maturity within your business logic. Rolling back or refactoring an immature design can lead to chaos, making the process much less efficient.
00:20:52.560 The conversation on Rails emphasizes that while it can be limiting, it’s also incredibly powerful when used correctly. The best applications focus on simplifying API calls while managing complexities elegantly.
00:22:38.160 With a discussion on design principles, we should recognize that while Rails has established conventions, it shouldn’t dictate all aspects of programming. Embracing modularity in design allows for flexibility, ultimately leading to improved maintainability and scalability.
00:23:56.160 While the conversation evolves, identifying techniques from other languages and frameworks can inspire our growth within Rails. AOP (Aspect-Oriented Programming) can introduce non-functional requirements, such as logging, to domain objects without overwhelming the core logic.
00:24:59.760 It’s an essential practice to minimize the public interface of an application to remain focused. Each public method should serve a specific purpose without clutter, making testing more manageable and improving object encapsulation.
00:26:41.040 The principle of keeping objects minimal can lead to enhanced reliability since we can assure that these components will perform adequately under varying conditions. The encapsulation of behavior over data paints a clearer picture of our application’s functioning.
00:28:42.560 Designing our systems around these behaviors offers better maintainability paths. By keeping systems focused solely on their roles, we enhance how developers interact with software components.
00:29:53.760 Finally, the field of software development is frustrating yet fascinating. The evolution of Rails highlights this dichotomy as both a convenience and a restriction; however, its continued development suggests that it remains a valuable tool for many applications.
00:31:18.960 While everyone has their criticisms of Rails, innovations like DCI highlight a shift in thinking. The community's growth is collectively learning to embrace modular and encapsulated designs, all built with a focus on behavior rather than just data.
00:32:44.640 In the end, using Rails doesn't have to mean adhering strictly to its conventions; we can blend practices from various approaches while capitalizing on what makes Rails a suitable choice for many developers. It’s about finding the balance that works for each development team.
00:34:29.680 However, we also need to be mindful of other frameworks and languages, as their solutions can inspire better practices in Rails. Discussions around best practices help the community grow and innovate on their designs and applications.
00:36:04.880 As we look at application separation and integration, we maintain that clear delineation between services is crucial. These boundaries allow for better testing, easier tracking of issues, and ultimately lead to better software development.
00:37:38.960 Additionally, it’s essential to remember the implications of our designs as we implement them over time. Keeping a close eye on the charge of APIs and ensuring they align with how our systems intend to function fosters a healthier software process.
00:39:34.240 We have to grow and adapt, and sometimes that means refactoring our ideas as we learn from our mistakes and experiences. In doing so, we can create shared understanding and best practices that lead individualized paths to success for each development team. Thank you for your attention!