patterns


I’ve have been pondering in the past 6 months - How do I get better at programing? What is the best way? do I need more books? At my current company, we whole heartedly engage in peer reviews, nothing gets checked in the repository without at least one person going over it. In that process, i’ve learned more about coding then I could from 10 books. I used to be a book fiend. I had about 10 books on every subject. Did I learn? yeah, some! But I think I’ve learned more from doing and practice. Practice, practice, practice! When the Chicago Ruby User Group offered this book in exchange for a review, I jumped at the chance.

“Refactoring in Ruby” written by William C. Wake and Kevin Rutherford.
Published by Addison-Wesley

“Refactoring in Ruby” is more like a “workbook” then a “how to write awesome code” book. If you download the code from github http://github.com/kevinrutherford/rrwb-code you have tests already written for the exercises.

The book is arranged in three parts, The Art of Refactoring, Code Smells, and Programs to Refactor.

There are explanations of “code smells” which are one characteristic of code that could be improved. Some of them are long parameter lists, unnecessarily complex, global variable, feature envy sections, etc. One thing I find interesting is the “How did it get this way?” section. It gives some insight into the thought process and reasoning behind the smell. I think this is good, as programmers our ego may be rather miffed to hear “This code stinks” but with some reasoning, it makes the pain less and I think firms up in our minds when this happens again, to do it this other way. I always want to know why when someone says I could do such and such thing better.

In addition to the code smell examples there are three programs to refactor in the end of the book. In a conversational tone, it walks through and gives some hints on what needs refactoring. Its almost as if you had a pair programming buddy working with you and identifying in small chunks what can be improved. This is definitely something I want to work through more carefully.

What I find odd, is that not all the code smells have code examples. The inspiration for the book I think is the Martin Fowler book “Refactoring Improving the design of Existing Code” which has examples for every code smell. Maybe Ruby smells less than Java? Or those fixes are really trivial? I don’t know. Overall, this is a great book and is certainly worth the price and investment and you will be a better programmer because of it!

There are explanations of “code smells” which are one characteristic of code that could be improved. Some of them are long parameter lists, unnecessarily complex, global variable, feature envy sections, etc. One thing I find interesting is the “How did it get this way?” section. It gives some insight into the thought process and reasoning behind the smell. I think this is good, as programmers our ego may be rather miffed to hear “This code stinks” but with some reasoning, it makes the pain less and I think firms up in our minds when this happens again, to do it this other way. I always want to know why when someone says I could do such and such thing better.

In addition to the code smell examples there are three programs to refactor in the end of the book. In a conversational tone, it walks through and gives some hints on what needs refactoring. Its almost as if you had a pair programming buddy working with you and identifying in small chunks what can be improved. This is definitely something I want to work through more carefully.

What I find odd, is that not all the code smells have code examples. The inspiration for the book I think is the Martin Fowler book “Refactoring Improving the design of Existing Code” which has examples for every code smell. Maybe Ruby smells less than Java? Or those fixes are really trivial? I don’t know. Overall, this is a great book and is certainly worth the price and investment and you will be a better programmer because of it!

Call me crazy, but this is why I classify myself as a language geek. When I learn something fascinating, i wonder hmm how can I do that with X language? My last post I did an example of the Builder pattern as described in Effective Java by Joshua Bloch. The main motivation for me to use Builder is to have flexible parameter lists, without worrying about order of parameters (there are a few other reasons outlined in the book, but this is what I find cool).

Its too easy.

My class:

RUBY:
  1. class Address
  2.   attr_accessor :street, :street2, :city, :state, :zip, :address_type
  3.  
  4.   def initialize(&block)
  5.    
  6.     #set default values
  7.     self.city = "Chicago"
  8.     self.state = "IL"
  9.    
  10.     #set value from block
  11.     instance_eval &block if block_given?
  12.  
  13.   end
  14.  
  15. end

And the usage of it:

RUBY:
  1. def testDefaultValues
  2.     myaddress = Address.new
  3.     assert_equal("Chicago", myaddress.city)
  4.     assert_equal("IL", myaddress.state)
  5.   end
  6.  
  7.   def testStreetStateZip
  8.     myaddress = Address.new do
  9.       self.street = "this is the street"
  10.       self.zip = "11111"
  11.     end
  12.     assert_equal("Chicago", myaddress.city)
  13.     assert_equal("IL", myaddress.state)
  14.     assert_equal("this is the street", myaddress.street)
  15.     assert_equal("11111", myaddress.zip)
  16.   end

Wow, huh? Compare to

JAVA:
  1. public void testBuilderDefaults() {
  2. Address expected = new Address.Builder("Chicago", "IL").build();
  3. assertEquals("State is IL", "IL", expected.getState());
  4. assertEquals("City is Chicago", "Chicago", expected.getCity());
  5. }

then the optional params are chained to that:

JAVA:
  1. public void testBuilderStreetStateZip() {
  2.    Address expected = new Address.Builder("Chicago", "IL").street("this is an address").zip("11111").build();
  3.   assertEquals("this is an address", expected.getStreet());
  4.   assertEquals("11111", expected.getZip());
  5.   assertEquals("IL", expected.getState());
  6.   assertEquals("Chicago", expected.getCity());
  7. }

Full source for Ruby (though I was able to paste it all here!)
Address class in ruby | Address test in ruby

And for Java, if you want to compare ...
Address class in Java | Address test in java

Yes... sometimes its hard not to gloat. :-D

yeah yeah yeah, its not really "fair" to compare strongly typed languages... but as I said, my motivation is to have easy parameter lists without having to remember specific ordering of params for constructor or use multiple set methods.

I have been reading Effective Java by Joshua Bloch and learned something new so I wanted to try it out.

Making long parameter lists in your constructor is not fun and prone to errors. Previously I thought that best way to handle this situation was to make a bunch of setter methods. This can get kind of tedious and hard to follow when there are alot of parameters:

JAVA:
  1. Address myaddress = new Address("Chicago", "IL");
  2. myaddress.setZip("44422");

Using a Builder object:

JAVA:
  1. Address myaddress = new Address.Builder().city("Chicago").state("IL").zip("44422").build();

Using a builder class allows you to specify params in any order too!

Here is the source code for my Address class with Builder. The builder is implemented as a nested class since it will only be used by the Address class.

Address class with Builder

Test for Address class

The required parameters are set in the Builder constructor:

JAVA:
  1. public void testBuilderDefaults() {
  2. Address expected = new Address.Builder("Chicago", "IL").build();
  3. assertEquals("State is IL", "IL", expected.getState());
  4. assertEquals("City is Chicago", "Chicago", expected.getCity());
  5. }

then the optional params are chained to that:

JAVA:
  1. public void testBuilderStreetStateZip() {
  2.   Address expected = new Address.Builder("Chicago", "IL").street("this is an address").zip("11111").build();
  3. assertEquals("Address is this is an address", "this is an address", expected.getStreet());
  4. assertEquals("Zip is 11111", "11111", expected.getZip());
  5. assertEquals("State is IL", "IL", expected.getState());
  6. assertEquals("City is Chicago", "Chicago", expected.getCity());
  7. }

The book goes into more discussion that I haven't quite wrapped my head around yet, but this is interesting stuff .. even though it is java ;)