**Author:** [[3. Resources/Authors/Adam Tornhill|Adam Tornhill]] # Book Overview ![[Your Code as a Crime Scene Visual.excalidraw]] ## About the Author Adam Tornhill is a programmer and Lisp enthusiast who combines interests in forensic psychology with software development. He built Code Maat, an open-source tool for mining and analyzing version-control data. His background spans Java, C#, Python, Clojure, C++, and Common Lisp, and he's applied his behavioral code analysis techniques across codebases of all sizes. He later expanded the ideas from this book into a commercial tool (CodeScene) and a follow-up book, *Software Design X-Rays*. ## Central Thesis You can't understand a large software system by looking at a static snapshot of the code. The current structure tells you what the code is, but not how it got there, where it's headed, or who shaped it. Tornhill argues that version-control data -- the record of every change, every committer, every co-change -- is an untapped gold mine for identifying design problems, predicting defects, and understanding organizational dynamics. The book borrows techniques from forensic psychology, particularly geographical offender profiling. Just as investigators map crime locations to predict an offender's home base, developers can map change frequencies and complexity to find code "hotspots" -- the modules that are both complex and frequently modified. These hotspots account for a disproportionate share of defects and maintenance costs. Beyond individual files, the same version-control data reveals architectural decay through temporal coupling, exposes knowledge silos through developer ownership patterns, and surfaces organizational problems that manifest as code quality issues. ## Why This Book Matters Most code analysis tools focus on static properties -- cyclomatic complexity, code smells, dependency graphs. These tell you what the code looks like right now. They don't tell you which parts actually cause problems in practice. A module can be ugly but stable; another can look clean but change constantly in ways that introduce bugs. Tornhill's contribution is making the case that behavioral data (how the code evolves) is a better predictor of trouble than structural data (what the code looks like). This matters because large codebases are full of complexity. You can't fix everything. The question is always "where should we spend our limited improvement budget?" Hotspot analysis gives a data-driven answer: focus on the intersection of high complexity and high change frequency. The techniques also work across languages, which is a real advantage in polyglot systems where language-specific metrics break down. --- # Chapter Summaries ## Chapter 1: Welcome Sets up the book's premise: maintenance is the dominant cost in software (40-80% of total project costs), and understanding existing code is the dominant activity within maintenance. Our primary job as programmers isn't writing code -- it's understanding code. The chapter introduces the forensic psychology metaphor and explains how the techniques complement (rather than replace) tests, static analysis, complexity metrics, and code reviews. Tornhill also argues that software development is a human problem as much as a technical one -- our brains weren't designed to parse walls of nested conditionals, and we need strategies that account for cognitive limitations. ## Chapter 2: Code as a Crime Scene Introduces geographical offender profiling as the conceptual foundation. Criminals build mental maps and commit crimes in patterns that form a circle around their home base. Investigators use this spatial data to identify hotspots -- high-probability areas where the offender likely lives. Tornhill maps this to code: version-control data tracks the "spatial movement" of programmers through the codebase. By combining change frequency (effort) with lines of code (complexity), you identify code hotspots -- modules that are both complex and frequently modified. Research shows that change frequency is a better predictor of defects than pure code size, and that hotspots cluster a disproportionate number of bugs into a small percentage of the codebase. On one system Tornhill studied, hotspots made up only 4% of the code but contained seven of the eight most defect-prone modules. ## Chapter 3: Creating an Offender Profile A hands-on walkthrough of mining version-control data. Tornhill uses Code Maat to analyze its own codebase (he's a Lisp programmer -- circular references are a feature). The chapter covers extracting git logs, analyzing change frequencies, counting lines of code with cloc, and merging the two data sets to produce a ranked list of hotspots. The result is a prioritized list of suspects: the most frequently changed, most complex modules in the system. The chapter also addresses limitations -- temporal period sensitivity, commit style differences, and the lack of normalization in the raw data. ## Chapter 4: Analyze Hotspots in Large-Scale Systems Scales the analysis to Hibernate, a large open-source Java library. Introduces circle-packing visualizations where each circle represents a module (sized by lines of code, colored by change frequency). The visualization immediately highlights that a handful of modules dominate the change landscape. Tornhill explores the distribution of hotspots and shows that in Hibernate, 50% of all modifications go to just 115 files out of roughly 6,300. The chapter also covers differentiating true hotspots from false positives -- configuration files, test utilities, and other modules that change frequently for legitimate reasons. ## Chapter 5: Judge Hotspots with the Power of Names Uses naming conventions as a cognitive heuristic for evaluating hotspots. A file named "SessionFactoryImpl" tells you it's a concrete implementation of a session factory -- and if it's a hotspot, that's concerning because implementation classes shouldn't need constant modification. A file named "build.gradle" changing frequently is expected. The chapter argues that good names encode domain knowledge and make it possible to quickly assess whether a hotspot signals a real design problem or is a benign artifact. ## Chapter 6: Calculate Complexity Trends from Your Code's Shape Introduces indentation-based complexity analysis -- measuring the "shape" of code by tracking whitespace patterns over time. Deeply nested code produces a distinctive visual profile. By tracking how this shape changes across revisions, you can see whether a hotspot's complexity is growing, stable, or improving. This gives you complexity trends that reveal whether your refactoring efforts are working or whether the code is getting worse. The technique is language-independent since it's based on indentation rather than language-specific constructs. ## Chapters 7-8: Temporal Coupling and Architectural Decay Introduces temporal coupling -- the idea that files that change together in the same commits have an implicit dependency, even if there's no explicit code reference between them. This reveals architectural decay: when files in different modules consistently change together, it signals hidden coupling that the formal architecture doesn't account for. Tornhill uses this to detect copy-paste issues, surprise dependencies, and design problems that aren't visible in the code structure. The technique also scales to system architectures by grouping files into logical components and measuring coupling between components. ## Chapter 9: Build a Safety Net for Your Architecture Applies the evolutionary analysis to test code. If production code and test code have low temporal coupling, it means tests aren't being updated when the code changes -- a sign that the test suite is drifting away from the system it's supposed to protect. The chapter covers how to measure test coverage from a behavioral perspective (not line coverage, but change coverage) and how to identify areas where automated tests are either missing or providing false confidence. ## Chapter 10: Use Beauty as a Guiding Principle Argues that code aesthetics matter because they reflect structural consistency. "Beautiful" code follows predictable patterns -- consistent naming, regular structure, minimal surprise. When a codebase violates its own conventions, it creates cognitive overhead for developers. The chapter analyzes layered architectures for surprising change patterns -- cases where changes in one layer consistently trigger changes in a layer that shouldn't need modification. ## Chapters 11-13: Social Aspects of Code Shifts from technical to organizational analysis. Chapter 11 covers group psychology biases (pluralistic ignorance, groupthink) that affect software teams. Chapter 12 introduces organizational metrics mined from code -- measuring how many developers touch the same files, detecting parallel development across team boundaries, and quantifying communication costs. Chapter 13 builds knowledge maps showing which developers "own" which parts of the codebase, revealing knowledge silos and bus-factor risks. When a developer who owns critical code leaves the project, the knowledge map highlights exactly where the risk is concentrated. ## Chapter 14: Dive Deeper with Code Churn Uses code churn (lines added and removed) as a more granular measure than simple change frequency. High churn in a module suggests instability -- code being written and rewritten. The chapter connects churn patterns to process problems and shows how to use churn data to predict defects. Tornhill also revisits the geographical profiling metaphor, comparing the "disposal sites" of serial killers to the files where buggy code accumulates. ## Chapter 15: Toward the Future A forward-looking chapter that encourages readers to move beyond Code Maat and develop their own analyses. Tornhill discusses alternative approaches, the importance of letting questions guide analysis rather than running tools mechanically, and the principle of writing code that's designed to evolve gracefully. --- # Key Themes and Highlights ## Version-Control Data Is Behavioral Data The book's foundational insight. Version-control systems record how developers actually interact with code -- not how they planned to, not how the architecture diagram says they should, but what they actually do. This behavioral data is a better predictor of problems than static code analysis. Change frequency predicts defects better than code size. Temporal coupling reveals architectural dependencies that don't show up in import statements. ## Hotspots: The Pareto Principle Applied to Code Defects and maintenance effort follow a power-law distribution. A small percentage of modules account for a disproportionate share of bugs and changes. Hotspot analysis exploits this by identifying the intersection of high complexity and high change frequency. On the system Tornhill studied in detail, 4% of the code contained the vast majority of defects. This means targeted improvements to a small number of modules can have outsized impact. ## Temporal Coupling Reveals Hidden Architecture The formal architecture (package structure, module boundaries, dependency graphs) tells you what the code is supposed to look like. Temporal coupling tells you how it actually behaves. When files in different architectural layers consistently change together, the real architecture has diverged from the intended one. This is architectural decay, and it's invisible to static analysis tools. ## Code Has Social Properties Code isn't just a technical artifact -- it's a social one. The number of developers who touch a file, the patterns of parallel development across teams, and the distribution of knowledge all affect code quality. Files modified by many developers tend to have more defects. Knowledge concentrated in a single developer creates bus-factor risk. Organizational structure influences code structure (Conway's Law in action), and version-control data makes these organizational dynamics visible. ## Complexity Metrics Alone Are Insufficient Complexity is only a problem if you have to deal with it. A hideously complex module that nobody touches is less of a priority than a moderately complex module that gets modified three times a week. Tornhill repeatedly makes the case that you need the temporal dimension -- how code changes over time -- to know which complexity actually matters. --- # Analytical Reading ## Main Arguments 1. Static code analysis tells you what code looks like, but not which parts actually cause problems. Behavioral data from version control is a better guide. 2. Code hotspots -- modules that are both complex and frequently modified -- are the strongest predictors of defects and maintenance cost. 3. Temporal coupling between files reveals hidden architectural dependencies that static analysis misses. 4. Knowledge distribution across developers is a code quality factor -- files touched by many developers or owned by a single developer carry different risks. 5. Organizational dynamics (team structure, communication patterns, parallel development) manifest in code quality and can be measured from version-control data. 6. Language-independent metrics (lines of code, change frequency, indentation patterns) enable analysis of polyglot systems where language-specific tools fail. 7. The forensic psychology metaphor -- treating code like a crime scene and version control like evidence -- provides a useful framework for prioritizing where to invest improvement effort. ## Methodology The book is practitioner literature built on a foundation of academic research. Tornhill cites empirical studies on defect prediction, code churn, and change coupling, then translates the findings into practical techniques using his open-source tool, Code Maat. The case studies use real open-source projects (Code Maat itself, Hibernate, nopCommerce, Craft.Net, Scala) that readers can reproduce. The approach is quantitative -- CSV outputs, ranked lists, visualizations -- but the interpretation is qualitative and guided by human judgment. Tornhill is upfront about limitations: commit styles can bias data, temporal periods affect results, and hotspots are guides rather than verdicts. ## Strengths The techniques are practical and reproducible. Every analysis in the book can be performed with free tools on any Git repository. The language independence is a genuine advantage -- most code analysis tools are language-specific, but change frequency and temporal coupling work across any technology stack. The forensic psychology framing makes the concepts memorable and intuitive. The emphasis on combining automated analysis with human judgment (hotspots as "guides, not verdicts") is mature and honest. The case studies use real, publicly available codebases, so readers can verify the results themselves. ## Limitations The book is from 2015 and reflects the tooling landscape of that era. The command-line workflows are functional but clunky compared to what's available now. The case studies are primarily Java and Clojure -- there's limited coverage of how these techniques play out in JavaScript/TypeScript ecosystems, microservices architectures, or monorepo setups. The book doesn't deeply address how branch-heavy Git workflows (feature branches, pull requests) affect the data, since temporal coupling depends heavily on commit patterns. Some of the forensic psychology parallels are stretched thin -- the Jack the Ripper case study is fun but the analogy breaks down under scrutiny. The organizational analysis chapters (Part III) are the most novel but also the most underexplored. --- # Personal Reflection ## Key Takeaways The core idea -- that version-control history is an underused data source for understanding code quality -- is simple, powerful, and still underappreciated a decade after publication. Most teams look at their git log as a record of what happened. Tornhill makes the case for treating it as a predictive tool: the code that changed most in the past will change most in the future, and the code that's both complex and volatile is where your bugs live. The hotspot concept is immediately actionable. On any project, you can run a change frequency analysis in ten minutes and have a ranked list of the files that deserve attention. That's a better starting point than any static analysis tool I've used. The temporal coupling analysis is the book's most underrated contribution. Finding files that always change together, even though they're in different packages or layers, is a direct signal of architectural problems that are invisible to dependency scanners. It's also a great way to discover copy-paste duplication you didn't know existed. ## Questions Raised - How do these techniques work in trunk-based development vs. feature-branch workflows? Branch merges create different commit patterns that could distort temporal coupling. - Can hotspot analysis be integrated into CI/CD pipelines as a quality gate? If a PR touches a known hotspot, should it trigger additional review? - How do microservices and distributed codebases change the analysis? When coupling crosses repository boundaries, version-control data can't detect it. - The knowledge map concept is powerful for identifying bus-factor risk. How should organizations act on that information -- forced code rotation, pairing requirements, documentation mandates? - How does AI-assisted coding (copilot, code generation) affect change frequency and churn patterns? Does generated code create new kinds of false positives in hotspot analysis? ## Connections to Other Works - [[Working Effectively with Legacy Code]] by Michael Feathers -- Feathers wrote the foreword, and his work on characterization tests and seam-based refactoring is the natural complement to hotspot-guided improvement. - [[Refactoring]] by Martin Fowler -- Tornhill's hotspot analysis provides the "where" that Fowler's catalog provides the "how" for. - [[The Mythical Man-Month]] by Fred Brooks -- Brooks' observation that adding people to a late project makes it later connects directly to Tornhill's findings about multi-developer file ownership and communication costs. - [[Thinking, Fast and Slow]] by Daniel Kahneman -- The cognitive bias discussions in Part III draw on the same psychological research Kahneman popularized. - [[Team Topologies]] by Matthew Skelton and Manuel Pais -- The organizational analysis in Part III anticipates Team Topologies' emphasis on cognitive load and team boundaries. - [[A Philosophy of Software Design]] by John Ousterhout -- Ousterhout's focus on complexity as the root cause of software difficulty aligns with Tornhill's argument that complexity only matters when paired with high change frequency. --- # Reading Notes - The forensic psychology metaphor is genuinely useful, not just marketing. Geographical offender profiling and code hotspot analysis share the same fundamental logic: past spatial behavior predicts future spatial behavior. - The Jack the Ripper case study is the book's hook, and it works. The idea that you can predict a serial killer's home base from crime locations -- and then apply the same math to code -- is memorable. - Michael Feathers' foreword nails the book's thesis: "We're abandoning the static view of code and seeing it as a verb." - The 4% statistic is striking: on the system Tornhill studied, hotspots made up 4% of the codebase but contained 7 of 8 most defect-heavy modules. - Lines of code as a complexity proxy is acknowledged as "terrible" but defended on practical grounds: it's fast, language-neutral, and research shows it correlates with more elaborate metrics anyway. - Temporal coupling is the concept that keeps giving. It surfaces copy-paste code, reveals hidden dependencies, detects architectural violations, and measures test coverage from a behavioral angle. - The knowledge map concept in Chapter 13 is where the book shifts from code analysis to organizational analysis, and it's the most forward-looking material in the book. - The "code as a cooperative witness" framing (Chapter 7) is a useful mental model: your code contains information about its own problems, but you have to interview it correctly to extract it, and you have to account for your own biases in interpreting the answers. - The indentation-based complexity analysis is clever -- language-independent, visual, and trend-trackable. It's a rough proxy, but roughness is the point: you don't need precision to identify the right targets. - Tornhill's emphasis on using analysis as a communication tool (not just a developer tool) is underappreciated. Sharing hotspot visualizations with test leaders, architects, and managers gives everyone a shared vocabulary for discussing code quality.