The biggest problems I have when developing (beside stupid typos) are:
- The name of a method which I often change to a supposedly more
descriptive name, which I will eventually change to an even more
supposedly descriptive name
- The arguments a method takes
Let’s say I have a class method: Product.find_if_purchased(product_id,
Let’s say it is called in 3 different controllers.
Now I want to change the name of the method to make it more clear and at
the same time I will throw a new argument to it:
Product.find_if_purchased_by_user_id(product_id, user_id, site_id)
Now this means I have to change the code in three controllers, and also
change the specs that test it with should_receive(:find_if_purchased).
This is painful.
And it demonstrates that controllers are tightly coupled to models which
shouldn’t be the case. Therefore we need names that don’t vary over
time. We want our models and controllers to work in a black box manner.
So based on the design pattern “convention over configuration”, why not
use methods such as:
Product.find_for_products_index or …_show, that are named after their
controller and action where they are called?
Moreover, instead of hardcoding the arguments that it requires, why not
pass a hash of arguments which is much more flexible? Indeed, when using
hardcoded arguments, if let’s say I want to define a default value for
product_id, then again I must change all code that calls it, because in
Ruby, arguments that have default values must be defined last.
What do you think about my idea? I have been trying it recently, and I
find it more pleasant to work with. It also prevents me from putting too
much code inside the controllers.
They are drawbacks though:
- the name of the method is not descriptive, a little comment in the
controller helps well here.
- when the method is reused by many actions, we need to create “dummy”
methods that simply call the real method. For instance,
find_for_products_show just passes the arguments to another method
called find_for_subscriptions_show which is where the real code sits
- there is a slight performance hit
Has anyone experienced such thing? The idea came to me yesterday when
trying to spec a chain of named_methods. I realized that the chain of
named_methods doesn’t belong to the controller, it should be wrapped in
a dummy method that calls the named_scopes.