Module 2: Conway's Law

2. You ship your org chart: the law, measured

Overview

By the end of this lesson you'll have Conway's Law turned into a tool that executes, not into a phrase that gets cited. First, the exact statement and its origin: in 1968 Melvin Conway wrote that "organizations which design systems are constrained to produce designs which are copies of the communication structures of these organizations". You'll understand why that is true —not by chance or bad luck, but by an inevitable mechanic: for two software modules to fit together, the people who write them have to agree, and that agreement requires communication; so the structure of the pieces ends up traced from the structure of who-talks-to-whom—. Second, and this is what separates this lesson from a trivia fact: you'll measure the mirror over Mercado. You'll take the map of who owns which module and what each module depends on, and you'll compute, by executing, how aligned the organization and the code are —classifying each dependency as intra-team (cheap) or cross-team (expensive), and deriving the communication graph the architecture demands of the organization—.

This matters because Conway's Law is only useful if you can measure it. "You ship your org chart" as a phrase gives you an intuition; measured, it gives you a diagnosis. The difference is the same as between "I think I have a fever" and "38.9°C". When you can compute that 61.5% of your system's dependencies cross team boundaries, you stop arguing about whether there's an organization problem and start arguing about which specific module concentrates it and what restructuring would lower it. Measurement transforms Conway from a passive observation ("ah, look, the system resembles the organization") into an active instrument ("these eight dependencies cross teams, and here's the map of the conversations your code demands and your org chart maybe doesn't have"). That map —the communication graph the architecture demands— is the lesson's central artifact, and it's the raw material of everything that follows: the monolith (lesson 3), the friction (lesson 5), and the inverse maneuver (lesson 6).

Connection with the module: this lesson lays the foundations. Lesson 1 gave you the intuition (the bridge, the teaser that predicts seams); this one makes it rigorous —the law stated precisely and measured over fixed data—. The ownership and dependencies map you build here is the same one you'll reuse throughout the module: lesson 3 measures it under two different organizations (to explain the monolith), lesson 5 computes its friction per module, and lesson 6 restructures it with the inverse maneuver. If lesson 1 was "a law exists and it predicts seams", this one is "here's the law, and here's how to measure how much your system complies with it".

For two pieces to fit, two people have to talk

Think of it this way, with no software at all. Imagine you're assembling one of those flat-pack pieces of furniture, but the work is split between two people: one assembles the left side of the closet and the other the right, and at the end the two sides have to join with some screws that pass from one side to the other. For those screws to fit, the two people have to agree: where the holes go, what diameter, at what height. If they talk well, the holes match and the furniture is solid. If they don't talk —each one makes the holes wherever they see fit—, when it's time to join the sides the screws don't go in, and the furniture ends up lame right at the joint.

Now notice the deep consequence: the number of "agreement points" the people need is exactly the number of physical connections between their pieces. If the furniture's design had the two sides joined by twenty screws, the two people would have to coordinate twenty holes. If the design joined them with a single big bolt, they'd coordinate a single point. The structure of the pieces (how many connections they have with each other) determines how much communication is needed between the people. And here's the twist Conway discovered: the arrow also points the other way. If the two people can barely communicate, they'll design —unconsciously— pieces that need few agreement points, because coordinating is expensive and they avoid it. And if they communicate all the time, they'll design pieces that intertwine without guilt, because coordinating is free for them.

Transfer that to software and you have the complete Conway's Law. Every time one team's module has to call another team's module —an API, a contract, a shared data format—, the people of the two teams have to agree on that interface. That agreement costs communication. Since teams avoid (without realizing) expensive communication, the system tends to have its interfaces right where the teams already communicate, and to avoid interfaces where the teams don't talk. The result: the system's structure ends up being a copy of the communication structure. Not because anyone plans it, but because it's the path of least resistance. That's why Conway isn't a recommendation ("you should align teams and architecture") but a descriptive law ("whether you're seeing it or not, your system already copied your organization").

Worked example: measuring the mirror in Mercado

We'll measure Conway's Law over Mercado's monolith. We need two maps. The first, the ownership map: which squad owns each module of the code —today, with the five squads—. The second, the dependencies map: which module depends on which other (who calls whom, who reads whose data). With those two maps we can classify each dependency of the code: if a module and the one it depends on belong to the same squad, it's an intra-team dependency —cheap, because the coordination is internal, the people sit together—; if they belong to different squads, it's cross-team —expensive, because it requires two squads to agree—.

