Module 2: Conway's Law
3. The monolith is your first org chart
Overview
By the end of this lesson you'll understand where that 61.5% of cross-team dependencies you measured in Mercado came from —and with it, the origin of almost every painful monolith you'll see in your career—. The answer is uncomfortable and liberating at once: Mercado's monolith isn't badly designed; it's perfectly designed for an organization that no longer exists. When Mercado was a single team of seven people, a monolith was the right architecture: zero internal boundaries to coordinate, free communication between all parts, a simple deployment. The monolith was the faithful reflection of a single team, and that's why it worked. Today's pain doesn't come from the monolith being bad, but from the organization changing and the code not following it: the business split into five squads, but the code stayed the same block, and now five teams try to own in pieces something that was designed for a single owner. You'll measure this by executing: the same codebase, without changing a line, goes from being perfectly aligned (0 cross-team dependencies with one team) to broken (8 cross-team dependencies with five squads).
This matters because it changes how you diagnose a problematic monolith —and what you do about it—. The engineer's instinct is to blame the code: "it's poorly modularized", "the ones who wrote it didn't know architecture". It's almost always unfair. The code was well modularized for its original organization; what broke was the correspondence between the code and a new organization. And that diagnosis changes the cure. If the problem were the code, the solution would be to rewrite it. But since the problem is the misalignment between a one-team code and a five-team organization, rewriting the code without fixing the misalignment only produces a new monolith with the same problem in a few months. Here appears the module's most expensive mistake, the one you'll see measured: reorganizing the teams without reorganizing the code —splitting the people into squads and leaving the monolith intact— produces what Mercado has today: a system that fights its own organization, with maximum friction and without the advantages of either form.
Connection with the module: this lesson is the origin story. Lesson 2 measured the symptom (61.5% cross-team, today); this one explains the cause (the code was born for one team and the organization multiplied). It uses exactly the same dependency map from lesson 2 —the same thirteen— but measures it under two different organizations, to isolate the single variable that changed: who owns what. And it sets up the two cure lessons: understanding that the monolith reflects a past team is what justifies the inverse maneuver (lesson 6) —aligning the organization with the architecture you want— and the team topologies (lesson 7) —designing teams that produce the right boundaries—. If lesson 2 was "here's the misalignment", this one is "here's how it got in, and here's how to avoid putting it in".
The house built for a couple and today inhabited by five
Think of it this way. A couple builds a house. Since they're two, they design it open: one big single space where the kitchen, the living room, and the dining room flow without walls, because between the two of them privacy isn't needed —they share everything, they hear each other from any corner, and a house without internal walls is cheaper, brighter, and easier to maintain—. For a couple, the open plan is the right design. It's not carelessness: it's the optimal form for that two-person organization.
The years pass. The family grows: children arrive, grandma moves in, then the sister with her partner. Now five adults and three children live in the same open-plan house. And suddenly the design that was perfect becomes a torment: there's nowhere to have a call without everyone hearing, grandma wants silence at nine and the teenagers want music, no one has their own space. The house didn't become bad; it became unsuitable for a family that's no longer the two-person one that designed it. The open plan was the reflection of a couple, and now an organization of eight inhabits it.
What do they do? Here's the important part. If they just divide the existing rooms —"this corner is yours, that one is mine"— without building walls, they solve nothing: they still hear each other, still have no privacy, only now with the illusion that "everyone has their zone". That's exactly what a company does when it splits the people into squads but leaves the monolith intact: it divides the ownership of an open space without building the walls that would make the separation real. The real solution is to raise walls —create internal boundaries where before they weren't needed—, and that's expensive, annoying, and has to be done on purpose. In software, raising walls is modularizing the code so each squad has its own real space; and —the module's lesson— doing it together with the team reorganization, not one without the other.
Worked example: the same code, two organizations
We'll measure the heart of the story. We take the same thirteen dependencies from Mercado that we used in lesson 2 —the code doesn't change—, and we measure them under two organizations: the 2019 one (a single team, core-team, owning everything) and the 2024 one (the five squads). The only variable that moves between the two rows is the ownership map. Everything else —the modules, their dependencies— is identical. If the cross-team dependencies change, the cause can't be the code: only the organization changed.
# Why Mercado's monolith reflects that at the start there was ONE team only.
# We measure the same codebase under two different organizations.
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"),
]
def cross_team_deps(owner):
"""How many code dependencies cross a team boundary."""
return sum(1 for s, d in deps if owner[s] != owner[d])
modules = [
"product_catalog", "search", "cart", "order_processing", "checkout",
"payment_processing", "invoicing", "shipping_labels", "delivery_tracking",
"auth", "notifications",
]
# PHASE 1 (genesis, 2019): a single team writes the whole monolith.
owner_genesis = {m: "core-team" for m in modules}
# PHASE 2 (today, 2024): the business split into 5 squads by domain...
# ...but the CODE stayed the same tangled monolith.
owner_today = {
"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",
}
total = len(deps)
c1 = cross_team_deps(owner_genesis)
c2 = cross_team_deps(owner_today)
print(f"{'organization':<28}{'teams':>8}{'cross-team deps':>18}{'alignment':>13}")
print(f"{'PHASE 1 (1 team, 2019)':<28}{1:>8}{c1:>15}/{total:<2}{(1-c1/total)*100:>11.1f}%")
print(f"{'PHASE 2 (5 squads, 2024)':<28}{5:>8}{c2:>15}/{total:<2}{(1-c2/total)*100:>11.1f}%")
print()
print(f"The code did NOT change a single line between the two rows.")
print(f"Only who owns what changed. The cross-team dependencies")
print(f"jumped from {c1} to {c2}: the monolith, perfect for 1 team,")
print(f"fights the 5 squads that today try to own it in pieces.")
What to expect. Running it:
organization teams cross-team deps alignment
PHASE 1 (1 team, 2019) 1 0/13 100.0%
PHASE 2 (5 squads, 2024) 5 8/13 38.5%
The code did NOT change a single line between the two rows.
Only who owns what changed. The cross-team dependencies
jumped from 0 to 8: the monolith, perfect for 1 team,
fights the 5 squads that today try to own it in pieces.
Stop at the two rows, because they're the origin story of Mercado's pain in two lines.
Row 1 — 2019, one team: perfect alignment. With core-team owning the eleven modules, zero dependencies cross a team boundary, because there are no boundaries to cross: everything belongs to the same team. The alignment is 100%. The monolith was, literally, the perfectly Conwayan architecture for a single team —every dependency is intra-team, coordination free, no fragile seams because there are no seams between organizations—. Anyone who in 2019 had said "this should be five microservices" would have been wrong: they'd have added five coordination boundaries to a team that didn't need them, pure cost with no benefit. The monolith wasn't technical debt; it was the right decision.
Row 2 — 2024, five squads: broken alignment. The code is identical —the same thirteen dependencies, byte for byte—, but now divided among five squads. Suddenly, eight of the thirteen dependencies cross team boundaries, and the alignment collapses from 100% to 38.5%. Not a line was written or deleted; only a new map of who owns what was drawn. That jump from 0 to 8 is the birth of the painful monolith: the same code that was perfect for one team became a source of friction for five, because now each of those eight dependencies requires two squads to coordinate something that before one single person did without asking anyone's permission.
Here's the central lesson made into a number: the monolith didn't degrade, it misaligned. The code didn't get worse between 2019 and 2024; what changed was the organization that tries to own it. Mercado's monolith is, in the most literal sense, the 2019 org chart fossilized in code —a snapshot of when they were one team, that the company keeps carrying even though it's now five—. That's why we say the monolith is your first org chart: the structure of your first system is a mold of your first organization, and that mold stays long after the organization changed.
And here's the expensive mistake, measured: row 2 is exactly what reorganizing the teams without reorganizing the code produces. The company did half the work —it split the people into squads (easy: it's an email and a change in the HR tool)— but not the other half —splitting the code into modules with clear owners (hard: it's months of refactoring)—. The result is the worst of the worlds: they have the expensive coordination of five teams (everyone has to agree) without the independence that would justify that coordination (no one can deploy without stepping on another). A single team with a monolith coordinates cheaply. Five teams with five services coordinate little and deploy independently. Five teams with one monolith coordinate expensively and don't deploy independently —the worst of both—. That 38.5% is the signature of that half-a-job.
Deep dive: why the monolith is the right choice at the start (and when it stops being)
It's tempting to read this lesson as "monoliths are bad, you should be born with microservices". That would be the wrong lesson, and a dangerous one. The truth is subtler and more useful: the monolith is almost always the right architecture at the start, precisely because of Conway.
When a product starts, the organization is small —one team, sometimes a single person—. For that organization, service boundaries are pure cost: each separate service adds a network that can fail, a contract to version, a deployment to orchestrate, and above all a coordination boundary that, within a single team, buys nothing —because the coordination was already free, everyone sits together—. Being born with microservices when you're three people is like the couple building the house with eight separate bedrooms "just in case the family grows": you pay today the cost of maintaining eight spaces when you only need one open one, and the product probably dies (or pivots) before the family grows. It's over-engineering, and Conway explains it: you gave the system boundaries your organization doesn't have, so those boundaries only get in the way.
The monolith stops being right when the organization crosses a certain size and internal coordination starts to hurt more than the boundaries would. That point arrives —you'll quantify it in lesson 4— when the communication channels within the big team grow so much that people spend more time coordinating than building. That's when splitting into teams (and into services that reflect those teams) starts to be worth it: you trade the internal coordination cost for the boundary cost, and at a certain scale the boundaries come out cheaper. The signal isn't "we reached X lines of code" or "microservices are trendy"; it's "the team became too big to coordinate as one", which is an organizational signal, not a technical one.
Mercado's mistake wasn't being born with a monolith —that was fine—. It was growing the organization without evolving the architecture at the same time. When they split the people into five squads, that was the moment to start splitting the monolith into modules (or services) aligned to those squads. Doing one thing without the other left them trapped in row 2. The lesson for your career: every time your organization changes shape —you hire, you split into teams, you merge two groups—, ask yourself whether the architecture has to change shape with it. Because if the organization moves and the system doesn't, Conway guarantees you'll end up with a system that reflects an organization that no longer exists —your first org chart, fossilized, fighting the current one—.
Common mistakes
Blaming the code instead of the misalignment (of diagnosis). What happens: the team sees the painful monolith and concludes "it's badly written, it must be rewritten", and launches into a two-year rewrite. They rewrite, launch the new monolith... and in a year it hurts the same, because they didn't touch the cause. Why it happens: it's easier and more satisfying to blame the code (which can be rewritten) than the organizational structure (which seems untouchable). How to spot it: if your plan to fix a monolith doesn't mention the team organization at all, you're treating the symptom. How to fix it: measure the misalignment (row 2); if the code was fine for one team and broke when split into five, the cure includes reorganizing the teams, not just the code.
Reorganizing the teams without reorganizing the code (of half-a-job). What happens: the company splits the people into squads by domain but leaves the monolith intact, and is surprised that everything got slower instead of faster. Why it happens: splitting people is cheap and visible (an announcement); splitting code is expensive and slow (months of refactor), so the first is done and the second is postponed "for later" —and later never comes—. How to spot it: if you have N teams but a single deployment where everyone steps on each other, you did half a reorganization; the number that gives it away is a high proportion of cross-team dependencies (Mercado: 61.5%). How to fix it: the reorganization of teams and of code go together or they don't go —either you build the walls when you divide the rooms, or you only created the illusion of zones—.
Being born with microservices "just in case" (of over-engineering, the opposite error). What happens: a three-person team starts a new product with twelve microservices "to be ready to scale", and drowns in the complexity of operating twelve services for a product that doesn't even have users yet. Why it happens: they confuse "microservices are good at scale" with "microservices are always good", and ignore that the boundaries their organization doesn't need only cost. How to spot it: if you have more services than teams —or more services than developers—, you almost surely over-fragmented. How to fix it: be born with the monolith (well modularized inside), which is the right Conwayan architecture for a small team, and split into services when the organization grows enough to justify the boundaries —neither before (over-engineering) nor much after (Mercado's delay)—.
Exercises
Exercise 1 — The intermediate phase. The example measures 2019 (1 team) and 2024 (5 squads). Imagine an intermediate point, 2021, when Mercado split into only two teams: commerce (owning product_catalog, search, cart, order_processing, checkout, payment_processing, invoicing) and logistics-platform (owning shipping_labels, delivery_tracking, auth, notifications). Without running the code, count how many of the thirteen dependencies would cross the boundary between those two teams.
See solution
With two teams, a dependency crosses only if its source and destination are in different teams. commerce = {product_catalog, search, cart, order_processing, checkout, payment_processing, invoicing}; logistics-platform = {shipping_labels, delivery_tracking, auth, notifications}. We review the thirteen:
search -> product_catalog: commerce → commerce. Intra.cart -> product_catalog: commerce → commerce. Intra.checkout -> cart: commerce → commerce. Intra.checkout -> payment_processing: commerce → commerce. Intra.checkout -> shipping_labels: commerce → logistics-platform. CROSS.checkout -> notifications: commerce → logistics-platform. CROSS.checkout -> order_processing: commerce → commerce. Intra.order_processing -> shipping_labels: commerce → logistics-platform. CROSS.order_processing -> auth: commerce → logistics-platform. CROSS.payment_processing -> invoicing: commerce → commerce. Intra.payment_processing -> auth: commerce → logistics-platform. CROSS.invoicing -> notifications: commerce → logistics-platform. CROSS.shipping_labels -> delivery_tracking: logistics-platform → logistics-platform. Intra.
Six dependencies cross (5, 6, 8, 9, 11, 12). Alignment = (13−6)/13 ≈ 53.8%.
The lesson: with two well-chosen teams, the misalignment (6 cross, 53.8%) is lower than with five poorly-aligned squads (8 cross, 38.5%). It's not the number of teams that creates the friction, but how well the team boundaries match the natural seams of the code. Two teams whose boundaries respect the code's clusters can be better aligned than five squads whose boundaries split them in half. This anticipates the inverse maneuver: it's about choosing the right boundaries, not the most.
Exercise 2 — The monolith that was actually fine. A colleague, on seeing 2019's 100% alignment, says: "so in 2019 they had the perfect architecture and they ruined it". Where are they right and where are they wrong? Would the 2019 architecture still be "perfect" if Mercado had grown to fifty engineers while staying a single team?
See solution
Where they're right: the 2019 architecture was indeed the right one for its organization at the time. A monolith with 100% intra-team dependencies is the optimal Conwayan form for a single team —zero boundaries to coordinate, maximum speed—. Being born with microservices there would have been an over-engineering mistake.
Where they're wrong: in two things. First, the word "perfect" is misleading: the architecture wasn't perfect in the abstract, it was perfect for that organization. "Perfect" is always relative to the organization, just as "the best car" is relative to what you want it for. Second, and more importantly: they didn't "ruin" it by changing the code —the code is still the same—; the misalignment was caused by changing the organization without evolving the architecture. Blaming the deterioration is like blaming the couple for their open-plan house when the family grew: the house wasn't ruined, it became unsuitable for a new family.
Would it still be perfect with fifty engineers in a single team? No, and this is the key. Even if they kept a single team (and therefore 100% intra-team technical alignment), fifty people in one team is a coordination catastrophe —you'll quantify it in lesson 4: fifty people are 1225 communication channels—. The monolith would still be "aligned" in the Conway sense, but the fifty-in-one organization would be unviable. That is: the 2019 architecture doesn't scale even keeping one team, because the problem at that scale isn't the code↔organization misalignment, but that the organization itself (a giant team) doesn't work. The 2019 monolith was right for seven people, not for fifty —under any organization—.
Exercise 3 — Design the evolution that was missing. Knowing what you know, what should Mercado have done at the moment of splitting the people into five squads so as not to end up in row 2? Describe the work that was missing and why it had to go hand in hand with the reorganization, not after.
See solution
What was missing was evolving the architecture at the same time as the organization: when they split the people into the five squads, they should have started splitting the monolith into modules (or services) with boundaries that matched the squads. Concretely:
- Give each squad a module (or service) it owns solely, with a clear API toward the others. product_catalog+search for catalog; the order flow for orders; charging for payments; etc. So each squad can change and deploy its piece without asking permission from the others.
- Extract the cross-cutting capabilities (auth, notifications) to a platform squad that offers them as a stable service, so the others consume them without coordinating every change —the x-as-a-service mode of lesson 7—.
- Attack the point of greatest crossing first: checkout, which crosses toward payments, shipping, and platform. Decide who owns it and give it a clean boundary (lesson 5 measures why it's the worst, and lesson 6 solves it).
Why hand in hand and not after: because if you reorganize the teams and postpone the reorganization of the code, you enter row 2 —the worst of the worlds— and you stay there. The "after" doesn't come: once you have five teams fighting over the monolith, each is so busy putting out the fires of expensive coordination that no one has time for the big refactor, and the friction becomes permanent. The window to evolve the architecture is when you change the organization, not months later. Reorganizing teams and architecture are the two halves of the same move; separating them in time is the trap. (The disciplined way to make this move on purpose is the inverse Conway maneuver, lesson 6.)
Summary and next step
In this lesson you discovered the origin of the painful monolith: the monolith is your first org chart, fossilized in code. With the open-plan house you saw that a design can be perfect for the organization that created it and become a torment for the one that inhabits it later, without the design having changed —what changed was the organization—. And you measured it by executing: the same thirteen Mercado dependencies go from 0 cross-team (100% alignment with one team, in 2019) to 8 cross-team (38.5%, with five squads, in 2024), without the code changing a line. You understood that the monolith didn't degrade but misaligned, that being born with a monolith is almost always right (and being born with microservices is over-engineering), and that Mercado's expensive mistake was reorganizing the teams without reorganizing the code —staying in the worst of the worlds: the expensive coordination of five teams without the independence of five services—.
Before moving on you should be able to: explain why a monolith can be perfectly designed for one organization and a torment for another; measure the misalignment by measuring the same code under two organizations; and recognize the half-a-job mistake (splitting the people without splitting the code) and why the two halves go together.
What follows is the economic reason for all this: why growing the organization without splitting it into small teams becomes unsustainable, and why the boundaries start to be worth it at a certain scale. In lesson 4 you'll execute the communication paths formula —n(n-1)/2— and see the coordination cost explode quadratically: 2 people need 1 channel, 10 need 45, 50 need 1225. You'll see, in numbers, why a team of fifty is unviable and why splitting into small teams lowers the coordination by a huge factor with the same people. It's the engine that makes Conway's Law have such expensive consequences —and the quantitative justification for small teams—.
Resources
- Martin Fowler — "MonolithFirst" — Fowler's argument that it's almost always best to start with a monolith and extract services later, not before; the direct backing of this lesson on why being born with microservices tends to be over-engineering.
- Martin Fowler — "Conway's Law" — useful again here for the idea that architecture and organization have to evolve together; the misalignment you measured is what happens when they don't.
- Skelton & Pais — Team Topologies, on "cognitive load" and team size — introduces why a team (or a module) that grows beyond a certain point becomes unmanageable, the concept lesson 4 will quantify with
n(n-1)/2.