reek 0.3.0 released

I’ve just released reek version 0.3.0. Highlights in this version include:

  • The main news is the arrival of a new smell: I’ve included a first naive check for the Control Couple smell.
  • I’ve also revised the command-line: reek now only checks sources passed on the command line — it won’t go searching for files in the current directory and subdirectories any longer.
  • Code snippets can be supplied on the commandline; if a command-line argument isn’t a filename, reek will assume it’s Ruby source code, and will look for smells in it.
  • If multiple files generate warnings, reek now lists them with headings, so you can more easily see which files had problems. Each heading also lists the number of warnings raised against the file.
  • There’s now a very naive Reek::RakeTask to run reek from rakefiles.
  • And finally, reek now exits with status 2 when smells are reported; this should help you integrate a call to reek in your continuous integration builds.

To get your copy: gem install reek, or gem update reek if you’re a reek user already. To use it, try


reek source_file.rb

or


reek lib/*.rb

or similar. Or add the new Reek::RakeTask to your rakefile. As always, all kinds of feedback is very welcome.

the anti-if campaign

I’ve just signed up to the Anti-If Campaign (link via Dave Nicolette). This is a movement to promote the use of strong object-oriented software design principles, by asking us to think twice before we allow any conditional branches into our code. This isn’t dogma, just a hook that can help direct our refactoring.

Long-time readers of this blog will know that I believe most conditionals to be duplication — see the following old posts for examples of my arguments here:

I’ve placed the Anti-If Campaign’s badge on my sidebar to show that I look hard at every conditional, and I invite you to do the same!

reek and feature envy

Feature Envy is the smell (anti-pattern) in which one code fragment makes more use of another object than it does of itself. reek currently (version 0.2.3) includes a very naive check for Feature Envy: For each method inspected, reek counts the messages sent to each recipient and also counts the references to self; if self has the highest count, reek doesn’t report feature envy.

Here’s a contrived example:

class Parcel
  def addressee
    "#{@person.first_name} #{@person.last_name}"
  end
end

When it sees this code, reek says:


[Feature Envy] Parcel#addressee uses @person more than self

That’s because the method sends two messages to @person, so this code fragment should be moved onto that object:

class Parcel
  def addressee
    @person.full_name
  end
end

class Person
  def full_name
    "#{first_name} #{last_name}"
  end
end

Now fewer messages are sent overall, so the Feature Envy is gone.

The current algorithm is quite naive, and reek will certainly report false negatives sometimes. I hope to be able to refine the algorithms and gradually make reek smarter; for example, I’ve considered adding a configuration option so you can turn off certain smells for certain methods, but somehow that feels like the start of a slippery slope. This winter I hope to find the time to work on the algorithms a bit more, so if you do find reek reporting a false negative (for any smell), please send me a code sample — or preferably a new test.

reek, a code smells detector for ruby

To complement the imminent (ie. sometime next year) publication of the Refactoring in Ruby I’ve been working on a little software tool called ‘reek’. Reek scans ruby code — either source files or in-memory Class objects — looking for some of the code smells discussed in the book. Right now it can detect (certain forms of):

  • Long Method
  • Large Class
  • Feature Envy
  • Uncommunicative Name
  • Long Parameter List
  • Utility Function
  • Nested Iterators

As time goes by I’ll be adding checks for more smells, and I hope to make the current checks a bit more sophisticated. But in the agile spirit of going ugly early, the current very early version is available for you to experiment with. To get the tool:

gem install reek

To run it:

reek file1.rb file2.rb ...

If you try it, please let me know what you think and what you’d like the next version to do!

You can browse the reek project’s code repository at http://github.com/kevinrutherford/reek/tree/master or http://rubyforge.org/projects/reek/, both of which are clones of the same Git repository.

Other Ruby tools operating in this same space include Marty Andrews’ Roodi, and flay and flog from the seattle.rb folks. All of these tools have been made possible by the excellent ParseTree gem from the amazingly productive folks at seattle.rb. Looks like Ruby code quality is a hot topic right now, which I think is great news.

ruby refactoring workbook

Way back in 1999 Martin Fowler published Refactoring — Improving the Design of Existing Code. Fowler’s book introduced the world to refactoring as an independent practice, and provides dozens of detailed mechanical recipes, each of which describes the steps needed to change one (usually small) aspect of a program’s design without breaking anything or changing any behavior.

To be skilled in refactoring is to be skilled not only in safely and gradually changing code’s design, but also in first recognizing where code needs improvement — recognition of code smells. This is where William Wake’s brilliant Refactoring Workbook (2003) comes in. Bill’s book focuses on Java code smells: Each chapter consists of descriptions of a few major code smells, followed by a number of exercises to work through (the challenges vary; some ask you to analyze code, others to assess a situation, still others to revise code).

But what if you’re not a Java developer? Good news: Early next year Jay Fields, Shane Harvie and Martin Fowler are publishing Refactoring, Ruby Edition. It’s available now as a Safari Rough Cut.

And as if that weren’t enough good news, Bill Wake and I are writing the Ruby Refactoring Workbook. Compared with Bill’s original Java Refactoring Workbook our Ruby edition will have a similar overall structure, but is otherwise a substantial re-write. We have retained the core code smells (and added a few more) and re-worked them to apply to Ruby’s more dynamic environment. We have replaced all of the code samples, and replaced or revised all of the exercises. We have also re-written much of the introductory material, mostly to reflect the rise in importance of test-driven development during the last five years. In short, we’re trying to create a stand-alone Ruby refactoring workbook for the modern developer, and not simply a Java book with Ruby code samples.

books

As things stand right now we have three chapters left to write, and a deadline to get the first draft to our publisher next month. I hope to start releasing draft text into the wild for comment fairly soon, so watch this space if you’d like to be involved!

revised maze refactoring challenge

Eighteen months ago I posted a Ruby version of Bill Wake’s Amazing maze refactoring challenge. I looked at it again this week and discovered that it is rubbish: the transliteration from Java is not very literal, and one of the test examples is broken. So I’ve re-created it and uploaded a revised version. My apologies if you tried working from the original version.

more users than you think

In the fresh light of day, I have a slightly different way of expressing the ideas in yesterday’s rant

When we’re designing and developing a system (and hopefully we do those two things at the same time), most of us have checklists of some kind in place to ensure that we consider the system’s various users (end users, managers, administrators, support persons, etc). What we often forget, though, is to consider another important group – programmers. We take great pains over user experience, always thinking that means only those folks who’ll use the system for it’s intended purpose. But unless we consider the user experience of the developers, the other users may never see the features they really want, because the code is too impenetrable to work with.

why refactor?

The (current) canon of dogmatic Agile (with a capital ‘A’) and test-driven development demands that we RefactorMercilessly at every turn, but that seems somewhat simplistic to me. When I refactor, I do indeed strive to refactor mercilessly; but sometimes I don’t feel the need to refactor at all…

Given a suite of acceptance tests for a software system, there is clearly a (countably) infinite set of possible program sources that will pass those tests. (If you don’t see that, consider that every variable in the program has an infinite set of possible names; the same is also true of function parameter ordering, curly brace positioning, sorting algorithm, method breakdown, class naming, whitespace…) And as the system grows during development and maintenance, we navigate this infinite space of programs. Every time we write, change or remove a line of code, our system moves to a new point in that space; every time we add or change an acceptance test, we define a new (countably infinite) space of possible programs, and our system instantly sits at one point in that space.

And so every time we add a new feature, or fix a defect, we have an infinite number of possible points to which we could move our system within the program space and still pass all the acceptance tests. Furthermore, these “neighbouring” points are not all equivalent: the points in the program space have attributes, or qualities. Each program possesses different amounts of readability, maintainability, resistance to certain directions of change, coupling, cohesion, and so on. Which means that each time we write a line of code we make choices about the qualities of the resulting system. And all too often we forget to make those choices consciously.

Now those qualities I mentioned all have one thing in common: they directly influence both the speed and cost of change of the system. That is, each point in the program space, given a fixed set of acceptance tests, will support some kinds of change cheaply and other kinds more expensively. So as we develop and maintain we should consciously select programs which align with our system’s intended lifecycle; in particular, a write-once-and-forget-about-it system will need different cost-of-change qualities than a system that is intended to survive and be supported for more than a few months.

Refactoring is the means by which we move around the program space. As soon as we have a passing test, we can cast around for a nearby program whose qualities are a good-to-great match for our business needs. How much time we spend doing this is an investment trade-off against those future needs, and should be judged accordingly. Sometimes any old thing is fine; other times it is worth chasing down every last ounce of duplication.

The point of all this is that every day the programmers make choices which affect the system’s qualities. We should do so consciously, and according to the needs of our business and of our users.

the wrong duplication

Here’s something I’ve seen many times in code right across the spectrum, and which I caught myself doing just the other day. It seems to occur particularly often in codebases that weren’t TDD’d, and which haven’t been kept lean with regular refactoring…

Imagine a codebase in which one particular text string occurs frequently. The string may be some kind of message header, for example, or an XML tag (both of these examples are usually accompanied by another repeated string, representing the message footer or the closing tag). As the codebase grows, you notice the string popping up more and more frequently, until the “duplication” bell goes off. What to do?

It turns out we’ve all been taught the answer: Create a manifest constant (a #define or a static final String or whatever, depending on the language), thereby giving the common string a name, and replace all instances of the string by use of the constant. There’s even a name for this refactoring in Martin Fowler’s catalogue: Replace Magic Number With Symbolic Constant. Duplication sorted, right? Wrong!
Continue reading