It is generally appreciated at an abstract level that the idea of improving the design of code that is already written is a good idea. I have the heart of a purist and I like to see nice, well structured code but I also work in a small business. I am acutely aware that refactoring costs time and time is most definitely money. So I ask, is refactoring worth the money?
Martin Folwer, in his famous book on refactoring, defined refactoring as:
Apart from getting a warm fuzzy feeling for code, why would I do this? Well, the principle argument for refactoring is that it speeds up the development of new features. The easier it is to develop a feature, the less money it costs.
Okay, so if refactoring saves us time then we might want to do a major refactoring project so that we can increase productivity amongst our developers. Let's say, that for the sake of argument, that refactoring saves 10% on development time. Let's say and I plan to spend a single developer's time on the effort for three months to achieve this 10% efficiency gain. Let's call the money made on this venture "Account A".
Further, let's take the same time we were going to spend on refactoring and invest it in a low risk savings account. There is nothing special about this account; any bank's saving rate on this will do. I'm going to choose Northern Rock's saving rate which is roughly 6% in the UK. Let's call this "Account B."
At first, this might seem a bit of a weird account to have, but this is meant to represent the minimum "opportunity cost" of doing refactoring. The money you spent on refactoring could have been allocated elsewhere to make you money. The most basic way you could allocate the funds is by simply investing it at market rates. If refactoring can't beat basic investment, it isn't work doing.
Because days of man time cost a fixed amount of money, we can just calculate interest on the development days directly and save the additional effort of having to manipulate values in any given currency.
Here is the table of data comparing both accounts:
Year | Account A | Account B |
---|---|---|
0 | 0.00 | 90 |
1 | 36.53 | 95.40 |
2 | 73.05 | 101.12 |
3 | 109.58 | 107.19 |
4 | 146.10 | 113.62 |
There are a couple of things to note here. After two and a bit years, you will have paid back your capital expenditure. After nearly three years you will beat what you would have earned if you'd just invested that development time in the bank.
It's worth noting that by staying the course on Account B, the exponential gains of interest will eventually out pace Account A. This occurs fifty or so years after the refactoring was done. That data point is of little practical relveance since the product will probably not exist by that time.
After just under three years we're getting more money from our refactoring exercise than the trivial case of investing the money in a savings account. That looks like a solid medium term investment.
I don't know of any studies that give the real productivity improvement of refactoring but I feel that 10% may be a little too generous. Let's say that refactoring improves developer productivity by 5% instead of 10%.
Our table of accounts table now looks like this:
Year | Account A | Account B |
---|---|---|
0 | 0.00 | 90.00 |
1 | 18.26 | 95.40 |
2 | 36.25 | 101.12 |
3 | 54.79 | 107.19 |
4 | 73.05 | 113.62 |
5 | 91.31 | 120.44 |
6 | 109.57 | 127.67 |
7 | 127.84 | 135.33 |
8 | 146.10 | 143.45 |
At this rate it takes a shade under five years to repay the initial cost of the refactoring. It takes about eight years for the refactoring to come out ahead of straight-forward investment.
In software, eight years is an age. If refactoring gives anything less than a 10% productivity improvement it probably isn't worth doing.
Except, that when you're done refactoring, are you really done? As time goes on, code gets more hairy and every so often you boss might factor in time to refactor your code. Let's say your boss wants to do three months of refactoring every five years. Let's be say that refactoring improves your productivity by 8%. This is somewhere between the two figures given in this article and represent my gut feel for how much time a well factored program can save.
Here is how our accounts look now:
Year | Account A | Account B |
---|---|---|
0 | 0.00 | 90.00 |
1 | 29.22 | 95.40 |
2 | 58.44 | 101.12 |
3 | 87.66 | 107.19 |
4 | 116.88 | 113.62 |
5 | 56.10 | 120.44 |
6 | 85.32 | 127.67 |
7 | 114.54 | 135.33 |
8 | 143.76 | 143.45 |
9 | 172.98 | 152.05 |
10 | 112.20 | 161.18 |
11 | 141.42 | 170.85 |
12 | 170.64 | 181.10 |
12 | 73.05 | 113.62 |
13 | 199.86 | 191.96 |
14 | 229.08 | 203.48 |
15 | 168.30 | 215.69 |
Every five years, 90 is subtracted from Account A to cover the cost of refactoring. It is clear that over each cycle, you will cover the cost of the refactoring but in the long term, simply investing the cash will give you a better return on investment.
This article is a mixed bag. For refactoring to be a better investment than just banking the cash, you have to improve productivity by 5-8% or more. This is quite a big ask and I have big doubts this can be achieved in practice. If your opportunity cost is much higher than the figures represented by "Account B" then you're probably best spending the money on something else, like new features or defect reduction technqiues.
This analysis also assumes that refactoring was done perfectly and didn't introduce errors. If refactoring is done even slightly imperfectly, it is very easy to wipe out the productivity benefits of refactoring through the increased debugging cost.
So where is refactoring useful? Well, I would say that refactoring has utility where a code base, as a black box, works but is unmaintainable. The more unmaintainable the code base, the more refactoring is likely to give you. If a code-base is horribly buggy then a large amount of logic is going to have to be reworked in any event. Refactoring may help in spotting problems but the real solution is to rewrite the buggy modules - which is really new development rather than refactoring.
Personally, I think refactoring solves the wrong problem. If code is badly designed then some process resulted in that bad design. Fixing the process is going to be a lot more effective than continually fixing the code.
If you just refactor periodically without learning anything about why you needed to refactor in the first place, then you have missed an important opportunity to fix things.
It should be obvious that fixing mistakes before they even occur is the cheapest way to fix a mistake. Refactoring seeks to fix a preventable mistake that should have been prevented.