And we do one more thing, the important one: for each cross-team dependency, we note the pair of squads that has to talk. The union of all those pairs is the communication graph the architecture demands of the organization —the drawing of all the inter-squad conversations the code needs to function—. That graph, per Conway, should match how the organization really communicates. Where the code demands a conversation the organization doesn't have, there's friction.

# Conway measured: the mirror between the structure of the organization
# and the structure of the code, computed over Mercado.

# Who owns each module (current ownership map: 5 squads).
owner = {
    "product_catalog":     "catalog",
    "search":              "catalog",
    "cart":                "orders",
    "order_processing":    "orders",
    "checkout":            "orders",
    "payment_processing":  "payments",
    "invoicing":           "payments",
    "shipping_labels":     "shipping",
    "delivery_tracking":   "shipping",
    "auth":                "platform",
    "notifications":       "platform",
}

# Code dependencies: (module, the-one-it-depends-on).
deps = [
    ("search",             "product_catalog"),
    ("cart",               "product_catalog"),
    ("checkout",           "cart"),
    ("checkout",           "payment_processing"),
    ("checkout",           "shipping_labels"),
    ("checkout",           "notifications"),
    ("checkout",           "order_processing"),
    ("order_processing",   "shipping_labels"),
    ("order_processing",   "auth"),
    ("payment_processing", "invoicing"),
    ("payment_processing", "auth"),
    ("invoicing",          "notifications"),
    ("shipping_labels",    "delivery_tracking"),
]

# Classify each dependency: intra-team (cheap) or cross-team (expensive).
intra, cross = [], []
team_edges = set()   # the communication graph the code DEMANDS between squads
for src, dst in deps:
    ts, td = owner[src], owner[dst]
    if ts == td:
        intra.append((src, dst, ts))
    else:
        cross.append((src, dst, ts, td))
        team_edges.add((ts, td))

print(f"{'dependency':<40}{'kind':<7}{'teams'}")
for src, dst, ts, td in cross:
    print(f"{src+' -> '+dst:<40}{'CROSS':<7}{ts} -> {td}")
for src, dst, t in intra:
    print(f"{src+' -> '+dst:<40}{'intra':<7}{t}")

total = len(deps)
print()
print(f"total dependencies : {total}")
print(f"intra-team         : {len(intra)}  ({len(intra)/total*100:.1f}%)")
print(f"cross-team         : {len(cross)}  ({len(cross)/total*100:.1f}%)")
print()
print("Communication graph the ARCHITECTURE demands of the ORGANIZATION:")
for ts, td in sorted(team_edges):
    print(f"  {ts}  must talk to  {td}")
print(f"inter-squad channels demanded by the code: {len(team_edges)}")

What to expect. Running it:

dependency                              kind   teams
cart -> product_catalog                 CROSS  orders -> catalog
checkout -> payment_processing          CROSS  orders -> payments
checkout -> shipping_labels             CROSS  orders -> shipping
checkout -> notifications               CROSS  orders -> platform
order_processing -> shipping_labels     CROSS  orders -> shipping
order_processing -> auth                CROSS  orders -> platform
payment_processing -> auth              CROSS  payments -> platform
invoicing -> notifications              CROSS  payments -> platform
search -> product_catalog               intra  catalog
checkout -> cart                        intra  orders
checkout -> order_processing            intra  orders
payment_processing -> invoicing         intra  payments
shipping_labels -> delivery_tracking    intra  shipping

total dependencies : 13
intra-team         : 5  (38.5%)
cross-team         : 8  (61.5%)

Communication graph the ARCHITECTURE demands of the ORGANIZATION:
  orders  must talk to  catalog
  orders  must talk to  payments
  orders  must talk to  platform
  orders  must talk to  shipping
  payments  must talk to  platform
inter-squad channels demanded by the code: 5

Here's the mirror, measured. Read it in parts.

