Logo
Logo
  • Home
  • About
  • Services
    • Fractional CTO
    • Application Architecture
    • Platform Audits
    • Platform Rebuilds
  • Projects
  • Writing
  • Work
  • Request Quote
Logo

Backed by 20+ years of hands-on software development expertise, mithra62 transforms ideas into powerful, reliable solutions—designed to work exactly how you want, every time.

  • Address

    Tucson, AZ 85712
  • Email

    eric@mithra62.com
  • Contact

    +1-310-739-3322

The Architecture Debt Nobody Tracks

  • Home
  • Writing
The Architecture Debt Nobody Tracks
09 Sep 26
  • Brain Dump
  • Programming
  • Rant

Every competent team has a running list of tech debt somewhere, a backlog of refactors everyone agrees are important right up until planning, and a shared understanding that someday, when things calm down, they'll finally pay it off. As is tradition though, things never calm down. But that list, sad and neglected as it is, is at least tracking real work; someone at least wrote the items down. There's a second kind of debt, larger and quieter, that never makes any list because it doesn't live in the codebase at all. It lives in the gaps between the code, in the heads of three specific people, and in a Slack thread from 2021 that scrolled off the top eighteen months ago. Nobody tracks it because nobody knows how to write a ticket for it.

Let me walk you through where it hides.

The schema was right, once

The data model made sense when there were three entity types. You had users, you had accounts, you had orders, and the relationships between them fit on a napkin, and the napkin was correct. You could hold the whole thing in your head. New engineers understood it in an afternoon.

Five years later every table has nullable columns that used to mean something, JSON blobs that started life as "we'll normalize this later," a metadata column that is now load-bearing for four features, and at least one foreign key relationship that exists only because deleting it would break a report nobody has looked at since the last reorg but everybody is afraid of. There is a boolean called is_legacy and a boolean called is_new_flow and no living person can tell you what happens when both are true.

The database isn't bad. The engineers weren't sloppy. What happened is that the business changed shape, quarter by quarter, and each change was a reasonable local edit to a model that used to match reality; and reality kept moving while the schema stayed mostly still. The mental model you onboarded with is no longer the mental model the tables encode, and the distance between those two models is a tax that every query, every migration, and every "wait, which flag do I set" conversation pays in full.

You didn't model the business wrong. You modeled it right, and then it became a different business, and the schema is a photograph of a company that no longer exists.

The flow nobody owns

Service A calls Service B, which needs something from Service C, which publishes an event onto the queue, which is consumed by Service D, which, for reasons that made sense during the great extraction of 2022, turns around and updates Service A. You know this because you spent a Tuesday tracing it, adding log lines through five repositories, and drawing the loop on a whiteboard that you then photographed because you knew you would forget.

Here is the thing about that loop: every individual hop is defensible. Somebody, at some point, had a good reason to have B fetch from C instead of A passing the data along. Somebody had a good reason to make it an event instead of a synchronous call, probably a very good reason involving a timeout that took down production one Black Friday. The decisions were locally rational. The sum of them is a distributed system where no single person can tell you, without a debugger and an afternoon, what happens when a request enters at A.

The service boundaries were supposed to make ownership clearer. Each team owns its service, each service has an interface, and the interfaces are the contract. That's the theory, and the theory is sound. In practice the interesting behavior lives in the choreography between services, and the choreography is owned by no one, because ownership was assigned per-service and the bug lives in the spaces in between.

The architecture is an org chart wearing a hoodie

There's a service in your system that exists because a team existed to own it. Not because the domain needed a boundary there. Not because the coupling analysis suggested a seam. It exists because in Q3 someone stood up a team, the team needed a mandate, the mandate needed a codebase, and so a service was born to give six people something to deploy.

Conway told us this would happen and we nodded and did it anyway. The system reflects the communication structure of the organization that built it, which means when the organization reorgs, the system is left holding the shape of a company that no longer sits together. The billing team merged into payments, but billing-service and payments-service are still two deployments with two on-call rotations and an HTTP call between them where a function call would do.

Six months after the reorg, every feature that touches both is a negotiation, the political kind, conducted through pull requests and calendar invites. You need a change on both sides of a boundary that only exists because of a whiteboard from a leadership offsite, and now shipping it requires two teams, two sprints, and a meeting where everyone agrees it's silly and nobody can fix it, because fixing it means merging the services, and merging the services means one of the teams admits it doesn't need to exist.

The debt stored in people

Only Dave really understands authentication. Not the login form; the actual flow, the token refresh edge case, the reason the session store is Redis and not the database, the specific way SSO breaks for the one enterprise customer whose IdP does something out of spec. Only Sarah understands billing, which means proration, which means the two weeks of the year when proration matters enormously and Sarah cannot take vacation. And everyone, universally, knows not to touch the reporting service, though almost nobody remembers why, only that the last person who touched it is no longer here and the timing felt related.

This is architectural debt. It just happens to be stored in people instead of code, which makes it invisible to every tool you own. Your static analysis won't flag it. PHPStan runs clean on a file that only one human alive can safely modify. The code looks fine. The code is fine. The problem is that the knowledge required to change the code without causing an incident exists in exactly one skull, and that skull has a two-week notice period.

You find out the balance on this debt the day Dave gives notice, and the interest rate is brutal, because you are now paying, at speed, for years of "Dave will handle it" that felt free every single time you said it.

Permission debt

Authorization started clean. You had a middleware that checked a role, and the role was on the user, and life was good. Then the requirements arrived, the way requirements do, one entirely reasonable exception at a time.

