Over time, code bases accumulate cruft and become hard to maintain and small changes take considerable effort. Code does not become complex over night, it happens slowly, line by line, feature by feature. And it’s not carelessness that makes it happen: just the work of hard-working people, building functionality on top of existing code. Sometimes it’s that you don’t fully grasp how an existing class works, you’re happy that you were able to make it work and get on with your life. After all, time is precious and there’s always more to ship. But eventually someone else will revisit this code and it will take their precious time to understand what is going on before they can actually apply their changes.
If your code will need maintenance in the future it pays off to invest some time in cleaning it up. Often people’s reaction goes like this: “There’s so much to improve. This will be a lot of effort. Therefore we can’t do it now.” That is, because they envision considerable improvements in a wider part of the code base, the whole thing has to be delayed until the team get managerial approval to spend on this. In the mean time, development will continue to be slow. Is there a better way? The “Boy Scout Rule” has a different approach. This is how Robert “Uncle Bob” Martin describes it:
The Boy Scouts have a rule: “Always leave the campground cleaner than you found it.” If you find a mess on the ground, you clean it up regardless of who might have made the mess. You intentionally improve the environment for the next group of campers. Actually the original form of that rule, written by Robert Stephenson Smyth Baden-Powell, the father of scouting, was “Try and leave this world a little better than you found it.”
What if we followed a similar rule in our code: “Always check a module in cleaner than when you checked it out.” No matter who the original author was, what if we always made some effort, no matter how small, to improve the module. What would be the result?
I think if we all followed that simple rule, we’d see the end of the relentless deterioration of our software systems. Instead, our systems would gradually get better and better as they evolved. We’d also see teams caring for the system as a whole, rather than just individuals caring for their own small little part.
Contrast this with our initial reaction. What does this mean for where to apply improvements (locality), how much effort to spend (scope) and when to do it (schedule)?
Locality — As you’re touching the code right now, it is therefore likely that you or someone else will need to touch it again. A different approach would have been to use a static code analysis tool and work on the bits that get the worst grades – which might be parts of the code that do not need maintenance, so this effort would be wasteful.
Schedule — Making it mandatory to only ship improved code makes sure that improvements are not delayed indefinitely. But how can we make up enough time for this?
Scope — We can always find the time to make an improvement when the scope is limited and the Boy Scout Rule does not ask for a lot.
There’s another nice side effect of slightly improving code as you’re working on it: the areas that change most often also get the most attention. So improvement is done where it yields most benefit.
In contrast to the “Boy Scout” metaphor, a programmer’s job is to put more functionality into the code base, which can create a mess over time if you’re not careful. For an actual boy scout it is trivial to spot rubbish on the camp site, and the solution is obvious. For programmers it’s not so easy. Abstractions we’re relying on might no longer be appropriate, past choices need to be reevaluated. This burden also gives us some benefit: we can adhere to the “Your aren’t gonna need it” (YAGNI) and “Keep it simple, stupid!” (KISS) rules from Extreme Programming (XP). If you can be sure that the proper abstractions will be implemented when necessary, you don’t have to build them early on when you might not have the full picture. In other words: the Boy Scout Rule can be a means of implementing XP’s continuous refactoring.
So you’re trying to be a good boy scout and start working on cleaning up the code. Improvements are a good thing, but now the feature you want to ship is going to be delayed. So when should you stop improving your code? Hear the cautionary tale of the shaven yak:
Yak Shaving is the last step of a series of steps that occurs when you find something you need to do. “I want to wax the car today.”
“Oops, the hose is still broken from the winter. I’ll need to buy a new one at Home Depot.”
“But Home Depot is on the other side of the Tappan Zee bridge and getting there without my EZPass is miserable because of the tolls.”
“But, wait! I could borrow my neighbor’s EZPass…”
“Bob won’t lend me his EZPass until I return the mooshi pillow my son borrowed, though.”
“And we haven’t returned it because some of the stuffing fell out and we need to get some yak hair to restuff it.”
And the next thing you know, you’re at the zoo, shaving a yak, all so you can wax your car.
I guess we all know how it feels like to go down these rabbit holes. Yak shaving teaches us when enough is enough: we should stop what we’re doing if the connection to our initial task is no longer obvious. If the other tasks are important, you’ll get around to doing them. To stay within the yak shaving story: your neighbor will eventually get his pillow back. If that other piece of code needs to be maintained, it will get its chance of getting some improvement. Yak Shaving makes you look busy even when you’re stuck. You’re delaying a more important task and do less important work instead. This is when you need to look for a different approach, a simpler solution or a workaround instead.
It’s my personal belief that software is best delivered incrementally. This comes from my experience of aiming at delivering something perfect and in the end not delivering anything at all. In software design, there’s a name for the sequential process of planning and then executing big chunks of work: that’s the waterfall model. Here’s the thing: you have to build and test your code incrementally anyway. If you delay shipping it you don’t really know if it actually works. And as experience shows, there’s always some aspect you weren’t aware of.
The problems with big refactoring efforts are similar to the problems with waterfall-style projects: you can’t be sure you’re doing the right thing until you get feedback from your end users. In the case of a refactoring project this could either be breaking existing functionality for customers or delivering an updated API or data model that is not flexible enough for developers. Sometimes this isn’t because your plan was flawed – maybe you couldn’t account for new requirements that came up while you were working.
The literature on refactoring teaches us how to make structural changes to existing code without altering its behavior. If your changes are safe, you can stop and ship anytime. Sometimes it’s not easy, though, to envision an incremental path. This takes ingenuity, persistence and practice. You need be aware of the big picture, the overall context as well. Your understanding will grow as you’re taking step after step, guiding you in the right direction.
Metaphors and stories are important tools. They help us reflect on our own behavior and exchange ideas with our coworkers. They’re best when they’re fun. What’s your favorite metaphor?
Big shout out to Simon who first made me apply the Boy Scout Rule and showed me the value of small, incremental steps.