The number that hurts: 61.5% of the dependencies cross teams. Of the thirteen dependencies of the system, eight cross a squad boundary and only five stay within a team. That's a system poorly aligned with its organization: most of the code's connections require two squads to coordinate. In a healthy system —well "Conwayed"—, you'd expect the opposite: most dependencies internal to each team, and a few, clean and well-defined, crossing boundaries. Mercado has the inverse pattern, and that 61.5% is the numerical signature of a monolith that was split into squads without splitting the code. (In lesson 3 we'll see exactly where that misalignment came from.)

Where the crossing concentrates: in checkout and in order_processing. Look at the CROSS rows: almost all involve orders. checkout crosses toward payments, shipping, and platform; order_processing crosses toward shipping and platform. Orders is the squad that crosses the most boundaries, because the purchase-flow modules (checkout, order processing) need to touch payment, shipping, and notifications —which live in other squads—. This confirms the intuition of lesson 1's teaser: orders is at the center of almost everything, and checkout is the most crossed module. In lesson 5 we'll put an exact number on that friction.

The central artifact: the communication graph the code demands. The last lines are the heart of the lesson. The system, by its dependency structure, demands that five pairs of squads communicate: orders with catalog, with payments, with platform, and with shipping; and payments with platform. That's the communication org chart your code demands —and notice it came from the code's dependencies, not from asking anyone how the company is organized—. Here's Conway's Law turned into a tool: if these five channels match how the organization really communicates, the system flows. If the code demands that orders talk to shipping but orders and shipping are in different buildings and coordinate by tickets, there —in that demanded but unsustained channel— is where the system will get stuck. The graph tells you exactly which conversations your architecture needs so it doesn't break.

An honest nuance about the measurement, because every metric hides assumptions. Counting "cross-team dependencies" treats all dependencies as equal, and they're not: a cross-team dependency toward a stable and well-versioned platform service (like auth) costs much less coordination than a cross-team dependency where both sides change at once (like checkout and payment_processing evolving together). The 61.5% is a first approximation —a coarse thermometer—; in lesson 5 we'll refine the measurement to weight the friction by how many teams must coordinate simultaneously, which better captures the real pain. For now, the 61.5% does its job: shouting that this system isn't aligned with its organization, and pointing to where.

Deep dive: why the mirror is inevitable (and what a homomorphism is without the jargon)

Academics describe Conway's Law with an elegant word: the system is a homomorphism of the organization. It sounds intimidating, but the idea is simple and worth understanding, because it explains why the mirror can't be dodged with good intentions.

A homomorphism, in plain terms, is a correspondence that preserves the structure. Think of a subway map: it's not geographically exact (the distances lie, the curves straighten out), but it preserves what matters —which station connects to which station, in what order—. If in reality station A connects to B and B to C, on the map too, even though the positions are distorted. The map is a homomorphism of the real network: different in the details, identical in the connection structure.

Conway says your system is a homomorphism of your organization in that same sense: it's not that each person is a module (that would be an exact copy, which isn't what happens), but that the connection structure is preserved. If in the organization team A communicates with B, in the system A's module connects with B's. If A doesn't communicate with C, it's very unlikely that A's module depends on C's —because building that dependency would have required a communication that doesn't exist—. The organization's connection map is traced onto the system's connection map. That's why, when in the example we derive "the communication graph the code demands", we're reading the homomorphism in reverse: starting from the code's structure, we recover the communication structure that must have existed to produce it.

Why is it inevitable? By the furniture mechanic: a connection in the code demands an agreement between people, and an agreement demands a communication channel. You can't build a dependency between two modules without the responsible people coordinating —even minimally— on the interface. So each edge of the system requires a communication edge in the organization. And conversely, cheap communication edges (within a team) become friction-free dependencies, while expensive or nonexistent edges (between teams that don't talk) become system boundaries. The communication structure is the mold; the system is what's cast in it. There's no way for the software to come out with a shape the communication doesn't allow —just as you can't pour concrete into one mold and have it come out with the shape of another—.

The practical consequence, which is the module's thesis: if you want to change the shape of the system durably, change the mold —the communication structure—, not the already-cast concrete —the code—. Redesigning the code without changing the communication is like re-sculpting the concrete by hand every time it dries: it works for a while and returns to the mold's shape. That is, exactly, the reason for the inverse Conway maneuver (lesson 6).

Common mistakes

