Organic Modularity · Note III

Good code is not a 'tree'

In 1965 Christopher Alexander showed that living structures overlap, and that the strict hierarchies we impose on them quietly kill what makes them work. The same amputation of organized complexity is built into almost every software coupling metric — including, until we looked, our own.

01 — The claim

Alexander’s quarrel with strict hierarchies

Christopher Alexander was an architect and mathematician who spent his career trying to say, precisely, what makes some built environments feel alive and others feel dead.

In his 1965 essay A City Is Not a Tree, he distinguishes two ways of organizing a set of parts into groups.

In a 'tree'A grouping where any two sets are either nested (one wholly inside the other) or completely separate. Never partly overlapping. A file-folder hierarchy is a tree. -- the strict hierarchy from graph theory that is only superficially related to a genuine tree -- whenever two groups share a member, one group must contain the other entirely. Groups never partly overlap.

But in a semi-latticeA grouping where two sets are allowed to overlap without either containing the other. The mathematical structure of any living, richly-connected system. It is a type of Directed Acyclic Graph., two groups are allowed to overlap — to share members without one swallowing the other.

That single difference, Alexander argued, is the difference between the artificial cities, which planners draw and impose on the world, and living cities that have grown naturally. In a real city, the corner drugstore beside the traffic light belongs at once to the system of “errands on the way home” and to the system of “this residential block” and to the system of “shops along this avenue.” Those systems overlap in that one place. A planner’s diagram, drawn as a tree, forces the drugstore under exactly one parent — and in doing so prevents the very overlaps that made the corner a place.

When we think in terms of trees, we are trading the humanity and richness of the living city for a conceptual simplicity that benefits only designers, planners, administrators and developers. Christopher Alexander, 1965

His target was 'rational' urban planners who were destroying cities. But the mathematics is about grouping anything — and a modern codebase is, similarly, parts organized into groups.

02 — See it

The same parts, organized two ways

Below is one small system of components — call them modules in a program. The connections between them never change. What changes is how we group them. Toggle between the two organizations and watch what the tree is forced to throw away.

Fig. 1 — Tree vs. semi-lattice over one component set
Tree view. Every module is filed under exactly one group. The grouping is tidy, and three real connections (shown faded) are ignored because they cross between groups the tree keeps separate. This is the diagram a file tree, a package layout, or a partition-based clustering algorithm produces.
group A
group B
group C
overlap zone

In the tree, two modules that genuinely serve two groups at once — a shared value type, a logging concern, a utility every subsystem leans on — must be assigned to one parent and only one. The connections that don’t fit the chosen hierarchy don’t disappear from the running program; they just disappear from the picture. The semi-lattice keeps them, by letting the overlap zone belong to both groups at once. That lime region is Alexander’s drugstore at the traffic light.

03 — Why the tree is tempting

Chunking, and the magic number seven

Why do we keep drawing trees when the world is more like a semi-lattice?

Alexander’s answer is that a tree is easy to hold in the mind. And there’s a well-known reason minds prefer it: Miller’s 7±2George Miller’s 1956 finding that human working memory holds only about seven items at once. We cope by chunking — grouping items into a few clusters, then grouping those clusters, and so on.. We can only keep a handful of things in working memory, so we cope by chunking — grouping items into small sets, then grouping the sets into small sets, recursively.

Chunk recursively and you get a strict hierarchy automatically: a 'tree', by construction. It’s comprehensible precisely because it forbids overlap — you never have to hold two cross-cutting memberships in mind at once. But that comprehensibility has a real cost. Every real relationship that crosses the chunk boundaries is discarded so the diagram stays clean.

This is the crux for software. When we impose a package tree, a layer diagram, or a partition of classes into disjoint clusters, we are chunking. And we are — usually without noticing — discarding exactly the cross-cutting structure that Alexander says carries the life of the system.

04 — The hidden flaw

Our own metric assumed a tree

