Reno, NV    +1 (800)0 621-0871

Go back

Development | Ruby on Rails | Tutorial

Learning how to break up Ruby classes to get faster tests

  |  January 30, 2013

Over the past year, I have learned to split up my super fat ActiveRecord models into smaller plain Ruby classes. In this post I list down the some guidelines that I follow when I decide to extract code from a model into a plain Ruby class.

The Problem

You end up not running tests when you have test suites that take too long to run. When you skip running tests, you will be more likely to break something, or checking Twitter while your tests run, just to forget to get back to work 10 minutes later.

Furthermore, code becomes difficult to maintain with huge classes. The class ends up doing too much.

Having a large model that does too much starts to become difficult to test. Throw in some callbacks, and you’re in for a slow test suite, because you will most likely be forced to create objects in the database just to trigger all the necessary callbacks. I have had my fair share of writing test suites that take 10-15 to run. In my opinion, unit tests should take less than 10 seconds to run. Integration tests, however, could (not should) take longer.

A Solution: Extract Class

By extracting methods from your model to other classes, you will get the benefits of having code that answers the problems above. They will be easier to test, and not to mention faster.

When I see a pattern in the methods I add to a model, I ask myself: what class can I put these methods?

As I place these methods into some external class, I try to make sure that the name of the class I am dumping these methods into properly describes that all the methods do. If there is a method that does something else, it probably belongs to its own class.

When I find myself wanting to test private methods, then it probably belongs to its own class as a public interface of that class.

A talk entitled The Deep Synergy Between Testability and Good Design by Michael Feathers shows a good example of extract class and testing private methods.

If you have been diligent with your podcasts and blogs, you’ll notice a lot of parallelisms with the (good) trend Plain Old Ruby Objects.

A lot of the links in this blog post I picked up from this excellent podcast from Ruby Rogues: Practical Object-Oriented Design in Ruby with Sandi Metz.

Tip: Let the instance do the work

The instances should do the work to avoid leakage of variables. Stop using class methods to do the work. Let the instance of the class do the work:

RuleTokenizer.new(:some => "args").tokenize
You might argue that doing so will make calls to that class so much longer. Add this to the class as a convenience method:
def self.tokenize(args)
  self.new(args).tokenize
end
so that you may call RuleTokenizer.tokenize(:some => "args")

Miss anything?

I want to hear from you folks: what did I miss? Has there been anything that has been particularly helpful when extracting methods into classes?