SOL[I]D - Interface Segregation Principle

We've covered three SOLID principles so far. But this one is going to be special. Interface Segregation Principle refers to Interfaces, but we don't have it in Ruby. Should we omit this part? I don't think so, we can still learn something from it.

This principle was defined by Robert C. Martin this way:

Clients should not be forced to depend upon interfaces that they don't use.

If you're not familiar with the concept of interfaces, I'll try to describe it really briefly, so you can get the idea.

An interface describes only the signatures of methods. A class that implements the interface must implement the methods of the interface that are specified in the interface definition.

As we can see if Mouse implements interface IMovable it must implement all methods described in the interface. In this case it's just one method Move() , but very often interfaces are getting "fat". Even if my class needs just couple methods described in the interface, I still have to implement all methods described in that interface.

There are couple more definitions that should help us to get the idea:

Clients should not be forced to depend on methods that they do not use.

Many client specific interfaces are better than one general purpose interface.

The dependency of one class to another one should depend on the smallest possible interface.

Uncle Bob suggests to split fat interface into smaller ones, so you don't have to implement all methods described in one giant interface. Instead you can pick the interface you need to implement with just subset of methods.

But, I use Ruby...

We don't have interfaces, but there is something that we can learn from this principle, especially from this part:

Many client specific interfaces are better than one general purpose interface.

Let me show you by example how we can break this rule using Ruby.
Let's say that we have FeeCalculator which allows us, well to calculate fee :)

They add new argument to calculate method, and pass true/false depending on the need they have.

Let's think why it's bad. First of all now we have to pass some weird boolean that changes behavior of method. I know that we could add default false value to method definition, but it wouldn't help us if we have additional params after save_result param.

So it violates the basic rule:

Clients should not be forced to depend upon interfaces that they don't use.

In our case we're not dealing with interfaces, but we depend on method signature. One of the clients, ProductController#show doesn't want to save fee at all, but it forced to pass false argument to keep using calculate that method.

To refactor this code we have couple options. First of all Interface Segregation says that we should create smaller interfaces. I would suggest to do something like this:

Pass no more than four parameters into a method. Hash options are parameters.

Really good rule to follow. If method has more than four arguments, probably you should split that big "interface" into smaller ones and make them more client-specific.

I know that many Ruby developers just skip this principle because we don't have interfaces, but it's good to understand ideas behind this principle. It helps C# and Java developers to write better code.

I hope it was interesting reading and you found something new here.
Thanks for reading!