We’ve all experienced this: you’re working on some code … probably code that was written a long time ago … and you realize that, with all the experience you’ve accumulated since the code was originally written, you could re-write (or refactor) the code so it would be much better.
The question is … how do you justify a refactoring of the code?
It’s been my experience that TPTB will rarely approve the effort involved in refactoring simply based on making the code base easier to work with, manage, and maintain. They want a concrete ROI for the change.
Refactoring provides many gives you the opportunity to enhance the code so it’s …
- More modern code.
- Easier to maintain.
- Easier to understand.
- Creates a standardized interface to the code.
… there are, however, many pitfalls …
- Takes a lot of time.
- Needs to be re-tested completely.
- Risks breaking other code that interacts with the original in unknown ways.
I’ve worked on a number of projects recently where the code base would have benefited greatly from refactoring. And, we had every intention of doing some level of refactoring, but in the end we had to settle with just writing an adapter procedure to the existing code as there just wasn’t enough time in the plan to fully refactor.
Our wrapper could have great promise to be a primary entry point to well written, highly structured, easily interfaced, code … but I doubt it will ever come to pass.
So the question is still there … how do you go about justifying a code rewrite?
I completely understand. The code base I’ve been working on for a few years now is growing increasingly crufted as we adapt the same code for one data conversion after another. It’s occurred to me to strip it down and rewrite it, but the client wanted reusable code, and it’s hard to go back to them and say “time to start over.”
We did have to do some restructuring when the client switched to Oracle 10, which made our benchmarks for the original code techniques invalid and forced me to revisit some pretty basic decisions about lookups and arrays. But even then, the revisions were overlaid on the existing code so that the core architecture did not have to change. There’s a lot of inertia – some of it institutional, some of it my own.
If you’re worried about interactions with other code, you probably really are looking at a re-write. Refactoring would fiddle the internals of a single routine; say breaking it into two separate functions so that you could reuse one of them elsewhere. Refactoring, I just… do. Like writing test jigs. If the boss found out I was spending time NOW to make test jigs instead of writing CODE he’d probably be perturbed. A year from now, when my test coverage is so much better and I make a change that doesn’t break my tests, I’ll have a LOT more confidence that I did a decent job with my mods.
A rewrite is another story altogether. I wouldn’t generally propose a rewrite. All that funky stuff is there for a reason – a reason no living soul probably knows, but was put there because someone at some point found a business reason to do so. Rewriting code like that inevitably leaves all those little strange things out.
If the code is really THAT bad, then the rewrite should sell itself. If it isn’t…
Then comes that strange middle ground, where a mod touches a lot of pieces of code – each needing a little touch-up. This is a judgment call on your part. When I do this sort of work, I add time for writing tests and refactoring into the part of the schedule allotted for testing. It isn’t coding, it’s part designing, and so I delicately propose adding unallocatable time in the testing phase. You’re going to encounter unexpected time there anyway.
It’s probably not fair to the boss to do that, but it isn’t fair for the boss to shrug aside my 30 years of experience when I say that these bits of code would profit from a tune-up. If he doesn’t trust my judgment, he ought to fire me. Words I’ve actually used.
Very interesting topic.
Depending on how the code is structured, refactoring could very well cause issues with other code’s interactions.
The kind of code I was talking about is, in general, really old code (written in the 80’s). My idea of refactoring it is to change the original, dynamically called, program in place … but only as a stub. Take the logic out of the original program and put it in a procedure. In this situation it’s quite possible to effect interactions with other programs. Which is why you need to completely retest it.
Is what I’m describing truly ‘refactoring’? Technically, I think it is. Practically, maybe not.
Yes, you’re in that middle ground. You have a subr called CHKCRD that does a CHAIN to CUSTMAST in order to get a credit score. But while we’re in there, we also check the ship-to address (saves a CHAIN elsewhere, right?) That’s exactly the sort of thing we did back then.
Is it really refactoring? It probably isn’t because of the amount of study needed to determine the ramifications. I think of refactoring as the sort of stuff I can fit in with not a lot of disruption to the schedule.
Having said that, there are times I take the time to do the analysis and break that code apart. Usually it’s because I’m in there anyway, and it’ll be more useful to make the ‘credit check’ more atomic from ‘check ship-to’ so that I can make one or both of them available to a subprocedure via a service program.
In that case, I try to realise up front that I’m going to be spending analysis time on the subr anyway, and add some time there and to the testing schedule to account for my rework.
When I discover one of those monsters after I’ve been in the work for a while, I usually leave it alone and write the new subprocedure, call it from the middle of that nasty subr and comment the fact that the subprocedure has the real, updated code, along with the reason I didn’t refactor out all the separate ‘functions’ (schedule constraints) so that the next guy in doesn’t think I was an idiot. Maybe he (probably me!) will have a little more time in the next pass and be able to pull out the other ‘function’ and turn that subr into a stub that invokes the subprocedures.
Basically, I’m agreeing with your thoughts. I just sort of slip the time to do the rework into the schedule rather than asking permission up front to do it.