Wednesday, 15 February 2012

Defining code as "maintainable" is just plain dumb!

There... I said it... and I've done it again, I've made another big-assed bold statement that I am sure will get flamed in some small corder of the universe.  Thankfully, I'll be too busy with my head somewhere else trying to unlock the mysteries of why people think the way the do about code maintainability.  Which means I'll be writing this blog article and totally oblivious to the little flame war that I expect will erupt and threaten to eventually engulf the entire universe if I don't manage to quell the flame with a good well reasoned commentary!  (Phew!! The universe really dodged a bullet there, let me tell you!!)... Where was I?

So the issue (oh yes, I have SO many) is that I really dislike hearing people say things like:
    "...this is good maintainable code..."

or even worse:
    "...this code is Un-Maintainable!!..."

I happen to be a believer that thanks to the almighty Uncle Bob and others who brought into the light Agile and Refactoring and all that really wonderful stuff, we can maintain ALL code.  Yes, I have found my true coder's calling and decided to preach to the unwashed masses that you who are the unbelieving lost binary souls can also learn that you don't have to throw out your code, just because someone has been spreading such a heathenous word as "Un...Maintainable..." (you may hiss and jeeer every time you hear that word spoken!).


Seriously though, it really annoys me when I hear someone say that something is unmaintainable.  It a misconception, a word play that hides the true feelings of the developer that says it.  You may not like the code.  You may find it difficult to read, poorly factored, and even just plain wrong, but that doesn't mean it is actually unmaintainable.  Instead, call the code what it is but accept that sooner or later, you will probably find yourself needing to maintain the code, and what you do at that point shouldn't be judged based on your dislike of the code, or how difficult it is to work with, but instead it should be judged on a combination of its business value, it's cost to maintain as is, it's cost to improve or replace, and whether making changes to the code will create costly problems elsewhere.  It really is all about the cost/benefit ratio, and not about whether or not developers feel it can or can't be maintained.

