Saturday, January 24, 2009

Fear of Changing Code

A common question on the TDD and XP mailing lists is how to get managers to approve refactoring and testing. The standard response is to ask in return why programmers need permission to write code that doesn't suck. The problem is that it is hard to know how to manage software development in a condition of rising Technical Debt.

I was a programmer a long time before doing any management. I had to learn to manage my unit of work, to do things people wanted to have done, etc. There is a certain amount of professional discipline necessary to be a good employee-programmer. I had a tendency to do X (which was required) and throw in some Y and Z. Where Y and Z were simplifications along the path to doing X, it's all good. This shouldn't need permission (one would hope) but what about when they were solving miscellaneous potential problems on the side? What if they scratched an itch? Under the reign of SAS70 interpretations and ISO 900x dreams and basic risk management, I had to learn to operate a little differently.

Avoiding fixes is an attempt at risk management. When you are reliant on manual testing and inspection (against Deming's advice), you are always concerned with the cost of testing and inspection. If technical debt is out of control there may be changes that take a week to code but which bounce around in QA (or QA test/fail/fix/retest cycles) for a month or even more. All estimation and planning is moot at that point.

"Change avoidance" is a knee-jerk response. A review board/person will choose which changes they can afford to test instead of choosing changes based on business value. The developer then takes a change ticket and performs the minimal work that clearly solves the problem as explicitly described in the ticket. The diff of the code change is reviewed, and the list of modules and screens modified will drive the laborious QA processes.

In this situation, collateral change is unwelcome. Even reformatting is fearful. Refactoring makes the diff harder to read. The unenlightened will place too much emphasis on a tidy diff rather than whether the change was an improvement overall. In this situation, even the smallest hygenic improvements will seem to be needlessly add risk.

A team finds itself making interest-only payments on technical debt.

Things won't get better, but the team will get better at working small in a big mess. This is akin to a teen boy clearing a narrow path from his bed to his door instead of cleaning his room. It's like washing only the dishes you need to cook and eat the current meal instead of doing them all after the meal. But not doing so feels like losing control.
"No passion so effectually robs the mind of all its powers of acting and reasoning as fear." -- Edmund Burke
"Fearing your own code is an indicator that you are headed for ruin. This fear is followed by self-loathing, project-loathing, career-loathing, divorce, infanticide, and finally chicken farming." -- Bob Martin
The problem is that technical debt is already out of control. Minimal, pretty diffs and long inspections won't create control. It will only foster the illusion of disciplined development.

Rewrites are doomed for the most part. The reasons are well documented and well understood. The risks of gaps and scope creep are legend.

Yet we see that code, left to a patch-n-release process, becomes messy and unmaintainable. It is the slow march of entropy and complication. Joel puts it this way:
Back to that two page function. Yes, I know, it's just a simple function to display a window, but it has grown little hairs and stuff on it and nobody knows why. Well, I'll tell you why: those are bug fixes. One of them fixes that bug that Nancy had when she tried to install the thing on a computer that didn't have Internet Explorer. Another one fixes that bug that occurs in low memory conditions. Another one fixes that bug that occurred when the file is on a floppy disk and the user yanks out the disk in the middle. That LoadLibrary call is ugly but it makes the code work on old versions of Windows 95.

This is why managers and indeed whole organizations want to tighten down on development, and demand minimal work though it brings minimal satisfaction. This dissatisfaction leads to cries for rewriting the application. Rewrite reduces the staff on hand for making changes, and can even lead to a total work-stop in which no value is delivered to the customer base.

The only way out is to pay down technical debt, which means making changes, which feels an awful lot like losing control. This is why the question comes up so often. Selling "unmanaged change" is hard to sell, and why software managers know and object if you reformat and refactor your code.


  1. "The objective of maintenance is to minimize the output of diff." said the project manager.

    A few months after that, he was fired.

    To this day, when I compare notes with those who worked on that project, no one has claimed to have found a worse project manager.

  2. Dude, you're bashing my favorite, pretty diffs. Ouch! I still love my pretty diffs. I especially like multiple phase pretty diffs, where few say this is how I refactored to get here, and the last one says this is what I did. That sounds like a lot of work but I have good tool support.

  3. "I especially like multiple phase pretty diffs, where few say this is how I refactored to get here, and the last one says this is what I did." -- darrint

    Actually, I'm inclined to agree with darrint: "Check in early and often." is a good guideline. I like the idea of checking in refactorings separately from functional changes. But I have to admit that I seldom do this, due to checking overhead that exists for much legacy code, and relative lack of tool support.

    I think the point of the "pointy-hared boss'" rule to minimize diff output was to minimize TOTAL diff output for any given system change request. (I doubt that he ever even considered the possibility that one might do multiple checkins for one system change request. I've hit the "one checkin per change request" assumption at a number of large companies.)

  4. I think the point of the "pointy-hared boss'" rule to minimize diff output was to minimize TOTAL diff output for any given system change request. -- Jeff Grigg

    The problem isn't with what's in the diff, it is in the idea that the code got so bad that draconian rules (no refactoring, no collateral changes, no reformatting, simplest possible diff for the whole change) were put in place.

    I still would rather see clean diffs, all other things being equal, but I want to see the refactorings and reformattings being done. And the testing. I really want to see that testing.

    BTW: Darrint did a pretty cool bash testing tool once. I wish I had it handy.

  5. Followup by Kevin Schlabach: