Are class methods evil?
In my opinion class methods are almost always a wrong approach to a problem. It’s not wrong as in “it doesn’t work” but wrong as “we can make it better”.
ActiveRecord and Rails
I blame the ActiveRecord pattern for the current class methods problem. Every Rails application I see is full of globals which are often results or causes of class methods. The problem with ActiveRecord is that it forces you to think in terms of sql tables. Almost every table exists as a class with lots of class methods that let you access the data from this table.
I mean methods like:
Can we do better?
One of the things Nick suggested is using user_factory. Overall he’s right, but I don’t think user_factory is a good name for that. We’re not producing users in our app, right? The users live in the context of our app. Is it a shop or a game or maybe a portal? Then create a class for that. This is your “factory”. Once you have it, always access users through this object. Not only users, you can do the same with products, prizes etc.
Instead of User.find(4) you now have game.users.find(4) or better game.find_user(4). You still gain from the ActiveRecord methods, without using the class methods, though.
How to implement the app class?
There are two ways that I’m aware of. Both are not ideal, mostly due to the way ActiveRecord works, but in my opinion they improve the code quality.
1. Create an ActiveRecord model for that.
If your app is a game then create a model called Game with the associated table (games). Yes, it will possibly have only one record and yes it may add some overhead to the queries that are generated by the ActiveRecord framework. Thanks to that however you may have only one “singleton/global” in your app.
class Game has_many :users has_many :prizes .... endI usually put the implementation in the ApplicationController and have something like:
def game Game.find_by_name(“Music Challenge”) end
Then, in every other controller I can access the game object and find all the data I need through its scope.
2. Non-ActiveRecord class
The other way assumes that you hide the globals in this class. It can be done in many different ways. One of them is:
class Shop def products Product.all end def find_product(id) Product.find(id) end endWhat’s my choice?
Overall, I prefer the first way. It has a nice side-effect that once you have the game/shop model you can easily turn your application from a single game to a platform of games (which we actually did in one project, but that's another story).
I also try hard to find the way out of the ActiveRecord and sql/nosql dependencies and go into a pure OOP direction with madeleine/prevayler-like tools.
What’s your choice? Do you see the problem with class methods?
If you read this far you should and subscribe to my RSS