How much ‘less code’ is better?

Let’s consider this piece of neat meta-programming sugar. We have two Rails Models, User and Role with Migrations defined as:

class CreateUsers < ActiveRecord::Migration
  def self.up
    create_table :users do |t|
      t.column 'role_id', :integer
      t.column 'email', :string
    end
  end

  def self.down
    drop_table :users
  end
end
class CreateRoles < ActiveRecord::Migration
  def self.up
    create_table :roles do |t|
      t.column 'name', :string
    end
  end

  def self.down
    drop_table :roles
  end
end

Let’s imagine that we have three types or Role, Root, Administrator and Customer. We want the Users to know which Role they belong to. Supposing Role looks as simple as:

class Role < ActiveRecord::Base
  has_many :users
end

… a perfectly acceptable implementation of User could be:

class User < ActiveRecord::Base

  belongs_to :role

  def root?
    self.role.name == 'root'
  end

  def administrator?
    self.role.name == 'administrator'
  end

  def customer?
    self.role.name == 'customer'
  end

end

Now, I get an uneasy feeling every time I see similar looking code repeated more than once and, thanks to Ruby’s monkey code remedy nature, I can achieve the same result by writing the above as:

class User < ActiveRecord::Base

  belongs_to :role

  Role.find(:all).each do |role|
    define_method("#{role.name}?") do is? role.name end
  end

  private

  def is? role_name
    self.role.name == role_name
  end

end

There’s another advantage to this approach. Come a time when I need to add more Role definitions, I will not have to worry about User, in terms of writing code for it to comply with the changes to Role.

But all this begs the question: Is every body better off with me trying to be clever and not doing the straightforward thing any ol’ dev could grasp in a second, even though I’m saving the world (and my app) a few bytes?

To be honest, I’m not particularly fond of the idea of compromising code effectiveness or elegance in order to accommodate mediocre developers. I find that to be a pessimistic strategy that could ultimately act against the benefit and integrity of the solution.

Having said that, being part of larger teams exponentially increases one’s responsibility towards the possible maintainers of their code, so I don’t feel I’m 100% right on the above declaration.

5 Responses to “How much ‘less code’ is better?”

  1. Paul Barry Says:

    I don’t think that code is too much magic. The methods are still defined in the User class. Any competent developer should be able to figure that out from looking at that code. It’s not like when programming in ruby you have an IDE for you where you could click on “user.customer?” and have it take you to the code where that is defined.

    One thing I would be worried about with the above code is name collisions. For example, what if you add a role called foo and then a method called “foo?”. you might run into some strange errors that are difficult to debug. Maybe make the auto_generated methods like user.role_customer? to avoid that?

    The area where I get really worried about having to much magic in the code is when you have some random code off in some other file that adds methods to a class.

  2. Travis Says:

    It’s true, ‘any competent developer could figure it out’ — The problem is the length of time it takes the developer to figure it out.

    I have recently been looking through a lot of code, all which can be ‘figured out’. I keep on thinking that it would be so nice if for each class there was some sort of human readable description that told me in general terms what the class does. Ah-HA! Documentation!!

    If you were to provide a one or two sentence description of what the clever code does in human readable terms, then you have gained both cleverness and readability.

  3. AnĂ­bal Rojas Says:

    I understand your point, programmers are not islands and the source code is part of social network.

  4. Tony Says:

    This is an argument for the use of comments. I know that they went out of fashion some time ago, but absolutism sucks.

  5. Chris Says:

    The code is certainly neater, however there is an argument that the interface of User is now unclear - we only know it responds to an administrator? method because there is a role in the data with the name “administrator”, and if that role name was to change or the role removed, then the interface to your class would also magically change - with possible undesirable effects on it’s clients.

    If the concept of these particular roles is required in the domain model, and is actively used by code (such as the client of User which is invoking administrator?), then I feel they should be represented directly in the code, possibly as an enumeration (and then these convenience methods could be defined by iterating over the enumeration). Of course this then begs the question of why Roles, now of fixed values from an enumeration, would be in the database at all.

    If, on the other hand, they are in the database because they are configurable, then it is probably better to not have these convenience methods at all - but rather to provide a single is? or inRole? method that takes a Role object (not a role name). The client that does care about particular Roles, like administrator, can then obtain the Role object it wants, and then invoke the is? method with that role. This allows the failure to find a particular role in the data to be indicated at precisely the point where the code is dependant on that role existing.