November 3, 2026
Building software wrapped in complex external dependencies introduces forced updates, breaking changes, and unpredictable maintenance costs. Prioritizing decoupled engineering on open standards keeps code bases portable, reduces technical debt, and ensures long-term application autonomy.
For most software teams, constant maintenance is a cost of doing business. Many products require frequent framework upgrades, dependency patches, and migrations. Teams build them into the roadmap as if they’re inevitable. At Liber, we think much of this can be avoided by building with the long-term in mind.
Software that needs rescuing every few months is often built on several commercial frameworks with different update cycles, feature roadmaps, and licensing terms.
Commercial vendors face pressure to continuously iterate to maintain growth and satisfy shareholders, even when the product doesn’t need it. Relying on products with frequent course changes can leave your engineers scrambling to follow rather than lead.
Routine updates won’t be a major concern for most teams. Bumping up a package version is usually a single command. The real cost of dependency bloat is in breaking changes, end-of-life upgrades, and the testing that follows. According to the Chainguard's 2026 Engineering Reality Report, engineers spend just 16% of their week writing code and building new features. Stripe’s 2018 Developer Coefficient report, meanwhile, found that the average developer estimates spending more than 17 hours a week on maintenance.
Of course, that number includes more than managing dependencies; there’s also debugging, refactoring, and so on. That said, we believe the biggest impact of maintenance is not the hours spent but the fact that it sets the agenda. Sprints that start with a major version bump and deprecated APIs rarely end with a new feature shipping on schedule.
The 2016 left-pad debacle is a high-profile example. Azer Koçulu unpublished over 250 npm modules overnight due to a legal dispute. This included left-pad, which thousands of projects, including React, Node, and Babel, relied on. The result was chaos as teams scrambled to fix broken builds, until npm took the unprecedented step of restoring the deleted package.
Some dependencies are unavoidable, of course. Every system relies on an operating system, language runtime, and so on. Layer too many of the wrong dependencies, and you start to lose control over your own product. You end up needing to adjust your development timeline to account for their releases, modify your prices based on their API rates, and rewrite your code to account for their changes.
There is, of course, nothing wrong with external companies changing their pricing and licensing – they need to survive too. The problem comes when your profitability relies on vendors’ terms staying the same.
The Google Maps API pricing change in 2018 is a clear example. While the company had signalled it would end keyless billing for years, pricing details dropped just 40 days before the deadline. One UK site owner thought he’d have to shut down entirely, while a German pharmacy finder faced mapping costs nearly four times its entire infrastructure bill. Organisations had to accept the new bill or migrate to an inferior platform in a matter of weeks.
Every outside package is a potential risk to your product. While trusting third-party packages usually works out, the exceptions can be costly. Take the popular JavaScript package event-stream, compromised in 2018. The original author handed the project to a volunteer, who soon added a new dependency with code designed to steal funds from BitPay’s Copay wallets.
BitPay quickly confirmed that Copay wallet versions 5.0.2 to 5.1.0 were affected and told users to assume private keys had been compromised. While the affected teams did nothing wrong, they inherited the risk. BitPay, meanwhile, was left looking vulnerable for trusting a package that had a reliable owner at the time.
Building stable, long-lasting software isn’t about avoiding third-party packages entirely; it’s about recognising that one you do add is a long-term commitment to another team’s release cycle and security posture.
Decoupling starts with asking which parts of the system are the product, and which are the plumbing. Aspects like pricing logic, account handling, and data model are your product and should use standard language code where possible. Frameworks can sit around it for routing, rendering, and the like.
Go, for example, has promised since version 1 that programs written to its specification will keep compiling and running unchanged. AngularJS, meanwhile, reached end of life in 2021, and devs had to rewrite code written in the framework’s style or leave the product outdated.
The point isn’t to make the product dull. Clear, standard code can still produce beautiful products. It’s about writing code that’s easier for a wide range of developers to read and less likely to be abandoned.
Even well-chosen dependencies can break or change terms, so the second step is to structure your product to contain them. Where possible, it shouldn’t talk to a vendor’s tool directly. Instead, it should talk to a wrapper that offers plain commands such as “save this record” or “send this message”. If the wrapper is the only part of the product that deals with the vendor, you only need to rewrite that piece if something changes.
This is simplified, obviously, and the catch is that the rule only works if you stick to it. Vendor-specific details have a habit of sneaking into the rest of your code: things like error types and pagination styles will bleed through if you let them. Translate those details inside your wrapper and enforce the boundary with code reviews, lint rules, and import restrictions.
Even so, it’s possible to overdo it. A wrapper that exposes one vendor’s unique features becomes vendor-specific again. Wrap the vendors you’re realistically likely to swap or that your product can’t live without.
The cost of not doing everything we’ve mentioned is usually far more noticeable than the benefits of doing so. When you’re in the middle of a rewrite because of a dependency, you’ll certainly curse past decisions, but you probably won’t notice the times nothing happened at all because you built a stable foundation. Usually, it manifests itself in the tasks you no longer have to do.
All code requires maintenance, even independent code. Security advisories, changes to the OS, language runtimes, and so on still need attention. At Liber, our goal is to reduce the amount of unpredictable, unscheduled maintenance that happens on someone else’s schedule. Those events are what tend to delay development timelines and affect customers.
Code that relies on a few stable components can run with minor security updates for years. SQLite’s maintainers, for example, have committed to supporting it until 2050 and have built it with backward compatibility in mind. Developers are unlikely to rewrite that code anytime soon beyond routine security patches.
Commercial frameworks are popular for a reason. They ship quickly, usually with extensive documentation and support backed by capable engineering teams. However, they also come with a roadmap shaped by corporate rather than developer interests. While the two often align, the times they do not can be costly. Take Adobe Flash. In 2005, more computers had Flash Player installed than any other media format. But growth of mobile phones left Adobe with little commercial interest to continue developing it, and so it announced its end of life in 2017 after countless security issues. The millions of sites that used it had to have large sections rebuilt on Adobe’s timetable.
Open standards don’t have the same problem. HTML, CSS, JavaScript, SQL, and HTTP have outlived most of the vendors that built on them. Since no single company owns them, nobody can retire them or revoke the licence for existing users. By contrast, when HashiCorp moved Terraform from an open-source licence to the Business Source License in 2023, the community forked it to form OpenTofu.
The benefit of this stability is that you can decide more confidently where engineering time goes and how the product can scale.
When the proprietary part of the software is yours, lifecycle management changes significantly. Rather than tracking other companies’ end-of-life dates, you can set your own. Upgrades, likewise, happen because you want a capability, not because a vendor added AI features and stopped supporting the version you’re on.
Over time, this approach makes scaling more sustainable. Product growth adds users and features with fewer external obligations. The most sustainable development frameworks are built on a small set of conventions, a few well-understood libraries, and clear boundaries between them.
Freeing engineers from forced migrations and emergency rewrites leaves more time for changes that add value for the customer: performance optimisations, features, reliability, accessibility, and security. Hiring also gets easier, since developers can pick up standard language code without first learning a framework’s quirks.
To be clear, in-house software has costs. It requires senior engineers, more up-front design, and often more up-front investment. That trade-off simply won’t work for every team. For those building products that are meant to last, however, it is usually worth the investment.
With AI assistance, competitors can now copy the features customers see in weeks. What’s much harder to copy is the stable codebase and the team’s understanding of it. That clean, robust code outlives its authors and the tools it was built with. This can even pay off in mergers and acquisitions, where acquirers often scrutinise technical debt, licence conflicts, and known vulnerabilities as part of due diligence. A codebase with fewer outside dependencies usually has less to flag.
Ultimately, building an architecture legacy is about making sure your in-house software outlasts the tools around it. Building the core of your product on commercial frameworks can expose you to unpredictable costs in time, budget, and attention. A decoupled codebase built on open standards makes costs more predictable and keeps the direction in your hands.
At Liber, we believe software should outlast the tools around it. That means asking what state your project would be in if a dependency’s maintainers walked away tomorrow. If the answer is alarming, it’s worth questioning how much of your codebase you really own.