All Articles
Technical DebtArchitecturePost-Mortem

The "Temporary" Workaround That Ran in Production for 4 Years

Nothing is as permanent as a temporary fix that quietly works. Here's how a four-year-old workaround nearly derailed a €12M platform modernisation.

MGMohamed Ghassen BrahimFebruary 17, 20269 min read

Nothing is as permanent as a temporary fix that quietly works. The ones that break announce themselves. The ones that survive become infrastructure.

I discovered this particular workaround during a technical due diligence engagement at a mid-size energy company. We were three weeks into a platform modernisation programme — scoping the migration of a core trading and settlement system onto a modern event-driven architecture. The CTO had budgeted 18 months and €12M. The board had signed off. The architecture decision records were written.

Then a senior engineer mentioned, almost in passing, that the nightly reconciliation process had "a bit of a workaround" they'd added to deal with a timestamp issue.

The workaround was four years old. It was undocumented. And it was load-bearing in ways nobody had mapped.

4 years
Workaround age in production
Added during a 'temporary' sprint
€12M
Programme budget at risk
Until the dependency was fully mapped
3 systems
Downstream dependencies
None of them knew the workaround existed
6 weeks
Delay added to programme
For proper remediation design

What the Workaround Actually Did

The original problem was simple: two upstream systems sent settlement data with timestamps in different formats — one in UTC, one in local Berlin time with no explicit offset marker. During a peak processing period four years earlier, a reconciliation mismatch caused a two-day reporting error. The fix needed to ship that week.

A developer added a transformation function that detected the upstream source by a field prefix, applied the appropriate offset, and normalised both streams before they hit the core reconciliation logic. It took a day to write and was supposed to be replaced within the quarter when the upstream systems were "aligned on a common format."

The upstream systems were never aligned. The developer moved to a different team, then left the company. The transformation function was buried in a utilities module with no documentation. The quarterly plan to remove it was deprioritised once, then twice, then forgotten entirely.

By the time I found it, the function had quietly accumulated three additional responsibilities:

  1. It was also filtering out a class of micro-transactions that an upstream feed had started generating in year two — someone had added a filter because the reconciliation kept flagging them, and the filter had lived in the transformation ever since.
  2. A downstream reporting system had been built that implicitly relied on the normalised output format this function produced. That system's developers did not know the normalisation existed — they thought they were receiving raw upstream data.
  3. A regulatory reporting process added in year three used the filtered-and-normalised stream as its canonical data source. The compliance team believed this was a direct feed from the settlement system.

Remove the workaround without understanding all three of these downstream realities, and you break regulatory reporting. In an energy trading context, that is not a product bug — it is a potential regulatory breach.

By the time the audit ran, the actual data flow through the workaround looked like this:

Why Temporary Fixes Become Permanent

I have seen this pattern in every industry I have worked in — reinsurance, energy, insurance, SaaS, manufacturing. The mechanism is always recognisable.

🔍

The four stages of workaround permanence

Stage 1: The fix works, the incident closes, the quarter moves on. Stage 2: The fix survives a deployment cycle, a codebase refactor, and onboarding of two new engineers who were never told about it. Stage 3: A new system is built that happens to rely on the fix's output. Stage 4: The original problem it was solving is no longer legible — only the fix remains.

The structural reasons are consistent across organisations:

Incident pressure kills documentation discipline. When you are fixing something under pressure, the documentation comes after. After never comes. The fix is live, the incident is closed, the team moves to the next sprint, and the "document this properly" task sits in the backlog until it is eventually groomed out.

Working code is invisible. A system component that fails announces itself. One that works provides no signal. The workaround that correctly normalises timestamps generates no alerts, no errors, no user complaints. It is functionally indistinguishable from properly designed code — until you try to replace it.

Technical debt has no compounding interest rate anyone can see. You can observe that a workaround exists. You cannot easily observe that three other systems have now been built that depend on it. The dependency accrual is invisible until someone tries to move something.

Prioritisation logic works against remediation. In any given sprint planning, "remove the temporary workaround from year one" competes against "ship the feature the product team needs by Thursday." The workaround is low-urgency (it works), low-visibility (nobody sees it), and high-effort-to-remove (because removal requires understanding all its dependencies). It loses every time.

The Dependency Audit

When we found the workaround, we paused the modernisation architecture work for two weeks to conduct a dependency audit. This is the right call every time, and it is always resisted on timeline grounds.

The audit involved three activities running in parallel:

Static analysis. We used code search to find every call site of the transformation function. There were eleven. Seven were in the reconciliation pipeline itself. Four were in other systems — including the regulatory reporting process, which had been refactored to call the function directly rather than via the API boundary that was supposed to isolate it.

Runtime tracing. We instrumented the function and ran it through a week of production traffic. The trace revealed that the micro-transaction filter had been quietly dropping between 0.3% and 1.1% of daily transaction volume — which downstream systems had been treating as complete data. Nobody had noticed because the dropped transactions were below the materiality threshold for manual reconciliation.