Here is the uncomfortable part. Our overcoupling work builds a dependency graph and runs a community-detection step to find a codebase’s “natural” structure. That step uses the Louvain methodA fast, widely-used algorithm (Blondel et al., 2008) that finds community structure by maximizing modularity. Critically, it returns a partition: every node in exactly one community., which returns a partition — every node placed in exactly one community.

The assumption we didn’t know we were making

A partition is a tree of depth one. By detecting only disjoint communities, our pipeline was structurally incapable of seeing an overlap even when one was really there. We built a tool to measure organic structure — on a foundation that assumed the structure was unnaturally mechanical.

This isn’t fatal, but it’s a real blind spot, and it distorts one metric in particular. Our BVC gapBoundary-Violation-Crossing gap: compares the boundaries a programmer declared (class/module lines) against the boundaries an algorithm detects. A negative gap signals intentional decomposition. compares the boundaries a programmer declared against the boundaries the algorithm detects. When those disagree, we read it as a warning. But Alexander predicts a case where disagreement is good: a living system has emergent groups that legitimately overlap the declared ones without nesting. A partition-based BVC cannot distinguish a healthy overlap from genuine disorder.

The fix is to stop demanding a partition. Overlapping community detectionA family of algorithms that let a node belong to several communities at once — recovering the semi-lattice instead of forcing a tree. — link-based methods that cluster the edges rather than the nodes — recovers the semi-lattice. The clearest is link clustering (Ahn, Bagrow & Lehmann, 2010): because every node touches several edges, and edges get grouped, a node naturally ends up in several groups at once.

# The tree-assuming version we shipped:
communities = louvain(graph)          # each node → exactly ONE community
overlap = 0                            # impossible to observe by construction

# The semi-lattice-aware upgrade:
link_comms = link_clustering(graph)   # cluster EDGES, not nodes
membership = defaultdict(set)
for comm_id, edge in link_comms:
    membership[edge.u].add(comm_id)   # a node can now join many communities
    membership[edge.v].add(comm_id)

overlap_index = sum(1 for n in nodes if len(membership[n]) > 1) / len(nodes)
# fraction of components that legitimately serve more than one group

That last line is a new metric — the overlap index — and it measures something no coupling metric in our suite, or the classic suite, or the modern state of the art, currently reports: how much of the system is a semi-lattice rather than a tree.

05 — A second reading

Living structure has many sizes

Alexander’s later work adds a companion idea worth previewing here, because it too is computable on our graphs: levels of scaleOne of Alexander’s properties of living structure: strong systems contain parts at many sizes, with a smooth, moderate ratio between adjacent sizes — never all the same size, never wildly jumping.. Healthy structures contain parts at a range of sizes, with a smooth ratio between adjacent levels. Rigid chunking — the strict application of 7±2 — produces the opposite: clusters quantized into a few identical sizes, a stepped and mechanical distribution.[1]

Run hierarchical clustering on a dependency graph and you get a dendrogramA tree diagram showing the order in which clusters merge, and at what “distance.” The sequence of merge sizes reveals whether a system has smooth levels of scale or mechanical steps. — a record of the sizes at which groups merge. The distribution of those merge sizes is a fingerprint:

Mechanical — stepped scales
Organic — smooth scales

We are not shipping a “levels of scale” metric yet — it needs validation before it earns a number. But it shows that Alexander’s mature vocabulary has faithful, computable corollaries, using exactly the graphs we already build. (Alexander's other properties -- that live in continuous physical space — do not transfer as easily to dependency graphs, using currently available methods. That's work for the future.)

[1]Rigid chunking means a fixed branching factor — every group holds about seven children. But uniform recursion can only tile a system of N parts by stacking powers of that number: groups of ~7, then ~49, then ~343. The merge sizes pile up at those powers and vanish in between — see the big-step histogram above left. Let clusters instead take whatever size the code's own structure calls for, and the merge sizes will spread more reasonably across the range.↩
06 — What it corrects

