00:00:08.650
Good morning, everyone. Let's get this started! I'm about to wrangle some stuff. Trust me, this is the talk, and I'll explain what I mean.
00:00:15.129
The title of my talk is "Wrangling Large Rails Codebases." My name is Stephan Hagemann, and I work for Pivotal Apps, where I pretend to be productive.
00:00:20.439
First, I want to ask: how many of you do a stand-up every morning? We have a practice where every morning we quickly discuss what has been happening, what is planned for the day, and any potential issues. Who's doing that? Have you ever repeated what someone else said?
00:00:35.530
Some of you have, so I like to keep stand-ups simple; everyone has to share something. Then, you can just reiterate what your pair said, which is quite nice. I want to summarize what was discussed in all the talks from yesterday morning.
00:00:57.309
I hope that by the end of this talk, you’ll see that I fit in with those discussions. While they focused on very small topics, I will be discussing much larger concepts. If a talk is like a steak, then this one is definitely not well-done. I hope it’s well-received, but it’s probably more medium rare!
00:01:17.200
The reason is that just two days ago, I had a conversation with my boss, Sandi, at our office. After that, I decided to redo everything, which is why I’m looking for your feedback as we go along. I will be using the next big thing as a reference for two of my examples, so keep that in mind.
00:01:36.430
Just a note: nothing I might say is something that others have stated unless I directly cite them.
00:01:48.130
Now, let’s talk about large applications. In fact, I would argue that you should never build large apps. Does anyone have thoughts on that? I would say it’s hard and can lead to a mess.
00:02:01.900
Sandi once joked that your code may want to kill you, and I had never thought of it that way. I always believed it to be the other way around.
00:02:19.550
Let's explore the wrangling theme a bit more. Just a couple of days ago, I discovered something interesting during a tequila tasting—someone told me I didn’t really know what wrangling meant. I thought it meant tackling something, like in football.
00:02:37.660
As a joke, one of you wanted to bring me Wrangler jeans so I could walk like a cowboy. Sorry, I only have this hat. If anyone is from Texas, you’ll know that it says, "Everything's bigger in Texas," on one side. If what Sandi says is true, then my code is surely out to get me!
00:02:55.590
By the end of this talk, I hope we can all feel more like cowboys or at least have a more relaxed approach to large codebases.
00:03:11.840
Partly because my brain is melting under this hat and because I might look ridiculous, let's move on. Again, I want to emphasize: never build large applications.
00:03:23.330
I built a tiny app called "The Next Big Thing." What is that, you might wonder? Well, it doesn't do much. You can sign up, but there’s ultimately nothing about that new feature.
00:03:35.100
I realize I should have made that smaller, but it doesn’t matter now. All you can do is sign up, and if the server ever wakes up, it will say, "Thank you for signing up." Right now, it looks like everything is still down.
00:03:43.200
So that’s what you can do with the app. Now, back to big apps: who has ever worked in a Rails codebase where the model's directory looked like a complete mess?
00:04:02.160
I feel your pain! I’ve taken the liberty of spreading that out, and it truly is a disaster.
00:04:10.100
I like to think that what I write is a pile of crap because if this is a massive pile, it's a massive pile of crap. I want several things for my application: I want structure.
00:04:25.500
To remind myself, I want to reference Ben, who said that when he had a method with a good name, the implementation was crazily complicated and unmanageable. Why isn't there more structure in a Rails app?
00:04:39.060
Another person I want to mention is Roy—he had a great approach to HTML structure. Everyone seems to be searching for that structure. I want my individual pieces to be understandable and agile.
00:04:56.420
Not in a process way, but rather in the sense that when a small feature request comes up, I want to make small changes without needing to dive into the chaos.
00:05:12.540
Ideally, the code should remain focused and manageable. We should prevent the big pile. We should reduce cognitive overload and allow for enough flexibility to enable change.
00:05:30.120
However, that’s not happening right now. I should say that it might be happening, but not for me at this moment. Wouldn't it be great if I could structure that big pile into smaller, more manageable pieces? Organizing code is like recycling—there's a vast difference between throwing it in a waste bin and putting it in a recycling bin.
00:06:05.700
So, in my analogy of a Rails application, this is a crucial difference that I want to discuss today. What if we could sort our codebase by filename and structure it a little better?
00:06:24.860
Yes, we can! We could use namespaces and modules to organize everything. We can define models clearly. It feels great to retrieve one more layer of organization!
00:06:42.470
But I still struggle with maintaining a smaller focus when everything is still lumped together. Wouldn't it be wonderful if I could isolate these modules into their own encapsulated environments?
00:07:00.300
Let's think about gems. You can create a gem that houses even a small piece of functionality that handles its own specifications. If you design it properly, that gem should live in its own space to prevent it from being cluttered with other codes.
00:07:17.920
Eric Evans wrote a book called "Domain-Driven Design," in which he speaks about modules that convey the story of your system containing a cohesive set of concerns. It’s not just about imposing structure; it’s about discovering the underlying structure that inherently exists.
00:07:35.660
In other words, it’s about finding cohesion without the chaos. To continue with this analogy: when you store away all your winter gear and summer gear together, it becomes a challenge to find anything against the mix of clothing.
00:07:55.180
Higher cohesion yields a simpler view of the world, allowing for looser coupling to the outside. So we’re looking for ways to pull our gems apart and introduce a bit more organization.
00:08:09.020
Let’s analyze modules based on their external interactions. The tighter the cohesion between components, the less outside interaction is needed—similar to organizing your winter clothing apart from your summer clothing.
00:08:29.070
As you can see, we need structure and separation to simplify the complex relationships at play. Now let’s see this app in action, which is our test example.
00:08:50.780
So I’ve made this box, and to illustrate better, I once built an "Annoyance Gem." It has two public methods. Because I don’t want to clutter the screen with too much information, I didn’t show you what they actually do.
00:09:07.860
But essentially, you can query the annoyance level, and it will tell you just how annoyed it is. It can also adjust the text you feed it. This little gem serves as an isolated piece within our application.
00:09:21.420
Every gem comes with its own set of rules and builds in a defined structure, making it much easier to organize.
00:09:37.370
Remember that gems provide explicit dependencies, and with gems, you know that they encapsulate a certain behavior. Just like Eric Evans pointed out, it’s important to identify those cohesive concepts and extract them as gems.
00:09:55.550
For all of the recent projects in our Boulder office, we’ve focused on these gems that are modular and encapsulate specific functionality. It's essential to note that you’re likely already using some form of gem to manage dependencies, such as payment services.
00:10:11.540
The crucial point is that by turning complex functionalities into standalone gems, you can maintain a cleaner application structure. This leads us to a better understanding of the dependencies—and from there, you can easily prove their existence.
00:10:28.650
Now, just to clarify, DHH might pop up at some point and question whether you’ve truly utilized Rails to the fullest or if all you do is work with functional compartments. That's something to think about!
00:10:54.680
Engines are not just for pagination or administration. Rails engines allow you to wrap distinct Rails applications or certain functionalities to share between applications.
00:11:08.125
I believe you should share your engines with yourself! It’s not just about sharing between different apps.
00:11:20.410
Yes, some people find engines to be a bit magical or complex, but let me try to demystify them using a simple example from "The Next Big Thing." This app doesn’t have an app holder as it is all contained within a single engine.
00:11:36.950
This engine, which I call "Teaser," encapsulates the core functionality of the app. Let's explore how engines work and how you can effectively implement them.
00:12:00.230
One way you can achieve functionality between your app and engines is to mount these engines. You can structure engines properly, maintain high cohesion, and let them handle their internal operations independently.
00:12:18.110
Further, for migration management, you can utilize these engines to manage your database migrations without cluttering up the main application database. This is critical for maintaining clarity between your app's core logic and the engines' functions.
00:12:36.520
Assets are another crucial aspect when integrating engines. With engines, all of your images or asset files are confined to their isolated namespaces, reducing confusion in organization.
00:12:51.250
I remember a project where we started with multiple engines. The setup may look complicated, but by labeling everything, we avoided the chaotic environment that often accompanies traditional Rails applications. It simplified our workflow.
00:13:05.350
I presented the "Teaser" app as an underpinning example—a TV-like production hub that integrates different functionalities such as sending text messages while streaming.
00:13:24.520
Engine architecture means that both gems and engines can boil down to encapsulating specific functionalities while maintaining the connectivity to the main app.
00:13:46.200
When implemented correctly, structure will improve by reducing the overall complexity we often associate with traditional Rails apps.
00:14:02.890
Now, transitioning from a traditional Rails application toward a model of using engines can be tough. You know where everything goes within a Rails application, but taking different approaches may leave some developers asking where specific components now reside and how they interact.
00:14:22.530
That said, this shift requires some learning; and if you embrace this transition and put the effort in, it will pay off. Consider how every gem you build will come with its own namespace—think of every Rails application as a world without boundaries, while a gem provides a box for good organization.
00:14:45.980
My takeaway for you today: every gem gives you a namespace that can help you provide structure in your application. In your next Rails project, try to define everything in terms of gems and engines.
00:15:01.870
Let’s start to think outside of the traditional parameters of Rails and adopt this new model. Thank you, everyone!
00:15:14.710
Now, do we have any questions?
00:15:16.210
Yes, of course, let’s have some questions!
00:15:25.360
The question is: what should you do if you find a gem has become too large or problematic? You need to address this carefully.
00:15:43.369
If you keep your migrations within each engine, it can present a challenge to move things as needed, but it’s vital to address it rather than ignoring it.
00:15:56.090
Eric Evans emphasizes doing so is necessary for the health of your application. If you aren’t prepared for such necessary modifications over time, that can lead to larger issues in the future.
00:16:08.700
So while it may be painful today, these pains can relieve a greater potential pain down the road.
00:16:19.870
No, you don’t need to restart your server every time. You can change your engine without having to restart your Rails application, which increases your development efficiency.
00:16:41.170
Engines were a bit more challenging in Rails 2, but in Rails 3 and later, this became much more manageable.
00:16:57.888
If you have engines dependent on each other, it’s crucial to ensure you define strong interfaces between each engine as they can communicate without inappropriate access.
00:17:25.300
As you work on your applications, focus on defining clearer interfaces, so each engine can communicate effectively without causing a ‘Pandora’s Box’ scenario where everything is tightly coupled.
00:17:45.050
Testing becomes vital when you have multiple engines integrated. In CI, a well-structured application can mean fast builds despite numerous dependencies.
00:18:02.270
It’s critical to facilitate testing across these interconnected components, ensuring that all are checked without compromising the efficiency of the build process.
00:18:19.190
Yes, in-engine testing might feel cumbersome, but structured effectively, it is manageable, and your tests will run efficiently.
00:18:30.720
To summarize, you can have clearly defined models, views, and controllers within an engine as long as you've structured your engines properly.
00:18:43.440
Your engine should have tightly coupled functionalities, but they should be independent enough that one does not adversely affect the other.
00:18:57.160
If there are no other questions, I thank you for your attention. Let’s continue to expand on how we can wrangle our large Rails codebases effectively.