Software Design X-Rays
Adam Tornhill ยท epub ยท 2018-03 source โ Reader ๐ฅ๏ธ
AI-Friendly Code (Code Health for Agents)Behavioral Code AnalysisCoordination CostMental Models & UnderstandingModularity & CouplingSociotechnical ArchitectureTechnical Debt
The real cost and risk in a large codebase is invisible in the code's current structure and can only be recovered by mining version-control history as a behavioral record of how people actually work on it โ and once recovered (as hotspots, change coupling, code age, developer fragmentation, and knowledge maps), that record should drive both technical refactoring priorities and the alignment of team structure with system structure (Conway's Law), because most expensive software problems are organizational problems wearing a technical disguise.
practical ยท mixed โ A practical, technique-driven book (how to mine version control and act on the results) built on a theoretical spine borrowed from cognitive and social psychology (schemas, the forgetting curve, diffusion of responsibility, process loss), and carried throughout by real open-source and commercial case studies (ASP.NET Core MVC, Linux, Android, Scala, nopCommerce, Spinnaker) that function as evidence, not decoration.
Structure
| Part | Role |
|---|---|
| Preface: The World of Behavioral Code Analysis | context |
| Part I, Ch.1 โ Why Technical Debt Isn't Technical | premise-setting |
| Part I, Ch.2 โ Identify Code with High Interest Rates (Hotspots) | method |
| Part I, Ch.3 โ Coupling in Time (Change Coupling) | method |
| Part I, Ch.4 โ Pay Off Your Technical Debt (Patterns) | method/evidence |
| Part I, Ch.5 โ The Principles of Code Age | method/evidence |
| Part II, Ch.6 โ Spot Your System's Tipping Point | method (scaling up) |
| Part II, Ch.7 โ Beyond Conway's Law | core argument |
| Part II, Ch.8 โ Toward Modular Monoliths through the Social View of Code | method/evidence |
| Part II, Ch.9 โ Systems of Systems (Multiple Repos/Microservices) | method/evidence |
| Part II, Ch.10 โ An Extra Team Member (Predictive and Proactive Analyses) | conclusion / synthesis |
| Appendices (Code Maat, data mining with Git/cloc/CodeScene, exercise solutions) | tooling reference |
Key terms
- Interest rate (on technical debt)
A property of code that can only be defined with a time dimension: how often you actually have to read/modify a piece of code. Bad code you never touch isn't debt because you never pay interest on it. - Hotspot
Complicated code (approximated, language-neutrally, by lines of code) that also changes at a high frequency โ the operational definition of 'technical debt that matters.' - Code age / the three generations of code
Code should be classed as recent (actively worked, fresh mental model), old (stable, safe to treat as a black box), or mid-aged (the expensive middle, where memory has decayed below the Ebbinghaus curve but the code must still be revisited) โ a reframing of Dan North's 'short software half-life.' - Fractal value (developer diffusion / fragmentation)
A normalized 0.0-1.0 measure of how diffused a module's authorship is across contributors (0 = single author, closer to 1 = many roughly-equal minor contributors), used as a proxy for coordination need and defect risk. - Diffusion of responsibility (applied to code)
The social-psychology finding (borrowed, with the bystander-effect as its classic illustration) that individual accountability for a shared resource erodes as the number of people sharing it grows โ applied here to explain why hotspots with many minor contributors stay bad for years despite being easy to fix. - Splinter pattern
An iterative refactoring that extracts a hotspot's responsibilities into new, imperfect-but-separable modules behind a facade that preserves the original API โ explicitly not a quality improvement in itself, but a structural precondition that lets multiple people work on a hotspot in parallel without freezing feature work. - Knowledge map / knowledge-loss simulation
A visualization of each file's main historical contributor (from authorship share), and a what-if analysis that removes a (soon-to-leave) contributor's commits to show which modules would lose their de facto expert โ turning offboarding risk into something measurable before the fact. - Technical sprawl / conservation of familiarity
The erosion of an organization's working knowledge of its own system (Lehman's law of 'conservation of familiarity') caused by unrestrained per-service technology choice in microservices โ measured via a fractal-value-style index over programming languages per service.
Propositions
- explicitdevelopedTechnical debt is not identical with bad or ugly code; code only becomes debt once you have to pay interest on it by repeatedly reading or modifying it, so interest rate is a function of time and requires a time dimension on the code to be measured at all.conf: highextendsTechnical Debt Quadrant ยท p2 โ Tornhill supplies a measurable, time-based operational test for 'is this actually debt' (change frequency x complexity, mined from version control), complementing Fowler's qualitative reckless/prudent taxonomy of what counts as debt.extends โCode Red: The Business Impact of Code Quality -- A Quantitative Study of 39 Proprietary Production Codebases ยท p7 โ Both papers share the TD-interest framing (debt is the recurring interest payment, not the remediation cost); this paper supplies the quantified interest rate (124% / 9x) that the book's hotspot/interest-rate metaphor leaves qualitative.
- explicitThe structure of the development organization is a stronger predictor of software defects than any code-level metric, including complexity and test coverage.conf: high
- explicitParallel development increases defect risk even within a strong peer-review culture โ shown empirically on the Linux kernel, where modules with the most parallel work had more security bugs despite open-source review norms.conf: high
- explicitProgrammers understand code through mental schemas built over time; heavy parallel/congested development invalidates those schemas faster than any individual can rebuild them, and this โ not code quality per se โ is the actual mechanism behind 'this code is hard to understand' complaints that get misdiagnosed as a purely technical problem.conf: highsupports11) AI-spesial med Vilde Opsal og Anders Sveen ยท p4 โ Supplies the cognitive mechanism โ code legibility as externalized support for a reader's mental schema โ behind why clear information architecture should matter to both human and agent 'readers' of a codebase.
- explicitVersion control is a behavioral log of how developers have actually interacted with the code, not merely a backup system โ and it is the only available source for the time dimension and social data needed to prioritize technical debt and detect organizational risk.conf: high
- explicitA hotspot โ complicated code (lines of code as a simple, language-neutral complexity proxy) that also changes at high frequency โ is the correct unit for prioritizing technical debt, because low-quality code that is rarely touched is not actually costly.conf: highextendsThe Economic Benefit of Refactoring ยท p9 โ The hotspot/interest-rate metric โ a measured proxy for where real maintenance cost concentrates, mined from version-control history rather than inspected from code alone โ is the direct conceptual ancestor of using a measured proxy like agent token cost as an 'AI-friendliness' signal.
- explicitComplexity-trend analysis โ an indentation-based, language-neutral complexity metric tracked across a file's historic revisions โ distinguishes files that merely grew in size from files that grew in complexity, revealing whether a hotspot is getting structurally worse over time.conf: high
- explicitChange coupling (files or functions that change together over time) is invisible in the code itself and detectable only by mining version-control history; the most valuable findings are 'surprising' couplings with no visible static dependency, because those point to hidden dependencies or missing abstractions.conf: high
- explicit'There's no such thing as just test code': unit tests that change together for reasons unrelated to the application code they test reveal missing test-design abstractions (shared test data, custom assertions), and poorly designed test suites become a disproportionate source of hotspots and change coupling.conf: high
- explicitThe splinter pattern โ extracting a hotspot's responsibilities into new modules behind a facade that preserves the original API, delivered in short iterations rather than on a long-lived branch โ is how you refactor a hotspot that is simultaneously under heavy, unavoidable parallel feature development.conf: high
- explicitCode-quality problems are typically introduced at the moment a file or class is first created, not accumulated gradually afterward โ so the pull-request/initial-design moment, not later cleanup, is the real intervention point.conf: medium
- explicitCode should be either very recent (still within active working memory) or old and stable (safe to treat as a black box); code of intermediate age is the most expensive category because memory of it has decayed (the Ebbinghaus forgetting curve) while it still must be revisited โ a reframing of Dan North's claim that software should have a short half-life.conf: high
- explicitThe risk of a new defect in a module declines roughly a third per year of the module's age, because time both exposes it to more use cases and lets it get 'patched into correctness' โ meaning complaints about old, untouched code are often organizational folklore rather than evidence of a live problem.conf: high
- explicitHotspot and complexity-trend analysis scale from individual files up to whole architectural subsystems by aggregating the same underlying change-frequency/complexity data at the logical-component level โ the level at which nontechnical managers can act on the results.conf: high
- explicitComplexity trends function as an organizational whistleblower against the normalization of deviance (gradually accepting code that keeps getting a little worse), because they give an unbiased historical reference point that day-to-day familiarity erodes.conf: high
- explicitModular boundaries aligned with problem-domain concepts, rather than solution-domain/technical layers, give each team natural end-to-end ownership and let architecture scale with the organization; technically oriented architectures instead force either universal cross-team coordination or single-team ownership bottlenecks โ this is the operational content the book draws out of Conway's Law.conf: high
- explicitMeasured empirically across real layered codebases, roughly 30-70% of commits cut across multiple architectural layers, showing that a layered architecture typically separates the wrong concern, since the real unit of change is a user-facing feature, not a technical layer.conf: high
- explicitDeveloper fragmentation โ many minor contributors to one module, measured via a normalized fractal value โ correlates with higher defect rates independent of a module's technical quality; a module with one clear primary author plus open contribution carries lower risk than one with many roughly-equal minor contributors.conf: high
- explicitCode ownership is a structural countermeasure to diffusion of responsibility, not an exclusionary claim on code ('stay away'); it should pair narrow operational ownership (who writes most of a module) with deliberately broad knowledge boundaries (who understands it, widened through reviews, rotations, and walkthroughs).conf: high
- explicitChange-coupling analysis can suggest domain-driven-design bounded contexts directly from how the code actually evolves โ sometimes revealing a bounded context the documented or intended architecture fails to capture.conf: medium
- explicitMicroservice architectures reproduce the coordination problems of layered monoliths at a different granularity: implicit change coupling across repository boundaries ('microservices shotgun surgery'), monolithic UIs that re-centralize what the backend split up, and technical sprawl from divergent per-service languages/frameworks that erodes the 'conservation of familiarity' Lehman's laws require.conf: high
- explicitKnowledge maps (visualizing each file's main contributor from authorship data) and knowledge-loss simulations (virtually removing a departing contributor's commits) turn offboarding risk from guesswork into a measurable, actionable simulation available before the departure happens.conf: high
- explicitSocial/organizational behavioral analyses are far more bias-prone than technical ones (hotspots, complexity trends): misattributed merge authorship, history-losing repository splits, squash commits, and unrecorded pair/mob programming all corrupt the social signal โ when data quality is in doubt, the technical analyses should be trusted over the social ones.conf: high
- explicitThere is a direct economic argument for readable code distinct from aesthetics or professional pride: because developers spend most of their time understanding existing code before changing it, optimizing for readability is an organizational efficiency choice; relatedly, a hotspot's history should be read through the fundamental attribution error โ as evidence of past situational pressure on the developers who wrote it, not of their incompetence โ which argues for forward-looking triage over retrospective blame.conf: high
- implicitEvery social metric the book introduces (code ownership, fractal value, knowledge maps, knowledge-loss simulation) is built from version-control authorship as a proxy for who understands the code โ the method tacitly assumes that writing and understanding stay coupled in one human contributor who can 'leave' or need 'onboarding,' an assumption the book never states as an assumption because it had no other kind of contributor to consider in 2018.conf: medium
Arguments
Technical debt should be prioritized using version-control-derived hotspots, not static code-quality scores alone. strength: high
Explicit premises:
- Interest rate โ the real cost of debt โ is a function of how often code is touched, not of code quality measured in isolation.
- Lines of code, though crude, is a language-neutral complexity proxy that combined with change frequency predicts real maintenance cost about as well as more elaborate metrics.
Implicit premises:
- Past change frequency is a reasonably reliable predictor of near-future change frequency.
- The organization has the discipline to act on hotspot priorities rather than cherry-picking a flattering subset.
Inferences:
- A static-analysis tool with no time dimension (like the '4,000 years of technical debt' tool in Ch.1) cannot, by construction, tell an organization where to start paying debt down.
Above a certain organizational size, architecture should be organized around problem-domain features/components rather than technical layers. strength: high
Explicit premises:
- Coordination costs increase with the number of people involved and the organizational distance between them (cited empirical research on coordination breakdowns and defects).
- A technically layered architecture requires every feature change to touch multiple layers, so no single team can hold sole end-to-end ownership of any one feature.
Implicit premises:
- Team structure and system architecture can be deliberately co-designed (Conway's Law can be worked with, not merely suffered).
Inferences:
- Below some team size the coordination cost layering imposes is small enough that the stylistic consistency of layers remains worth it โ the book's own 'Optimize for the Ordinary' aside gestures at this threshold without ever quantifying it.
Organizations should run knowledge-loss simulations proactively, before a departure, rather than discovering the gap after the fact. strength: medium
Explicit premises:
- Version control already encodes which developer wrote which code, in what proportion.
- Onboarding and knowledge transfer are measurably more effective while the original author is still present to explain trade-offs invisible in the code or commit log.
Implicit premises:
- Authorship share is a valid proxy for depth of understanding, not merely volume of typing.
Inferences:
- If authorship and understanding ever decouple โ for instance if code is written by one actor but reviewed and effectively 'owned' in the knowledge sense by another โ a knowledge-loss simulation built purely on commit authorship would point at the wrong people.
Narratives
- An organization runs a quantifying tool on its 15-year-old codebase and is told it carries '4,000 years' of technical debt, leaving no way to decide where to start.
โ Shows that a technical-debt measure with no time dimension is operationally useless for prioritization, motivating the hotspot concept. - A project with its schedule compressed from one year to three months by quadrupling headcount ends up with high defect rates and low morale, even though the author, reviewing the code directly, finds it 'by no means particularly hard to understand.'
โ Demonstrates that organizational congestion, not code quality, was the real driver of the team's struggles โ grounding the chapter's mental-schema argument. - A hotspot analysis of Microsoft's ASP.NET Core MVC identifies a 2,500-line unit test, ControllerActionInvokerTest.cs, as the top hotspot, and a complexity-trend analysis confirms its complexity has grown sharply without a corresponding increase in comments.
โ Shows the hotspot + complexity-trend combination jointly locating and confirming a real maintenance problem in a real, inspectable codebase. - Android's ActivityManagerService.java, a 20,000-line hotspot with only 33 lines of unit-test coverage, is refactored using the splinter pattern โ extracting cohesive behaviors into new classes behind a delegating facade, in fast, incremental steps rather than on a branch.
โ Makes the splinter pattern concrete and shows it is deliberately designed for code too large and too contested to refactor in one sweep. - A consultant is hired to review a flawed, much-complained-about database framework, only to find via code-age analysis that the code hasn't been touched in a year and isn't actually defect-dense โ the complaints were folklore, not data.
โ Illustrates that old, stable code is often mistakenly targeted for rewrite based on reputation rather than evidence, supporting the 'your best bug fix is time' proposition. - Two long-time Scala contributors, Paul Phillips and Simon Ochsenreither, publicly announce they are leaving; a knowledge-loss simulation on the Scala codebase shows the interactive REPL package in particular loses its main developer.
โ A real-world case study of knowledge-loss simulation in action, including an example of classifying the resulting risk as low (REPL, widely understood in general) versus high (Scala-specific type-system internals). - In a medical-domain codebase, a shared 'Patient' class accumulates getters and setters for unrelated use cases โ including a UI editor's fields and an entirely separate subsystem's network-transfer status โ forcing every consumer to depend on properties irrelevant to their context.
โ Motivates bounded contexts as a remedy for a shared global model, and sets up change-coupling analysis as a way to discover where such contexts actually are.
Questions addressed
- โ
Given a large codebase with far more subpar code than time to fix it, how do you decide where to start?
Hotspots: rank code by change frequency x complexity, both mined from version control. - โ
Does the current architecture actually support the way the system evolves, or does it fight the way people work?
Change-coupling analysis across files, layers, components, and services reveals where the architecture's stated boundaries diverge from the real, evolving ones. - โ
Where are the hidden interteam coordination bottlenecks in a large organization?
Developer-fragmentation (fractal value) analysis combined with Conway's-Law-aligned architecture. - โ
How do you know, before someone leaves, what knowledge the organization would lose?
Knowledge maps plus knowledge-loss simulation on version-control authorship data. - โญ What happens to all of these author-based social metrics once a large and growing share of commits comes from an AI agent rather than a human who can 'understand,' 'leave,' or need 'onboarding'?
Gaps
- incompleteEvery social metric in the book (ownership, fractal value, knowledge maps, knowledge-loss simulation) is built entirely on human-author version-control identity as a proxy for who understands the code. The book has no answer for a world where a large share of commits are authored by AI agents under human supervision/review, which breaks the implicit equation of 'who wrote it' with 'who understands it' exactly where agent-authored commits are frequent and numerous. For AI-era teams, this suggests the next generation of these metrics may need 'who understands this code' decoupled from 'who/what wrote this code' โ reviewer/approver identity or demonstrated modification history might be better proxies than raw commit authorship once agents are prolific contributors.
Read next: Look for post-2023 work that re-derives social code metrics (ownership, knowledge mapping, bus-factor-style analyses) using reviewer/approver signals rather than commit authorship, and for any extension of Tornhill/CodeScene's own Code Health work into the social half of this book. - incompleteThe hotspot/interest-rate framework (technical half of the book) has a documented modern descendant โ CodeScene's Code Health metric, shown elsewhere in this corpus (extract-codescene-refactoring-at-scale-with-agents) to predict agentic refactoring performance on at least one case study. But that validation covers only the technical metric; it remains untested in this corpus whether the book's social/organizational metrics (ownership, developer fragmentation, knowledge maps) predict anything about agent-era risk at all, since agents don't suffer diffusion of responsibility or the forgetting curve the way human teams do.
Read next: Look for empirical work correlating team-level social code metrics (fractal value, ownership diffusion) with outcomes in codebases where AI agents do a large share of the implementation work. - incompleteThe book's code-age argument depends specifically on human memory decay (the Ebbinghaus forgetting curve) to explain why mid-aged code is the most expensive category to maintain. If AI agents โ which have no forgetting curve within a session but also no persistent memory across sessions without deliberate context engineering โ become primary code modifiers, it is unclear whether 'mid-aged code' remains the most expensive category, or whether a different, session-reset-driven risk curve applies instead.
Read next: Look for work on how code-age-based maintenance risk should be modeled when the dominant modifier re-derives understanding from scratch each session regardless of the code's calendar age. - incompleteThe book repeatedly asserts that layered/technically-oriented architectures are worth their coordination cost 'for small teams' but never quantifies the threshold at which that trade-off flips โ the 'Optimize for the Ordinary' aside gestures at the cost without giving any decision procedure for when an organization should migrate from layers to package-by-feature/component or microservices.
Read next: Look for later work (e.g., Team Topologies, or empirical studies of architecture migrations) that attempts to quantify team-size or coordination-cost thresholds for abandoning layered architectures.
Closes gaps elsewhere
- Bliki: Mythical Man Month ยท g2 โ Tornhill resolves the tension Fowler leaves unexamined between chief-architect-style conceptual integrity and collective code ownership by reframing ownership as a countermeasure to social-psychology's diffusion of responsibility rather than exclusion: pair narrow operational ownership (who writes most of a module) with deliberately broad knowledge boundaries (who understands it, via reviews/rotations/walkthroughs), backed by empirical findings that clear primary ownership lowers defect rates while broad knowledge boundaries ease interteam coordination.
Related documents
- 11) AI-spesial med Vilde Opsal og Anders Sveen
- The Economic Benefit of Refactoring
- Technical Debt Quadrant
- The Hard-Stop Rule: From 3 HCM Monoliths to 120 Domain Microservices
- Code Red: The Business Impact of Code Quality -- A Quantitative Study of 39 Proprietary Production Codebases
- Architecture Modernization: Aligning software, strategy, and structure โข Nick Tune โข CodeCrafts 2024
- Agents don't know what good looks like. And that's exactly the problem.
- AI coding creates two kinds of debt. You're only measuring one
- The "funhouse mirror": How AI reflects the hidden truths of your software pipeline
- Case Study: Refactoring at Scale with Agents