Class methods per se are not an anti-pattern but they are often overused/abused.
How I use class methods
“Factory” methods
In general, I tend to use class methods in a factory-esque role where they return an instance of the class. For example:
Game.read_from_save_file(my_save_file) # => instance of Game
If the behavior starts to grow complex, I would extract it into a GameSaveReader
class that might be used like this:
reader = GameSaveReader.new(my_save_file) # => GameSaveReader instance
reader.extract_game # => instance of Game
I might still keep Game.read_from_save_file
and just change its implementation to delegate to GameSaveReader
.
Aliases
Sometimes, creating an instance and then calling a method on it can be a little cumbersome. In that case I will create a class method that will delegate to an instance. Going back to the example above:
class GameSaveReader
def self.extract_game_from(save_file)
new(save_file).extract_game
end
end
Note that this is just a convenience method. All the heavy lifting is done by the instance.
ActiveRecord
ActiveRecord gives you two main class method types: those that return an instance of the model (such as find
) and those that return a collection of instances (such as where
). Most of the behavior that you will write with class methods here will be collection-related while the single object behavior would be implemented at the instance level.
A classic example of user-written class methods for ActiveRecord models would be scopes. These return a collection of instances that match a certain criteria.
ActiveRecord is a little strange because it handles both the collection of objects at the class-level and single objects at the instance level. Typically you would have separate collection object whose instance methods would handle collection-level behavior (such as scopes). Most front-end frameworks (Backbone, Ember, and friends) are built this way. However, ActiveRecord is what it is and I’m not recommending that you re-write all your models to break up collection behavior into it’s own class.
Anti-patterns
Multiple responsibilities
Class methods are prone to feature envy. If you have a lot of class methods in your model, take a moment to think: Is the class taking over a responsibility that should belong to the instance? Or perhaps this behavior deserves its own class?
Non-stateful methods are all defined on the class
Just because a method does not touch state does not mean that it should be a class method. Does anyone but the instance use this method? If not, it almost certainly should be a private instance method.
Conclusion
The main responsibility of class methods is to create instances. Because they are global in nature and resist refactoring, you typically want the business logic to be implemented at the instance level (this is object-oriented programming after all).
So are class methods evil? No, they have a vital (but limited) role to play in the implementation of your project.