Citing Conway without measuring it (of superficiality). What happens: someone says "by Conway, this system reflects the organization" and stops there, as if naming the law resolved something. They never compute how much it reflects it or where. Why it happens: the phrase is catchy and gives a sense of understanding without the work of measuring. How to spot it: if you mention Conway in a meeting but can't say what percentage of your dependencies cross teams or which ones, you're citing, not measuring. How to fix it: build the two maps (ownership and dependencies) and classify each dependency, as in the example; the 61.5% is a diagnosis, "you ship your org chart" is just a slogan.

Confusing the formal org chart with the real communication structure (of literalness). What happens: someone takes the company's official diagram —who reports to whom— and assumes that's the structure Conway predicts will be copied. But Conway talks about real communication, not reporting lines. Two teams that are in different departments on the org chart but sit together and lunch together communicate a lot, and their software will couple; two teams under the same boss but in opposite time zones barely communicate, and their software will separate. Why it happens: the formal org chart is visible and the real communication is invisible. How to spot it: if your Conway analysis uses the HR diagram and not how information really flows, you're measuring the wrong mold. How to fix it: map the real communication —who talks to whom, how often, how fluidly—; that's the structure that gets copied, not the org chart PDF.

Believing a good design can beat Conway (of voluntarism). What happens: the architect insists that "with enough discipline" the teams will keep the boundaries the diagram asks for, even if the organization pushes against it. They design independent microservices for teams that share everything, and trust willpower to sustain the separation. Why it happens: they underestimate that Conway is a law, not a tendency discipline nullifies. How to spot it: if your plan depends on people "being careful not to couple things" against the gradient of their own communication structure, you're betting against gravity. How to fix it: align the organization with the architecture you want (inverse maneuver) instead of asking people to fight the current forever; discipline runs out, structure doesn't.

Exercises

Exercise 1 — Recompute with a different boundary. Suppose Mercado merges the orders and payments squads into a single squad called commerce (because checkout forced them to coordinate so much they decided to unite them). Without running the code, which of the example's eight cross-team dependencies would stop crossing a boundary? How many cross-team dependencies would remain?

See solution

By merging orders and payments into commerce, any dependency that previously crossed between orders and payments becomes intra-team. Reviewing the example's eight CROSS:

  • cart -> product_catalog (orders → catalog): still crosses (catalog is another squad). Cross.
  • checkout -> payment_processing (orders → payments): now both are commerce. Stops crossing → intra.
  • checkout -> shipping_labels (orders → shipping): still crosses. Cross.
  • checkout -> notifications (orders → platform): still crosses. Cross.
  • order_processing -> shipping_labels (orders → shipping): still. Cross.
  • order_processing -> auth (orders → platform): still. Cross.
  • payment_processing -> auth (payments → platform): still (payments is now commerce, but platform is another). Cross.
  • invoicing -> notifications (payments → platform): still. Cross.

Only one stops crossing: checkout -> payment_processing. Seven cross-team dependencies would remain (before, eight).

The lesson: merging orders and payments fixes the friction between those two (checkout with payment, which was the original pain), but doesn't touch the dependencies that cross toward catalog, shipping, and platform. Reorganizing teams is surgical —it changes exactly the crossings that involve the teams you move, no more, no less—. That's why the inverse maneuver (lesson 6) requires choosing which boundaries you want to eliminate and organizing around that, not merging teams haphazardly.

Exercise 2 — The demanded channel that doesn't exist. The example derived that the code demands that orders talk to shipping. Imagine that in the real organization, orders and shipping are in different offices, have different bosses, and only coordinate when something breaks. According to Conway's Law, what will happen to the dependencies checkout -> shipping_labels and order_processing -> shipping_labels over time? What symptom would you see in the system?

See solution

When the code demands a communication channel (orders → shipping) that the organization doesn't sustain (different offices, coordination only by emergencies), one of two things happens, both bad:

  1. The interface rots. Since orders and shipping barely talk, the interface between their modules (the shipping_labels contract) becomes a point of misunderstandings: orders assumes one behavior, shipping changes another without warning, and things break in production right at that seam. It's the center of the bridge between two crews that don't coordinate. Symptom: recurring integration bugs in the shipping flow, always "the other team's fault".

  2. The system evolves to avoid the channel. Since coordinating with shipping is so expensive, orders starts building shortcuts —copies shipping logic inside its own module so it doesn't have to ask shipping for anything, or duplicates data—. The system deforms to sidestep a communication it can't sustain, and shipping logic appears scattered in orders. Symptom: duplication, shipping logic that "mysteriously" lives in the wrong team.

