If you write software, you’ve heard about Joel Spolsky’s famous blog post, “Things You Should Never Do, Part I,”. He advises coders to never throw out a codebase and rewrite from scratch. The notion became the theme of the startup playbook.
But the advice is not one size fits all. For many of us it’s wrong…
What do I mean, wrong? Let me explain.
I worked with a startup playing in the competitive space with SnapChat and Instagram. We did image and video sharing from an iOS mobile app. I joined late, and when I did, a server and natively coded client app were humming along in beta. The team hired me because they needed an engineer who could work on the back end. When I first jumped in, minor changes were extremely hard to make. Part of the difficulty was the Wild West nature of Node.js development. Mostly, though, the obstacles stemmed from decisions the original tech team made on day one.
The team imagined the state of the app down the road, with thousands of users and a heavy tech load. Sharing and storing video files is hard, and they wanted a better way to do it, so they chose Raik, a key-value database. It included an Amazon S3-compatible file storage interface. Then they jammed all of the other data – users, following, data records and more – into Raik.
The upshot: The developer had to wrangle the nuts and bolts of asynchronous database access in Node along with a custom-coded database middleware. Then, the developer had to hand code all database indices with additional code.
Every type of search had to be handled inside Node, or be pre-indexed in a custom, single-purpose index file. Every API required tens, if not hundreds, of callback promises. The overhead for doing anything was enormous, and the weight of a ponderous back end slowed and probably killed an innovative video-sharing app.
The proper move was to replace the back end with easily managed technology. A relational database, or a hybrid system like MongoDB, would have provided significant improvements. Moving to S3 for media storage directly would have made a couple features a bit more cumbersome, but would have massively simplified the development process. Alternative base platforms like Rails or Django would have simplified the app’s biggest single feature, user management.
The CEO listened to my suggestions, and then elected to move forward with what he had. He felt that taking the “rewrite from scratch” to his board and investors would have resulted in a “never rewrite from scratch situation.” This is Joel’s basic argument.
Ultimately, the unwieldy and unmanageable codebase slowed the app’s progress to a crawl, as we searched for senior developers. The codebase, and adhering to Joel’s advice, significantly contributed to the company’s collapse. Failing to identify the problem of intractable code and replace it killed the app. Joel’s advice was fruitless in that situation.
Joel wasn’t, however, writing about this. He was writing about mature products with users and market and traction. He worked on Excel. He starts by saying the Borland lost market share by doing this. He says what killed Netscape was a total rewrite that took focus away from users between version 4 and 6.
He could be right. If you’re working on something like this, you probably shouldn’t rewrite from the ground up. But if you’re a startup, and you’re doing it right, you’re probably going to have to, at least once.
Every startup I have had experience with has needed one technical thing above all: the ability to change the feature set rapidly, or to change the behavior of the application for the user.
This leaves dead ends all over the app. Abandoned features littered the back end of the last startup I sold in 2017. The app was a mess; we had pivoted at least three times trying to find our sales stride. In most cases, I simply pulled functionality out of the front end, and left things in the back end untouched. Our migrations file – yes… Rails – had entire tables added, modified, and dropped. Tests were added and deleted willy-nilly.
Once we found our market fit, the app needed a total rewrite, because, as Joel says, it’s easier to write code than to read it. Knowing what the app needs to do, specifically – because your customers are using a version hacked together with bubble gum and bailing wire – allows you to write a clean, efficient code, and based on solid unit and integration tests. Doing that is significantly easier than trying to unbundle features and databases with unused legacy relationships, and code that causes side effects elsewhere.
Essentially, instead of spending your time asking, “Hey, what does this code do?” simply write a test detailing what it should do. Then, write the code to pass the test. Consider the best architecture, and which back-end technologies are necessary. Is a relational database with limited JSON object capabilities a better plan, or is a JSON database with some limited relational sugar?
Essentially, the choice comes down to why you’re rewriting the code. Spolsky seems to believe all of his examples were rebuilt because of the developers’ vanity, or because they didn’t like the codebase. And that’s not a good reason to rewrite an application, though it is a reason to hire a new team.
Intractable tech slowing your ability to iterate while you’re trying to achieve market fit, well, that might be a decent reason.
And cleaning up a kludge of code from a three-year journey to identify your market? It just might be easier to start from zero there, too.
In a nutshell, there are some very good reasons to start over, and Spolsky was writing before the first dotcom bubble burst in 2000. The thing most of us are doing today is very different from the monoliths that are Excel or QuattroPro. Don’t let this specific case of conventional wisdom tie you to a boat anchor.
If the code doesn’t do what you need, and you can’t seem to make it, maybe it is time to start over with a clean repository.