ruby


29
Dec 09

book review: design patterns in ruby

design patterns in ruby

Go buy this now

I am back from the holiday break and a perfect storm has come together, I’m currently working on a rails project, and I have a wonderful girlfriend who embraces my geekiness and buys me Design Patterns in Ruby. I have been reading this thing for the past few days and can’t put it down, I wanted to read a chapter last night before bed, I sleepily set it down 5 chapters later.

Just so you understand something, although I love to read, I am a slow reader, books are hard for me to get through, I also have a ton of things to read and play around with, so you better keep my attention. I have also read the classic GoF book, so I’m coming into this book well versed in design patterns. I’ve played with ruby a few times before, but nothing too serious (if you look back in the archives you will see that my first post was on ruby koans).

Let’s talk about this great book by Russ Olsen. The book does not require you to know anything about ruby, the first chapter is, in fact, a great primer to the language. Olsen comes from a background of 25 years of software development experience, as he puts it

I have been building software for more than 25 years. I’ve done assembly language, FORTRAN, Pascal, C, C++, Python, Java and now Ruby.
  -Russ Olsen

The introduction to ruby feels like it was written for someone with programming experience in a Java-like language. Throughout the book Olsen makes reference to the Java way to do things (which will be easy to grasp for the .Net crowd too). The primer to the language is interesting in that it skips some of the core things that makes ruby what it is (the whole meta-programming, monkey patching, message passing thing). This would seem like an oversight at first, but was helpful for me as a new ruby user. I wasn’t bogged down in the different of ruby, so I could focus on the same. This let me feel comfortable with the language and focus on the patterns, as we will see, these parts missing in the primer will be fully explored later in the book.

The book is structured very much like the GoF book, with each chapter focusing on a particular pattern. Olsen opens up the chapter with some example situation, then he moves into how you could solve it with inheritance or ugly code. Then the problem is re-examined, a pattern starts to emerge, and then is described. The pattern is explained in the classic GoF style with example code (in ruby) and UML diagrams, the best part though is the clear, concise, approachable explanation provided by Olsen. The pattern now being firmly understood, the book digs into the pattern and looks at ways that we can ruby-ize it. At this point we are normally treated to some new interesting ruby language paradigm that let’s us quickly and easily rewrite the pattern, making it more concise and elegant. There is then a discussion of the uses, and probably more importantly, the abuses of the pattern. Every chapter ends with a nice summary of what was learned and (as I found out last night) an enticement to keep reading as the next pattern is introduced.

rocket sauce

Pure unadulterated rocket sauce!

The writing is incredibly approachable, Olsen does not get bogged down in technical jargon, he explains everything that’s going on in a concise and understandable way. There are copious code examples that are excellent at providing a concrete example to the abstract pattern Olsen is discussing. The author mixes in some humor here and there and will show how other programming languages implement the patterns and historical reasoning for why things are the way they are in ruby.

The overall impression I got from this book is that it is win, condensed down into ink on paper. I have learned a ton about ruby, relearned some great patterns, and gotten a great insight on the ruby way to solve problems. If you find yourself thinking, “Well I don’t need to learn design patterns, I’m so smart!” Well you are not, I’m going to use one of my favorite quotes here with a bit of a twist.

Those who don’t understand design pattern are condemned to reinvent them, poorly.
  -Matt Nowack (original attribution to Henry Spencer)

Design Patterns are all around you, learning these will help you solve future problems, understand how rails works (in fact there are several occasions in the book where Olsen shows how rails uses this pattern or that one). This book is a pleasure to read, and I suspect will serve as a nice reference for implementing patterns correctly in ruby. I’m glad to have it in my toolbox, and I would suggest you get it for yourself.


23
Dec 09

decompress

festivus card

Get ready for the feats of strength

