This week (or, rather, last week) I finished Refactoring: Ruby Edition by Jay Fields and performed some more refactorings on Redmine. I discovered that the second half of the book had more value than the first and that even good code can be improved significantly.

Refactoring: Ruby Edition

After reading the first half of the book, I stated that the book didn't provide too much value beyond Fowler's original. After reading the second half, I would disagree with that assessment. The catalog continually introduced several alternative ways to do something in Ruby that you wouldn't be able to do in Java (the language of the original book).

These alternative methods are actually very powerful when put into practice. After playing with the refactorings, I believe that they give a Ruby developer better tools to refactor and could, possibly, give the Ruby developer the power to create better abstractions that allow for better code.

Some of my favorite refactorings given in the catalog include those that use the Ruby block syntax. For example, the following code

def total
    result = 0
    
    items.each do |item|
        result += item.value
    end
    
    result
end    

can be refactored into

def total
    items.inject(0) { |sum, item| sum + item.value }
end    

and I absolutely love that. As long as you know what inject means (and, while that's a bad name, there doesn't seem to be a better one), this code makes perfect sense, is shorter and very DRY. I like all three of those. In Java, to do this you would need to create a convoluted anonymous class that wouldn't necessarily improve the code.

I would recommend this book to any developer that is writing serious Ruby code, perhaps even experienced ruby developers. While experienced developers may be familiar with the Rubyisms, this book describes a methodical, structured way to introduce those Rubyisms during refactoring. For people new to Ruby, this is a must; and, for people that practice TDD, this book should be attached to your hip.

Refactoring Redmine, Part 3

This was my last encounter with Redmine and I came away happy with my work. While Redmine has some very good, solid code throughout, there were always areas that could be refactored. This particular area was a very small class file that likely was never revisited after it was written.

Step 1

Extract Methods

http://github.com/hammerdr/redmine/commit/08fb53b9ade8f021b24b1d5fa1f70627048c0970 http://github.com/hammerdr/redmine/commit/fb0cca25319efac87d3408bd45565a1eb2e674b5 http://github.com/hammerdr/redmine/commit/ef921d57bd4228313eeacb284f16978247eea95e http://github.com/hammerdr/redmine/commit/94a8bef751e41bc8e624a0f18cfd6f4d28b5635f http://github.com/hammerdr/redmine/commit/1cea1d0f50ffb65b07628198f7c38e114588630b

Step 2

Introduce Guard

http://github.com/hammerdr/redmine/commit/aebd019fa59d9abd23f6b3b964e45822b9ba2d70

Step 3

Extract Methods

http://github.com/hammerdr/redmine/commit/160d0a0392be269f7a2e043f9aea04470e09e68c http://github.com/hammerdr/redmine/commit/9c6a2c7c449695b9dcc64a0a6d2874c8ebc614a6

Step 4

Introduce Guard

http://github.com/hammerdr/redmine/commit/f5e8311724fa6e708622dfbf1a6250c5582f315a

Step 5

Rename methods

http://github.com/hammerdr/redmine/commit/51805b7d4356ad3ba150d5c3ca2240d4893f5fb1 http://github.com/hammerdr/redmine/commit/84d5285348343425910d9a67e3b8330207c8ae48

Step 6

Extract Methods

http://github.com/hammerdr/redmine/commit/e04e5d5eaeeb4020f02d0a3e7be844218eec7b3c http://github.com/hammerdr/redmine/commit/e04e5d5eaeeb4020f02d0a3e7be844218eec7b3c http://github.com/hammerdr/redmine/commit/7c4c6aa5487c406589675c7d6c64b5c6b4518771 http://github.com/hammerdr/redmine/commit/cbc0603eb08578093c6b941446d2a195ef8bd333

Step 7

Introduce Default Parameter

http://github.com/hammerdr/redmine/commit/31a6ab321640386d15c8c86b8ab6da7a0223a764

Step 8

http://github.com/hammerdr/redmine/commit/62ac466835c3f5b6820e7c52a7805a54717a294d http://github.com/hammerdr/redmine/commit/526d5fed1aa5b2f5319ee43d72d5054ff21d65e3 http://github.com/hammerdr/redmine/commit/b8ccc9807b9f5a9a6f17afc3351558566a6af275

Step 9

Rename Method

http://github.com/hammerdr/redmine/commit/6fe721d81fc0c1f1a07bde2bf56c8abb96d818ec

Step 10

Decomposing if block to guard clauses. I think that this is a great refactor for the arrow head anti-pattern. Quick and easy to get rid of.

http://github.com/hammerdr/redmine/commit/11b7b259c5039ee12a93dbad96d5f1b175efc19b

Step 11

Extract Conditional To Method

http://github.com/hammerdr/redmine/commit/563025817503459e98032596a9d4dcdad0d0963e

Step 12

Consolidating Conditional. I think that this is a really cool, effective refactor. It is obviously a mix of Extract(/Inline) Method and Consolidate(/Break Up) Conditional, but its effectiveness is more than the sum.

http://github.com/hammerdr/redmine/commit/5d755cee63561836a0e711b5d48540532daaa306

Step 13

Rename Method

http://github.com/hammerdr/redmine/commit/fe29e2c88b13125ccad69b968a38ce7c962d1550

Analysis of Redmine Refactor

I felt that this was by far my best refactor to date. The code that I refactored was not terrible. I could read the code without much struggle. However, because I applied the refactoring tool, I think that the code turned out orders of magnitude better. I could now quickly glance over the code and understand what was going on.