Refactoring

Summarized using AI

Counterintuitive Rails Pt. 1

Ivan Nemytchenko • April 16, 2018 • Wrocław, Poland

The video titled 'Counterintuitive Rails Pt. 1' features Ivan Nemytchenko discussing the complexities and challenges faced by developers when using the Ruby on Rails framework. During his talk, he emphasizes the need for better management of complexity within Rails applications and provides insights into effective practices that can improve code organization and maintainability.

Key Points Discussed:

  • Managing Complexity in Rails: Nemytchenko highlights how developers often suffer when using Rails due to a lack of explicit rules and guidelines in managing their code, leading to common pain points.
  • Empiric Rules and Best Practices: He reflects on the implicit rules developers create, such as avoiding callbacks and maintaining fat models with skinny controllers. These rules are often individual to one’s experience but can become unmanageable as projects grow.
  • Learning and Adapting: The speaker advocates for continuous learning and the incorporation of new techniques, emphasizing the need to control the power afforded by Ruby and Rails tools.
  • Organizational Structure in Projects: He critiques the flat structure of models and controllers in Rails applications, suggesting an alternative approach based on entity dependencies to improve clarity and organization.
    • For instance, he describes using a folder structure that relates to an article and its comments to maintain organization as projects scale.
  • Domain-Driven Design: Introducing principles from Domain-Driven Design, he recommends separating different contexts in a project to reduce complexity and enhance maintainability.
  • Avoiding Complexity: Emphasizing the importance of avoiding unnecessary complexity, he advises prioritizing simplicity in code and discussing complex development paths with business teams to find more straightforward solutions.
  • Separation of Concerns: Nemytchenko stresses the significance of clean architecture where services encapsulate single business processes and controllers manage operational flow without mixing business logic.

Concluding Thoughts:
Nemytchenko brings to the forefront the need for engineers to be disciplined in their approach to development, advocating for structured organization and a focus on clarity. He notes that many Rails applications struggle with layering and dependencies that complicate future refactoring. Overall, he encourages developers to examine their practices critically, adopt more effective structures, and avoid both code bloat and unnecessary complexity within their projects.

Counterintuitive Rails Pt. 1
Ivan Nemytchenko • April 16, 2018 • Wrocław, Poland

wroclove.rb 2018

