Rado's blog

Preserving named arguments on inheritance

I don't use inheritance very often, but some times it is the best solution. Ruby is not much carrying when you overwrite a method. The method is just replaced by the new method. It doesn't care about arguments at all.

Since 2.0, Ruby support named arguments. I'm starting to use them more and more. But they are a bit tricky in terms of overwriting.

Lets say we have a class which creates user objects named UserBuilder:

class UserBuilder  
  def create(name: )
    puts "name: #{name}"
  end
end  

When I have to create a CustomerBuilder, which creates customers (user with address), I can write it like:

class CustomerBuilder < UserBuilder  
  def create(address:, name:)
    super name: name
    puts "address: #{address}"
  end
end  

This works, but creates a coupling between UserBuilder and CustomerBuilder. This coupling is a bit tricky to catch. Imagine the following scenarios:

  • name become optional in UserBuilder
  • name is renamed to full_name in UserBuilder
  • name is split into first_name and last_name in UserBuilder

In all of those cases change in UserBuilder triggers change in CustomerBuilder.

Such dependancies are toxic. Here is a better solution:

class CustomerBuilder < UserBuilder  
  def create(address:, **args)
    super **args
    puts "address: #{address}"
  end
end  

Now we can add, change, remove named arguments to UserBuilder#create and CustomerBuilder#create is not affected. Named arguments are just delegated down the change.

Not Just Code Monkeys

I really liked Martin Fowler's talk at OOP 2014:

This was part II of his keynote. Part I was Workflows of Refactoring.