this is a blog by Jeff Perrin, a software developer based in calgary alberta

What I Learned From X That Makes Me a Better Programmer in Y

Reginald Braithwaite says he'd love to hear stories about how programmers learned concepts from one language that made them better in another. This pretty neatly coincides with a post I've been meaning to make for months, so I might as well just get on with it and write something (because as CHart reminded me, I haven't even posted for months). Sometime around late 2004 - early 2005 I heard about Ruby on Rails for the first time. I'd never really programmed in any languages but Java/C#/PHP before, but I'd read posts by guys like Sam Ruby and Martin Fowler about how Ruby the language was really expressive and compact. However, it wasn't until Rails started getting some buzz that I really looked at any Ruby code and tried to decipher what it was doing. Rails put Ruby within a frame of reference that I was very familiar with (web development) allowing me to easily contrast the "Ruby Way" with the .NET/Java way I was familiar with.

The first thing that really caught my eye was the extensive usage of blocks, or anonymous methods. Coming from Java/C#, I had a hard time deciphering what was really going on when I saw something like this in Ruby code:

list.find_all{ |item| item.is_interesting }

It was pretty easy to see what the end result should be, but how does it actually work? All I knew was that a simple one liner in Ruby seemed to balloon into this in Java:

List interesting = new ArrayList();
for(Item item : items){
  if(item.isInteresting()){
    interesting.add(item);
  }
}

Sometime later, a pattern was introduced into the Java project I'm currently working on by another developer. This pattern seemed to accomplish roughly the same thing as the Ruby example (conceptually, there was still a lot of code in the Java version).

new Finder(list, new InterestingItemSpecification()).find();

Astute readers might recognize this as a variation on the Specification Pattern I'd written about almost a year ago. The point of this pattern is to allow the developer to specify how to filter a list of items, rather than manually iterating over the list by themselves. Never mind the fact that doing this in Java requires as many lines as the standard for-loop example... It's the concept of telling the list what you want, rather than looping through manually to take what you want that's interesting here.

I eventually created a sub-class of Java's ArrayList that allowed it to be filtered directly, just like Ruby arrays and C#'s generic list class. Now the code ended up looking like this:

list.Where(new InterestingItemSpecification());

Once I got this far, things really started to fall into place. I started to see duplication everywhere. Hundreds of methods (it's a pretty large project) that selected slightly different things from the same lists, the only difference lying in a little if clause. I started deleting entire methods and replacing them with Specifications. Booyah. Then I started seeing other patterns.

Accumulation/Reduction/Folding:

public BigDecimal getTotal(){
  BigDecimal total = BigDecimal.Zero;
  for(Item item : getItems()){
    total = total.add(item.getSubTotal());
  }
  return total;
}

Mapping/Conversion

public List getConvertedList(){
  List converted = new ArrayList();
  for(Item item : items){
    converted.add(item.getAnotherObject());
  }
  return converted;
}

Applying actions/commands to each item

public void calculate(){
  for(Item item : items){
    item.calculate();
  }
}

For each of these common informal patterns I was able to create a formal method for accomplishing the same thing. The goal became to distill each method down to just the part that made it different from another method. The act of iterating a list is boring, boilerplate noise that just doesn't have to be there. Here's the end result:

Accumulate

list.reduce(new SumItemCommand());

Map

list.convert(new ItemToThingConverter());

Actions

list.forEach(new DoSomethingToItemCommand());

There's still the overhead of creating a class for each action/command/converter, etc, but the main goal was reached. (I realize C# doesn't have this problem, but once again, it's the concept that was important to my learning).

I eventually started to get really good at seeing these patterns in code, even though a method might combine several of the above concepts. It really is amazing how many different ways a method can be written, but how easy it becomes to distill it down to accumulation, conversion, filtering, and just basic actions once you've had this "revelation."

Over the last few months I started seeing some other, more specific examples of the above patterns. Summing was just a version of accumulation that acted on numbers. SelectMany (which I stole from C# 3.0) was simply accumulating into a list. By the time I got around to almost implementing GroupBy, I just stopped. Whoah. I was well on my way to implementing SQL on in memory objects. Maybe I should just stop this madness and write a SQL query to get what I want in the first place.

It's amazing when I think back on it, but simply being exposed to another language (Ruby) because the code looked so pretty caused me to learn the hows and whys of basic functional programming techniques. I also gained a new respect for SQL, as I completely stumbled upon most of its basic concepts in my quest to remove needless duplication from Java code. It's funny to think that Lisp has been around for ages, yet most programmers either aren't even taught the basic building blocks of functional programming (I wasn't), or else forgot about it. The sad part is, it's all just basic fucking Math.

Self Conscious Development

Arguments You’ll Almost Never Hear