Alright, why not. :)
So this tweet by Promit Roy got a lot of attention recently, and I think it’s really great advice.
As someone who ends up building a lot of architectural and infrastructure code, there's one thing I cannot emphasize enough: do the simplest thing that works. Do not try to imagine future requirements, or support ill-defined potential use cases. It will always change later.— Promit Roy ⚡ (@promit_roy) June 18, 2021
Beginners tend to have trouble hearing this advice. I think this is in part due to many schools still teaching the opposite approach, but also, because planning is attractive in and of itself. “Sure, my plans didn’t pan out this time, but next time will be different!”
In case you’re not sure whether this is good advice, here are some people you should probably trust on this topic agreeing in the replies:
It is hard for less experienced developers to appreciate how rarely architecting for future requirements / applications turns out net-positive. https://t.co/lusGdzkfd3— John Carmack (@ID_AA_Carmack) June 18, 2021
I used to do a lot of planning, and it always turned out to be a waste of time, and I'd have to rewrite large chunks anyway - either because the requirements changed, or because I didn't understand the problem until I actually wrote the code.— Tom Forsyth (@tom_forsyth) June 18, 2021
Alright, so, are we settled on that?
Lets get on to my rant.
So, you’ve been convinced. You take this advice to heart and go off to build a giant piece of software–each step of the way keeping it as simple as possible–until one day, the inevitable happens.
You need to make a nontrivial change.
That’s okay! You knew this day would come eventually! In fact, you planned on it! But…what’s the most productive way to handle this scenario?
Sometimes, it’s easy to see how you could modify what you already built to support your new needs. Other times, the thing you built feels so at odds with your current needs that rewriting it from scratch seems like the better approach.
It’s a tradeoff, of course, but in this post I want to argue that for any sizable system it’s very rarely worth it to start over.
The question here isn’t how many lines of code to replace, it’s by what method you choose to replace them. You can make incremental changes to a system until none of the original code remains, that’s a valid option that for the purposes of this argument I don’t consider a rewrite.
Usually, the temptation to rewrite from scratch is twofold:
- You’ve already written it once, how long could it take to rewrite it with the knowledge you now have?
- The thing you’re trying to do now is at odds with what you already built, making the change incrementally would be too difficult!
The problem is, these two beliefs contradict eachother!
If it’s true that the thing you’re building is so similar to what you’ve already built that it’ll be easy to rewrite, then there’s no point in rewriting it. If it’s so different that incrementally adapting it is tricky, rewriting would also be a huge investment–that’s not a clear win.
What Tends To Happen
Here’s what tends to happen, realistically, during a large rewrite.
Things start out smoothly. You’re basically just building what you already had, but cleaner, and that feels good.
And then…the problems begin. It turns out, there were actually a lot of good reasons you did things the way you did originally. And you forgot most of them in the time since.
It turns out your new design doesn’t quite work. Oh well, that’s fine, you can adjust as you go–oh, that doesn’t quite work either.
And so on.
Eventually, after spending a lot of time on the rewrite, you either end up basically recreating what you already had, or you end up with something that solves your existing problem at the expense of a bunch of new ones. Sometimes, sometimes, you end up with a better system–but it’s usually one that you could’ve built more quickly through incremental changes to your old implementation.
Deciding to rewrite is easy, because you don’t pay the cost at decision time. Deciding to achieve your goals through a series of incremental changes is difficult, because you need to think hard up front about how exactly to do that. It sometimes seems impossible, but often, you just need to give it a little thought.
So, when should you rewrite?
IMO, only when the piece of code is either small or very well encapsulated, such that the cost of the rewrite is clear up front, or when you’ve tried and failed to make the change incrementally.
A working system is a valuable asset. It works. It lets you test new ideas cheaply. Don’t take that for granted.
If you enjoyed this post and want to be notified about future posts you can sign up for my mailing list or follow me on Twitter. If you want to give me an early birthday present, you can wishlist my game on Steam whose engine I will not rewrite from scratch when it comes time to start my next game, despite my conviction that I would totally do it better given a clean break.