Fork me on GitHub

Friday, April 25, 2008

Ruby: Builder Pattern

Today morning I was reading through the blogs when I found this interesting post from Venkat on Groovy fluency. It is actually a builder pattern for constructing emails. I thought this example to be in╦łtriguing. As I am a ruby guy (Not a geek or a hacker. I am not sure if I am qualified to call myself that :-) ) I thought if I can write this in Ruby.

The problem is to create a mailer class in which you can set from, to, subject and body and send it. The from, to, subject and body needs to be passed through a block to the send method of mailer. Venkat has refactored to a stage where you call the mailer like this.


Mailer.send{
from "Sai"
to "matz"
subject "Ruby"
body "I love ruby"
}


I knew the solution was in using instance_eval. The problem was how to delegate each line of code in the block passed to be executed in the context of the mailer. First I tried to yield inside the instance_eval block. Unfortunately it did not work out. Later I figured out if I pass the block to the instance_eval then it will be possible to execute the block with respect to the mailer instance. So here it goes.
class Mailer
def from(fromAddress)
puts "from : #{fromAddress}"
end
def to(toAddress)
puts "to : #{toAddress}"
end
def subject(theSubject)
puts "subject : #{theSubject}"
end
def body(theBody)
puts "body : #{theBody}"
end
def self.send(&blk)
m = Mailer.new
m.instance_eval(&blk)
puts "sending the mail..."
end
end

Mailer.send{
from "Sai"
to "matz"
subject "Ruby"
body "I love ruby"
}

The pattern used here is builder pattern normally employed to construct complex objects out of different components. Take a look at GOF patterns book or Ruby design patterns for reference.
Usage as far I know are Markaby, XML builder, Shoes GUI toolkit. May be more are out there.
If you know any known usage in Ruby please add it to the comments.

Hope this post was useful as it was for me.

Tuesday, April 22, 2008

DRY and Testing projects

As an agile developer a lot of practices figure into my way of working like pairing, refactoring, TDD (Test Driven Design or Development. I prefer design.) Of all these practices the one which the most important, often mistaken to be the simplest and has definitive effect is DRY short for Don't Repeat Yourself.

The basic principle is to remove any kind of duplication in any kind of knowledge. But the catch which most people fail to get is it is not only with the code. We should not have duplication in code, data, tests, configuration, environment setup and tear down and even documentation. It is a well known fact that duplications will increase the maintenance effort of the code, lead to logical inconsistencies and poor factoring.

As a person with role of developer in a automation testing team, I have a chance to see a lot of people writing a lot of code. One of the sad things which I notice most often is when writing test code people tend to leave out practices like DRY or refactoring. The reason may partially be they are not familiar or they tend to think test code is write and throw away code, a trend partially encouraged by GUI recorders or code generators. I got the idea of writing this article from the experience I got from a pairing session with my friend while writing some code in WATIR.

We have a hybrid driven framework for WATIR internally used with in the company. One of the aspects of the framework is its ability to create a suite by selecting test cases from excel sheet. They have used three different workbooks for this purpose. One for creating the business flow from individual business components, one for the suite creation and other for the test data. The problem is there is duplication of test cases between the business flow sheet and the suite selection sheet. When I pointed out to my friend his instant reply was it was not in the code and so its not a problem. This was pretty odd to me and I explained to him that even though the test cases are low now, it is twice the job when we need to update something. And also if the test cases increase the work becomes even more difficult. So we moved the suite controlling as well as business flow to a single sheet. This removed the duplication we had as well as the maintenance attached with it.

The duplication here is subtle but these are the places we usually miss until it grows to a larger problem. Most of the time we concentrate on code and miss out to make our test data, environment, configuration, build scripts, test code DRY. I tend to see a lot of testers tend to write code for testing but fail to understand that tests are also code which need to be maintained. This leads to brittle test code and throw away test code which has data hard coded, code duplicated, non refactored. It is difficult to maintain such code and it is an over head to throw away it.

DRY is one of the most important principles of Agile because it helps to create a design which has maintainability in built to it. It is important to realize its importance and try to refactor our work at regular intervals to reduce duplication where ever it is and what ever code it may be.

Monday, April 21, 2008

Meta programming and documentation

I have been working on ruby for sometime and one of the things which attracted me to ruby is its meta programming capability. I work in DSLs a lot in Ruby and am currently working on a fluent interface for WATIR. Naturally meta programming comes into the picture in a lot of places in this implementation.

There are two problems I faced during the usage of meta programming. One is it hinders the way of using auto document generation like rdoc, the other is without proper documentation it is difficult to understand what you have written after sometime.

The first problem is more with the end user documentation. When I code an API I normally have comments in the methods and classes as here documents and at a later stage use rdoc to generate the documents. But when I use meta programming the code I am writing becomes concise but looses its meaning.

For example in one of the projects I wrote a geocoding API wrapper for yahoo geocoding service. I used a class called location for which I can set street, city, zip code or address as its attributes. Initially I wrote it as individual accessors but I found it to be too verbose and repetitive so I used method_missing to accomplish this.

class Location
def method_missing(method_name, args)
attr_name = method_name.to_s.chomp("=").to_sym
if %w[street city state zip address].include? attr_name.to_s then
@messages << attr_name.to_s
eval %(
class << self
attr_accessor :#{attr_name}
end
)
send(method_name, *args) if respond_to?(method_name)
else
raise "No method of name #{attr_name} error"
end
end
end



The job is accomplished easily but its meaning is a bit lost. I can still give the comment there and the rdoc will pick it and will use it. But still it will not be as effective as giving the normal documentation. The only solution which is ineffective that I can think of is to use dummy methods which mock the actual methods with comments during the document generation. I am not able to think of a better way.

The second problem is more on the developer's perspective. When using meta programming like this most of us feel happy that the work is done with lesser number of lines. But unfortunately the code's expressiveness is lost. So when you read the code after sometime it is difficult to understand why you used it actually. I normally follow TDD and even with the tests expressing my intent I find it difficult to understand the meta programmed code normally after a few days of coding it.

One of the important things when using meta programming is to write the code comment conveying your intent along with the code you are writing. This will go a long way in helping you at a later stage when you want to change something.

If you have anything related to this or want to discuss more in this regard please drop me a mail or add it to the comments.