Now, I'll admit that there are times when I've looked at the massive job ahead of me to try and clean up a big spaghetti-coded mess and thought that it would be simply easier to chuck it all in and start again, and yes, there are actually times when I have done that, but I would never say that I couldn't possibly maintain existing code simply because I don't know how to maintain it, or because I don't know enough about it. The reality is that when developers choose to opt for the "unmaintainable" label, they are mostly being lazy, or they are scared, or both.They look at the job ahead of them and they find themselves so averse to the task that they'll say anything to avoid needing to take on the responsibility. They may even have a point, that the job may be too big, or that it may be very difficult and perhaps even beyond their skill level, but certainly not unmaintainable. (Managers you're going to love the next bit.)

Most programmers I have worked with (and perhaps even myself a good long time ago) tend to forget that the software that the business owns is an investment.  In some cases it can be a million dollar investment.  When you get that software package written, you want to get a huge return on your investment, and you certainly don't want to face needing to replace your software because the costs can be prohibitive.  Imagine the fuss your favourite bank would make if you told them that the database system that underpins all of their ATMs and Accounts, and that maintains the transfer records between the banks each night, imagine if you told them that that database they have spent literally years customising will need to be replaced because their new programmers took one look at it, didn't like what they saw and told the bank that the code was unmaintainable! Your mean bank managers would probably fire the programmers on the spot.  The nice ones would probably do a rude back-of-the-napkin calculation and politely tell you that they disagree... and then might fire the programmers. Me, well I'd probably skip the firing bit and would instead try to convince the programmer to seek a less costly alternative.

Let's do our own rudimentary math to highlight what I've been talking about.  Let's say you are a big bank.  You've bought your database system in for $500,000 to cover all of your licensing costs.  You've paid another $200,000 to hire a DBA for a year from the ACME Database Company (yeah, that weird coyote guy), and ongoing upgrade and support costs of a measly $100,000p/a. Now let's assume that you need a team of your own DBA's to maintain and implement your databases over the years.  So we'll assume a system's architect at $120,000p/a, a couple of senior project leaders at about $100,000p/a each, 8 analyst programmers at about $70,000p/a, and a handful of graduates (perhaps 4) at around $40,000p/a... and if you think these guys are underpaid, remember this is a bank :-P!! Assume your database has been operational with these staffing levels for the last 10 years. Add that all up:

+    500,000 (database)
      200,000 (Coyote)
      900,000 (on-going licensing/support)
      120,000 (architect)
      200,000 (seniors)
      560,000 (A/P's)
      160,000 (Grads)
-------------------------------------------
   2,640,000

So to replace the system with something new, you might roughly assume that it will take nearly as much time, and will cost you in today's dollars more than $2.5 million to replace your system with something new that your programmers might assure you that will be "maintainable". That's a 2.5 million investment plus time and it underpins all of your business which gives you an annual turnover in the billions. The reality is of course that programmers come and go over the years, and in another 5-10 years, just after your new system has gone live and the old system has finally been switched off, your new crop of programmers will take a look at the code they have to work with and will come up to the boss and say "The system is really old, and there is a lot we don't understand.  It's basically unmaintainable"!!!

Now what if instead your programmers have said to you "The system is very old, and there is a lot we don't understand. We can fix it, but we will need to learn more about the system, and it will take time to do it.  This will unfortunately affect our ability to cope with other priority work, and may cause some downtime."?

What this second scenario gives you is options.  You can do a short feasibility study to discover what work is needed to bring the system up to an easier to maintain standard, and you can get an idea about how much that will cost.  You can try and determine if any deficiencies in the system are costing the company money due to wasteful inefficiencies, and if costs relating to failures and downtime, refactorings and rewrites, are likely to lose the company valuable business and market leadership. You have the option to re-prioritise work, or to hire additional stuff to work alongside existing staff for a time to fix those parts of the system that aren't quite correct, and more importantly, you have the option to avoid a panicked knee-jerk reaction by thinking the matter through in order to protect an already expensive investment that has probably saved the company millions of dollars by making much of the work automated and efficient.

Ok, perhaps some of my math may be suspect.  My estimates off, and perhaps my assumption that the system that runs your business may not actually save you any money.  You've got to admit though that the cost to replace software can be prohibitive, particularly when you are investing your resources in other ways to grow your business.  You don't want to be chasing your company's software demons endlessly as it can become a real drain on your resources. As software professionals, these are the sorts of matters we really need to be aware of, and there is no point complaining that the old code is poorly written either, because we learn from year to year to do things differently to how we were taught 10 or 20 years ago. We may on the other hand have a valid complaint that the code could possibly have been written in a form that would have made it easier to maintain. And the truth of the matter is that the problem has never really been about whether or not the code is actually maintainable, but instead about the accrual of unpaid technical debt.

The concept of Technical Debt has been around for a very long time so this isn't a particularly new revelation, but it is a very profound one. To sum it up, it's like paying rent. When you rent a house or an apartment, you agree to pay a certain amount to your landlord every month. When you make your payments on time, you don't have any problems, and if you've got a nice happy landlord, then you won't have to worry about keeping the place well maintained because your landlord will take care of things for you. When you forget to pay your landlord on time, you make him unhappy, and you end up owing him for the back rent. While you have an additional debt to your landlord, he's going to be slow about getting around to fix your leaky toilet, and if you end up owing him several months worth of rent, then you're pretty much going to only get help from the landlord when you desperately need it, and then only grudgingly.  Technical Debt is conceptually the same. When you have a code base (the house), you need to put an effort into maintaining it. Keeping things neat, clean and refactored is your way of paying off your monthly debt, and your landlord (the entire software team) will remain happy, and will probably manage to do small maintenance jobs without  too many problems. When you let things go in your code, and you don't keep an eye on the mess you are creating, it's like you're missing rent payments.  Every unfinished class or function, every half-done job, every unattended test failure, every method that has not been tested, every time you've left poorly factored code, every commented code block, basically every code smell you've left behind, and generally every bug you haven't fix, these are all missed payments to your landlord.  And just as with your home rent, every missed payment adds up until you end up with a very serious problem that appears almost impossible to solve. You end up with a large technical debt owed, and a big headache.

You could abandon your project and start again, but all this ends up doing is writing off one debt in order to create another.  You'll soon end up in the same position later that you are in today if you don't learn how to budget your resources properly in an effort to manage your technical debt. This budgeting is the responsibility of your project leaders and other senior team members for the most part, but the average developer needs to be aware of the technical debt, and to be sure to know how to avoid adding unnecessarily to the level of debt presently accrued. Managing technical debt is all about managing resources and time, and getting the balance right between new work, and the maintenance work that you have probably been putting off for months. Just the same as when putting off paying your financial makes it near to impossible for you to repay them, so too does putting off the technical debt. Think of every time you ever had a problem area of code that you had chosen to neglect, and how you you ended up finding every possible work-around you could just to avoid touching that code.  All of the additional interfaces and structure that you might have put into place to shore up the weaker areas of your code, just to leave this core mess of functionality alone because it was "working". Each new kludge you manage to squeeze in  is a problem that has taken longer to solve, and even longer to implement, let alone test. So not only is your technical debt getting worse, and the problem getting larger, but you now have to face the fact that you are unable to work efficiently with the code and your resourcing costs are higher as you find yourself dedicating more time and effort to avoid fixing a problem.  This is the really ugly side of having an unmanaged technical debt, and probably the part of the problem that is the least discussed.  It's the hidden cost that you forget to account for when you need to work out your yearly budget. Seriously, wasted resources through inefficiency and neglect is wasted income, and should be the best argument for doing everything you can to avoid technical debt in the first place, not to mention that it is like never maintaining your car in good order. Sooner or later something is going to break.  If a driving instructor fails to maintain the investment he has in his car, he's soon going to lose something very important to him which contributes directly to his income. It's the same with unmanaged Technical Debt in software.  Your investment will fail to deliver sooner or later, and you'll end up throwing good money after bad if you don't do something about it.

So we certainly have a very good argument for taking preventative measures by maintaining your software to reduce the impact of technical debt, but what about all of those projects out there that are already in a lot of trouble. What about all of those projects that fail and run late due to unmanaged technical debt (and yes, this can be a reason for projects failures just as much as poor planning and changing requirements do)? For those projects that are already in a mess, you've got to make a well reasoned decision. One choice is to cut your losses and start again, accounting for what the delay in having a ready product will cause your company, as well as the losses you will have getting another project off the ground to replace the prior failure. The other is to allocate programmers to go through the code, and apply some careful refactorings to try and reduce your technical debt, and to get into the habit of trying to chip away at the debt as often as you can, for as long as you can, until the technical debt is reduced to a much more manageable level.  This can occur regardless of the state that a poorly designed system is in. You might not manage to fix everything, but you just might manage to get enough done so that you can see if there might be a way to replace a smaller part of the system, rather than throwing your entire investment out. You just might make it easier to see where to refactor next, or even where it would be best to make an additional investment to improve another part of the software, while determining which areas should be reasonably avoid for the time being.

Working with a beautifully written product is a programmers dream, and yet programmers generally enjoy solving problems. It's at the very heart of what we do. Rather than falling into the trap of believing that code cannot be maintained, we should look to protecting our investments by rising to the challenge of improving what we have already invested so much into. Recognizing that "difficult to maintain" does not equate with "unmaintainable" provides us with the means to do this.  Changing our preconceptions, altering the mind-set so that we give ourselves more options, and the tools to make better business-focused decisions based on sound reasoning rather than emotionally-laden and poor judgments, these are the things that we can do as professionals to provide our businesses with the best value for the money invested in us.

No comments:

Post a Comment