eldelto
Created:

Falling Into the Rewrite Trap

To rewrite or not to rewrite, this is the question.

  • Some medieval code peasant

When working with a system for long enough there always comes a point where we get tired of its idiosyncrasies, amass code paths that are not pleasant to work with but also not quite bad enough to do something about it, or we straight up think that the whole project should be kicked into the garbage can where it so rightfully belongs. This is the time where the most forbidden thought crime gets committed and we think to ourselves:

"Let's just do a rewrite."

The Journey Begins

Eagerly we set off to our new adventure with nothing but good intentions in mind. We finally get to redeem all of our ancestors sins (and our own of course) and build a thing of pure beauty - easy to read, a breeze to maintain and new features will just fall into place thanks to our perfectly chosen abstractions.

For this to work out we need to change the API, refactor the data model, update our tech-stack, or even better, switch it out alltogether for something better. We will finally be able to free our business logic from the shackles of our old and encrusted monolith and ride into a bright future of unencumbered change.

We manage to convince the business people by insisting that this refactoring project is absolutely necessary or otherwise feature development will soon slow down to a crawl and so we get six months of time to complete it - let's gooo.

We start dissecting the old business logic, vow to leave all the cruft behind that makes it so unpleasant to work with and set out to create the new design. Theory is followed by practice and we port the old business logic to our new service. Code is created quickly and everyone involved is having a blast.

The new tech we've chosen needs a bit more time to figure out than anticipated as some of its drawbacks weren't immediately visible but things are going well and we are only slightly behind schedule - nothing to worry about.

Visions

Weeks pass by and with every new piece of functionality we unravel a new edge case that wants to be handled and we didn't anticipate in our original plan. We port everything nonetheless but our new implementation starts to eerily resemble the legacy code we so desperately wanted to escape.

The clean business logic started to grow some additional limbs and as the complexity increases so does the amount of work required to surmount it. The deadline gets pushed out a bit for good measure but we still have high hopes to be finished by the original due date.

"Nothing to worry about." we tell ourselves as all temporary workarounds can be removed once everyone migrated to the new API. Speaking of which... The new API is not backwards compatible and therefore clients are required to change as well, but not everyone is able or willing to migrate within our allotted time frame - uh, oh...

Stuck in the Tar Pit

If it wasn't obvious by now, this is the point were things really start to break apart.

With the API consumers not able to change in time and the project already running behind schedule we choose to introduce an API translation layer that bends over backwards to pretend that the old API contract is still supported by the new service.

This will get rid of most compatibility issues but creates another big chunk of unforseen work and of course will make our late project finish even later. Meanwhile our product team is getting cranky (rightfully so) because planned features are being pushed out as we want to avoid duplicated implementation effort in the old and the new code base.

One thing leads to another and we decide to give in and scrap our plans for a gradual migration and instead opt for a hard switchover, faster but definitely riskier as well.

Weeks turn into months and the API translation layer is finally finished and the migration eventually happens, but everything around it wasn't a pleasant experience at all. Team morale is low and the final code doesn't necessarily look better but is for the most part just different. Clients still need to migrate until the temporary API translation layer can be removed again and one question hangs in the air...

Was it worth it?

Resisting the Chaos

What a ride... Unfortunately projects suffer a similar fate more often than they should. But how can we avoid this slippery slope and what are the signs to look out for to stop a derailing (refactoring) project?

Purpose

The earlier we can spot doomed projects the better and that process already starts in the design phase. If we ask why we want to do something and how it will improve the product and we only get fuzzy answers, it's time to stop and really start digging if it is worth doing at all or if the time could be better spent doing something else.

Not only is it a waste of time and money for the company when effort is poured into projects that don't accomplish any concrete goals but it is also detrimental to team morale if you're working away on something that doesn't have the expected impact or worse, is considered just busywork by other people.

Feedback

Generally speaking, the bigger a project the more likely it is to spiral out of control, especially when there is no good feedback loop in place.

Rewriting parts of your system and going live when everything is done? Nope.

Working on a new and complex feature for months without getting customer feedback on a minimum-viable-product? We may want to reconsider.

Getting something out of the door and into the real world is essential and not doing so is one of the best ways to ensure failure. After all, how else do we know if we are building the right thing if nobody tells us what's good or bad about it?

External Dependencies

If our project needs another team to do something in order to be completed, we better be damn sure that they are reliable or we will quickly find ourselves in a world of hurt. All it takes is a single deprioritisation of the required work and suddenly the project starts slipping.

Giving up agency about acomplishing our own deadlines should always be carefully considered and if deemed unavoidable, the outside teams should be enabled to start their work as soon as possible by agreeing on the interface contracts early in a project's life and supplying them with necessary documentation.

This way the risk can be minimized and we already get feedback on our new interfaces and docs, a win-win situation.

Refactoring Projects

Last but not least, by now I believe that dedicated refactoring projects mostly result in a bad time for everyone involved.

I can definitely see the appeal when one argues for dedicated time to push through a big refactoring, as it is theoretically the most efficient option, but only so if everything goes according to plan.

For starters, it is a ticking time bomb as there are usually some hefty unknown unknown's lurking in a dark corner of the legacy code, waiting to ruin our day. When they get uncovered they either delay the project in the best case or force the refactoring effort to be cancelled at their worst.

Moreover refactoring projects induce a lot of pressure to finish them quickly, even more so when they block feature development. Developers suffer because it is often not very engaging work but the deadline is looming in the corner all the time. Product will get crankier the longer the whole thing takes as it delays new and important features.

Gradual migrations or even improving the legacy code in place, might be the more appropriate way to go, even though it will take longer and require more effort all things considerd. Of course your mileage may vary depending on the size of the refactoring but I believe that slow and steady refactorings result in an overal better experience for everyone.

Parting Words

Alright, that's it with my half-rant about doing software refactoring projects. It is quite hard to gain sufficient experience with them, as per definition they only get really hairy when they are big, therefore you can only do so many in a year.

If you have any advice on how to tame them, please drop me an E-mail at eldelto77@gmail.com.

One man's treasure is another man's refactoring project. - Unknown poet