Dependency inversion principle in Ruby

Hi,

Can any body help me to understand, how one can use DIP from S.O.L.I.D
in Ruby. I didn't find a Ruby implementation for this.

A. High-level modules should not depend on low-level modules. Both
should depend on abstractions.

B. Abstractions should not depend on details. Details should depend on
abstractions.

I got one http://blog.siyelo.com/solid-principles-in-ruby/ .

From this blog example -

(1) Which one is High and Low level module I didn't get.
(2) Point B from wikipedia really nothing I got there.

Please someone help me to understand how this principal works, or in
Ruby how far this principal is truly implementable.

Thanks,

Arup

Regards,
Arup Rakshit

These rules are easier to understand in languages where variables are
typed. Example in Java:

class OrderProcessor {
  private VisaPaymentService paymentService;

  public OrderProcessor() {
      this.paymentService = new VisaPaymentService();
  }

  public processOrder() {
      paymentService.charge(amount);
  }
}

In this example, the OrderProcessor depends on a VisaPaymentService.
This means that it depends on a low level module, or an implementation
detail. It would be much better to have OrderProcessor depend on an
abstraction, for example a generic PaymentService (receiving it from
the outside):

class OrderProcessor {
  private PaymentService paymentService;

  public OrderProcessor(PaymentService paymentService) {
      this.paymentService = paymentService;
  }

  public processOrder() {
      paymentService.charge(amount);
  }
}

PaymentService could be an interface with several implementations like
VisaPaymentService, PaypalPaymentService, etc. Now, OrderProcessor
depends on an abstraction and so it's easier to change.

When you apply this to Ruby, where there's no need to predefine
interfaces but we rely on duck-typing, this example is just easily
solved:

class OrderProcessor
  def initialize payment_service
    @payment_service = payment_service
  end
  def process_order
    @payment_service.charge amount
  end
end

The not-solid (liquid? :)) example in Ruby would be:

class OrderProcessor
  def initialize
    @payment_service = VisaPaymentService.new
  end
  def process_order
    @payment_service.charge amount
  end
end

As the blog article explains, don't confuse DIP with Dependency
Injection, which is a technique to implement DIP. As you see here, we
remove the construction of the VisaPaymentService from inside the
OrderProcessor class, and receive the object from the outside: the
outside injects the dependency into the OrderProcessor.

In Java, you could have dependency injection and not achieve DIP, if
you expected a VisaPaymentProcessor inside the class. In Ruby, as the
instance variable is not typed, DI pretty much achieves DIP.

Jesus.

···

On Tue, Feb 24, 2015 at 11:03 AM, Arup Rakshit <aruprakshit@rocketmail.com> wrote:

Hi,

Can any body help me to understand, how one can use DIP from S.O.L.I.D
in Ruby. I didn't find a Ruby implementation for this.

A. High-level modules should not depend on low-level modules. Both
should depend on abstractions.

B. Abstractions should not depend on details. Details should depend on
abstractions.

I got one http://blog.siyelo.com/solid-principles-in-ruby/ .

From this blog example -

(1) Which one is High and Low level module I didn't get.
(2) Point B from wikipedia really nothing I got there.

Please someone help me to understand how this principal works, or in
Ruby how far this principal is truly implementable.

Problem :

···

On Tuesday, February 24, 2015 12:00:11 PM you wrote:

On Tue, Feb 24, 2015 at 11:03 AM, Arup Rakshit > <aruprakshit@rocketmail.com> wrote:
> Hi,
>
> Can any body help me to understand, how one can use DIP from S.O.L.I.D
> in Ruby. I didn't find a Ruby implementation for this.
>
> A. High-level modules should not depend on low-level modules. Both
> should depend on abstractions.
>
> B. Abstractions should not depend on details. Details should depend on
> abstractions.
>
> I got one http://blog.siyelo.com/solid-principles-in-ruby/ .
>
> From this blog example -
>
> (1) Which one is High and Low level module I didn't get.
> (2) Point B from wikipedia really nothing I got there.
>
> Please someone help me to understand how this principal works, or in
> Ruby how far this principal is truly implementable.

These rules are easier to understand in languages where variables are
typed. Example in Java:

class OrderProcessor {
  private VisaPaymentService paymentService;

  public OrderProcessor() {
      this.paymentService = new VisaPaymentService();
  }

  public processOrder() {
      paymentService.charge(amount);
  }
}

In this example, the OrderProcessor depends on a VisaPaymentService.
This means that it depends on a low level module, or an implementation
detail. It would be much better to have OrderProcessor depend on an
abstraction, for example a generic PaymentService (receiving it from
the outside):

class OrderProcessor {
  private PaymentService paymentService;

  public OrderProcessor(PaymentService paymentService) {
      this.paymentService = paymentService;
  }

  public processOrder() {
      paymentService.charge(amount);
  }
}

PaymentService could be an interface with several implementations like
VisaPaymentService, PaypalPaymentService, etc. Now, OrderProcessor
depends on an abstraction and so it's easier to change.

When you apply this to Ruby, where there's no need to predefine
interfaces but we rely on duck-typing, this example is just easily
solved:

======

As per the Wikipedia --

In conventional application architecture, lower-level components(VisaPaymentService) are designed to be consumed by higher-level components(OrderProcessor) which enable increasingly complex systems to be built.

In this composition, higher-level components depend directly upon lower-level components to achieve some task. -- It means OrderProcessor always depends on the VisaPaymentService to process the payment of the order.

This dependency upon lower-level components limits the reuse opportunities of the higher-level components. -- Means in this composition, If I want my OrderProcessor to process the payment of the order using PaypalPaymentService, I wouldn't be able to do it. This is because Higher and lower level is coupled with each other.

The not-solid (liquid? :)) example in Ruby would be:

class OrderProcessor
  def initialize
    @payment_service = VisaPaymentService.new
  end
  def process_order
    @payment_service.charge amount
  end
end

Soltuion:

The goal of the **dependency inversion principle** is to avoid this highly coupled distribution(as mentioned above) with the mediation of an abstract layer(In our case payment_service), and to increase the re-usability of higher/policy layers(means OrderProcessor is a higher layer, which can now be reused to process orders using via any kind of payment service).

It means, we just inverted/reversed the dependency direction lower(VisaPaymentService) to higher(OrderProcessor) module. The technique we used to reverse the direction is called **Dependency Injection**.

class OrderProcessor
  def initialize payment_service
    @payment_service = payment_service
  end
  def process_order
    @payment_service.charge amount
  end
end

As the blog article explains, don't confuse DIP with Dependency
Injection, which is a technique to implement DIP. As you see here, we
remove the construction of the VisaPaymentService from inside the
OrderProcessor class, and receive the object from the outside: the
outside injects the dependency into the OrderProcessor.

Nevertheless the ″inversion″ concept does not mean that lower-level layers depend on higher-level layers. Both layers should depend on abstractions that draw the behavior needed by higher-level layers. - True, because Higher and Lower level depends on now PaymentService module(abstract layer).

Jesus.

Thanks for the explanation :

The presence of abstractions to accomplish DIP have other design implications in an Object Oriented program:

A. No class should derive from a concrete class - Why ?
B. No method should override an implemented method - Why ?

--

Regards,
Arup Rakshit

Debugging is twice as hard as writing the code in the first place. Therefore, if you write the code as cleverly as possible, you are, by definition, not smart enough to debug it.

--Brian Kernighan