In both cases, Conway's moral: a channel demanded by the code but not sustained by the organization is a guaranteed source of friction. The cure isn't "they should try harder to coordinate" (that runs out); it's to align —either put orders and shipping into a structure where communicating is cheap, or make shipping_labels a service with a contract so stable that orders doesn't need to coordinate to use it—. This is the tension the team topologies (lesson 7) resolve with the x-as-a-service mode.

Exercise 3 — Read the homomorphism in reverse. You're given only the "communication graph the code demands" of an unknown system: frontend ↔ backend, backend ↔ payments, backend ↔ notifications. Without seeing the code, what can you infer about how the company is organized? And which module is the most central and why is it probably a bottleneck?

See solution

Reading the homomorphism in reverse (from the system to the organization), you can infer quite a bit:

The organization has (at least) four groups that communicate like this: a frontend group, a backend group, a payments group, and a notifications group. The backend talks to the other three; frontend, payments, and notifications don't talk to each other (there are no frontend↔payments or payments↔notifications edges). Probably frontend, payments, and notifications are "leaf" teams that only coordinate through the backend —or payments and notifications are services the backend consumes—.

The most central module (and team) is the backend, because it's the only one that appears in all three edges: all the communication passes through it. That makes it the number-one candidate for a bottleneck, for two reasons that reinforce each other: (1) technically, it's the module everything depends on, so any change of its affects many and any outage of its takes down everything; (2) organizationally, the backend team has to coordinate with the other three, so its communication load is the highest and everyone else's work gets stuck waiting for it. It's exactly the position of orders in Mercado —the central module that crosses toward all the others—. Conway's Law let you diagnose the bottleneck (technical and organizational) without seeing a single line of code, just by reading the demanded communication graph.

Summary and next step

In this lesson you turned Conway's Law from phrase into tool. You met Melvin Conway's original statement (1968) and —more importantly— why it operates: for two modules to fit, the people who write them have to communicate, so the structure of the pieces is traced from the structure of who-talks-to-whom (the two-person furniture, the homomorphism that preserves the connection structure). And you measured the mirror over Mercado: you classified the thirteen dependencies of the system into intra-team (5) and cross-team (8), you got the diagnosis —61.5% of the dependencies cross boundaries, the signature of a poorly aligned system—, and you derived the central artifact: the communication graph the architecture demands of the organization (five inter-squad channels, with orders at the center of almost all).

Before moving on you should be able to: state Conway's Law precisely and explain why it's inevitable (a connection in the code demands an agreement between people); measure the mirror in a system —classify dependencies into intra and cross-team and compute the alignment—; derive the communication graph a code demands; and distinguish real communication (what gets copied) from the formal org chart (which sometimes lies).

What follows is explaining where that 61.5% of misalignment came from —why a system ends up like this—. In lesson 3 you'll see why Mercado's monolith reflects that at the start there was a single team: you'll measure the same codebase under two different organizations —the 2019 one (one team) and the 2024 one (five squads)— and see the cross-team dependencies jump from 0 to 8 without the code changing a single line. It's the story of almost every painful monolith: it was born perfectly aligned with a single team, and became misaligned when the organization grew and the code didn't follow it.

Resources

  • Melvin Conway — "How Do Committees Invent?" (1968) — the founding paper, with the exact formulation of the law. Worth reading in full (it's a few pages): Conway already observed in 1968 the example of the two-pass compiler written by two groups, and anticipated almost everything this module measures.
  • Martin Fowler — "Conway's Law" — the best brief explanation of why the law operates and what it implies; it introduces the distinction between the formal org chart and real communication, and the idea that the design inherits the shape of the communication.
  • Skelton & Pais — Team Topologies, chapter on Conway's Law — the free summary of key concepts, which treats the org↔architecture "mirror" as the starting point for designing organizations on purpose; the direct bridge to lessons 6 and 7 of this module.