The tree assumption runs through the whole field

Once you see it, the same amputation appears everywhere coupling has been measured. Overlap-awareness is not a tweak to one metric — it is a correction to a shared foundational assumption, from the 1994 classic through today’s state of the art.

1994 · C & K

Chidamber & Kemerer — CBO, LCOM

CBO (Coupling Between Object classes) counts the distinct classes a class is coupled to, and LCOM (Lack of Cohesion in Methods) measures cohesion by how methods partition around shared instance variables. Both treat the class boundary as a hard, disjoint wall — a tree. Neither can express a responsibility that genuinely lives in two classes at once.

Correction: the overlap index measures precisely the cross-cutting membership C & K’s per-class counts must discard.

2004–08 · State of the Art

Modularity & DSM metrics — Q, propagation cost, Decoupling Level

Newman modularity and the Louvain method that maximizes it are defined over a partition. Design-Structure-Matrix metrics assume each element sits in one block. The strongest modern whole-system measures inherit the tree assumption in their mathematics.

Correction: overlapping community detection generalizes modularity to a semi-lattice; the overlap index reports what the partition version cannot see.

Our metrics · v2

Organic Modularity — BVC gap, worker CCR

Our own pipeline ran Louvain and so assumed a tree. The BVC gap could misread healthy overlap — emergent groups that cross declared lines without nesting — as disorder.

Our correction: an overlap-aware BVC separates “declared and detected differ because the code is tangled” from “they differ because the code is a living semi-lattice.” This is the v3 upgrade, and it makes an existing metric more truthful rather than adding a new alarm.

Partition-based metrics misread every legitimate boundary-crosser as 'disorder'. But these 'crossers' are a family of different characters: orchestrators (star centers that coordinate), shared kernels (star centers that serve), and true brokers (nodes woven into several dense regions at once). The CCR orchestrator rule catches the first by its outward direction; the overlap index catches the third by its multiple memberships. Neither subsumes the other — together they begin to enumerate the ways a connecting node can make positive contributions to the code.

There is a pleasing loop here. Alexander’s 1965 essay diagnosed a flaw in how planners think. The same flaw, transposed to graphs, turns out to sit inside the standard toolkit for reasoning about software structure. And the correction — to allow overlap — simultaneously repairs a metric we had already shipped.

07 — A note on classes

Why we don’t center classes like 1994

A careful reader will notice that C & K’s suite is organized around the class and its inheritance tree — DITDepth of Inheritance Tree: how far a class sits below the root of its inheritance hierarchy. A core CK metric. and NOCNumber of Children: how many classes directly inherit from a given class. The other inheritance-based CK metric. measure inheritance depth and breadth — while our work leans on the call-and-dependency graph and treats deep class hierarchies lightly. This is deliberate, and the field moved this way for good reasons.

Deep inheritance hierarchies proved hard to understand, navigate, and maintain; the inherited context a programmer must hold in mind grows with depth, and behavior scatters across ancestors. The Gang of Four made “favor object composition over class inheritance” a foundational principle in 1994 — the same year as C & K. Empirical work through the 2000s repeatedly found that deeper inheritance correlates with higher fault-proneness. C & K themselves observed the tendency toward shallow trees in their own data, and read it as designers trading reuse for comprehensibility. Modern practice has largely settled that trade: composition-first designs, flatter hierarchies, and — fittingly — structures where a capability is composed from several collaborators rather than inherited down a single line.

Composition is, of course, the semi-lattice again: a class that composes three collaborators participates in three groupings at once, where a class that inherits from one parent sits at a single place in a tree. The historical shift from inheritance to composition is the field, in practice, drifting from tree toward semi-lattice — without, until now, a metric that names the move.

08 — Where this goes

Measure the overlap, not just the cut

