Monday, May 01, 2006

Why do *YOU* like Ruby?

An old friend of mine recently sent me this:
In short, why do *YOU* like Ruby?
It's a fair question. I'm currently developing exclusively in Ruby and writing almost only about Ruby. The short answer is Ruby requires less to get the job done. I'll elaborate, but remember, this is why *I* like Ruby, not an attempt to compare Ruby to any other language.

#1. It's easy to add behavior to objects. You can extract patterns and put them in modules or add them to existing classes. Once you have added the behavior you can quickly add responsibilities to your objects with much less code. Since I've been developing in Ruby I've found myself using Attribute Initializer and Initialization Chain quite often. By having the patterns for both of these behaviors extracted out to class methods I can reduce the code necessary which also reduces the potential for errors.

#2. Ruby's duck typing allows me to easily create dependencies. I strongly believe in the Unit Testing Guidelines I previously posted. The guideline I suggest in that entry is: Only one concrete class (with behavior) should be used per test. Because of duck typing I can follow this rule by creating stub dependencies without worrying about interfaces. Consider the following class:
class Consultant
def initialize(boss, phone, laptop)
@boss, @phone, @laptop = boss, phone, laptop
@phone.on if @phone.off?
@laptop.on if @laptop.off?
end

def text_boss(message)
@phone.text(message,@boss.number)
end

def send_email(email)
@laptop.send_email(email)
end
end
Consultant has a dependency on Boss, Phone, and Laptop. Additionally, when a Consultant instance is created it calls the on method of both the phone and laptop. Because the Consultant instance calls methods on phone and laptop in the constructor, nil cannot be passed as either argument.

Now, I want to test the Consultant class in isolation so I need to create stubs for Phone, Laptop, and Boss. In a statically typed language I would need a Phone, Boss and Laptop interface and each stub would need to implement the full behavior of the interface. However, in Ruby I can create simple stubs that only define behavior I'm interested in:
class StubLaptop; def on; end; def send_email(e); end; end
class StubPhone; def on; end; def text(msg, num); end; end
class StubBoss; def number; end; end;
Now I can use these stubs and define mocks that allow me test only the isolated Consultant class and it's interactions. Also, these stubs are really only in the test for support, thus making them essentially noise. The less noise I am required to include in a test the more readable (and maintainable) the test becomes.

#3. The dynamic features of the language allow me to more easily write Domain Specific Languages (DSL). At my current project we've provided the client with a domain specific language that allows definition of variables and reuse of those variables later in the script.

In the script a variable is defined similar to define :jay => thoughtworks.developer. Obviously, we are really using Ruby to call the method define with a hash where :jay is the key and thoughtworks.developer is the value. When the define method is executed it defines a method dynamically by the key and sets the return value to the value of the hash. Later in the script the variables are used similar to work jay, mike, charles. Again, no magic here, the work method is being called with the return values from the jay, mike, and charles methods. However, the end result is a very readable DSL which empowers my business users to code part of the system.

The same functionality could be achieved by changing the work line to read work :jay, :mike, :charles and storing the values in a hash. But, this is a step down from the above syntax in most business users eyes.

Similarly, I recently had a requirement build an ad-hoc sentence using dot notation. For example, this.was.the.syntax.but.the.sentence.needs.to.be.free.form. By using method_missing I was able to support this style with very little code required other than protecting keywords.
Post a Comment