Rewrite or Refactor?
Editorial Note: I originally wrote this post for the NDepend blog. You can find the original here, at their site. While you’re there, take a look at some of the other posts and announcements.
I’ve trod this path before in various incarnations, and I’ll do it again today. After all, I can think of few topics in software development that draw as much debate as this one. “We’ve got this app, and we want to know if we should refactor it or rewrite it.”
For what it’s worth, I answer this question for a living. And I don’t mean that in the general sense that anyone in software must ponder the question. I mean that CIOs, dev managers and boards of directors literally pay me to help them figure out whether to rewrite, retire, refactor, or rework an application. I go in, gather evidence, mine the data and state my case about the recommended fate for the app.
Because of this vocation and because of my writing, people often ask my opinion on this topic. Today, I yet again answer such a question. “How do I know when to rewrite an app instead of just refactoring it?” I’ll answer. Sort of. But, before I do, let’s briefly revisit some of my past opinions.
Getting the Terminology Right
Right now, you’re envisioning a binary decision about the fate of an application. It’s old, tired, clunky and perhaps embarrassing. Should you scrap it, write it off, and start over? Or, should you power through, molding it into something more clean, modern, and adaptable. Fine. But, let’s first consider that the latter option does not constitute a “refactoring.”
A while back, I wrote a post called “Refactoring is a Development Technique, Not a Project.” You can read the argument in its entirety, but I’ll summarize briefly here. To “refactor” code is to restructure it without altering external behavior. For instance, to take a large method and extract some of its code into another method. But when you use “refactor” as an alternative to “rewrite,” you mean something else.
Let’s say that you have some kind of creaky old Webforms application with giant hunks of gnarly code and logic binding the GUI right to the database. Worse yet, you’ve taken a dependency on some defunct payment processing library that prevents you from updating beyond .NET 2.0. When you look at this and say, “should I refactor or rewrite,” you’re not saying “should I move code around inside this application or rewrite it?” Rather, you’re saying, “should I give this thing a face lift or rewrite it?”
So let’s chase some precision in terms here. Refactoring happens on an ongoing and relatively minor basis. If you undertake something that constitutes a project, you’re changing the software. You’re altering the way it interacts with the database, swapping out a dependency, updating your code to a new version of the framework, etc. So from here forward, let’s call that a reworking of the application.
To Rework or Rewrite
With that out of the way, we can examine the question in clearer terms. To do that, I will first recall another piece I wrote — one that became fairly popular (and slightly controversial). I called that post, “The Myth of the Software Rewrite.”
In that post I offered a relatively narrow thesis. I made the case that organizations should not undertake a rewrite because the developers piled up too much technical debt to continue effectively. When developers clamor for a rewrite to escape a mess of their creation, you have an organizational smell. Rewarded with a blank slate, the same people will promptly recreate the same problem that landed them where they are. Conceding to this rewrite today almost certainly means conceding to subsequent ones at regular intervals. A team in this situation needs to bite the bullet and learn how to clean up and evolve software.
But that covers only a narrow case. Specifically, I mean the case where the main impetus for a proposed rewrite is the team saying, “we’ve made a mess and need to start over.” What about situations where either the team doesn’t push for the rewrite or else the team pushes for another reason?
Reasons to consider a rewrite abound. Perhaps the software runs on dated hardware or perhaps it has outsize dependencies on dying software. It could be that new feature requests are radically incompatible with the existing architecture or that the way it interacts with other systems has evolved. It might even be that the software is simply a mess, but your team inherited it rather than being responsible for it. I addressed none of these situations with my previous post. And yet, they all merit consideration.
I can offer a relatively simple answer in all cases. In fact, it’s the same basic premise that I use with my clients. You should rewrite when reworking would cost more than starting from scratch. And you should only do either one once you’ve demonstrated a value proposition for change.
The Business Case
Okay, so I’ve offered an overarching bit of wisdom but without much detail. Perhaps you’d even consider what I said somewhat glib. But you have to understand the importance of this central consideration. The decision to rework or rewrite is a business decision based on dollars and cents. Your task now is to make the case for each.
How to build that case would fill at least another entire post. But you can get to a decent approximation with a fairly simple exercise. Take the desired end state of the system, and construct a sequential, architectural roadmap of how you might get there from current state.
First of all, if you can’t do that in the first place, then you should probably consider a rewrite. It might be that no clear path exists from some COBOL, green-screen database application to Angry Birds 2 for iPhone. In that case, just write Angry Birds 2.
If you think you can get there, lay out the steps required for the rework and the components involved in a rewrite. Then, do a grossly high-level exercise in the agile concept of relative sizing. In other words, don’t figure out how many man-hours all of these tasks require. That will take forever, and you’ll just be wrong. Instead, compare sizes. If “build a data access layer” is a 3, then is “decouple all GUI dependencies” more like another 3 or like a 5? You don’t need to think about time — just relative complexity.
This exercise can give you at least an early sanity check. When you build the actual case to bring to the business, you’ll want to factor in other concerns. These might include relative outage times, team morale, licensing costs, etc. And you’ll naturally want to dive deep on some of the estimates, using metrics like coupling and fan-in to see how difficult separation may prove.
But to start, lay out your path and do a bit of sizing. The “rework or rewrite” debate can drag on endlessly and cause a great deal of hand-wringing. Get out in front if it. Chart your course, do some relative sizing, and see how it looks.