Code Farming: Sprouting Some Methods

You probably can’t impose unit testing on a whole system all at once. But you probably can increase the portion of the code under test a little bit at a time. When you’re busy but need to make small changes, consider Sprout Method (59).

I am trying, with only partial success, to apply what I’ve learned in Working Effectively With Legacy Code by Michael C. Feathers.

Feathers is a huge advocate of test-driven development. He puts it out there on page xvi: “Code without tests is bad code.” He defines “legacy code” as, strictly speaking, any code that isn’t already under unit tests. At first it struck me as a funny definition, because obviously lots of code is written today–even by me–without unit tests, and how can it be right to refer to software nobody’s even thought of yet as “legacy”? But for purposes of the book it works.

The bulk of this text consists of techniques for making changes in existing code, either while bringing into a unit testing regime or while carefully working around the lack of one. Thoughtfully, each of the chapters is titled with a question or complaint, to wit:

  • How Do I Add a Feature?
  • I Need to Make Change, but I Don’t Know What Tests to Write
  • My Test Code Is in the Way

and so on.

Within each chapter, Feathers gives one or more coping techniques. The effect is quite a lot like that of Design Patterns by Gamma et al., sort of an indexed glossary of solutions. With names. Throughout the text, solutions are referenced by name and page number, such as when the Sprout Method (59) solution suggests use of Pass Null (111).

Sprout Farming

And that’s the one I want to talk about today: the Sprout Method solution. I’ve used this a lot recently and it makes sense even if it looks weird at first.

Is making non-sucky software your bag? Then get onto my eZine mailing list. It has a complete eZine mailing about once a month, with articles and links and special offers that help you do your job, as well a quick note with something funny or interesting every week or so. And vegetarian recipes too! Go. You want to.

Here’s the problem.

You need to add some code to a method, you might need to do it in multiple places in the system, you want the changes to be unit-tested, and you need to do it right away without a lot of refactoring.

Here’s the solution.

You write the added code as a new method and call it where needed, rather than typing the new code in every place it goes.

This can be kind of ugly at first, because your original method might have thirty lines of logic-logic-logic and then there’s this one crazy method call in the middle of it that does about five lines of stuff and it’s not obvious why you didn’t put it in the main method.

But here’s the thing. The new method can be put under unit test, and then you’ve gained a little bit more control over the next change and the change after that. Maybe bits and pieces of the big methods migrate into your little new method over time. Maybe your big methods eventually turn into lots of these little methods, and then you realize the big methods are now completely unit tested anyway and you’ve succeeded!

What it’s good for

If today were endless, we’d spend it refactoring everything into logical units and placing it all under test with JUnit or NUnit or the like. That would be cool. But alas, the world is not that cool, and we don’t get to muck around with code that already works just to make it hypothetically easier to change in the future. What we can do is get the most benefit from the changes that we have to make anyway.

So Sprout Method (59) is a good start. Long story short, when you need to add a few (or more) lines of code to an existing method, consider making the new code a testable method of its own.

 

4 thoughts on “Code Farming: Sprouting Some Methods”

  1. There’s something I always wondered about this approach and I haven’t read Feather’s book so I’m not sure the answer. Maybe you can enlighten me.

    When you pull out that method what protection level do you give it? I assume public, although you could probably do protected as well and reference it through a “fake” inheritor in your test class.

  2. Interestingly, Josh, I don’t think Feathers answers this directly. However, if you’re going to use NUnit (with .NET code), I don’t know of a better approach than the one you describe.

    Man, I’m just full of no answers for you. 🙂

Leave a Reply

Your email address will not be published. Required fields are marked *