Back to Blog

In Defense of the System That Remembers

flux pro 2.0 A turtle balanced impossibly atop an ornate Victorian fence post its shell a tra 4

There's an old saying: if you see a turtle on a fence post, you know it didn't get there on its own.

Legacy systems are full of turtles on fence posts. Logic that looks arbitrary. Workflows that seem convoluted. Permissions that appear unnecessarily complex. And the natural instinct of every modernization effort is to look at all those turtles and say, "Let's simplify this. Let's clean it up. Let's make it modern."

Sometimes that's the right call. But sometimes you're about to throw away decades of institutional memory encoded in code that nobody remembers writing.

The Report That Almost Lost Its Memory

I was working on a modernization project for an old VB web forms site. There were legitimate reasons to modernize: the tech stack was ancient, the look and feel was dated, and the primary maintainer wanted to retire. Finding someone who could maintain this thing long-term was becoming a real problem.

But there was also a ton of nuance buried in that old application.

One report in particular stands out. It was sensitive: legal considerations, PII concerns, the whole nine yards. The permissions around it were incredibly complex. Who could create the report, who could approve it, who could view it. All of it depended on specific circumstances that had been carefully worked out over years.

The first couple iterations of the new system didn't capture this nuance at all. The team was building something cleaner, simpler, more modern. And in doing so, they were about to expose sensitive information to people who shouldn't see it.

I had to stop them. "Guys, we need to step back and really mine through this logic in the old app."

Here's what had happened: at some point, legal had come in and said "here's who can view this and why." That guidance got written into the code. It wasn't documented anywhere else. The code was the documentation. And when we tried to modernize without understanding that, we nearly created a compliance nightmare.

It took a few days of digging through the legacy codebase once we committed to figuring it out. Then another couple weeks of testing all the scenarios, discussing edge cases with stakeholders, and getting sign-off. But we needed to make sure we got this right because the stakes were real.

The Problem with "It Still Works"

There's a recent survey showing that 50% of organizations don't upgrade legacy systems because "the current system still works." I've been in plenty of meetings where that argument comes up.

The modernization advocates usually have good arguments. I agree with many of them. I'm part of a lot of modernization efforts myself. But the tensions in these conversations are real, and they pull in opposite directions.

The Case for Staying Put

"Still works" sometimes means exactly that. The system does what it needs to do. People use it every day. The pain isn't severe enough to justify the risk and cost of replacement.

The Case for Moving On

"Still works" sometimes means working in a degraded fashion. The system forces the business to keep legacy practices and legacy workflows that need to be optimized. People end up working around the system rather than with it. Things start happening outside the software. You get this mismatch between what the system does and what the business actually needs.

The Trap of Innovation for Innovation's Sake

A lot of modernization efforts just come down to "we don't know how to work on this old system" or "we want to do things a new way." This happens constantly in UI work. It feels like every year there's a new frontend framework, and every year the frontend people want to completely rewrite the codebase because of new patterns that have been established. That's a tough sell. Today it'll be different. Tomorrow there'll be another framework.

The Trap of Sticking Around Too Long

On the other side, there are people who want to stick with the legacy system well past the time when it's like, we need to make some changes so our processes can evolve.

Neither extreme is right. The answer depends entirely on the specific business and the specific system.

Artifacts Without Architects

When you do this archaeological work on legacy systems, you find all these artifacts of decisions that were made. But you very often don't have the decision maker. You don't even know who that was.

You don't necessarily know that it was Sue in accounting who made that decision because she worked in a certain way. Sue's retired. She trained someone, who trained someone else. The "why" got lost. Only the "what" remains, fossilized in code.

This is why good documentation matters so much. The code always tells you what decisions were made. Your comments, your supporting documentation: that's what fills in the why.

Without that context, you're left trying to reconstruct the reasoning. You compare what people are currently doing with what the system is doing. You figure out what behaviors exist because the system is a certain way versus what behaviors exist because they're actually efficient.

Practical Archaeology: Tools That Help

Before you start changing anything, you need to photograph the archaeological site. Two approaches make this safer.

Characterization Tests. Before touching the code, write tests that document what the system actually does. Not what it should do. What it does. These tests become your safety net. If you change something and a characterization test breaks, you know you've altered behavior. Maybe that's intentional. Maybe it's not. But at least you know.

The Strangler Fig Pattern. Instead of a big bang rewrite where you replace everything at once, you migrate functionality piece by piece. The new system grows around the old one like a strangler fig around a tree. Each piece of institutional memory gets examined and either preserved or deliberately discarded. You're not betting the whole system on getting everything right at once.

Both approaches force you to understand before you change. That's the whole point.

The Grandma's Roast Problem

There's this old story about a family making a roast for Christmas dinner. The first direction in grandma's recipe was to cut the roast in half. The daughter does it, then the granddaughter does it. Eventually someone asks: "Why do we cut the roast in half?"

The mom says, "That's just the way we always did it. That's how you make the roast."

But when they ask grandma, she says, "My pan didn't fit the roast without cutting it in half."

The constraint was never part of the recipe. It was dealing with a limitation that no longer existed. But it got passed down as if it were essential.

