Code Review Misses Architectural Decay
Code review catches line-level bugs but misses architectural decay entirely. Learn why your repo rots one approved pull request at a time and how to catch it.
Your codebase can pass every code review and still rot. Code review is a local process: a reviewer looks at a diff, checks that this change is reasonable, and approves. Architectural decay is a global phenomenon that happens across hundreds of individually reasonable changes, none of which is wrong on its own. Each pull request adds one more dependency, one more shortcut, one more thing coupled to one more thing, and each one is fine in isolation. The reviewer sees a small, sensible diff and approves it, correctly. Nobody sees the aggregate, because no diff contains the aggregate. That is how a repo full of well-reviewed code becomes an unmaintainable tangle, one green checkmark at a time.
Why review is blind to the aggregate
A reviewer looks at what changed, not at what the change did to the whole. When someone adds an import that couples the billing module to the notification module, the diff shows one new import line. It looks harmless. The reviewer has no view of the fact that this is the fortieth cross-module dependency added this quarter, that coupling across the system has been climbing steadily, that the architecture is quietly collapsing into a ball where everything touches everything. The information needed to catch decay is not in any single diff. It is in the trend across all of them, and code review, by design, never looks at the trend. This is the same limitation I described for per-file tools in static analysis vs repo intelligence: judging changes in isolation cannot catch a problem that only exists in aggregate.
Reviewers also optimize for shipping. The pressure is to unblock the author, and blocking a reasonable-looking change on a vague "this feels like it is making the architecture worse" is a hard, unpopular argument to make without data. So the change ships, because individually it should. Decay is the sum of a thousand individually correct decisions.
What decay looks like when you measure it
The signals of architectural decay are all system-level and all trend-level, which is exactly why you have to measure them over time rather than review them per change.
Rising coupling. Modules getting more entangled, more cross-dependencies, more cycles appearing. A single new dependency is invisible. The slope of dependencies over months is not, and it is the clearest decay signal there is, the coupling metrics that predict real pain tracked as a line instead of a snapshot.
Spreading hotspots. More files entering the high-churn, high-complexity quadrant over time means complexity is accumulating in exactly the places you change most, which compounds.
Climbing dependency drift. The tree falling further behind current versions, which I covered in how to measure dependency drift. No single skipped update matters. The trend is a forced migration waiting to happen.
Concentrating ownership. Critical modules sliding toward a single owner as the team routes hard work to whoever is fastest, the bus-factor risk that re-forms if you do not watch it.
None of these show up in a diff. All of them show up in a trend line, and a tool like ReformCode tracks them over time precisely so the aggregate becomes visible, so you can see coupling climbing three months before it becomes the release that breaks everything.
Add a system-level check to your process
Code review stays. It catches the local bugs it is good at catching, and nothing here replaces it. What you add is a second loop that operates at the level review cannot reach.
Run repo intelligence on a schedule and read the trends, not just the snapshot. Is coupling rising or falling this quarter? Are hotspots spreading or shrinking? Is drift climbing? Those questions have answers, and the answers tell you whether your architecture is getting healthier or sicker regardless of how clean each individual pull request looked. This is a strategic review, the kind I do before planning debt work or a refactor, as in repo intelligence before you refactor.
You can even feed some of it back into review. When a change would push coupling past a threshold or add a dependency to an already-overloaded hub, that is the moment a reviewer can make the architectural argument with data instead of a feeling: not "this feels wrong" but "this adds the eleventh dependency to a module that is already our top coupling risk." Data turns an unpopular vague objection into a defensible specific one.
The uncomfortable conclusion
A team can do everything right at the diff level and still ship itself into an unmaintainable codebase, because the thing killing the codebase is not visible at the diff level. Architectural health is a property of the whole system measured over time, and no amount of careful per-change review sees it, any more than inspecting individual bricks tells you the wall is leaning. If your only quality process is code review, you are watching the bricks and missing the wall.
The fix is not more review or stricter reviewers. It is a different altitude of looking: measure the system's trends, watch coupling and drift and hotspots and ownership as lines that move over months, and act when the slope turns bad. Catch the decay while it is a trend and it is cheap to correct. Catch it when it is a crisis and you are back to talking about a rewrite. Code review was never going to save you from this. Only looking at the whole repo, over time, will.