Showing posts with label ruby. Show all posts
Showing posts with label ruby. Show all posts

Monday, March 19, 2012

The Interface Segregation Principle in Dynamically Typed Languages

When I first heard that 'duck-typing is the interface' it only meant one thing to me; it meant that I could not explicitly use an interface. The ramifications of this were not immediately apparent, but what did that matter? I had duck-typing! Later on I started to understand what it meant to have implicit interfaces. Only after did I have a few 'fix this forward facing class and watch everything break' refactorings did it start to sink in. I needed to really treat certain classes and modules differently than the rest of my code. I needed to create pieces that I could depend on. I needed pieces that were static because they encapsulated ideas that should not be changing often. I wanted to switch the implementation at will and the only way I was going to accomplish this was to really understand that duck-typing is the interface.
When I say create a class to depend on it means a couple of things. First, it means that the class is for the client and not for the implementer. This if often said of interfaces in a statically typed language so of course it holds true for an implicit interface. An example would be any gem worth using (pick your favorite). They provide a forward facing interace that is not meant to change rapidly and does not change for weak reasons. Gems are to be used by clients and are meant to be predictable with each release. Imagine if you had to rewrite your code with each gem version because the implementer had a new idea for code arrangement. You would not do it, you would stick with the version you were previously using, missing out on the new tweaks and features. For this reason the interface we provide in dynamically typed languages needs to be static and only change for a very well thought out reason. This way the client can have a high confidence in their expectations of the code. Remember that pulling a method out from under a client in a dynamically types language causes run time exceptions (although, they ought to be testing).

What if the implicit interface being provided is staring to feel bloated and too big. It started out as one coherent idea but is now many fragmented ideas? Then, it is time to break it up into smaller interfaces. We do not want to sacrifice the dependability, but we also do want to bring our classes and modules back to a coherent state. It is then time to refactor to smaller classes, however, it is important to keep the client of the interfaces in mind. It is entirely possible for classes to 'implement' two or more interfaces keeping in mind that our implicit interfaces are forward facing for the client's use. Moving forward, however, it is important to remember that we have two or more ideas being implemented in this module and that these ideas do not always need to be implemented together.

When we provide a public API to our code we allow ourselves to change the implementation at will. What if, for example, we provide a class that talks to an external service. Behind this interface we manipulate the data we receive from the service and return only what is necessary to the client. We expose this to our client through an implicit interface. Then, one day, the backend service changes completely. We can still receive and use the same data but how we retrieve this data is completely different. So, of course, the implementation changes. But, our client of our interface never has to know about the implementation changing. We can pass a completely different class around, but since it conforms to the interface the client never knows, and frankly, never needs to. The client never noticed a disruption in service because the client's expectations of the interface were always met.

Uncle Bob writes about a copy program when discussing the Dependency Inversion Principle. I think it is a great read and it really helped me understand what it meant to invert dependencies when I was still struggling with the idea. What I wanted to highlight is not really the dependency inversion, but the interface segregation that also takes place. I'll rewrite the system in ruby to show what I mean.


When we look at this it looks trivial. Why not just call gets and puts directly instead of putting them in a class? Well, let's see what this looks like when the implementations change.


We want the client to use the file read and write instead of the standard IO read and write that we were using before. Notice that the client's implementation (the copy method) did not have to change at all. This is only accomplishable because we hid both implementations behind the Reader and Writer interfaces respectively. This is the power of thinking with interfaces in a dynamically types language.

Although it is not explicitly declared, it is important to remember the Interface Segregation Principle. With ISP we can create dependable interfaces for our clients. We can also switch implementations at will without having to wait and see what breaks. These are powerful tools to use and they ought to use them in our dynamic languages. Even if interfaces are not explicit we still have access to the idea.

Monday, February 27, 2012

Ruby's Functional Programming

Ruby is a fully object oriented language and is, in fact, so dedicated to objects that every entity in the language is an object. After hearing that statement it might seem a little weird that ruby also has functional support. Ruby's functional aspects are powerful and complete which makes it worthwhile to learn. We can invoke operations such as reduce and filter with the use of code blocks. We can also pass functions around directly with the use of lambda and Proc objects. In this post I'll show you some of the more powerful tricks, show their potential pitfalls, and document the experience with code to play with.

Each method call can be given an additional code block. If you don't believe me then put a block on the end of every method call that currently does not have one and watch as (almost) everything still works as intended (please don't really do that). I'll introduce code to show this, but first let's see a straight forward imaginary workflow:

Now get_name just returns the name attribute of an object, as you might guess. If we wanted to use this to get the name of an employee we would first find the employee and then pass it in here as a parameter as we have done above. Let's show the same workflow, but this time let's allow the code block to give use the name:

Cool right? We can build any employee interaction we want off of get_employee using code blocks. This is an imaginary case, however, and code blocks aren't always the best option so use them wisely.

Code blocks are a part of some of the standard library's methods. It allows us to make use of functional ideas in ruby code. For example, let's look at an inject that sums all of the elements given multiplied by two.

These are powerful expressions because the intermediary steps (i.e. the summations and a single element's multiplication by two) are stateless. We simply put data into the inject and a single answer comes out with no side effects. Other such functional actions include (but are not limited to) reduce, collect, and reject. Ruby's Enumerable has lots of functional methods.

The last functional item I want to share is the use of closures. In Ruby we can make use of lambda, Proc, and method(:name) to create closures. They all appear to be very similar, but have subtle differences. For the sake of learning we will ignore the subtle differences and use Proc to explain the concept. Procs are objects that encapsulate executable code. With a Proc we can bundle up some code and pass a Proc object around until we are ready to call it. For a simple example let's look at the following:

This should feel very similar to the code blocks we had discussed earlier. This is because code blocks are a type of closure! Think of Proc's as a code block that can be held for later use. Let's explore closures a little more:

What happened here? We invoked gen_bar in the Example::Bar object and therefore Bar.new should invoke a new Example::Bar, right? Wrong! Procs are always evaluated in their declared scope. That means that in this case the Proc was executed in the context of module Foo even though it was called in module Example. This is something to keep in mind as closures are passed between classes and modules.

Functional concepts in Ruby can make coding easier, cleaner, and more expressive. It's important to understand the concepts in order to use them correctly when a problem being faced could use a functional solution.