Last updated: July 13, 2026
By Kris Drouet, Engineering Executive, in partnership with KORE1
Engineering organizations grow afraid to refactor legacy code when years of small, reasonable changes pile up into load-bearing spaghetti, where every piece is quietly holding up another and nobody can predict what a fix will break. The fear is rational, not weak. It is an information problem. Here is how a codebase gets that way, how to spot it early, and the tactical path back to touching your own code without holding your breath.
I get called into engineering organizations after the velocity has already stalled, usually by a leader who cannot explain why a team full of good people slowed to a crawl. Last year one of them described the symptom perfectly without meaning to. “Every time we touch something, something else breaks.”
I have a name for that condition. Load-bearing spaghetti. Nobody planned it this way. It just grew until everything was holding everything else up, and now nobody wants to touch it. The tangle is doing real work. That is precisely why the team is afraid of it.
Here is the part most leaders get wrong. They treat the fear as a courage problem. Push the team. Tell them to be bolder. That approach never works, because the fear is not irrational. When you cannot see what a change will break, refusing to change things is the correct call. The way out is not bravery. It is operational discipline, the unglamorous practice of making change safe, visible, and owned, so that touching the code stops being a gamble.

How a Codebase Becomes Load-Bearing
Load-bearing spaghetti is code that became structurally essential by accident. No single engineer designed the dependencies. They accumulated one deadline at a time, until a change in one corner produces failures in three others, and the team can no longer reason about the blast radius of a simple edit. That is the disease.
Almost every engineering org has a module like this. In Stack Overflow’s 2024 developer survey, technical debt was the single most common frustration engineers reported, ahead of every other complaint by a wide margin. If your engineers are scared of a module, they are not fragile. They are normal. Almost everyone is.
Nobody sits down and designs a system this brittle. It accretes. A deadline forces a shortcut, the shortcut ships, it works, so nobody goes back. An engineer who understood the billing module leaves and takes the why with her, and all that survives is a comment that says do not change this without explaining what happens if you do. A bug gets patched with a flag instead of a fix, because the fix felt risky, and now there is a flag that three other things quietly depend on. Repeat that a few hundred times across a few years and you have a system where the knowledge of how it holds together left the building one resignation at a time.
Michael Feathers, who wrote the book most working engineers reach for on this exact problem, defines legacy code simply as code without tests. I would push it one step further. Legacy code is code you are afraid to change, and the fear is a precise instrument. It measures how much you cannot see. A module with strong tests and clear ownership does not scare anyone, no matter how old it is. A clever service written last month with no tests and one author who is now on parental leave is already legacy. Age is not the variable. Visibility is.
The Tells: How to Know Your Team Is Already Afraid
The fear rarely announces itself. It hides. It shows up as a set of small, sensible-looking habits that a busy leader reads as caution. Here is what to actually watch for.
| The tell | What it actually means |
|---|---|
| A one-line change gets a two-week estimate | The team is pricing in fear, not effort. The extra time covers everything they cannot see. |
| “We do not touch that service” shows up in planning | A no-go zone has formed. The most important code is now the code nobody will enter. |
| Bugs get fixed with flags and wrappers, never at the core | The core is treated as radioactive. Every workaround makes the next one necessary. |
| One engineer reviews everything in one area and never truly unplugs | The knowledge lives in a single head, and that head is now a single point of failure. |
| “We should just rewrite it” becomes the reflex answer | The team has quietly concluded the code cannot be changed safely, only replaced. |
Read that list as a leader, not an engineer, because every item sounds reasonable in the moment. Of course that service is risky. Of course we should rewrite it eventually. Of course Priya reviews the payments code. She knows it best. Each decision is locally sane, and together they are the quiet, cumulative sound of an entire engineering organization backing away from its own product, one reasonable-looking choice at a time, until half the roadmap routes around the parts that matter most. I watched a team at a healthcare software company quote six weeks to add one field to a patient record. The field was trivial. The six weeks was the fear tax on a module nobody had tested since 2021. Nobody dared.

