Skip to content

Avoiding a Legacy Codebase. Keep it Evergreen

Sponsor: Do you build complex software systems? See how NServiceBus makes it easier to design, build, and manage software systems that use message queues to achieve loose coupling. Get started for free.

Learn more about Software Architecture & Design.
Join thousands of developers getting weekly updates to increase your understanding of software architecture and design concepts.


Nobody wants their codebase to turn into a brownfield mess legacy codebase having to use outdated technology. Here are 3 tips for keeping your codebase evergreen.

YouTube

Check out my YouTube channel, where I post all kinds of content accompanying my posts, including this video showing everything in this post.

Understanding Stability and Advancements

How do you keep your codebase Evergreen and avoid it being a legacy codebase? Let’s say you recently started a greenfield project, and you know it will be maintained over the years, adding new functionality. You don’t want it to turn into legacy or something that’s considered brownfield.

The first tip is understanding the stability and advancements of the core pieces of technology you’re building your system around. This includes the actual underlying platform, programming language, frameworks, libraries, databases, and the infrastructure that forms the foundation of your system.

Understand the stability of these technologies. How often are they making breaking changes or major version increments? Are there breaking changes? Recognizing that this isn’t necessarily a bad thing is essential; it’s about being aware of the likelihood of these changes and how they will affect your development moving forward.

When selecting or evaluating your underlying technology, get a sense of its historical stability. For instance, when I started a codebase nine years ago, it was running on .NET Framework 4.7 on Windows. Today, it runs on .NET 8 under Linux. This evolution was possible because I bet on .NET. Although there was a transition from .NET Framework to .NET Core (now just referred to as .NET), Microsoft has been incredible at maintaining backward compatibility. Consequently, much of the code didn’t need to evolve significantly over time to accommodate this transition.

Managing Dependencies

The second tip to avoid a legacy codebase revolves around dependencies. When you decide to take a dependency, it’s essential now your problem. Everything about it becomes your responsibility, whether it’s maintenance, security issues, or breaking changes. Sure, someone might maintain it, regardless of whether it’s open source or not; if there is some issue with it, it doesn’t mean they will fix it. It’s your issue.

Like the first tip, when you choose a dependency, think critically about how you’re using that API and the degree of coupling you have to that dependency.

For example, suppose you’re using a third-party library to generate PDFs. The degree of coupling is important. Do you depend on that library in 12 different usages across your codebase, or do you have 200? If you ultimately need to replace the third-party library, are you fixing 12 usages or 200? This consideration is a significant factor in whether you want to create an abstraction. The goal of abstraction is to simplify the surface area of the API you’re using, making it easier to manage.

Incremental Changes and Localized Areas

The third tip explains why the second tip is so important. There’s only one way to eat an elephant: one bite at a time. When you have a large system developed over years, you don’t want to look at it as a massive elephant that turns into a big ball of mud—or as I often say, a turdpile.

Instead, think about creating smaller turd piles. This approach allows you to make incremental changes in localized areas for various reasons. For instance, if you have a dependency that’s no longer supported, you can change that localized turd pile to another third-party dependency.

Moreover, this isn’t just about dependencies; it also pertains to your code and development patterns. Everyone knows that when you look at older code you’ve written, you might think, “Oh, maybe we should do this differently moving forward.” Defining boundaries or these little turd piles allows for this evolution.

In a real-world example, the nine-year-old codebase I worked on had to evolve over time due to defined boundaries, such as different DB contexts using Entity Framework. As Entity Framework Core emerged, we could gradually change these boundaries to start using it. We still used the same underlying database but transitioned one at a time. This incremental approach facilitated the adoption of new technologies without overwhelming the entire system.

Keeping your codebase Evergreen is fundamentally about your ability to evolve and keep up with the pace of technology over time. Understanding the platforms, libraries, and frameworks you’re betting on and their potential impacts on you and your codebase is crucial. By maintaining everything within boundaries, you can localize collateral damage when changes occur, allowing for gradual upgrades and dependency shifts.

Join CodeOpinon!
Developer-level members of my Patreon or YouTube channel get access to a private Discord server to chat with other developers about Software Architecture and Design and access to source code for any working demo application I post on my blog or YouTube. Check out my Patreon or YouTube Membership for more info.

Leave a Reply

Your email address will not be published. Required fields are marked *