00:00:24.270 Before we start, let me ask you to follow this link. Open it and answer a couple of questions while I go through this introductory part. It will give us a lot of interesting data, which I'll show you tomorrow before the second part of my talk. I believe we will learn a lot about how we use Rails and how we manage complexity within it. I think it's pretty important, and it will be interesting.
00:01:08.369 So we all love Rails, and that’s why we’re here. However, we know that sometimes it can make us suffer; it can hurt us. Sometimes, we switch to new projects with the hope that this time it will be different. In some cases, it is different, but in a new way, causing us to feel pain in a different manner. Some of us develop new frameworks, new languages, or just switch to other languages because we can no longer deal with the pain.
00:01:50.880 But what about the rest of us who are just trying to get our job done? I believe we have developed some empiric set of rules or habits on how to deal with Rails. For example, avoid callbacks if possible, no concerns, please; fat models and skinny controllers. This is just an example. Everyone has its own set of rules, and we try to follow them, but they are not explicit; they are more like implicit ones.
00:02:14.660 Of course, we try new techniques. We visit conferences, hear new things, and attempt to incorporate these techniques into our software development practices. Another point I'd like to make is that Ruby is a powerful language; it allows us to build many handy tools. However, we can often waste the beauty of these tools, as power can indeed be dangerous and sometimes harmful.
00:02:57.000 Despite my appreciation for the new style of conference websites, I want to highlight that the previous one actually reflected very important ideas: we need to learn how to control our power. Good teams develop constraints that allow them to manage that power effectively. To summarize, I've coined a rather silly name to encapsulate the main idea I want to present.
00:03:50.920 Now, a bit about me: I started using Rails back in 2006, which feels like a long time ago. I have a diverse background in programming, freelancing, working with agencies, attending conferences, teaching, and various other activities. I spent time in a role as a European developer advocate, but in that role, I didn’t get to touch any code, which was quite unfortunate. Nevertheless, I have plenty of stickers to share, which is always a perk in the development world.
00:04:19.490 Three years ago, I found myself in the same spot as many of you, feeling a bit lost. That was when I began to discover design patterns, the SOLID principles, and how to apply them in my Rails applications. I documented the things I learned on a website and even began writing a book. If you leave your email there, you can receive the first chapter, although I must admit, there are no further chapters yet, as I find myself in a situation where I have more questions than answers.
00:05:06.659 As for how I ended up here today, I haven’t been actively developing with Rails in the past three years. However, I recently decided to refresh my Rails knowledge by taking on a new freelancing project. I attempted to apply what I remembered and developed the project using techniques like services and form objects. However, I wasn't entirely satisfied with the result.
00:05:50.820 Fortunately, I attended a workshop conducted by another Russian developer that lasted two and a half days, and my mind was blown by what I learned. He was essentially teaching me the concepts I wanted to write about in my book. Since I didn’t have an active project to apply my newfound knowledge, I applied to speak at a conference, hoping to consolidate my understanding and share it with others.
00:06:45.920 I submitted a proposal to the most thoughtful Ruby conference. The organizers were so impressed with my proposal that they even removed two speakers and gave me prime time slots on both days. And that’s how I ended up here. Let’s finally start with some statements. I want to make it clear that while I may not be the most well-prepared speaker, I intend to be the most impactful, or at least to provoke your beliefs.
00:07:59.440 Let's use our imagination for a moment. What would be an ideal system we want to build? An ideal system must resist bad code, much like React does. In React, even for a junior developer, it’s relatively hard to write bad code because of its structured layers. It doesn’t mean it’s impossible, but it does oppose bad practices.
00:08:56.700 The second point is that the system we build shouldn’t fight against its framework. Instead, it should leverage defaults whenever possible. Lastly, there should ideally be only one way to accomplish a task. Programmers shouldn’t be artists led by inspiration, but engineers who analyze options, choose the best path, and standardize it.
00:09:15.130 However, we have to deal with reality. Sometimes we're lazy, or perhaps we’re just tired. We have many external factors to consider, such as family, and at times we don't have the mental capacity to reflect on the decisions we're making. Relying solely on discipline to construct such a system is, I believe, unwise. Discipline consumes mental energy, which can be costly.
00:09:50.680 When a system demands extensive discipline, it resembles a labor-intensive project. There is a theory, a practice, and a dream; theoretically, everything is beautiful, but in practice, reality often falls short. We know there will always be some level of 'dirt' in our code, which we must deal with. Attempting to build beautiful abstractions is great until they reach a level where they start to crumble.
00:10:53.580 However, it is important to note that the presence of problems and 'dirt' is not an intrinsic issue, as long as it does not expose your system’s weaknesses and helps to build a solid framework. We are finished with these statements, and now we can move on to discussing beliefs.
00:11:44.540 The first belief we've developed is a flat model structure. We have a models folder where we place everything, which works fine for small projects. However, as projects grow larger, challenges arise.
00:12:03.130 For instance, in a project I worked on, we had 17 models in a single folder, which quickly escalated to 130 models without any folder structure. This presents a significant challenge for anyone trying to navigate and understand the project’s organization.
00:12:49.930 Instead, I suggest using a structure based on entity dependencies. This method is somewhat related to the idea of an aggregation root. For example, if you have an article with comments that are tied to that article, create a folder for that article and keep everything related to it there to enhance clarity.
00:13:35.940 This approach not only improves understanding of your application but also underscores the relationships between your models. It’s supported by Rails, which facilitates the use of namespaces and enhances clarity throughout the project. Starting with this structure from day one can save significant refactoring headaches later on.
00:14:10.450 The same applies to the flat controller structure. Initially, we can have a controllers folder where we place our files but as the number of controllers increases, the logic within those controllers can become convoluted, often hiding complex conditional statements throughout.
00:15:28.640 We often apply the respond_to method without fully understanding its application in our systems. In small-scale scenarios, it might seem harmless, but as complexity increases due to multiple representations of the same resource, the maintainability of your code can decrease.
00:16:20.020 Using REST represents our resources through various formats and requires clearer boundaries within controllers. By creating separate namespaces, we can simplify the routing and organization of our application, avoiding unnecessary complexity while enhancing clarity.
00:17:55.840 Applying Domain-Driven Design (DDD) principles offers an additional perspective where we can identify bounded contexts. For instance, if we have an article that requires different representations for authors and moderators, we should treat these as separate contexts rather than complicating our validations within a single controller.
00:20:03.230 This principle eliminates the need for extensive conditional logic, yielding a cleaner implementation while balancing responsibilities among different controllers. The advantages become apparent when considering the simplicity in understanding application flow and authorization processes.
00:21:32.390 Let's move onto the crucial subject of modularity. At its core, modularity means there should be no circular dependencies impacting your models, controllers, and services. Controllers should be completely decoupled from the model logic, ensuring a clean architecture that allows for scalability and maintenance.
00:22:41.650 Unfortunately, many Rails applications blur the lines between layers, introducing global states and dependencies that complicate refactoring and application growth. Using too many gems that violate the MVC architecture can lead to blurred responsibilities, creating a tangled web of interactions that are difficult to manage.
00:23:45.870 To develop effective services, we must prioritize clarity. A service should encapsulate a single business process rather than acting as a mix of multiple responsibilities. We should strive to create intentional, well-defined service classes that promote responsibility segregation.
00:24:56.230 Lastly, I want to talk about handling complexity within our code. The first rule is to avoid unnecessary complexity. When presented with a task that doesn’t have an obvious straightforward solution in Rails, we shouldn't hesitate to reach out and discuss potential workflow adjustments with the business team.
00:26:37.210 For instance, if a simple checkbox leads to complex validation paths that require extensive development time, consider if there’s a more straightforward solution. Prioritize understanding the problem at hand and develop solutions based on a clear understanding of your application’s structure and its responsibilities.
00:27:54.560 By employing well-thought-out services and separation of concerns, we can achieve a clearer codebase. Our controllers should focus on managing the flow of operations rather than becoming bloated with business logic, improving both usability and maintainability. In our development journeys, we should always be aware of where we place our logic—discern application logic from business logic.
00:29:32.430 Finally, I appreciate everyone’s time today. Please feel free to check out my website or reach out via Twitter. I have two accounts—one in Russian where I post frequently, and another in English that I rarely update. Before you leave, if you haven’t filled out the survey yet, please do so. I look forward to analyzing the results tomorrow!
00:30:21.990 Thank you! If you have any questions, I'm here to answer them.
Explore all talks recorded at wroclove.rb 2018
+9