Feature Complete: Now Build It Again!

Rudy Luthi
In Media Res
Published in
4 min readJul 12, 2018
“On to v1.1!” (📷: The Run Factory)

This post is part of the Caseworx Summer Series 2018, where we investigate the intersection of learning, technology and media from every wacky angle we can find. We run from the 4th of July to Labor Day.

It takes a special kind of sickness to spend weeks on a feature, months on an app, even a year plus building a product, and then immediately redo significant portions of it. Product development happens in a time crunch, and it is often a better decision to put flawless software design on the back burner and concentrate on your product and getting to market. Some excellent arguments are presented in these articles: The Duct Tape Programmer and Embrace Technical Debt. As a startup with limited resources post-release, there’s an endless litany of reasons to keep maintaining and iterating on Version 1 Point O. Once you’ve released, you have customer support, requests for minor features, bug fixes, etc. Running lean means out-kicking the (test) coverage from time to time, so that in-turn causes QA issues, and the list goes on and on. I wanted to address some reasons and circumstances that may justify significant rewriting or refactoring of completed code.

Reason 1: Significant changes to the business require a whole new scaling strategy.

This may seem obvious, but if you’re a startup, you’re in growth and investment mode. As Justin Wolske noted in this post, for better or worse the mantra for startups is “fail fast, fail often” and “devour the world.” If you’re traffic undergoes explosive growth, or you raise a significant amount of money and hire 100 new engineers, often the platform that set you on the path to growth is not the one that will support your new scale. In this case, a new database, a new cloud, a new caching layer, a new CDN strategy, a much more conservative browser support requirement, or all of the above, is a small price to pay. Inevitably a platform change is going to require significant code changes. It’s time to go cloud native.

Reason 2: The code is a mess, or poor design decisions (pure technical debt)

Hopefully this can be contained and fixed as you build, or refactored over time, but sometimes there’s just no way around it. The key here is to realize it before it becomes insurmountable. For me, the first signal is when I find myself resisting adding something that customers want because it’s going to take too long or add too much complexity. The second signal is when the only efficient way to accomplish a task is to start playing tricks with the event loop or cooking up some starchy code pasta. Usually this type of technical debt doesn’t need a full rewrite, but it could be time to rethink how your code layout matches the product layout — the best way I’ve found to ensure this: design your apps around your user flows, not inheritance and shared code. Save the slick stuff for last.

Reason 3: Merging two apps together

This could perhaps be a hybrid of the first two reasons — your world devouring included a side dish of another company’s technology, and now it’s time to merge it together. Another scenario: you’ve been trying some different product ideas and now it’s time for the ecosystem to mature and there’s a need to combine several smaller products into a cohesive application. Often you’re confronted with different tech stacks, and there’s no avoiding significant rewriting to make it happen. Please avoid creating The Blob in your laboratory.

Reason 4: Open Source giveth, Open Source taketh away

When it comes to building things quickly, there’s nothing so helpful as leveraging the open source model. Steaming and fresh from your forked repository you have t̵e̵s̵t̵e̵d̵ and m̶a̶t̶u̶r̶e functioning code. Really, many popular packages and frameworks are quite well tested and mature. However, the core developers who wrote and are maintaining the package are simply not on the same development schedule as you and your team, and they may rewrite, deprecate features, and re-architect their project. There’s a choice — usually there are long-term-support (LTS) versions that are maintained and stable. The risk of staying on the LTS is significant — you could be building on a dead end. Recently we had (the amazing opportunity) to switch language versions (Python 2.7 to Python 3.6) because Python 3 was required by the new version of one of our core packages. Was the app working before? Yes, but the resulting refactor from switching resulted in a significantly higher-performing, more modern piece of software, and it was completely worth the pain.

In Conclusion

Even if you ship clean code every time and test every line, business circumstances or open source packages still can and will change beneath you. In an environment of limited resources and compressed time schedules, the decision to throw away working code will affect your business timelines (especially in the early stages), so ensure that it’s primarily a business decision and not because you want to try a clever new design pattern. At the same time, nothing is too precious, and when the situation calls for it — be prepared, current, and know the next steps needed to evolve your codebase.

Rudy Luthi loves to talk about aligning technical design to product flow in addition to Django Channels, websockets, InfernoJS, and Mobx. He’s using all of the above at Caseworx. You should join us.

--

--

Rudy Luthi
In Media Res

Rudy is a product builder/designer. He's cofounder of Caseworx and lives in Los Angeles, CA.