Why the Big Rewrite Is the Wrong Escape Hatch
When a team is afraid of its own code, one idea always surfaces, and it is always the same idea. Throw it out. Start clean. Rewrite it properly this time. It is the most natural instinct in engineering, and it is usually a trap.
Joel Spolsky made the definitive version of this argument more than twenty-five years ago and it has aged into a law. His point was simple. That ugly old code you want to burn down is ugly because it works. Every strange conditional is a bug someone hit in production and fixed. Every awkward branch is an edge case a real customer walked into. Rewrite from scratch and you throw all of that hard-won knowledge in the bin, then spend two years rediscovering the same bugs in a new accent. The spaghetti is load-bearing. That is not only the problem. It is also the reason a clean-room rewrite so often ships slower and buggier than the thing it replaced. Slower and buggier. Read that twice.
The economics do not favor the rewrite either. When McKinsey asked CIOs to size the problem, they estimated that tech debt equals 20 to 40 percent of the value of their entire technology estate. That is not a bill you pay down by opening a blank file. A full rewrite freezes feature work for a year or more while the debt sits there accruing interest on a product your customers are still using. You are not escaping the debt. You are taking out a bigger loan to avoid reading the statement. That is denial.
Sometimes the rewrite is genuinely the right call. The platform sits on a framework that hit end of life. The original assumptions no longer match the business at all. Those are real reasons, and they earn a real rewrite, run with a migration plan while the old system keeps serving traffic, one capability moved at a time until the lights finally go out on the old box. That is a strategic replacement. Not a panic exit dressed up as vision. But scared is not a reason. If fear is the thing pushing you toward a blank file, you do not have a rewrite problem. You have a visibility problem. And a much cheaper fix.
The Tactical Path Back to Touching Your Code
You beat legacy-code fear the same way you beat any fear that is really information starvation. You add information. None of what follows is clever. All of it works, and the order matters more than the tools.
Start by making change observable. Before you refactor a line, wrap the scary module in characterization tests, tests that pin down what the code does right now, including the parts that are wrong. You are not testing for correct. You are testing for current. The instant a refactor changes behavior you did not mean to change, a test goes red and tells you. That one move converts a blind edit into a visible one, and it is where I start every single time.
Then turn on the lights. Logging, tracing, and metrics around the module so you can see what is actually happening under the hood before a change reaches production. Refactoring without observability is surgery in the dark. Plenty of teams try it anyway. It goes badly. You can hear the results in the incident channel.
Change at the seams, not the center. The strangler-fig pattern is boring and it is undefeated. You build the new behavior alongside the old, route a thin slice of traffic through it, watch, and widen the slice only when the data says it is safe, which means a bad step costs you a rollback and an afternoon, not an outage and a postmortem. No heroic cutover. No weekend where the whole company holds its breath. A slow, reversible migration where every step is small enough to undo.
Where the coupling itself is the load-bearing part, cut the joint. This is the deepest fix and the most expensive one, and it has the clearest payoff. A mortgage-tech platform I worked on was strangling on point-to-point integrations, so we pulled them apart with an event backbone. Downstream latency dropped 45 percent, but the number that mattered more never showed up on a dashboard. The next change got cheaper instead of scarier. That is the real prize. I wrote the whole migration up, including the parts that hurt, in our Kafka pub/sub case study. Decoupling is how you make the tangle stop being load-bearing in the first place.
Last, keep it from growing back. Every fix above decays without the operating habits that hold the line, which is the whole reason discipline is the cure and not the tests by themselves. Tests rot if nobody runs them. Ownership blurs if nobody names it. The team that clawed its way out of the fear once will spaghetti itself again in eighteen months if the discipline does not become routine. Making code safe to touch is a project. Keeping it safe to touch is a practice.