Consumer interviews. We talked to the teams who owned the downstream systems. None of them knew the transformation existed. Two of them had made architectural decisions based on assumptions about data format and completeness that were only true because of the workaround.

Downstream SystemKnew Workaround Existed?Architecture Assumption at Risk
Settlement reconciliationYes (original owner)None — this was the intended consumer
Management reportingNoAssumed raw UTC timestamps, was receiving normalised data
Regulatory reportingNoAssumed complete transaction set; 0.3–1.1% was silently filtered
Data warehouse ETLNoHad hardcoded format expectations matching normalised output

That table was the deliverable that changed the programme. Not a code review, not an architecture diagram — a four-column table showing four teams making decisions on false premises.

What Remediation Actually Looked Like

There is a version of this story where the answer is "we removed the workaround and fixed the upstream systems." That version takes about six months and requires cooperation from teams that have their own roadmaps and priorities.

The version we actually executed was more pragmatic.

Step one: We made the workaround visible. The transformation function was extracted from the utilities module, given a proper name (SettlementStreamNormalizer), documented with full context — the original problem, the current responsibilities, the known downstream dependencies, the known gaps — and registered in the architecture decision record.

Step two: We added explicit telemetry. The micro-transaction filter now emitted a metric with every filtered event. Operations could see, in real time, what was being dropped and why. The regulatory reporting team could now verify their feed's completeness independently.

Step three: We redesigned the modernisation migration to treat the normaliser as a first-class component rather than something to be silently replaced. The new event-driven architecture had an explicit SettlementEventEnricher service that performed the same normalisation with proper documentation, a defined API contract, and tests that encoded the current behaviour as a baseline.

Step four: The upstream timestamp alignment work — the original "temporary" fix for which the workaround was written — was formally scoped as a programme work stream rather than a backlog item. It shipped in month nine of the programme.

The six-week delay this added to the programme timeline was, in retrospect, the cheapest outcome available. The alternative — shipping a new architecture that silently broke regulatory reporting because we didn't understand the workaround — would have cost considerably more.

⚠️

The modernisation that surfaces these dependencies is not the problem

I have seen programmes cancelled or de-scoped because a dependency audit revealed that the legacy system was more complex than anyone thought. That is exactly backwards. The modernisation did not create the complexity — it revealed it. The complexity was there already, accruing risk in production. The audit is the good news: you found it before it found you.

How to Find Your Workarounds Before They Find You

Every organisation above three or four years old has these. The question is not whether they exist — it is whether you know where they are before you need to change something that touches them.

The signals that indicate an audit is overdue:

  • Engineers use the phrase "there's a bit of a thing" when describing any part of the codebase. That phrase is almost always concealing something load-bearing that nobody has documented.
  • Your architecture diagrams were last updated during an onboarding presentation 18 months ago. Diagrams that aren't updated aren't accurate — they're historical fiction.
  • New team members discover significant system behaviours by reading code rather than documentation. The knowledge lives in the codebase, not in any artefact a non-engineer can access.
  • You have a "utilities" module, a "helpers" module, or any module whose name describes what it is rather than what it does. These are where workarounds go to retire.
  • A senior engineer who has been at the company for more than three years has not written a detailed "things I know that aren't written down anywhere" document. That knowledge is a single departure away from being lost.

The audit itself does not need to be a massive programme. The most effective approach I use is a two-week targeted review: find all components that have been in production for more than 18 months without significant modification, instrument them, trace their consumers, and interview the teams that own those consumers. The result is almost always a map of hidden dependencies you can act on.

The Business Framing

Technical leads will find the forensic detail of this interesting. The conversation with boards and CFOs is different.

Every undocumented workaround that has been running for more than 12 months is a contingent liability. You cannot value it on the balance sheet, but you can estimate its cost if it goes wrong. In the energy company's case: a regulatory reporting breach in the German energy market carries a potential fine of up to 10% of annual revenue, plus mandatory disclosure, plus the cost of remediation under pressure.

The cost of the six-week audit and design delay: approximately €400k in programme time. The cost of discovering the regulatory dependency after shipping a broken migration: potentially eight figures.

That is the framing that gets technical debt taken seriously in boardrooms. Not "we have technical debt" — every company has technical debt. But "we have a specific class of undocumented system dependency that represents a quantifiable regulatory and operational risk, and here is what it would cost to surface and document it."


If your organisation is heading into a modernisation programme, a platform migration, or a due diligence process and you want to find these dependencies before they surface on their own, let's talk. A 30-minute discovery call is enough to determine whether a structured technical audit would change the risk profile of your programme.

Ready to act

Ready to put this into practice?

I help companies implement the strategies discussed here. Book a free 30-minute discovery call.

Schedule a Free Call