The holidays are upon us and no matter what holiday your particular sky god has you celebrate (Festivus for the Rest of Us!) there is one thread of humanity that binds us together at this time, days off from work. When you have some time off of work you can spend it doing any number of worthwhile things

  • Drinking egg nog until you black out
  • Eating your weight in sugar cookies
  • Having that same argument with your family that you’ve been having for the last 10 years
  • Watching 24 hours of A Christmas Story
  • Spending quality time with friends and loved ones
  • Living through the same day over and over and over, á la Groundhog’s Day (Best saved for the actual Groundhog’s Day)

If you are reading this blog there is a good chance that you are some sort of programming nerd, its ok, I don’t care what the New York Times says. As a proud nerd you have probably heard of some sort of technology that interests you, maybe clojure has piqued your curiosity, or you finally want to learn that “rails” thing all those young whippersnappers keep talking about. I would argue that this can be a great way to decompress, if you do it right.

First off, find something different than what you are used to, if your 9-5 is .Net don’t spend your precious free time learning more .Net, that’s stupid. Go find something radically different, maybe look at a functional programming language, go find that weird kid in the corner and talk to him, he probably has interesting stories about fire. This might seem like a waste of time at first, but it’s not. It’s all too easy to get locked into an ecosystem, doing the same thing day in and day out, to get comfortable there and to start thinking that your way is the only way or the best way. Reading about other technology outside of your realm might not have a direct benefit to your 9-5, but you may gain a perspective or understanding that would be incredibly difficult to get from your standard frame of mind.

Second off, this isn’t work, this is fun. You are allowed to make mistakes and change your mind. If you work through a tutorial or get done with the first chapter of something and find that you really don’t care, then go find something else, the software world is full of interesting things. The thing is, only stop if you grok the subject and dislike it, don’t necessarily stop just because you don’t get it at first.

erlang source in gedit

What? Caroling? No fuck that, I got some erlanging to do!

Third off, this is just to whet your whistle. Don’t ignore your loved ones, squirreled away with your Beginner’s Guide to Erlang because you’ve fallen in love with the idea of massively parallel systems. Take this time to investigate several things, learning the basics and setting up your love affair for the next few months. Then make sure you tell the people you care about that you love them and eat too much food and do people things.

For me this break will be about Rails. I’ve followed rails for a while, I’ve always been impressed with it, and I’ve had a few false starts. I’ve gone through the Getting Started tutorial more than once. I’m a php guy at my core, but learning how other people do the web is worthwhile. I’ve started the adventure already and think that this time it might stick. I have a 2 hour car ride up to Cleveland and back that I plan to fill with listening to Rails podcasts.


That’s all for now, go relax and decompress, that’s what I plan on doing for the next 4 days. As a side note I will probably not update during the holiday break so if you obsessively check or your rss feed gets lonely don’t worry I will be back on the 28th.


6
Oct 09

ruby koans (2)

I still have the good fortune of not having any huge problems with our production application. During this time I’m brushing up on some ruby, sharpening the blade. I’ve been doing this by working through EdgeCase’s Ruby Koans. In my first blog post ruby koans I suggested that anyone interested in ruby utilize this resource and pointed out some problems I had encountered. I still suggest that anyone wanting to learn ruby and who has a basic understanding of programming use this great resource.

Working through the koans I have found some more issues, this time in the about_message_passing.rb file. One is just an oddity, the other a potential show stopper for someone new to programming.

Starting at line 50 there is a class called MessageCatcher (technically they are reopening the class defined on line 5)

class MessageCatcher
  def add_a_payload(*args)
    return :empty unless args
    args
  end
end

This is a very oddly named function, it doesn’t seem to add a payload to the the arguments, and it is coded in such a way that it will never return :empty. For it to return :empty, args would have to evaluate to false. The only falsey values in Ruby are nil and false, the only values args can be is an array. Arrays, even empty arrays, are true in ruby. If you don’t believe me, go ahead and run this in irb

:empty_arrays_are_true if []