Every coupling metric worth having so far has measured separation: how cleanly can we cut the system into disjoint pieces. Alexander’s correction is that the health of a living structure is also in its overlaps — the places two systems legitimately interlock.

The overlap index is small, computable today, and it fixes a real flaw in metrics we already ship. It is the first concrete thing “A City Is Not a Tree” gives our project. The larger prize — Alexander’s centers, and the recursive field where strong structures reinforce one another — is a deeper piece of mathematics we take up separately. This note only had to establish the foundation: good structure is a semi-lattice, the tree is a comprehension shortcut that quietly discards what matters, and the overlap it discards can be measured.

A city is not a tree. Neither is a living codebase.

References & notes

  1. C. Alexander, “A City Is Not a Tree,” Architectural Forum, vol. 122, 1965 (Part I no. 1, pp. 58–62; Part II no. 2, pp. 58–62). The origin of the tree / semi-lattice distinction.
  2. G. Bryant & G. Williams, “The Necessity of Organic Modularity, and Metrics for Eliminating Compound Overcoupling in Generative Code,” 2025. https://zenodo.org/records/21015575 — the paper this note extends.
  3. C. Alexander, Notes on the Synthesis of Form. Harvard Univ. Press, 1964. The equilibration-time argument our first note builds on.
  4. G. A. Miller, “The Magical Number Seven, Plus or Minus Two,” Psychological Review, vol. 63, pp. 81–97, 1956. Working-memory limits and chunking.
  5. S. R. Chidamber & C. F. Kemerer, “A Metrics Suite for Object Oriented Design,” IEEE Trans. Software Eng., vol. 20, no. 6, pp. 476–493, 1994. CBO, LCOM, DIT, NOC.
  6. M. E. J. Newman & M. Girvan, “Finding and evaluating community structure in networks,” Phys. Rev. E, vol. 69, 026113, 2004. Modularity Q — defined over a partition.
  7. V. D. Blondel, J.-L. Guillaume, R. Lambiotte & E. Lefebvre, “Fast unfolding of communities in large networks,” J. Stat. Mech., P10008, 2008. The Louvain method.
  8. Y.-Y. Ahn, J. P. Bagrow & S. Lehmann, “Link communities reveal multiscale complexity in networks,” Nature, vol. 466, pp. 761–764, 2010. Overlapping communities by clustering edges — the basis of the overlap index.
  9. G. Palla, I. Derényi, I. Farkas & T. Vicsek, “Uncovering the overlapping community structure of complex networks,” Nature, vol. 435, pp. 814–818, 2005. Clique percolation; an earlier overlapping-community method.
  10. A. MacCormack, J. Rusnak & C. Y. Baldwin, “Exploring the Structure of Complex Software Designs” (propagation cost, DSM), Management Science, vol. 52, no. 7, 2006.
  11. S. Mancoridis, B. S. Mitchell, et al., “Bunch: A Clustering Tool for the Recovery and Maintenance of Software System Structures,” Proc. ICSM, 1999. Modularization quality (MQ), a near cousin of our Q/CCR family.
  12. G. C. Murphy, D. Notkin & K. Sullivan, “Software Reflexion Models,” Proc. FSE, 1995. Declared-vs-extracted model comparison — the closest ancestor of our BVC gap.
  13. E. Gamma, R. Helm, R. Johnson & J. Vlissides, Design Patterns. Addison-Wesley, 1994. “Favor object composition over class inheritance.”
  14. V. R. Basili, L. C. Briand & W. L. Melo, “A Validation of Object-Oriented Design Metrics as Quality Indicators,” IEEE Trans. Software Eng., vol. 22, no. 10, 1996. Deeper inheritance associated with higher fault-proneness.
  15. K. El Emam, S. Benlarbi, N. Goel & S. N. Rai, “The confounding effect of class size on the validity of object-oriented metrics,” IEEE Trans. Software Eng., vol. 27, no. 7, 2001. Why size-confounded class metrics mislead.