Too Complicated to Simplify

Too Complicated to Simplify

When a team says a part of the system is too complicated to change, that’s usually about knowledge that left with the people who had it, not about what’s hard. The team there now often never knew it, and finding out used to be expensive.

The status logic was too complicated to touch. Everyone agreed. It had been the answer for years. Then a product manager read the code and found six branches and a bug nobody had logged.

Six branches. The kind you could draw on a whiteboard in five minutes. The bug was a case where the status quietly reset itself under a condition no one had noticed, because no one had looked.

Nobody on that team was being evasive. “Too complicated” was the honest, repeated, years-old description of how that part of the system worked. They’d inherited the description along with the code. What they’d never inherited was the understanding behind it.

What “too complicated” actually means

Sit with that sentence, because it’s doing more work than it looks like. “Too complicated to change” sounds like a statement about the code. More often, it’s a statement about the people.

Three things tend to be stacked underneath it, and none of them is that the work is genuinely hard.

The logic was never written down. It worked, so nobody documented why. The person who built it understood it well enough that writing it down felt like a chore for someone else’s benefit, and that someone else never showed up.

Then that person left. Teams turn over. People get promoted, change companies, retire, move to the next project. The understanding left with them, and it left quietly, because understanding doesn’t sit in a repository where you’d notice it going missing.

And the team that’s there now inherited the system without ever being handed the context. This is the part people get wrong when they call it forgetting. The current team didn’t forget how the status logic works. They were never told. They started after the people who knew were already gone, so the gap was there on their first day and nobody filled it.

That’s a cost statement wearing a complexity costume. The real sentence underneath is simpler: understanding this would take real time, and we’ve never had the time to spend.

The sentence got cheap to test

Here’s what changed. That cost collapsed.

Understanding a tangled subsystem used to mean pulling an engineer off delivery for a few days, having them trace the logic by hand, read it function by function, follow it across files, and come back with an explanation. Expensive in the most literal sense. Engineering time is the scarcest thing most teams have, and “go spend three days reading old code so we can decide whether to change it” is a hard sell when there’s a roadmap to ship.

So the reading didn’t happen. Not because anyone was lazy, but because the math never worked. The squeeze was a sprint, and the juice rarely looked worth it.

Point an AI coding assistant at the same subsystem and the math is different. The cost of a first-pass understanding collapsed. Someone who can’t write the code can still ask the codebase what it does, in plain language, and get an answer grounded in the actual files. That doesn’t make them an engineer, and it doesn’t replace the judgment a careful read still needs. It means engineering isn’t the only doorway into comprehension anymore. More people can take the first pass, and the trace that used to cost an engineer the better part of a week can often be done in an afternoon, without taking the engineer at all.

This is the quiet, valuable work worth coming back to: not generating something new, but understanding what’s already running. I made the larger case for comprehension over generation elsewhere. This is what it looks like aimed at one stubborn subsystem. The capability is new enough that the habit hasn’t caught up to it. The tool can read the system. Many teams just haven’t started pointing it there.

What the read surfaces

When the reading actually happens, a few things show up with surprising regularity.

The branches are countable. The subsystem that was “too complicated” turns out to have a handful of paths, not an uncountable thicket. Six branches. Nine. A number small enough to draw. The complexity was in the not-knowing, not in the structure.

The hard part is smaller than the legend. Usually there is a genuinely tricky piece in there, some edge case or integration that earns real caution. But it’s localized. It’s one corner, not the whole room. Once you can see it, you can wall it off and change everything around it, instead of treating the entire subsystem as untouchable because one part of it is.

Sometimes you find a live bug. This is the one nobody expects. When you read code that hasn’t been read in years, you occasionally find something broken that’s been broken quietly the whole time, doing the wrong thing in a case rare enough that no one filed a ticket. The reading wasn’t even looking for it. It surfaced because someone finally looked.

Before you fund the rewrite

This matters most right before a big decision. A lot of rewrite pitches rest on a single load-bearing claim: the current system is too complex to extend, so we have to replace it. That claim is now testable for the price of an afternoon. Take it seriously, point the tool at the subsystem in question, and a surprising share of the time the complexity is smaller than the pitch needed it to be. You don’t rewrite what you can finally read. The rewrite trap deserves its own treatment and I’ll come back to it. The point here is narrower: the claim that justifies the rewrite is exactly the claim that just got cheap to check.

The question that changed

If you lead the team, this should change a reflex.

The old reflex, when someone said a part of the system was too complicated to change, was to treat it as a fixed cost and route around it. Either you funded a rewrite to escape it, or you lived with it and stopped asking. Both responses accepted the sentence at face value.

The new reflex is a question. Has anyone actually read this recently? Not the person who wrote it, who’s gone. Not the team’s collective memory, which never had it. Has anyone sat down with the code in the last week and traced what it does? If the answer is no, then “too complicated to change” isn’t a finding. It’s an assumption nobody has tested, and testing it is no longer expensive enough to skip.

Too complicated to change isn’t a fact about the system. It’s a fact about who has looked, and how long ago. The people who understood it are gone. The reading that would replace them used to cost a sprint. Now it costs an afternoon. The only question left is whether anyone spends it.