When the Fix Is a Hire, Not a Refactor
Here is where I owe you my angle. KORE1 pays me to write for them, and KORE1 makes money when you cannot staff this work yourself. So weigh the next paragraph accordingly. I would still rather say it, because it is true more often than engineering leaders want to admit. Bias on the table.
Some teams cannot refactor their way out of the fear because nobody currently on the roster has ever done it. Characterization tests, strangler migrations, and untangling a coupled system are a specific craft, and it is not the same craft as shipping features fast. The engineer who is brilliant at greenfield work is often the same engineer who has never had to make a scary twelve-year-old module safe without a rewrite. That skill gets learned in the trenches, and it is rare, and you usually need only one or two people who have it to change a whole team’s relationship with the code. KORE1 has placed engineers across more than 30 U.S. metros for two decades, their recruiters average over fifteen years in the business, and 92 percent of the people they place are still in the seat a year later. On legacy-surgery work, retention is the number I care about, because the person who finally makes your payments module safe to touch is the last person you want walking out at month nine. KORE1’s software engineer staffing team runs these searches constantly, often on a direct hire basis when the role is core enough to own for years.
What Engineering Leaders Ask Me About Brittle Code
How do I know if we are afraid of our code or just being careful?
Careful stops at the edge of what you can see. Fear stops well short of it. If your estimates balloon for changes your team technically understands, that gap between the real work and the quoted work is fear, and it is measurable.
Run the test on a single ticket. Ask the engineer what the change actually requires, then ask what they padded the estimate for. If the padding is “we are not sure what else touches this,” you have found fear, not diligence. Diligence knows what it is protecting against. Fear is protecting against the unknown, and the unknown is exactly the thing tests and observability turn into a known. That is the whole game.
Should we ever just rewrite it?
Almost never for the reason you want to. Rewrite when the platform is genuinely obsolete and you have a real migration plan. Never because the code is scary. Fear is a visibility problem, and a rewrite adds zero visibility on day one.
The rewrite that works is unglamorous and incremental. You stand up the new thing beside the old thing, move one capability at a time, and keep shipping the whole way. The rewrite that fails is the big-bang, the eighteen-month rebuild that goes dark, ignores the edge cases the old code already solved, and arrives late to discover the business moved. If you cannot name a specific technical reason the current platform cannot evolve, you are not ready to rewrite it yet.
The scary module has zero tests. Where does the first test go?
Around the highest-traffic path, pinning current behavior, wrong parts included. You are not fixing it yet. You are installing a smoke alarm before you go near the wiring, so the next change cannot break something silently.
Pick the single busiest path through the module and write a test that asserts what it does today, not what it should do, ugly assertions and all, because a rough net that actually exists beats a beautiful one that does not. Once you have a few of those, the module stops being a cliff edge. Teams get paralyzed trying to test everything at once. You do not need everything. Start there.
How do I sell a refactor to executives who only see feature delay?
Executives do not buy refactors. They buy risk going down. Stop pitching cleaner code and start pitching fewer 2 a.m. pages, fewer deadlines blown by nasty surprises, and faster delivery on the next ten features that all touch this one module.
Put a number on it they already feel. “Every change to this service currently costs us two weeks and a coin flip. After this work, it costs two days and a green test run.” That is a sentence a CFO can act on. Nobody funds tidiness. Everybody funds predictability, and a codebase your team is not afraid of is the single most predictable, most compounding asset an engineering organization can own, which is exactly why this pitch lands in a budget meeting when “let us clean up the code” never does. Sell the predictability.
Is this a tooling problem or a hiring problem?
Both, and the order matters. Buy the visibility first with tests and observability, because tools are cheaper than people. If the team still cannot perform the surgery after that, it is a hiring problem, and one experienced hand changes the math fast.
Tooling gets you the map. It does not give you the surgeon. Untangling a coupled system under production load is a judgment skill, and judgment does not come from a linter. If you have added the visibility and the team is still circling the module without landing, the gap is experience, and the fix is bringing in someone who has done this before rather than asking your feature team to learn legacy surgery on your most important code. Buy the map first. Then the surgeon.
Before You Green-Light Another Rewrite
Do one thing this week. Pick the module your team flinches at, the one that shows up in every risky estimate, and put a single characterization test around it. Not a refactor. Just one test that proves you can watch it move. That is the first inch of ground you take back, and the fear starts shrinking the moment the code stops being invisible.
If you are staring at a codebase nobody wants to touch and you cannot tell whether the fix is a refactor or a hire, connect with me on LinkedIn and tell me which module scares you. I read those. And if the honest answer is that nobody on the team has done this kind of surgery before, talk to KORE1’s engineering hiring team before you sign off on burning the whole thing down. The right hire is cheaper than the rewrite you are about to regret.
Related reading: Operational Discipline Is Not Bureaucracy, Kafka Pub/Sub Case Study: How Decoupling Cut Our Downstream Latency 45%, and The Clarity Stack: 3 Reasons Engineering Velocity Stalls.
