On Wheels and Reinvention

4 minute read Published: 2025-09-04

"Why are you reimplementing $feature when you can just import $library? You're reinventing the wheel!"

I think the warning against reinventing wheels—and presumably other simple machines—has blinded us to more subtle truths about when it's okay to build something that already exists, but closer to home.

This will be a quick one, I promise. Too long for social media but under my normal blog word count.

When a developer writes code that solves the same problem as code available elsewhere, it isn't always "reinvention," per se. Think of it as sourcing the part locally rather than establishing a needlessly complex supply chain. Sometimes, it really is cheaper to build in-house. Regarding wheels:

Sometimes, the existing wheel is bigger, shinier, more feature-filled than I need. I'm building a bike, but the available wheel is for a Formula 1 car.

Sometimes the wheel was built with a slew of other components I don't want to worry about.

Sometimes the wheel comes from carpenters whose work has proven shoddy in the past.

Sometimes the wheel comes with incomprehensible instructions, or none at all.

Sometimes the wheel has security issues that allow others to...take control of the cart?

The metaphor may be wearing thin. Let's talk about code.

Most reading this will be familiar with the term "technical debt," but I'm not sure how many think about how much is incurred when adding dependencies to their software. I maintain a fair few projects that rely on the code of others, and let me say this with love: it breaks. All. The. Time. Between bugs introduced by those developers, their dependencies, or breaking changes in the APIs they're targeting, it can become messy and time-consuming to track all the ways in which a dependency can kill your project rather than streamline its development.

These are costs, whether they feel like them or not. And they become long-term costs as your project develops, becoming more and more intertwined with its dependencies. It is a kind of lock-in. Yes, of course, nothing is stopping any developer from changing up their dependency chain, but the more established a project, the more practically difficult that becomes, due to both codebase complexity and the development team's folk wisdom.

If npm install or cargo add cost money up front per usage, I guarantee developers would be a lot more willing to reimplement existing solutions. The apparent zero cost of adding software dependencies blinds us to the long-term debt we can incur by building a project wholly dependent on external code.

Not all costs are unreasonable! The bazaar of code should be enjoyed, shared, and enriched. In many (most?) cases, adding that dependency is the right call—but not without consideration.

For my own projects, I have arrived at a philosophy of minimizing dependencies. If the programming problem to be solved is clear and approachable, I should find reasons not to write the code myself. Will I end up duplicating someone else's work? Probably. But the resulting code is a native component of my codebase, and something that requires no external entities to maintain. Not for nothing, but it can also make understanding the code easier for newcomers, since the entire implementation is laid out before the developer.

Oh, and I have the surest guarantee that the mistakes in the code are my own, and not the result of convoluted generative model output. We have no way to distinguish human code from model code, and that alone increases the risk of dependencies from unknown, untrusted sources.

So go ahead. Build that wheel in your own backyard.