Now the authorization logic is in the controller, and also in a policy class, and also in middleware, and also in a boolean column on the users table, and also behind a feature flag, and also in a hardcoded check for one customer's account ID that somebody added at 11pm during an outage and never removed. To answer the question "can this user do this thing," you cannot read one file. You have to reconstruct the decision from six places that don't know about each other, and half of them can veto the other half in an order that depends on which one runs first.

Eventually you reach the state that every mature system reaches, where nobody can tell you why a given user has the access they have. They can only tell you that this user has it, that it's been that way for a while, and that changing it is out of the question because the last time someone tightened a permission "that couldn't possibly matter," it turned out to gate the nightly payroll run, and payroll did not go out, and that is a meeting no one wants to attend twice.

Configuration debt

Where does the application actually get its behavior? Some of it is in environment variables. Some is in feature flags, which live in a third-party dashboard nobody has admin on. Some is in the admin_settings table, edited through a UI that three people know exists. Some is in a config/services.php that reads the env vars but also has defaults that override them in a precedence order documented nowhere. Some is a JSON file. Some is a magic constant named MAX_RETRIES = 3 that has meant something different in every service it was copy-pasted into.

Every deployment becomes archaeology. Before you can change how the system behaves in production, you have to first discover where "how the system behaves" is even defined, and the answer is: yes. It's defined in all of those places, and they interact, and the effective configuration is the result of a precedence chain that no document describes and no test covers, so you find out what a setting does by changing it and watching what breaks.

Operational debt

There are systems in your infrastructure that can only be safely deployed by the person who knows. The command itself is one line; anyone can run it. What makes it dangerous is everything around the command, the unwritten steps, the order that matters, the thing you have to check first, and the specific way it fails that only looks scary if you haven't seen it fail that way before.

There is no runbook. There was going to be a runbook. The runbook was going to be written during the calm period. There is no rollback plan more sophisticated than "redeploy the old version and pray the migration was backward-compatible," and nobody has actually tested whether it was. There is no confidence, only a person, and the person is a single point of failure who also, inconveniently, would like to sleep through the night occasionally.

Confidence is infrastructure. You just can't put it in Terraform, so it doesn't show up in any inventory of what you own, which means you don't notice you're missing it until the one night the person who knows is unreachable and the thing that only they can deploy is the thing that needs deploying.

Decision debt

This one is my favorite, mostly because almost nobody names it.

The code is not hard because of the implementation. The implementation, when you finally read it, is often boring. The code is hard because nobody remembers why it was built that way, and so every engineer who touches it has to spend a day, sometimes a week, rediscovering the constraint that someone else already discovered and solved three years ago, at some cost, in some incident, under some pressure that has long since evaporated from institutional memory.

The retry logic looks paranoid until you learn about the payment provider that used to double-charge on timeouts. The seemingly pointless denormalized column exists because a report was killing the primary and this was the fix at 2am. The weird ordering constraint is load-bearing for a race condition that bit hard, once, badly. None of this is written down. The git blame leads to a commit message that says "fix bug," authored by someone who left in 2023.

So the knowledge dies, and the code keeps the scar without the story, and every future engineer treats the scar as either sacred or stupid, and both readings are wrong, and the cost of being wrong is a re-learned lesson, paid again, in an incident that already happened once and taught you nothing because nobody wrote it down.

The thing all of these have in common

Notice that almost none of this is about code quality. The functions are fine. The tests pass. PHPStan is happy at level 8. You could run every linter and every scanner and every code-quality tool ever written across the entire monorepo and it would report a clean bill of health, and it would be lying, because the debt was never in the code.

The debt is cognitive load. It's the standing cost of the gap between how the system works and how anyone understands it to work.

Every "wait, why does it work like that?" has a price, and you pay it in engineer-hours, and you pay it over and over because the answer isn't written anywhere. Every architecture diagram that has to be explained out loud because the diagram alone doesn't capture the three exceptions that actually matter. Every "don't touch that." Every one-off exception that made sense in isolation. Every hidden dependency that only reveals itself when you break it. Every concept whose sole surviving documentation is a Slack thread that Slack will helpfully delete on the ninety-day retention policy your company set to save money.

This is the debt nobody tracks, because there is no tool that measures it and no metric that surfaces it and no ticket that captures it. It doesn't slow down the machines at all. Your response times are great. Your servers are bored.

Technical debt makes code harder to change. Architectural debt makes systems harder to understand. And people are the more expensive resource, they don't scale horizontally, and you cannot spin up a new one when the old one is at capacity; you can only wait for them to spend another Tuesday rediscovering the loop, redrawing the whiteboard, and photographing it, so they'll have it next time, until they leave, and it scrolls off the top, and someone new arrives to draw it again.

If your codebase looks healthy but every change still requires archaeology, the problem might not be the code. I help teams find the architectural debt hiding around it.

Get Started

Recent Post

  • The Architecture Debt Nobody Tracks
    The Architecture Debt Nobody Tracks
    09 Sep, 2026
  • The Industry's Obsession with Proxies
    The Industry’s Obsession with Proxies
    02 Sep, 2026
  • Programming Is The Easy Part
    Programming Is The Easy Part
    26 Aug, 2026

follow us

Logo

Backed by 20+ years of hands-on software development expertise, mithra62 (Eric Lamb) transforms ideas into powerful, reliable solutions designed to work exactly how you want, every time.

© Copyright 2026 | mithra62

Useful Links

  • About
  • Projects
  • Writing
  • Work
  • Request Quote

Services

  • Fractional CTO
  • Application Architecture
  • Platform Audits
  • Platform Rebuilds

Contact Info

Get in touch now to begin work immediately.

  • Email: eric@mithra62.com
  • Contact: 310.739.3322