# data[].attributes.attachment_link.readable_text
We recently helped one of our clients speed up their Rails app in development mode.

This Rails 3.2 application runs on Ruby 2.1, it has 200+ models, 1,500+ routes and rendering a page in development mode takes about 12 seconds. After 250 requests, this number goes up to 30 seconds!

Within a couple of days, we succeeded to make it 7 times faster on average in development environment.

Please join us on this journey towards better performance, developer-happiness, and saving $$$!

Speed up serving individual assets by 14x

Visiting the home page would take about 4 seconds to render and 7 more seconds to serve about 100 asset files.

Serving 100 asset files should not be that slow to serve. We used Flame Graphs with rack-mini-profiler to dig into this.

To set this up, just add the following to your Gemfile:

... and visit a page with ?pp=flamegraph. Boom! It displays a Flame Graph!

Flame Graphs are disabled for assets by default, so comment out this line to render a Flame Graph for assets.

Here is a Flame Graph for rendering /assets/jquery.js:

90% of the time serving assets is spent running the garbage collector (GC) because of a custom rack middleware. This custom rack middleware would disable the Garbage Collector for the duration of the request and trigger a Garbage Collection at the end of it. While this middleware had a positive impact in production, it was responsible for slowing down serving assets in development environment by 14x.

Disabling this middleware in development environment brought serving 100 assets from 7 seconds down to 0.5 seconds. Serving a page with assets would take 5 seconds, instead of 10. That's 2x faster!

ActiveAdmin, Y U RELOAD?

Now that the asset issue is fixed, let's see what we can do to speed up page rendering. We decided to focus on rendering a page without changing any files.

As you can see, ActiveAdmin reloads its configuration files which isn't necessary. We've submitted a patch which saves about a second to render a page. 1.2x faster!

Routes, Y U RELOAD?

The previous Flame Graph shows that the routes were reloaded with no reason. Digging into the Flame Graph, we figured out that rails_dev_tweaks was responsible for this. Upgrading to the latest version fixed that bug and saved another two seconds. 1.4x faster!

One worker is enough!

Seven unicorn workers were used in dev environment in order to mitigate the slow asset issue. Now that it's fixed, we get similar performances with a webrick server to run one request.

Using one worker is obviously better for memory usage as it uses about 7x less memory. That prevents swapping and speeds up the entire system. It is also better for Rails code reloading and caching since having seven workers means that each worker will have to reload the code or recompile an asset when you perform a change.

Here is a chart that demonstrates this problem using seven workers. We perform a code change, and then refresh the page 10 times. The first request hits a unicorn worker that reloads the code (4 seconds). The second request hits another unicorn worker that reloads the code (4 seconds). The third request is lucky and hits a worker that has already reloaded the code (2 seconds). And so on... After the tenth request, 6 out of 7 workers have reloaded the code.

With one webrick worker, the code is reloaded once at the first request:

Less code reloads = less memory leaks

After 250 requests, it would take about 30 seconds to serve a page and the web server would take about 1gb of memory. The fixes we introduced which prevented unnecessary code reloads helped mitigate the memory leak. After 250 requests, it would only take 2 seconds to serve a page. 15x faster!

Measure it, spot it, fix it and make it better, faster, stronger

The process we followed was pretty straightforward:

1. Measure response time using the Chrome Developer Tools and ApacheBench

2. Find a bottleneck with rack-mini-profiler and Flame Graphs

3. Fix it

4. Repeat until the performances are good enough

We fixed a rack middleware that was forcing GC runs, we improved ActiveAdmin to only reload code when necessary, we upgraded a rack middleware (rails_dev_tweaks) that was forcing code reloads, and we finally used only one web worker to reload code once after a file change.

In the end, the app is 3x faster when loading a page after a code change and up to 17x faster when loading a page without code change and after 250 requests. It took us a couple of days to make this application 3 to 17 times faster in development environment.

With 10 developers working on it full-time... well, I'll let you do the math!

# data[].attributes.attachment_link.description
We recently helped one of our clients speed up their Rails app in development mode. This Rails 3.2 application runs on Ruby 2.1, it has 200+ models, 1,500+ routes and rendering a page in development mode takes about 12 seconds. After 250 requests, this number goes up to 30 seconds!

# data[].attributes.headline
"Warning: Authentication failure. Retrying... " after packaging box · Issue #5186 · mitchellh/vagrant

# data[].attributes.subject
"Warning: Authentication failure. Retrying... " after packaging box · Issue #5186 · mitchellh/vagrant

# data[].attributes.attachment_link.title
"Warning: Authentication failure. Retrying... " after packaging box · Issue #5186 · hashicorp/vagrant

# data[].attributes.attachment_link.description
I am able to vagrant up and have ssh running fine from a base box that I've provisioned. I then package up the said box and keep getting errors with ssh. I've packaged numerious boxes before with this same process just yesterday. Not sur...

# data[].attributes.headline
7 Patterns to Refactor Fat ActiveRecord Models - Code Climate Blog

# data[].attributes.subject
7 Patterns to Refactor Fat ActiveRecord Models - Code Climate Blog

