I've recently heard that Bill Wake and Kevin Rutherford are working on a Ruby version of his excellent Refactoring Workbook. Bill and Kevin were kind enough to spend a little time with me talking about their upcoming book.
First there was Design Patterns in Ruby, then a Ruby Edition of Refactoring, and now your reworking of Ruby Refactoring. What makes Ruby different enough to warrant these new editions?
Kevin A few things, I think.
Firstly, Fowler's original Refactoring book — which I hold in very high esteem — is predicated on the GoF design patterns, and on the constraints imposed by a statically typed language. Ruby's dynamic aspects — notably duck typing and open classes — mean that patterns such as Strategy, say, can be expressed differently, and the forces for applying those patterns will also subtly alter. That, in turn, means that some of the "moves" in Refactoring may need to be revised for Ruby. And in some cases, it means we need completely new refactorings.
Second, Ruby is now over ten years old, and during that time there's been little attention paid to code quality, maintainability and "habitability". Yet there must now be a growing body of "legacy" Ruby code out there. I think that's why we're seeing a rash of new code analysis tools for Ruby right now: the time is right.
Finally, Rails has lowered the bar for entry into the world of web services development, and brought Ruby programming to a more diverse audience. So there's a strong need for good books about coding practices, to support the Ruby-powered development newbie.
Bill Ruby's dynamic typing means that you have to adjust the mechanics of refactorings (and sometimes lean on the tests more). But for me, the driver was more the community than the language. It's a way for me to contribute, focusing on something like refactoring in a way that a reader familiar with Ruby can focus on the idea at hand, not constantly also having to translate from Java et al.You mentioned that Ruby needs some completely new refactorings. Can you describe one of these?
Kevin Your best source for these is Jay Fields and Shane Harvie'sRefactoring: Ruby Edition, which is a re-working of Martin Fowler's original Refactoring. One of the new refactorings they introduce is "Replace Loop With Collection Closure Method". (Their book is available as a Safari rough-cut:.)I'm also intrigued by your call for good books on coding practices for Ruby-powered newbies. Have you seen Gregory Brown's Ruby Best Practices? Are there other books you'd like to see written (or translated into Ruby)?
Kevin Yes, I've seen RBP; I think the time seems to be right — the Ruby community seems ready to step up to the next level of maturity in terms of "professionalism" in software development.
As for other moves, top of my list would be a Ruby-specific version of Michael Feathers' brilliant Working Effectively with Legacy Code.What did you learn about refactoring as you started to apply the ideas in the Workbook to Ruby?
Bill I've become much less focused on the mechanics and more focused on the philosophy of small safe steps. Writing this book gave me the incentive to go back through and try to discern the overall patterns that refactorings use, as well as the small internal steps that have varying forms.
Kevin Lots! Coming from a C/C++/Java background back in the mists of time, I hadn't really appreciated just how much the GoF patterns and the Refactoring moves depend on the forces that arise from static typing. But when that static typing is removed, some of the concepts work less well.
Here's an interesting example: Fowler introduces the Feature Envy smell, which tells you to move a code fragment into the class whose fields it accesses the most. In the C family of languages this works well, because ints and strings can't acquire new methods: they act as a brake on the process. But in Ruby, you need a lot more static analysis in order to discern whether a particular object could become the new home of your code. The smell, and the refactorings that fix it, are easier to express and apply in a static language.
Another: Modules offer the Ruby programmer the opportunity to simulate a kind of multiple inheritance, using a mix-in style. Java doesn't have that, and so there's a whole set of possibilities open to us that Martin Fowler didn't have.
And from the Gof patterns: The shape of the Strategy pattern (someone once said that everything boils down to Strategy in the end) includes an abstract class/interface representing the common "type" of the actual strategies. It isn't needed in Ruby, due to duck typing.
All this meant that we spent a large portion of our time checking whether the patterns, code smells and refactorings still applied in Ruby, and what might be different or unnecessary.What did you learn about Ruby as you applied the ideas?
Kevin Less, I think. I've been a semi-serious Rubyist since 2004, and during that time I had done a lot of refactoring. So I was used to working in Ruby as a malleable medium, even though I'm sure there are corners of ruby-fu I've never seen. We have also deliberately avoided delving too far into the details of any particular Ruby library — this is mostly a book about technique, rather than knowledge.
My principal concern about the new workbook is whether we have noticed all of the places where GoF, Refactoring and the original workbook depend subtly on static typing or other aspects of the Java experience. Which is why we've recruited an awesome band of reviewers to help us weed out those hidden assumptions.
Bill Two things hit me. The first is that I still seem to fight too many "environment" battles, trying to get tools and dependencies just right. But the second is that once I'm in the program and using Ruby, the language feels very expressive, with just the right thing ready-to-hand.