I think software maintenance is one of the least understood concepts among engineering managers. By maintenance I mean all the small little tasks developers do to make their code nicer to work with, refactoring, testing, as well as fixing bugs. This part of the development process is difficult to manage for several reasons. For one, developers tend to be quite bad at making a case for why these activities are necessary. Maintenance is essentially a technical task so there is a mismatch in communication between decision makers and developers that is difficult to overcome. Often a developers arguments for refactoring reduce to aesthetic principals of best practices for coding that are difficult to reason about clearly but may still be impactful on the outcome of the project. The decision to spend resources for maintenance activities must involve a degree of trust in developers to spend their time wisely. And my experience tells me that often they don’t, so maybe managers are right to be a little skeptical.
While a little skepticism towards maintenance activities is healthy for managers, I believe this point of view when taken to extremes can cause managers to hold an inaccurate model of how their software is actually being developed. I once had a manager say to me that “refactoring is a bad word” and in my personal experience, tasks related to code quality have been the most difficult to pitch because this bias is so common. In fact, Stripe recently published a paper which identifies these activities as waste with the implication that if developers just wrote their code correctly the first time, we could save 85 billion dollars in lost GDP per year.
While it’s possible to be an effective manager with this simple heuristic, I think there’s a different understanding of the process of developing software that is closer to reality although maybe a bit less intuitive. The uncomfortable fact is that maintenance activities are seemingly unavoidable and sometimes refactoring really is the most impactful thing your developers can be doing for the outcome of the project. While these decisions may rarely make or break the project, having a good understanding of software maintenance is a great way to become a more effective leader and gain respect among your engineers.
The Current Metaphore
Metaphores and language shape the culture of our teams. Just like the ancient Greeks created myths to explain the chaos of the world in human terms, we do the same thing as engineers and managers. The current metaphore of maintenance is understood in the same way as home maintenance. For instance, my kitchen sink clogged up recently so I had to have a plumber come to the house to fix it and he charged me $300. It’s easy to understand this cost as a waste. My sink worked perfectly well, then I called the plumber and the end result is the same as it was before the clog: a working sink. If the plumber would have offered to rearrange the pipes to be more efficient for a cost of an extra $500, I would have respectfully declined.
Depreciation is a real phenominon for code, but it happens for a different reason than plumbing or factory equipment. The reason code requires maintenance is not because it wears out when you use it. Code is just a description of a deterministic logical process. Given the same inputs and state of your hardware, you will get the same sort of result now that you will get 20 years from now. Rather, code depreciates because people change the way they use it over time.
With the home maintenance metaphore, bugs are understood to be clear cut and well defined (we call these regressions: when something used to work and now it doesn’t), but the overwhelming majority of bugs I’ve encountered are not regressions, but rather come from the user using the software in a way that was not expected by the original designer. The user did something that seemed like it should have worked, but then the software did something else entirely. In this case, the line between a bug and a feature is not clear and it’s often not useful to make the distinction at all. For instance, if the user installs my software in an environment I didn’t do any tests for and runs into problems, is it a bug because the software is not working correctly or a feature to add support for the new environment? Whatever we call it, usually it doesn’t affect the discussion so we don’t bother with semantics. Sometimes we just tell the person we don’t want to support their use case and close the bug as
wontfix. Windows users should be used to this by now.
Most “maintenance” work is actually feature development in disguise. The cause of most bugs are changes in user expectations. Your developers want to refactor the code base because they are anticipating changes in user expectations and they want to get an early start implementing the features they think you’ll need while they have the problem fresh in their mind. If you understand things this way, you should see that the home maintenance metaphore is limiting for practical decision making about maintenance activities.
The Golf Metaphore
I rather see maintenance not as a wasteful activity, but rather an important part of the development process. To me, a software project is a lot like a round of golf. The object of the game of golf is to get a ball into a hole across a field using clubs with as little effort as possible. Effort is measured by strokes, or how many times you hit the ball.
On the first stroke (the drive), you are very far away from the hole. The objective of this stroke is not necessarily to get the ball in the hole. It could happen, but getting a hole in one is really just a lucky outcome that can’t be attributed to the skill of the golfer. There are a lot of factors the golfer is not thinking about at this point like the exact speed of the wind that may alter the ball’s trajectory by several feet. The best you can hope for is to get close enough to make the rest of your shots easier.
Let’s notice some things about a good drive. First of all, the ball travels about 80% of the distance to the hole during this shot. Second, this shot costs the same as any other: one stroke. If you do a naive calculation of distance per stroke, you will come to the conclusion that your drive is by far your most efficient shot. With this data in hand, a good golf coach might tell his player your drive is your most efficient shot, so just do that every time. Worse yet, if you golf as a team and have a designated driver, you might mistakenly think this is your star player because he moves the ball the farthest. Truly this must be a 10x golfer!
But in reality you can’t drive every time (even if you could, you may never get to the hole). Your next shot requires a different set of skills and even a different set of clubs. The ball will travel much less distance during this shot, but it still counts the same as the shot before: 1 stroke. Finally, you are close enough that it’s time to putt. The putt uses the smallest club and causes the ball to move the shortest distance, but the effort required is the same as the drive.
Software maintenance work is like putting. At this point, small details matter like the contours of the earth and the length of the grass. And while this shot is not nearly as efficient as the drive, it’s the best way to play golf (as long as you don’t make the mistake of doing it too early). Some people even make a game out of just this part: minigolf and it’s pretty fun.
So if you think about a software project like this, you should see that maintenance work is just part of software development just like putting is part of golf. If your code base needs refactoring or you have bugs, it doesn’t mean that anybody made a mistake or wrote “bad code” just like a golfer who doesn’t make a hole in one isn’t a bad golfer. That’s just how golf works.