# data[].attributes.attachment_link.readable_text
When teams use Code Climate to improve the quality of their Rails applications, they learn to break the habit of allowing models to get fat. "Fat models" cause maintenance issues in large apps. Only incrementally better than cluttering controllers with domain logic, they usually represent a failure to apply the Single Responsibility Principle (SRP). "Anything related to what a user does" is not a single responsibility.

Early on, SRP is easier to apply. ActiveRecord classes handle persistence, associations and not much else. But bit-by-bit, they grow. Objects that are inherently responsible for persistence become the de facto owner of all business logic as well. And a year or two later you have a User class with over 500 lines of code, and hundreds of methods in it's public interface. Callback hell ensues.

As you add more intrinsic complexity (read: features!) to your application, the goal is to spread it across a coordinated set of small, encapsulated objects (and, at a higher level, modules) just as you might spread cake batter across the bottom of a pan. Fat models are like the big clumps you get when you first pour the batter in. Refactor to break them down and spread out the logic evenly. Repeat this process and you'll end up with a set of simple objects with well defined interfaces working together in a veritable symphony.

You may be thinking:

"But Rails makes it really hard to do OOP right!"

I used to believe that too. But after some exploration and practice, I realized that Rails (the framework) doesn't impede OOP all that much. It's the Rails "conventions" that don't scale, or, more specifically, the lack of conventions for managing complexity beyond what the Active Record pattern can elegantly handle. Fortunately, we can apply OO-based principles and best practices where Rails is lacking.

Don't Extract Mixins from Fat Models

Let's get this out of the way. I discourage pulling sets of methods out of a large ActiveRecord class into "concerns", or modules that are then mixed in to only one model. I once heard someone say:

"Any application with an app/concerns directory is concerning."

And I agree. Prefer composition to inheritance. Using mixins like this is akin to "cleaning" a messy room by dumping the clutter into six separate junk drawers and slamming them shut. Sure, it looks cleaner at the surface, but the junk drawers actually make it harder to identify and implement the decompositions and extractions necessary to clarify the domain model.

Now on to the refactorings!

1. Extract Value Objects

Value Objects are simple objects whose equality is dependent on their value rather than an identity. They are usually immutable. Date, URI, and Pathname are examples from Ruby's standard library, but your application can (and almost certainly should) define domain-specific Value Objects as well. Extracting them from ActiveRecords is low hanging refactoring fruit.

In Rails, Value Objects are great when you have an attribute or small group of attributes that have logic associated with them. Anything more than basic text fields and counters are candidates for Value Object extraction.

For example, a text messaging application I worked on had a PhoneNumber Value Object. An e-commerce application needs a Money class. Code Climate has a Value Object named Rating that represents a simple A - F grade that each class or module receives. I could (and originally did) use an instance of a Ruby String, but Rating allows me to combine behavior with the data:

Every ConstantSnapshot then exposes an instance of Rating in its public interface:

Beyond slimming down the ConstantSnapshot class, this has a number of advantages:

The #worse_than? and #better_than? methods provide a more expressive way to compare ratings than Ruby's built-in operators (e.g. < and >).

Defining #hash and #eql? makes it possible to use a Rating as a hash key. Code Climate uses this to idiomatically group constants by their ratings using Enumberable#group_by.

The #to_s method allows me to interpolate a Rating into a string (or template) without any extra work.

The class definition provides a convenient place for a factory method, returning the correct Rating for a given "remediation cost" (the estimated time it would take to fix all of the smells in a given class).

2. Extract Service Objects

Some actions in a system warrant a Service Object to encapsulate their operation. I reach for Service Objects when an action meets one or more of these criteria:

The action is complex (e.g. closing the books at the end of an accounting period)

The action reaches across multiple models (e.g. an e-commerce purchase using Order, CreditCard and Customer objects)

The action interacts with an external service (e.g. posting to social networks)

The action is not a core concern of the underlying model (e.g. sweeping up outdated data after a certain time period).

There are multiple ways of performing the action (e.g. authenticating with an access token or password). This is the Gang of Four Strategy pattern.

As an example, we could pull a User#authenticate method out into a UserAuthenticator:

And the SessionsController would look like this:

3. Extract Form Objects

When multiple ActiveRecord models might be updated by a single form submission, a Form Object can encapsulate the aggregation. This is far cleaner than using accepts_nested_attributes_for, which, in my humble opinion, should be deprecated. A common example would be a signup form that results in the creation of both a Company and a User:

I've started using Virtus in these objects to get ActiveRecord-like attribute functionality. The Form Object quacks like an ActiveRecord, so the controller remains familiar:

This works well for simple cases like the above, but if the persistence logic in the form gets too complex you can combine this approach with a Service Object. As a bonus, since validation logic is often contextual, it can be defined in the place exactly where it matters instead of needing to guard validations in the ActiveRecord itself.

4. Extract Query Objects

For complex SQL queries littering the definition of your ActiveRecord subclass (either as scopes or class methods), consider extracting query objects. Each query object is responsible for returning a result set based on business rules. For example, a Query Object to find abandoned trials might look like this:

