00:00:12.400
Before we start, I want to know why you are here. I'm genuinely interested in what brings you to this workshop.
00:00:19.720
Does anyone here have an application with a code base of, say, a hundred thousand lines of code? If so, please raise your hand if you're looking for a change.
00:00:27.599
Okay, a couple of hands. That's cool. It can be frustrating to manage such a large code base.
00:00:33.640
Is anyone here frequently writing Rails apps, perhaps through consulting? Anyone doing that? Cool.
00:00:38.840
So, initially, I had a three-hour proposal. The second half was going to involve a really large code base that we aimed to deconstruct.
00:00:44.800
In reality, tearing apart a large code base takes months, not just 90 minutes, but it would have been a condensed session.
00:00:50.239
This part of the workshop focuses on refactoring from a sample app called 'Sports Ball'.
00:00:55.559
I hope that you will see how these ideas apply even in larger contexts.
00:01:01.440
Whenever you work with architecture, you create examples that might seem overly complicated for minor problems. That's going to happen again today, so bear with me.
00:01:08.280
Getting started with component-based Rails applications, I should introduce myself. My name is Stephan Hagemann.
00:01:15.320
I work for Pivotal Labs and fall into the category of developers who have built many Rails applications.
00:01:21.840
I've been involved with one client in particular for almost two and a half years, and the app we developed became really large.
00:01:30.479
We sought ways to bring more structure to the application without abandoning the monolithic architecture.
00:01:36.159
I continued this approach with almost every app I worked on thereafter.
00:01:42.720
It's a strange subject to talk about because if we were at a Java or Go conference, I wouldn't be giving this talk.
00:01:49.079
In many languages, structuring code within applications is a common topic, yet in Ruby, it remains an issue.
00:01:55.960
I've become somewhat obsessed with improving this situation.
00:02:02.719
If you want an overview, check out Confreaks for the talks I've given on this topic.
00:02:10.200
Despite this not being a typical talk but more of a lab session, I want to quickly answer the question: why would you want to pursue component-based Rails?
00:02:16.640
I see numerous benefits when you introduce a component as a tool in your Rails toolbox.
00:02:22.160
The main change is that you'll gain the ability to visualize the application differently, incorporating something akin to a graph.
00:02:28.760
Let me go through some examples to illustrate how vital this structure really is.
00:02:35.040
Even without knowing the context of the application, you can deduce that there is an importer related to programs, as indicated in the graph.
00:02:41.120
And, clearly, there's something going on involving sources and masters—likely some form of import and reconciliation.
00:02:48.560
The important takeaway is that we can talk about an application at a higher level.
00:02:55.560
Traditionally, Rails provided module names, but modules alone don’t offer this kind of hierarchy.
00:03:02.039
The important feature of components is that they incorporate directional arrows, which allow for clearer communication.
00:03:07.319
I can draw arrows from one box to another, but not in reverse, which is a critical aspect.
00:03:12.520
This structure makes it easier to collaborate on the application.
00:03:18.759
For instance, if I’m working on the Source module today, and you’re working on the User module, we can see how these fit together.
00:03:25.320
With this clarity, if I only change Source, then I don’t need to run tests for Masters, Programs, Reports, Users, and Styles.
00:03:31.920
My Source code doesn't interact with that other source code, so there’s no need to run those tests.
00:03:39.120
Similarly, there may be other parts of the code that are unaffected by my changes, meaning we can reduce testing efforts.
00:03:45.679
Ultimately, while everything remains a single application, we can optimize testing processes.
00:03:51.839
When you're ready to roll out a larger feature, you can place it within a component, effectively making it available during development.
00:03:58.760
You can control when it's visible to users, easily toggling it on or off with a single line of code.
00:04:04.039
For example, consider reports as an API; if we want to switch from a SOAP API to a JSON API, we can duplicate and rename the reports component.
00:04:10.560
We can gradually implement the changes, deprecating the former implementation when ready.
00:04:16.840
Underlying all these benefits is comprehension. You can easily manage and understand these components.
00:04:22.800
This facilitates onboarding for new team members and reduces cognitive overhead as it allows for easier navigation within the code.
00:04:29.159
The structure of the application becomes simpler and more intuitive.
00:04:36.079
Now that Ruby is installed, let's get started with the application.
00:04:41.440
I don't know if anyone has started it already, but this is a tiny app.
00:04:49.560
I used scaffolding to create the team pages here, featuring teams like the Falcons and Braves, who actually play against each other.
00:04:56.760
Interestingly, the Falcons won that game, which raises some questions because the Braves have a team as well.
00:05:03.240
The primary function of the app is to predict the outcome of games. For now, we only have one game where the Falcons emerged victorious.
00:05:09.520
So, this is what the app does, and I invite you to open the source code.
00:05:15.799
The structure of the application is interesting. If you look at the source code, the first thing you’ll notice is the presence of components.
00:05:21.600
Interestingly, there’s no app directory, meaning you can delete the application directory since you replicate it within a component.
00:05:27.880
When I refer to components, I mean gems and engines that are integrated within the codebase.
00:05:33.920
Yes, there is a components folder, but to grasp what is happening, the routes are crucial.
00:05:40.560
Inspecting the routes of the component reveals a more familiar structure.
00:05:46.160
You'll see the games, teams, and prediction routes. Please keep browsing the code and shout if you see something odd.
00:05:51.920
Now, I'll discuss how I view these components and their relationships.
00:05:57.840
The interesting aspect of the Gemfile is that it needs to load the application.
00:06:04.480
For instance, we have a gem app defined in line four, pulling from the required path.
00:06:09.040
Typically, this path is known for gems in development, where a local dependency is referenced, indicating another gem being developed.
00:06:16.720
In this case, however, it's about how many apps exist within this environment. When you bundle the application, it will show you everything.
00:06:23.720
This indicates that it’s looking for the app from the Source.
00:06:29.040
When we talk about engines, many developers assume they must be published. However, I believe they need not be published.
00:06:34.840
Instead, you will have a singular application that contains everything you need.
00:06:41.720
Yes, all files will still be present.
00:06:44.920
When you check the app, you'll find everything is organized and structured.
00:06:50.440
If we go through the files, there’s nothing unexpected. Everything is namespaced according to engine semantics.
00:06:57.440
The controller files—games, predictions, and teams—are all under respective namespaces, and we also find a welcome page.
00:07:05.840
Everything continues to operate normally. When we check the migrations, they are also appropriately placed.
00:07:11.880
The migrations for the component are namespaced, containing an appropriate naming convention.
00:07:18.000
You'll see migrations live within the engine structure, which is a common requirement, especially with engines and additional gems.
00:07:25.760
Remember earlier when I indicated that migration files should be isolated to their respective tables? You should adhere to that principle.
00:07:33.440
The important thing to note is that Ruby installations can become cumbersome.
00:07:39.440
I mentioned initially that I prefer to keep everything under a single component to avoid the hassle of dealing with multiple repositories or gem installations.
00:07:45.920
Maintaining a single codebase simplifies usage, ideally not needing to deal with migrations.
00:07:52.280
I explained earlier the benefits of having a single repository. As we discussed when bundling, grouping everything together makes life easier.
00:07:58.160
Taking components such as predictors and games and isolating them properly allows for easier navigation and maintenance.
00:08:05.360
So far, we've learned about the essence of refactoring toward a more component-based approach.
00:08:11.760
We now have better control over the application, and hopefully, you're starting to see the merit of applying components in your own work.
00:08:18.000
Next, let's examine how we can further break down components.
00:08:24.520
What does your integrated app look like when components start to interact?
00:08:32.000
Next, let's explore some refactoring options you'd consider for your Rails applications.
00:08:39.359
If I provided an example from another domain, say something related to user-management systems, you'd see the same challenges arise.
00:08:45.920
The goal is to create components that can be scalable and applicable across various systems.
00:08:52.440
While discussing the importance of separating concerns, how do you keep modules focused and prevent over-complexity?
00:09:00.000
We must also address the importance of maintaining clarity while making changes.
00:09:05.600
Relying on small, reusable components helps ensure this and should be part of your design philosophy.
00:09:11.920
The moment you rely on a handful of dedicated components, the application becomes highly maintainable.
00:09:16.880
This allows your team to quickly adapt and respond to changes in requirements without being overwhelmed by complexity.
00:09:23.040
When you begin breaking things down, ensure your components are meaningful. Each should serve a singular purpose rather than attempting to address everything.
00:09:34.000
Sometimes, you may have multiple narrow components that cater to a specific domain.
00:09:39.760
Once you've done your refactoring, it becomes essential to revisit your architecture.
00:09:46.000
You should always strive for clarity in your code as it reduces complexity.
00:09:53.760
Therefore, be ready to reassess your components often.
00:10:01.240
One suggestion is to conduct regular reviews and assessments of your codebase.
00:10:07.200
This maintains quality and ensures that components remain usable across contexts.
00:10:12.680
Having focused discussions on what each component is doing and adjusting them will make them invaluable.
00:10:19.440
This also helps in documenting for future reference or onboarding new colleagues.
00:10:26.600
A well-structured Rails application with an architectural approach fostering smaller components becomes much easier to tackle.
00:10:33.360
But it’s not just about structuring—it’s about the mindset you adopt towards component architecture.
00:10:39.480
Make decisions to build intuitive and comprehensible structures.
00:10:46.160
And ensure you're always fostering an environment that encourages feedback and improvement.
00:10:52.960
For consistency in your application, it's acceptable to lean into frameworks or patterns that already exist.
00:10:59.680
The trick is to make those components work seamlessly with one another, supporting the overarching application.
00:11:07.520
If you maintain discipline throughout, you will see the direct benefits this approach brings, especially as teams grow or change.
00:11:16.160
In conclusion, I hope this component-based approach to Rails has sparked some thoughts on how to streamline your own applications.
00:11:24.760
Shake hands with your code, break it down to its essential parts, and rebuild!
00:11:30.720
Thank you!