Editorial Note: I originally wrote this post for the NDepend blog. Go check it out over there, if you’re so inclined. You’ll like the posts over there if you like static analysis and philosophical discussions of software design and architecture. Also, this week will probably consist mainly of cross posts as my wife and I are going to spend a few days in a hotel in New Orleans, taking in the spectacle of Mardi Gras.
One of the things I remember most vividly from my CIO days was the RFP process for handling spikes in demands on my group’s time. In case you haven’t participated in this on either side, the dance involves writing up a brief project description, sending it over to a handful of software consulting firms, and getting back tentative project proposals. I’d pick one, and work would begin.
There were a lot more documents and legalese involved, but the gist, writ small, might be something like, “we need an application that will run in our data center, take information about customers out of our proprietary database, and put it back into our CRM as notes, depending on a series of business rules.” The response, in proposal form, would essentially be, “we’ll do that, and we think it’ll cost you about $30,000.”
This is what most people think of as the cost of a software project. Perhaps it’s not a little, 5-figure line of business utility. Perhaps it’s a $300,000 web or mobile application. Perhaps it’s even a $30,000,000 enterprise workflow overhaul. Whatever the case may be, there’s a tendency to think of software in terms of the cost of the labor necessary to write it. The consulting firms would always base their proposals and estimates on a “blended rate” of the hourly cost of the labor. Firms with in-house development staffs tend to reason about the cost of software projects as a function of the salaries of the folks tasked with the work.
Of course, if you’re a veteran at managing software projects and teams, you realize that there’s more to the total spend than just the cost of the labor. No doubt you factor in the up-front and licensing cost of the tools you use to develop the software as well as the cost of the hardware on which it will eventually run. You probably even factor in the cost of training users and operations folks, and paying maintenance programmers to keep the lights on.
But there are other, more subtle costs that I’d like to discuss — costs related to your approach to software development. These are variable costs that depend on the nature of the code that your team is writing.
To really get at the total cost of software ownership requires an understanding of the concept of technical debt. To communicate this concept, I’ll use an analogy rather than talking about software. Imagine that you’ve cooked dinner, and you’ve used a whole lot of different dishes and utensils, all of which are now piled haphazardly in the sink. They’re dirty and covered with drying food debris that, left untended, will make them very hard to clean.
You’re faced with a choice. You can do the “right” thing, giving them a quick rinse and light scrubbing now. This is the best way to minimize the total time you’ll spend cleaning the dishes. Or, you can take on ‘technical debt’ by deciding to let them sit in the sink while you eat your hot dinner. By electing to enjoy your dinner while it’s still hot, you’ve increased the total time you’ll spend cleaning the dishes, since you know you’ll have to hack and scrape at them later. And, the longer you go without paying the piper, the nastier and nastier the chore becomes.
This is the same decision pattern that developers face constantly in the code base. Delivery pressure is a regular fact of life, and there are many other sorts of circumstances that will cause them to do something expedient today that makes life a little harder tomorrow. If you’ve heard of technical debt, you may have heard it mentioned only pejoratively. But in and of itself, it’s neither good nor bad — just a tradeoff, an option to delay work needed for the codebase to be in good shape.
But, thought technical debt is a metaphor, its accumulation has real financial costs. These are definitely not obvious when contemplating the total cost of ownership of your software, but they are real and they are important to understand.
Sluggish Reaction to Change
Think of a software product you’ve worked on that has lasted a year or more. Do you remember progress being lightning quick in the beginning, and then slowing over time? Do you recall implementations of patches or new features starting to take so long that you found it hard to believe?
Those are symptoms of a codebase carrying heavy technical debt. Don’t let anyone tell you that this is inevitable. This type of slow-down is, in fact, quite preventable, and if you’re experiencing it, the drag on time to market for features is a very real cost that you’re incurring.
Tangled code bases, high in tech debt, don’t just mean sluggish development speed. When changes finally do make it into production, they’re more likely to be plagued by bugs and weird behaviors. Users notice and complain about these deficiencies.
Escaped defects aren’t just embarrassing. They have a real cost, albeit one that’s hard to quantify. But on the whole, users will drift away from buggy products and head toward cleaner, more polished competitors. And beyond that, the software and company will suffer a reputation hit, becoming known as purveyors of mediocre work product.
It’s true that this is difficult to quantify, but the fact that we can’t easily quantify the cost does not alter the fact that it IS a cost.
Attrition and Morale
The last hidden cost of software approach that I’ll mention is, perhaps, the most subtle of all. It’s the cost of attrition in your group. Anytime a developer leaves and you have to backfill the role, there is a knowledge transfer and onboarding cost that can be pretty steep. And this learning curve is steepest in code bases heavy in technical debt, since these tend to be the hardest for newbies to understand.
Now, attrition is, obviously, a risk in any group. But when a code base accrues technical debt, the risk of attrition increases. Tech debt, like credit card debt, can easily become a vicious cycle. The poor state of the code slows down delivery, causing missed milestones. The misses ramp up delivery pressure, which causes the team to take on still more tech debt.
It’s a grind to work on a team like this. There’s constant pressure, and the joy is sucked out of programming because the task becomes less like building a cool piece of software and more like playing a game of high stakes Jenga at knife-point. And, since the market is really hot for software developers, the good developers tend to leave situations like this faster than they would other companies or other groups. And their departure is costing you dearly.
Have a Conversation
So what can you do? Well, there’s no simple answer to that question. The complexity and subtlety of these considerations makes this a hard problem. But what you can start by doing is having a conversation with your team about where things stand with respect to technical debt. They might even be waiting for you to ask, because they already have suggestions on how to address the issue.