You might use it in a background job to send emails:

Since ActiveRecord::Relation instances are first class citizens as of Rails 3, they make a great input to a Query Object. This allows you to combine queries using composition:

Don't bother testing a class like this in isolation. Use tests that exercise the object and the database together to ensure the correct rows are returned in the right order and any joins or eager loads are performed (e.g. to avoid N + 1 query bugs).

5. Introduce View Objects

If logic is needed purely for display purposes, it does not belong in the model. Ask yourself, "If I was implementing an alternative interface to this application, like a voice-activated UI, would I need this?". If not, consider putting it in a helper or (often better) a View object.

For example, the donut charts in Code Climate break down class ratings based on a snapshot of the codebase (e.g. Rails on Code Climate) and are encapsulated as a View:

I often find a one-to-one relationship between Views and ERB (or Haml/Slim) templates. This has led me to start investigating implementations of the Two Step View pattern that can be used with Rails, but I don't have a clear solution yet.

Note: The term "Presenter" has caught on in the Ruby community, but I avoid it for its baggage and conflicting use. The "Presenter" term was introduced by Jay Fields to describe what I refer to above as "Form Objects". Also, Rails unfortunately uses the term "view" to describe what are otherwise known as "templates". To avoid ambiguity, I sometimes refer to these View objects as "View Models".

6. Extract Policy Objects

Sometimes complex read operations might deserve their own objects. In these cases I reach for a Policy Object. This allows you to keep tangential logic, like which users are considered active for analytics purposes, out of your core domain objects. For example:

This Policy Object encapsulates one business rule, that a user is considered active if they have a confirmed email address and have logged in within the last two weeks. You can also use Policy Objects for a group of business rules like an Authorizer that regulates which data a user can access.

Policy Objects are similar to Service Objects, but I use the term "Service Object" for write operations and "Policy Object" for reads. They are also similar to Query Objects, but Query Objects focus on executing SQL to return a result set, whereas Policy Objects operate on domain models already loaded into memory.

7. Extract Decorators

Decorators let you layer on functionality to existing operations, and therefore serve a similar purpose to callbacks. For cases where callback logic only needs to run in some circumstances or including it in the model would give the model too many responsibilities, a Decorator is useful.

Posting a comment on a blog post might trigger a post to someone's Facebook wall, but that doesn't mean the logic should be hard wired into the Comment class. One sign you've added too many responsibilities in callbacks is slow and brittle tests or an urge to stub out side effects in wholly unrelated test cases.

Here's how you might extract Facebook posting logic into a Decorator:

And how a controller might use it:

Decorators differ from Service Objects because they layer on responsibilities to existing interfaces. Once decorated, collaborators just treat the FacebookCommentNotifier instance as if it were a Comment. In its standard library, Ruby provides a number of facilities to make building decorators easier with metaprogramming.

Wrapping Up

Even in a Rails application, there are many tools to manage complexity in the model layer. None of them require you to throw out Rails. ActiveRecord is a fantastic library, but any pattern breaks down if you depend on it exclusively. Try limiting your ActiveRecords to persistence behavior. Sprinkle in some of these techniques to spread out the logic in your domain model and the result will be a much more maintainable application.

You'll also note that many of the patterns described here are quite simple. The objects are just "Plain Old Ruby Objects" (PORO) used in different ways. And that's part of the point and the beauty of OOP. Every problem doesn't need to be solved by a framework or library, and naming matters a great deal.

What do you think of the seven techniques I presented above? What are your favorites and why? Have I missed any? Let me know in the comments!

P.S. If you found this post useful, you may want to subscribe to our email newsletter (see below). It's low volume, and includes content about OOP and refactoring Rails applications like this.

Further Reading
Thank you to Steven Bristol, Piotr Solnica, Don Morrison, Jason Roelofs, Giles Bowkett, Justin Ko, Ernie Miller, Steve Klabnik, Pat Maddox, Sergey Nartimov and Nick Gauthier for reviewing this post.

# data[].attributes.attachment_link.title
7 Patterns to Refactor Fat ActiveRecord Models

# data[].attributes.attachment_link.description
Code Climate provides automated code review for your apps, letting you fix quality and security issues before they hit production. We check every commit, branch and pull request for changes in quality and potential vulnerabilities. If an issue is found, you're notified immediately - it's that simple.

# data[].attributes.headline
Exploring Query Locks in Postgres - Big elephants

# data[].attributes.subject
Exploring Query Locks in Postgres - Big elephants

# data[].attributes.attachment_link.title
Exploring Query Locks in Postgres - Big elephants

# data[].attributes.attachment_link.description
Understanding query locking is key to using postgres concurrently. So let's look at an example to learn more about how locking works and how to ...

# data[].attributes.headline
Confreaks TV | ZOMG WHY IS THIS CODE SO SLOW? - Ruby Conference 2010

# data[].attributes.subject
Confreaks TV | ZOMG WHY IS THIS CODE SO SLOW? - Ruby Conference 2010

# data[].attributes.attachment_link.title
Confreaks TV | ZOMG WHY IS THIS CODE SO SLOW? - Ruby Conference 2010