That will evaluate to :empty_arrays_are_true, which proves my point. This is really a minor issue, but when filling out the corresponding test, the results aren’t really obvious.

The much bigger problem starts with the TypicalObject example

class TypicalObject
end

def test_sending_undefined_messages_to_a_typical_object_results_in_errors
  typical = TypicalObject.new

  assert_raise(NoMethodError) do
    typical.foobar
  end
  assert_match(/foobar/, exception.message)
end

This results in a nasty error when you rake, that looks something like this

You have not yet reached enlightenment ...
undefined local variable or method `exception' for #<aboutMessagePassing:0xmemory>

Please meditate on the following code:
./about_message_passing.rb:78:in `test_sending_undefined_messages_to_a_typical_object_results_in_erros'
./edgecase.rb:143:in `send'
./edgecase.rb:143:in `run_test'
./edgecase.rb:135:in `run_tests'
./edgecase.rb:134:in `each'
./edgecase.rb:134:in `run_tests'
./edgecase.rb:204
./edgecase.rb:203:in `each'
./edgecase.rb:203
./edgecase.rb:202:in `catch'
./edgecase.rb:202
path_to_enlightment.rb:27

If you are new to programming this could throw you off your game, the interpreter does helpfully tell us the line number to look at, line 78.

Looking at line 78 we see that we are using a local variable named `exception’, but we never define this variable. The way to fix this is to assign the result of the assert_raise to the variable exception, like so

class TypicalObject
end

def test_sending_undefined_messages_to_a_typical_object_results_in_errors
  typical = TypicalObject.new

  exception = assert_raise(NoMethodError) do
    typical.foobar
  end
  assert_match(/foobar/, exception.message)
end

That simple assignment, which does appear correctly in the test right after this one, solves the problem and allows you to continue on your ruby learning way.


2
Oct 09

ruby koans

EdgeCase’s Ruby Koans are a great way to get started with the Ruby programming language. I’ve worked through them once before and have had some free time at work so decided to work through them again.

The quality of the koans are normally excellent, there are a few times where a comment is left in the code to make you think, and you really wish that there was an answer key somewhere. There are also what look like a few errors in the code

In about_sandwich_code.rb, the find_line and find_line2 functions don’t seem to make much sense. You would imagine a function would find a line matching a given regular expression, but the regular expression is hardcoded to /e/ which doesn’t seem very realistic. This is the original.

def find_line(file_name)
  file = open(file_name)
  while line = file.gets
    return line if line.match(/e/)
  end
ensure
  file.close if file
end

A more realistic function would be

def find_line(file_name, regex)
  file = open(file_name)
  while line = file.gets
    return line if line.match(regex)
  end
ensure
  file.close if file
end

I’m sure this was done to simplify the exercise, but it violates the rule of least surprise by adding magic functionality to the function.

In the last function of about_scoring_project.rb, named test_score_of_mixed_is_sum, the first assert reads

 assert_equal 50, score([2, 5, 2, 2, 3]) 

The rules of the game clearly specify that

# * A set of three numbers (other than ones) is worth 100 times thenumber. (e.g. three fives is 500 points).
# ...
# * A five (that is not part of a set of three) is worth 50 points.

This means that the score should be 200 (for the set of three 2′s) + 50 (for the 5) = 250. The first assert should be changed to

 assert_equal 250, score([2, 5, 2, 2, 3]) 

If you are interested in learning ruby, this is an indispensable way to learn not just the syntax, but to get the flavor, and to start thinking in ruby.

Expand this block of source to see my solution

def score(dice)
  result = 0
  counter = {}
  (1..6).each { |x| counter[x] = 0 }
  dice.each { |d| counter[d] += 1 }
  if counter[1] >= 3
    result += 1000
    counter[1] -= 3
  end 

  (2..6).each do |x|
    if counter[x] >= 3
      result += (100 * x)
      counter[x] -= 3
    end
  end

  result += (counter[1] * 100)
  result += (counter[5] * 50)
end