Institutional memory works the same way. Some of it is precious. Some of it is a trap. And they look identical from the outside.

Today's Framework Is Tomorrow's Pan

Here's the uncomfortable truth: every modern framework we use today is simply tomorrow's "grandma's pan."

That shiny new React architecture you're building right now? In fifteen years, some developer will be doing archaeological work on it, trying to figure out why you made the decisions you made. The constraints you're working around today, the browser limitations, the library quirks, the performance considerations, will be irrelevant. But your workarounds will live on in the code, looking like bizarre choices to whoever inherits them.

This is why the federal government's COBOL problem isn't some exotic edge case. It's your future. It's everyone's future.

The developers who wrote those Social Security systems weren't incompetent. They were solving real problems with the tools they had. The sixty million lines of COBOL at Social Security alone represent decades of policy changes, administration transitions, and legal requirements. All encoded. All hacked upon, hacked upon, hacked upon.

I have a friend who works for a corporation that's been hacking on the same system for about 20 years. Not 60 years like the federal government, but still significant. He talks about finding random one-off logic buried deep in giant files that are just massive if-then-else blocks.

This is a huge problem going both ways. There's probably tons of stuff in these systems that are landmines waiting to go off. But also ticking time bombs that are about to go off on their own. You try to move it and it blows up. You don't do anything and it blows up.

The difference between those ancient COBOL systems and your current codebase is just time. Twenty years from now, someone will be trying to understand why you did what you did. The question is whether you're leaving them any clues.

When Someone Deliberately Blocked What You Want

Here's a pattern that comes up more than you'd expect: a user asks for a new workflow or feature. You dig into the code. And you can tell that things were intentionally set up to prevent that workflow. It wasn't that no one had thought about it. Someone thought about it and said no.

When I bring this to stakeholders, the reaction is usually "let me talk to this person." The problem is that sometimes you don't know who that person was. You just know the decision was made.

Most of the time, this slows them down enough to actually think it through. They'll sit down and try to figure out why we would have made this decision. Sometimes they figure it out on their own. Sometimes they decide they don't care and want to change it anyway. But at least they're making an informed choice rather than accidentally undoing something important.

Finding the Right Person

When I discover something that needs a decision, I have to find the right person to make it. Stakeholders aren't a monolith. They sometimes have competing interests.

My general rule: go as low down the totem pole as you reasonably can.

Is this really just affecting day-to-day workflow? Talk to a user. Is it more tactical, like how we report on things or approve things? That's your middle manager. Is it strategic, affecting how people interact with the system at a fundamental level? That's when you need the highest-level stakeholder.

It comes down to understanding system design well enough to tell the difference between a preference on workflow and a strategic decision about how the business operates.

What Can Be Forgotten

When a modernization succeeds without losing institutional memory, the team was mindful about it. Good documentation. Developers aware and documenting things they're seeing so the BAs and product owners can follow up with stakeholders. Continuously validating assumptions on both sides.

But here's something important: not everything needs to be remembered.

On that same project with the sensitive report, there was an approval workflow where one person might need to approve for multiple positions. In the old system, they had to go in separately and do each approval individually. In the new system, we asked: if they're approving once, shouldn't that cover everything they're approving for?

That was something that could be forgotten. It was fine to let go.

The key is that I'm not usually the one making these calls. I'm the one discovering the information and finding the right person to make the decision. The difference between precious memory and unnecessary baggage is a business decision, not a technical one.

The Modernizer's Rubric

Before you rip out a piece of legacy logic, ask three questions:

1. Can I explain why this exists?

If you can trace the logic back to a specific requirement, constraint, or decision, you have something to work with. If you can't, you need to dig deeper before you touch it. Write a characterization test. Talk to a long-tenured employee. Find the turtle's origin story.

2. Does the original constraint still apply?

Grandma's pan doesn't exist anymore. Neither do a lot of the technical limitations, legal requirements, and business rules that shaped legacy systems. But some constraints are eternal. Compliance requirements. Security considerations. Business logic that reflects how your industry actually works. Figure out which one you're looking at.

3. Who would know if I'm wrong?

If you delete this logic and it turns out to matter, who gets hurt? Who would notice? That person needs to be part of the decision. If you can't identify anyone who would know, that's a red flag. Either this logic genuinely doesn't matter, or you don't understand your system well enough to change it safely.

If you can answer all three questions confidently, you're ready to make an informed decision about whether to preserve or discard. If you can't, you're not done with your archaeology yet.

The Point

Modernizing for the sake of modernizing is an exercise in making your institution forget where it came from. Unless there's identifiable pain, unless the system is actually failing to serve the business, the risk of losing encoded institutional memory often outweighs the benefits of having shinier technology.

That doesn't mean legacy systems are sacred. Sometimes they're genuinely broken. Sometimes they're forcing the business into workflows that no longer make sense. Sometimes the constraints they embody are like grandma's pan: real at one point, irrelevant now.

The difference between a good modernization and a disaster is whether you treat the old system as something to understand or something to escape. The code remembers things that people have forgotten. Your job is to figure out which of those memories still matter before you throw them away.

Share: