00:00:22.930
All right, so my name is John Bender.
00:00:26.289
You can find me in various places. I work at Adobe, where I am employed full-time with jQuery Mobile.
00:00:30.500
The reason I mention this is because I’m really grateful for the opportunity to work in a field I enjoy.
00:00:34.390
So, today I want to address a common issue in programming.
00:00:38.059
What are we really focusing on today?
00:00:39.739
This talk is about the problems with very large classes, particularly in Ruby on Rails.
00:00:49.430
I think everyone in this room is familiar with gigantic user classes in Rails applications.
00:00:52.870
Let me ask, how many of you are Rails developers? And how many have encountered a massive user class in a Rails application? Hands, please!
00:01:03.559
It’s a pretty common occurrence — these gigantic classes with pages and pages of methods. Today, I would like to address that and offer a technique for improvement.
00:01:16.100
There are existing solutions for handling large classes. One approach is to mix in functionalities.
00:01:22.820
I will present some examples but you don't need to read all the code — the key takeaway is context.
00:01:30.950
For instance, in a Rails app, you can utilize session-based modules where each class is a simple include. This way, everything is logically grouped, and you avoid scrolling endlessly through an enormous class.
00:01:50.670
Another approach is object composition, which is essential when refactoring your codebase.
00:01:56.209
An example: if I have a lamp, I need to know about maintenance methods like finding out bulb age.
00:02:02.819
This is a simple illustration, but conceptually important.
00:02:03.909
The bulb age inquiry is encapsulated within the lamp class. Instead, we can delegate the inquiry to the bulb, separating concerns.
00:02:10.180
This demonstrates object composition — moving methods to where they logically belong.
00:02:14.319
Today, we will focus on Rack middleware as an abstraction.
00:02:16.290
But first, how many of you are familiar with middleware? Raise your hands if you have worked with it before.
00:02:25.080
Not everyone, but that’s okay. I will be using the terms middleware and middlewares interchangeably.
00:02:35.720
Now let's take a quick review.
00:02:37.720
To understand middleware as a general-purpose abstraction, we need to look at it in its native environment. So, how does Rack middleware work?
00:02:50.139
For those who are not familiar, a brief overview is needed. Middleware is designed to process requests, modifying them as they pass through.
00:03:02.319
A middleware stack operates as the request flows through. At the top of the stack, the first middleware gets a chance to manipulate the request.
00:03:14.180
Let’s take a simple middleware example.
00:03:16.629
When a request comes in, it initializes the middleware, providing the next middleware in the stack as an argument.
00:03:29.799
It's critical that every middleware calls the next middleware in the chain; this distinguishes middleware from endpoints, which do not delegate.
00:03:41.919
In this scenario:
00:03:43.340
the request moves through the stack where each middleware can manipulate the request or response before passing it along.
00:03:56.030
Let’s clarify the differences between using middleware with Vagrant and traditional Rack middleware.
00:04:09.440
Vagrant's middleware processes requests in a more straightforward manner. You simply create a lambda function, and it handles calling the next middleware for you.
00:04:18.400
On the other hand, Rack assumes you’re aware of the next middleware in line, which means when coding for Rack, you need explicit calls to pass on the requests.
00:04:38.600
This is crucial to ensure every middleware in the stack can process requests appropriately.
00:04:55.000
At this point, I want to ensure everyone's clear on these foundational ideas before moving ahead. Do you have any questions?
00:05:03.370
If not, I’ll proceed, and we’ll touch on how Vagrant utilizes middleware to perform actions.
00:05:13.940
So, how many of you have used Vagrant? Great! For those who haven't, Vagrant helps manage virtual machines easily, streamlining their use in development.
00:05:28.990
Utilizing Vagrant requires various operations, including system configurations, port forwarding, and file sharing.
00:05:39.000
Let’s dive into a simple command example. When managing a virtual machine with Vagrant, suspending it is straightforward.
00:05:56.000
Here’s what the middleware stack looks like for suspending a VM. These are the necessary operations for successful suspension.
00:06:06.561
As you can see, the VM moves through each middleware in order, which facilitates the suspension process.
00:06:21.480
When we run the command, it first checks the configuration to ensure it's valid—this is essential for the functioning of the virtual machine.
00:06:31.690
If the configuration is incorrect, Vagrant raises an error and halts further processing. However, if everything is valid, it continues with the middleware processing.
00:06:46.030
Next, it verifies access to the environment to ensure no issues arise with the virtual environment.
00:07:00.090
If all checks are successful, it proceeds to actual suspension of the virtual machine using appropriate Vagrant commands.
00:07:15.470
The importance here is that Vagrant handles middleware management, streamlining the process without manual delegation.
00:07:25.000
Lastly, creating a VM from scratch involves numerous operations, but thanks to middleware, these processes can be reused efficiently.
00:07:39.800
Simplifying the operations involved prevents an overly bloated class that’s difficult to navigate.
00:07:54.880
We learned early on while developing Vagrant that we wanted to avoid large classes, as they lead to convoluted dependencies and testing complications.
00:08:11.470
So we sought an intermediate solution between large classes and middleware to streamline our development process.
00:08:23.560
To illustrate, let’s refactor a Rails application, specifically targeting the user class of the Diaspora social network.
00:08:32.070
The Diaspora user class is notably large, consisting of numerous methods that can be refactored to enhance maintainability.
00:08:48.240
As I show you this, consider grouping these methods to create a distinct class that can handle specific responsibilities.
00:09:03.319
We can extract methods that show dependencies and group logic, making it much simpler to manage.
00:09:17.080
First, we need to identify methods free from many dependencies to facilitate extraction. This will make our refactor simpler.
00:09:30.320
For instance, with the invitation method, even without diving into specifics, we notice possibilities for extraction.
00:09:43.520
Now, as I move this to a new class, the idea is to define responsibilities clearly and make proper use of middleware design.
00:09:58.890
I will create a class with the relevant methods needed for handling this aspect. It will interface smoothly with the existing environment.
00:10:12.480
The process allows for cleaner organization and a better design pattern, which ultimately aids testing and code readability.
00:10:27.570
Furthermore, it enhances flexibility, allowing method calls based on context and requirements.
00:10:41.670
The user environment facilitates injecting dependencies during these calls, making our operations seamless.
00:10:58.670
This kind of segmentation into middleware adheres to code reusability, especially when we anticipate multiple methods doing related processing.
00:11:10.410
With this implemented, adapting our architecture to fit future needs becomes less cumbersome.
00:11:25.890
To wrap up, here are some signs indicating when middleware is a suitable solution.
00:11:39.890
When you find common functionality scattered across various classes, consider consolidating actions into middleware.
00:11:52.490
Avoid relying solely on mixins as they may complicate your class structure; instead, utilize object composition to modularize your code.
00:12:05.310
Furthermore, if methods essentially wrap existing behavior, reassess their structure and possibly designate them as middleware functions.
00:12:17.590
Code organization and abstraction, such as companies where functionality is frequently utilized, are excellent candidates for this approach.
00:12:30.750
In conclusion, middleware presents a powerful method for enhancing class abstraction and organization.
00:12:43.850
If you consider these ideas, reshaping how you deal with large classes and their responsibilities will significantly benefit the overall performance of your applications.
00:13:05.600
Thank you for your time today, and I hope you found these insights helpful!