Ruby on rails with programing to interface pattern
Fri 03 Jan 2020

Developing methods of class for other classes to use, that is interface. Interfaces should not be changed time by time. Because that is knowledge which the other classes know about this class. Those are also connections. 

Separating interface from implementation equals separating what rarely change from what change regularly. Interfaces should be same. But implementation is not. In other words, the knowledge that other classes know about class A should be same. Not exact same but at least those are not changed. Regarding to Open/Close principle we close for changing and open for expanding. Changing and expanding are different. 

For example, we have Watch class like below.

class Watch
  def show_time
  end

  private 

  def show_numbers
  end 
 
  def show_timekeeper
  end 
end

show_time is interface method. Other classes know that we can show time using Watch. That means any Watch's instances which are able to show time. If this system has been running for many years and one day we change show_time to time_show. But show_time is a message that other classes would send to an instance of this class. Now it becomes wrong message. That is bad impact if we don't close for changes. We are able to handle it well but how about big system with a bunch of connections? We even can not do this or going crazy by doing this. It costs time and taking risk.

So we should not change this part. This is interface. We have to look for a method name which is in common, like a plug, an interface for many things. That recalls us about abstract level.

class Watch
  def show_time
  end
end

It's necessary to say that Naming is very important, especially name for interfaces which should not be changed in future. Every time we code, let's think about interfaces.

  • What interfaces are we working on?
  • Are we putting implementation to interface?
  • Are we changing interface methods?
  • What are impacts and boundaries?

Getting back to above code, what we should do if we want to change how it does but not what it is? . Look! WHAT IT IS? is usually about Interface. HOW IT DOES? is the implementation. Implementation is a sign for a thing which change regularly. Programing to interface does not mean we put a bunch of code to interface methods. But that means we uses Interfaces as the main messages, exactly INTERFACE, a port or an electric plug. Implementation would being used by putting code to these interfaces.

Look at above electric plug! People (other classes) don't know exactly where it would go. They have no idea about the electric cables behind which are new or not. 

  • WHAT IT DOES? - providing electricity.
  • HOW IT DOES? - no idea! The person who installed this would know. This plug can be moved to another house and being reused. Interface is same but another implementation (in another house).

That is way of critical thinking in coding and design.

According to above explanation we can implement like this.

class ClassicSkin
  def show
  end
end 

class Watch
  attr_reader :skin 

  def initialize(skin)
    @skin = skin
  end

  def show_time
    skin.show
  end
end

Now ClassicSkin becomes the implementation of show_time interface. show method is also other interface method which belongs to ClassicSkin. But it can be the implementation for show_time interface method. Or another implementation level here:

class WatchSkin
  def show_classic
  end

  def show_digital
  end
end

Feel free to change show_time implementation by involving different method. By using first solution we can have two classes:

  • ClassicSkin
  • DigitalSkin

So we use Dependency Injection because this instance can be changed regularly.

However, with second solution, we have only one class WatchSkin with different methods so we even don't need to create instance. We use Isolation by private method.

class Watch
  def show_time
    skin.show_classic
  end

  def skin
    @skin ||= WatchSkin.new
  end
end

We use DI because skin changed regularly whenever creating object - it created in constructor initialize method. Thus, we get to know the implementation might change regularly so we should separate them from interface. In order to do that, we have to know what exactly interface and where they are in code.

Thank for reading!