references/case-studies.md
# Case Studies: Team Topologies in Practice
## Table of Contents
- [Case Study 1: A Scale-Up Drowning in Cross-Team Dependencies](#case-study-1-a-scale-up-drowning-in-cross-team-dependencies)
- [Case Study 2: Converting a Bottleneck Ops Team into a Platform-as-Product Team](#case-study-2-converting-a-bottleneck-ops-team-into-a-platform-as-product-team)
- [Case Study 3: Splitting a Monolith Along Fracture Planes](#case-study-3-splitting-a-monolith-along-fracture-planes)
- [Key Takeaways](#key-takeaways)
## Case Study 1: A Scale-Up Drowning in Cross-Team Dependencies
### Context
A 40-engineer logistics SaaS scale-up serves shippers and carriers. Teams are organized by technology: frontend (8), backend (12), mobile (5), QA (6), data/DBA (4), and a "DevOps team" (5) that owns CI/CD and infrastructure. Product managers coordinate features across all six teams.
### The Problems
**Every feature crossed four to five teams.** A typical feature — "let carriers set availability windows" — needed backend endpoints, frontend screens, mobile screens, QA test cycles, and a DevOps ticket for a new queue. Lead time averaged nine weeks, of which roughly two were active work.
**Coordination had become the main job.** A weekly "dependency sync" with 14 attendees managed a spreadsheet of 60+ open cross-team dependencies. Two delivery managers existed purely to chase blocked tickets.
**Quality was nobody's problem.** Backend considered features done at API merge; QA found integration breaks two weeks later; on-call belonged to DevOps, who could restart services but not fix them. Incident retros assigned actions to four teams and none completed.
**The architecture mirrored the org — exactly.** One shared backend monolith with module boundaries matching backend sub-guilds, one shared mobile app, and a CI system only the DevOps team could change. Conway's law was operating, unmanaged.
### The Redesign
**Step 1: Map streams of change (week 1).** Six months of shipped features were sorted by who they served. Three clear streams emerged: shipper booking experience, carrier operations, and billing/settlement. A fourth cluster of work — pipelines, environments, observability — served other teams, not end users.
**Step 2: Design the target topology (week 2).** Four stream-aligned teams (shipper web, carrier web+mobile, billing, and tracking/visibility — added after change-coupling analysis showed tracking changed independently), each 6-8 people and cross-functional: frontend, backend, and embedded QA together. One platform team formed from DevOps plus two backend infrastructure specialists. The QA team dissolved into streams, with the two most senior testers forming a temporary enabling pair for test automation. Cognitive-load check: each stream got one complicated domain at most.
**Step 3: Declare interaction modes (week 2).** Streams ↔ platform: X-as-a-Service for CI/CD and environments, with one declared exception — an eight-week collaboration between the platform team and the carrier team to co-design the new deployment pipeline, the platform's first product iteration. Enabling pair ↔ each stream: facilitating, six weeks per stream, exit criteria written down.
**Step 4: Move ownership artifacts (weeks 3-4).** Repos re-partitioned with CODEOWNERS per stream; on-call moved to streams ("you build it, you run it") with the platform team providing paved-road observability; the dependency spreadsheet and the 14-person sync were deleted on day one of the new structure — deliberately, to remove the safety net that would have preserved old habits.
**Step 5: Checkpoint (weeks 10 and 18).** Flow metrics reviewed; one boundary corrected (tracking absorbed a notification component originally left with billing, after change-coupling data showed it moved with tracking work).
### Results After 5 Months
| Metric | Before | After |
|--------|--------|-------|
| Lead time (median feature) | 9 weeks | 2.5 weeks |
| Teams touched per feature (median) | 4-5 | 1 |
| Open cross-team dependencies | 60+ tracked | 8, all declared modes |
| Deploys per week (org total) | 3 (batched) | 40+ (per-team) |
| Coordination meetings | 6 hrs/week/lead | 1 hr/week/lead |
| Change failure rate | ~28% | ~12% |
### Lessons Learned
1. **Streams were discovered, not invented.** Sorting six months of actual shipped work revealed the streams; designing from the org chart or the architecture diagram would have reproduced the existing silos.
2. **Embedded QA outperformed the QA gate immediately,** but only because the enabling pair existed — streams lacked test-automation skills, and without facilitation the embedded testers would have become four isolated manual-test bottlenecks.
3. **Deleting the dependency spreadsheet was the highest-leverage act.** While it existed, it legitimized cross-team dependencies; without it, a dependency became an exception requiring a declared interaction mode.
4. **One boundary was wrong, and that was fine.** The checkpoint cadence made correcting it routine rather than an admission of failure.
## Case Study 2: Converting a Bottleneck Ops Team into a Platform-as-Product Team
### Context
A 120-engineer fintech runs a central operations team of nine. All infrastructure work — environments, deployments, DNS, certificates, database changes, monitoring — flows through their ticket queue. The ops team is skilled, overworked, and increasingly resented.
### The Problems
**A three-week ticket queue throttled every stream.** Median time to get a new test environment: 16 days. Teams padded sprints with whatever wasn't blocked, inflating WIP everywhere.
**Shadow infrastructure was spreading.** Two product teams had quietly acquired their own cloud accounts on company cards. Security found out during an audit.
**The ops team was burning out.** Five hundred tickets a month, an oncall that paged nightly for systems they didn't write, and no time for the automation they kept proposing. Two of nine had resigned in the previous quarter.
**Mandates were masking failure.** Use of the central deployment tool was mandatory, so its 40-minute, frequently-flaky pipeline had no competitive pressure to improve — complaints were compliance problems, not product feedback.
### The Conversion
**Step 1: Classify the queue (weeks 1-2).** All tickets from the previous quarter were sorted into: automatable (62% — environments, deploys, DNS, certs), teachable (23% — debugging help, config questions), and should-stop (15% — work for systems that had owners). This became the platform roadmap, the enabling backlog, and a stop-doing list respectively.
**Step 2: Define the Thinnest Viable Platform (week 3).** Not a portal, not a Kubernetes abstraction — a single paved road for the top ticket type: self-service ephemeral environments via one CLI command, documented on one page. The team explicitly deferred everything else.
**Step 3: Staff it like a product (week 3).** A product manager was assigned from the product org — the single most contested decision, and later rated the most important. She ran user interviews with eight teams in the first month. Two ops engineers moved into a temporary enabling duo focused on teaching streams to own their own on-call.
**Step 4: Collaborate with first consumers (weeks 4-10).** Two pilot streams adopted environments-as-a-service in a declared six-week collaboration; their friction reports drove daily fixes. After the pilots, the capability went org-wide as X-as-a-Service — docs, office hours, versioned CLI.
**Step 5: Make adoption optional, visibly (week 11).** The deployment-tool mandate was revoked. Teams could use anything that passed the security baseline. This was the platform team's forcing function: capabilities now survived only if chosen.
**Step 6: Drain the queue (weeks 11-24).** Deploys and DNS followed environments onto the paved road. Stream on-call ownership transferred team by team with facilitation. The should-stop 15% was returned to system owners with management backing.
### Results After 6 Months
| Metric | Before | After |
|--------|--------|-------|
| New test environment | 16 days (ticket) | 25 minutes (self-service) |
| Ops/platform ticket volume | ~500/month | ~90/month |
| Deployment pipeline duration | 40 min, flaky | 12 min, 99% pass |
| Voluntary platform adoption | n/a (mandated) | 14 of 16 teams |
| Ops team pages per week | ~35 | ~9 (platform services only) |
| Shadow cloud accounts | 2 known | 0 (pilots migrated back) |
### Lessons Learned
1. **The ticket queue was the requirements document.** Classifying real demand beat any platform vision exercise; the team built what was already being asked for 500 times a month.
2. **Optional adoption changed the platform team's behavior more than the consumers'.** Within weeks the team was writing release notes, fixing onboarding friction, and deprecating features nobody used — product behaviors no mandate had ever produced.
3. **The product manager mattered more than any technology choice.** User interviews killed two planned capabilities that no team actually wanted and surfaced the certificate-automation need nobody had ticketed (they had given up asking).
4. **Burnout fell when the pager matched ownership.** Ops pages dropped 70% once streams owned their services' on-call — and streams' pages were tolerable because they could actually fix what paged them.
## Case Study 3: Splitting a Monolith Along Fracture Planes
### Context
An insurance company's policy administration system: a 15-year-old monolith, 70 engineers in component teams (policy core, batch, integration, UI, DBA), quarterly release train with a six-week regression phase. The board wants monthly releases and a new usage-based product line the monolith cannot price.
### The Problems
**One release train coupled everything.** A one-line pricing change waited up to four months for the next train. Each release bundled hundreds of changes; each regression phase found cross-component breakage.
**Regulatory scope taxed every change.** Solvency reporting requirements subjected the whole monolith to change-control sign-off, though only a fraction of the code computed regulated figures.
**Pricing actuaries and engineers worked at cross purposes.** Pricing logic — the fastest-changing, most revenue-relevant code — was smeared across policy core and batch components, owned by no one.
### The Split
**Step 1: Capability inventory and clustering (weeks 1-2).** An event-storming workshop produced 47 capabilities, clustered into six candidate contexts: quote & pricing, policy lifecycle, claims intake, solvency & regulatory reporting, document generation, and partner integration.
**Step 2: Choose fracture planes deliberately (week 2).** Business domain was the default plane, with two exceptions argued from evidence: solvency reporting split on the *regulatory* plane (isolating change-control to one context), and quote & pricing justified also by the *change cadence* plane — git history showed it changed 6x more often than policy lifecycle. Seam scoring flagged one red seam (policy lifecycle ↔ document generation shared 31 tables); document generation was deferred to phase two rather than forced.
**Step 3: Inverse Conway — form the team first (week 4).** A pricing team (7 people: engineers from policy core and batch plus two actuarial analysts) was formed *before any code moved*, owning the pricing domain in the monolith. For six weeks they shipped pricing changes within the old structure, building shared language — and the case for extraction.
**Step 4: Extract with declared modes (weeks 10-26).** Pricing was extracted strangler-style behind an internal API. Modes were explicit: pricing ↔ policy-core teams in collaboration for eight weeks to define the quote interface, then X-as-a-Service with a versioned contract; a two-person enabling pair facilitated the policy teams' adoption of consumer-driven contract tests; the DBA team's two members joined pricing and reporting respectively, dissolving the shared-database gate. Each extracted context took its tables with it.
**Step 5: Decouple the trains (week 27 on).** The pricing service moved to weekly releases against its contract-test suite. The regulated reporting context kept formal change control — now scoped to 9% of the codebase. The monolith remainder stayed quarterly, by choice, pending phase two.
### Results After 9 Months
| Metric | Before | After |
|--------|--------|-------|
| Pricing change lead time | up to 4 months | 1-2 weeks |
| Code under regulatory change-control | 100% | ~9% |
| Release cadence | quarterly (everything) | weekly (pricing), quarterly (core, by choice) |
| Regression phase | 6 weeks, all hands | 2 weeks, core only |
| Cross-team commits at pricing seam | n/a | <3% of pricing commits |
| New usage-based product | not feasible | priced and piloted |
### Lessons Learned
1. **Two planes beat one.** Domain alone would not have freed pricing from the audit regime; the regulatory plane carved the change-control boundary, and cadence evidence prioritized which context to extract first.
2. **Forming the team before extracting the code made the extraction pull-based.** The pricing team extracted a service they already owned conceptually — scope debates that normally stall such projects were settled inside one team.
3. **Red seams are schedule information.** Deferring document generation (31 shared tables) avoided spending the first phase on the hardest, lowest-value boundary.
4. **Not everything must speed up.** Leaving the monolith remainder on a quarterly cadence was a legitimate topology decision, not a failure — flow was needed at the pricing seam, not uniformly.
## Key Takeaways
**1. Evidence beats opinion at every step.** Shipped-work sorting, ticket classification, and git change-coupling located streams, platform scope, and seams. Every failed reorg these teams had previously attempted started from an org-chart drawing instead.
**2. The sequence is: team first, then code, then cadence.** All three cases moved ownership and communication paths before (or while) moving software — the inverse Conway maneuver in practice. Code-first splits leave old communication structures intact, and the old architecture grows back.
**3. Declared interaction modes did the quiet work.** Time-boxed collaboration, then X-as-a-Service, appears in all three cases as the mechanism that made new boundaries real — and the deletion of generic coordination rituals (dependency syncs, ticket queues, release trains) is what made the declared modes binding.
**4. Optionality and exit criteria keep supporting teams honest.** The platform survived because adoption was voluntary; enabling engagements worked because they ended. Mandates and permanent helpers would have rebuilt the bottlenecks under new names.
**5. Topologies stayed under review.** Each org corrected at least one boundary within months, cheaply, because checkpoints and sensing signals (friction, wait times, on-call pain) were scheduled from the start. The design assumption was evolution, not a final answer.
references/cognitive-load.md
# Assessing and Managing Team Cognitive Load
Cognitive load is the limiting reagent of team performance: a team can only build and run well what it can collectively hold in its head. Team Topologies makes load a first-class design input — software is sized to teams, domains are allocated against explicit heuristics, and overload is detected early rather than discovered through attrition. This reference covers how to assess load in practice, the team API template that reduces inter-team load, domain-allocation heuristics, and the warning signs of overload.
## The Three Types of Load, Applied to Teams
Borrowed from Sweller's cognitive load theory and reinterpreted at team scale:
- **Intrinsic load** — the skill demands inherent in the work itself: the languages, frameworks, and core technical knowledge needed to do the job at all. *Managed by hiring, training, and pairing — not eliminable, but plannable.*
- **Extraneous load** — the mechanics that surround the work but add no product value: flaky environments, manual deployments, undocumented internal services, ticket queues, six observability tools. *The first target: minimize aggressively via platforms, paved roads, and automation.*
- **Germane load** — the valuable thinking: the business domain, the users, the design trade-offs. *This is what you are buying when you fund a team; protect and maximize it.*
The design goal: spend the team's finite capacity on germane load. Every hour spent fighting environments or deciphering another team's undocumented API is capacity the org paid for and then burned.
## Assessing Team Cognitive Load in Practice
### Start with the one question
The book's simple instrument, asked of the whole team anonymously:
> "Do you feel like you're effective and able to respond in a timely fashion to the work you are asked to do?"
Scale of 1-5. Anything averaging below 4, or with a wide spread, warrants the deeper assessment below. Re-ask quarterly; the *trend* matters more than the absolute number.
### Survey instrument (10 questions, 1-5 agree/disagree)
1. I understand all the parts of the system my team owns well enough to change them confidently.
2. I can get a change to production without waiting on another team.
3. Our tooling and environments mostly stay out of my way.
4. I know who to ask (or where to look) when I need something from another team — without a meeting.
5. On-call for our services feels manageable and fair.
6. I have time to learn the domain, not just close tickets.
7. We rarely context-switch between unrelated domains in the same week.
8. New joiners become productive on our team within a few weeks.
9. The number of technologies our team must master feels reasonable.
10. We have slack to improve our own tooling and pay down debt.
Scores of 1-2 cluster diagnostically: low 1/7/9 → too many or too-complex domains; low 2/4 → boundary/interaction problems; low 3/10 → extraneous load, platform gap; low 5 → on-call scope exceeds team scope.
### Count and classify domains
The most decision-relevant assessment is a structured inventory:
1. List every distinct domain of responsibility the team owns — subsystems, products, significant components, recurring duty areas (e.g., "payments reconciliation", "the legacy reporting stack", "GDPR exports").
2. Classify each as **simple** (well-understood, low change, good docs), **complicated** (needs expertise but is analyzable; most established subsystems), or **complex** (high uncertainty, much experimentation: new products, novel tech).
3. Apply the allocation heuristics (next section) and compute the gap.
Most "underperforming" teams turn out to be over-allocated, not under-skilled.
### Measurable proxies
Pull these from existing systems rather than asking:
- **On-call scope:** services per rotation, pages per week, fraction of pages the responder could actually fix. A team paged for systems it cannot change carries pure extraneous load.
- **Tooling sprawl:** distinct languages, frameworks, and operational tools the team touched in the last quarter (repo + CI history shows this).
- **WIP and interrupt rate:** concurrent workstreams per person; fraction of sprint work that arrived mid-sprint.
- **Wait-time map:** for one representative change, hours of active work vs. days of elapsed time; long waits on other teams indicate boundary or mode problems rather than load per se — but teams compensate for waiting with more WIP, which *becomes* load.
## Domain-to-Team Allocation Heuristics
From the book, used as hard defaults rather than aspirations:
1. **One team per domain.** A domain split across two teams produces shared ownership of the seam; both teams slow down.
2. **A team can hold 2-3 simple domains** alongside its main work — but beware: simple domains still cost context-switches.
3. **At most one complicated domain per team.** Two complicated domains do not fit in one collective working memory, even when each looks "only medium-sized" — and do not split one complicated domain across two teams to compensate; transfer one whole domain instead.
4. **A complex domain gets a dedicated team** — and that team should hold *at most* one simple domain besides, preferably none.
5. **Don't allocate a complex and a complicated domain to the same team.** The complicated domain's deadlines will always win, and the complex domain's experimentation will quietly stop.
**Worked example.** A 4-team group owns 9 domains: checkout (complex — new market), payments (complicated), catalog (simple), search (complicated), promotions (simple), the legacy ERP bridge (complicated), invoicing (simple), notifications (simple), and an internal admin portal (simple).
| Team | Allocation | Check |
|------|-----------|-------|
| Team A | checkout (complex) | OK — dedicated; nothing else |
| Team B | payments (complicated) + invoicing (simple) | OK — one complicated + one simple |
| Team C | search (complicated) + notifications (simple) | OK |
| Team D | ERP bridge (complicated) + catalog, promotions (simple) | At limit — watch the survey |
| Unassigned | admin portal (simple) | Candidate for platform absorption or deletion |
The exercise routinely surfaces a remainder like that admin portal — unowned or everywhere-owned software is itself a load source and should be explicitly re-homed, platformized, or retired.
## The Team API Template
A team API treats the team itself as having an interface: everything other teams need in order to interact without a meeting. It reduces *other* teams' extraneous load and protects this team's focus. Publish it where engineers actually look (repo root, internal wiki) and review it quarterly.
```markdown
# Team API: <team name>
_Last reviewed: <date> · Next review: <date>_
## Identity
- Team type: stream-aligned | enabling | complicated-subsystem | platform
- Mission: <one sentence: the stream of change or capability this team exists for>
- Time zone(s) & working hours: <e.g., CET, core hours 10:00-16:00>
## What we own
- Domains: <list, each tagged simple/complicated/complex>
- Services & repos: <name → link, one line each, incl. production status>
- Dashboards & runbooks: <links>
## What we provide to other teams
- <capability/API/service> → docs: <link>, support: <channel>, SLA: <statement>
## How to engage us
- Chat channel: <#channel> (default; we answer within <N> working hours)
- Requests for work: <how — e.g., issue template link>; triaged <cadence>
- Office hours: <when/where>
- Do NOT: <e.g., DM individual engineers for production requests>
## Current interaction modes
- <Team X>: collaboration — <purpose>, ends <date>
- <Team Y>: X-as-a-Service — we consume <their service>
- <Team Z>: facilitating — they coach us on <capability>, ends <date>
## On-call & escalation
- Rotation: <link>; what we are paged for: <scope>
- Escalation: <named role> → <named role>
## Roadmap & priorities
- Now / next / later: <link>
- What we are explicitly NOT doing this quarter: <list>
## Working agreements
- <e.g., trunk-based development; PRs reviewed within 24h; no deploys after 16:00 Friday>
```
The "Do NOT" and "NOT doing this quarter" lines do disproportionate work: they convert recurring boundary skirmishes into a published, reviewable decision.
## Warning Signs of Overload
Watch for these before the survey says it out loud:
- **Perpetual looking-it-up:** the team owns code no member can explain without reading it first — ownership has gone shallow
- **Improvement work always slips:** every retro action item dies; debt items are bumped every sprint for three months
- **Rising WIP:** people run 3-4 concurrent tasks to mask wait states
- **Defensive planning:** the team pads estimates and resists any new scope, even trivial — a rational response to hidden load
- **On-call dread:** pages routinely require waking a second specific person; vacation handovers take days of prep
- **Hero dependence:** one person is on every incident call; bus factor of 1 on a complicated domain
- **Quality oscillation:** incident clusters after each delivery push, then a freeze, then another cluster
- **Recruiting can't keep up:** the team believes "we just need more people" — but new joiners take quarters to be useful because the domain set is too broad
**Responses, in order of preference:**
1. **Shed domains** — transfer a whole domain to another team or a platform (fastest, most effective)
2. **Cut extraneous load** — adopt platform services, delete bespoke tooling, automate the top recurring toil item
3. **Split the software, then the team** — if one domain has outgrown any single team, split it along a fracture plane into team-sized pieces first
4. **Add people last** — and only within Dunbar limits (~9); beyond that, you are creating two teams and should design them deliberately
Headcount as the first response is the classic mistake: it raises coordination load immediately and only dilutes domain load after months, if ever.
references/fracture-planes.md
# Fracture Planes: Splitting Software for Team Ownership
A fracture plane is a natural seam along which a software system can be split so that each resulting piece fits one team's cognitive load and can be owned outright. Splitting along natural seams keeps most changes inside a single team; splitting along arbitrary ones (or technology layers) converts every feature into a cross-team project. This reference catalogs the planes with selection criteria, walks through a monolith-to-team-ownership mapping exercise, shows how to align with DDD bounded contexts, covers the options for shared code, and gives a sequencing plan for an inverse Conway reorg.
## The Fracture-Plane Catalog
**1. Business domain (bounded context) — the default.** Split along the business's own conceptual seams: ordering, payments, fulfillment, identity. Changes cluster within domains because business requests arrive in domain language, so domain-aligned pieces localize change best. *Choose when:* almost always, as the starting hypothesis. *Watch out for:* contexts drawn from the current database schema rather than from the business — schema reflects yesterday's org (Conway in reverse).
**2. Regulatory compliance.** Isolate the parts subject to a heavy regime (PCI-DSS, HIPAA, SOX, medical-device class rules) so audits, change controls, and sign-offs apply to a small surface instead of the whole system. *Choose when:* compliance overhead measurably slows unregulated work. *Watch out for:* the regulated piece still needs a clear domain identity, or it becomes a dumping ground "because it's already audited."
**3. Change cadence.** Separate parts that change weekly from parts that change yearly so the slow part's caution stops throttling the fast part. *Choose when:* release trains exist mainly because one stable subsystem demands heavyweight verification. *Watch out for:* cadence differences that are actually symptoms of missing tests — fix the tests before fracturing.
**4. Team location / time zone.** Split so that each piece is owned within one time zone band; follow-the-sun handoffs inside a single codebase produce miscommunication at the seam. *Choose when:* the org is genuinely multi-site and intends to stay so. *Watch out for:* using geography to avoid fixing a domain split that is wrong everywhere.
**5. Risk.** Separate high-risk-tolerance surfaces (experimental features, growth experiments) from low-risk-tolerance ones (billing, ledger), letting each run an appropriate change process. *Choose when:* one risk regime is imposing its ceremony on everything. *Watch out for:* "risky" used as a euphemism for "untested."
**6. Performance isolation.** Carve out the part with extreme performance or scale needs (a matching engine, a real-time bidder) so it can use specialized technology and tuning. *Choose when:* a hot spot's requirements differ by an order of magnitude. *Watch out for:* premature extraction before a profile proves the hot spot.
**7. Technology.** Split where a genuinely different technology demands different expertise — firmware vs. cloud backend, native mobile vs. web. *Choose when:* the skill sets barely overlap and hiring confirms it. *Watch out for:* this is the most abused plane — frontend/backend/database splits create handoff chains through every feature. Treat technology as a last resort, not a habit.
**8. User personas.** Split by who is served — consumer app vs. enterprise admin vs. internal back-office — when each persona's needs evolve independently. *Choose when:* personas have distinct pace, compliance, or support profiles. *Watch out for:* shared underlying capabilities (identity, billing) still need a home; expect a platform team to emerge.
**Selection summary:**
| Plane | Choose when | Primary risk |
|-------|-------------|--------------|
| Business domain | Default — start here | Contexts drawn from schema, not business |
| Regulatory | Compliance taxes everything | Regulated piece becomes a dumping ground |
| Change cadence | Slow part throttles fast part | Masking a testing gap |
| Location/time zone | Multi-site is permanent | Avoiding the real domain question |
| Risk | One risk regime taxes all | "Risky" = untested |
| Performance | 10x divergent requirements | Premature extraction |
| Technology | Truly disjoint expertise | Recreating layer silos |
| User personas | Independent persona evolution | Shared capabilities left homeless |
**The litmus test for any candidate split:** *could this piece plausibly be offered as a separate service or SaaS, with its own API, docs, and on-call?* If imagining that exposes a tangle of shared state and chatty calls, the seam is wrong — keep looking.
## Exercise: Monolith-to-Team-Ownership Mapping
A one-to-two-day workshop, repeated as needed. Participants: tech leads of affected teams, an architect, a product lead, someone with git-history tooling.
**Step 1 — Inventory capabilities (2-3 hours).** List what the system *does* in business terms (event storming or a capability map both work): "quote a policy", "settle a payment", "generate the picking list". Aim for 20-60 capabilities, written on cards. Ignore module names; they encode the old org.
**Step 2 — Cluster into candidate contexts (1-2 hours).** Group capabilities that share language and change together into 4-10 candidate bounded contexts. Name each in business language. Disagreements about where a card belongs are data — park them on a "contested" list; they usually mark the real seams.
**Step 3 — Score the seams with evidence (2-3 hours, partly offline).** For each pair of adjacent candidate contexts, measure coupling:
- **Change coupling:** from 6-12 months of git history, how often do commits touch both candidates? (Tools: `git log` co-change analysis, CodeScene-style hotspots.) High co-change across a proposed seam = wrong seam or missing third context.
- **Data coupling:** which tables/collections would both sides need? Every shared table is future API or future pain.
- **Runtime coupling:** would a request routinely cross the seam synchronously more than once?
Score each seam red/amber/green. Only green and amber seams are viable near-term splits.
**Step 4 — Overlay teams and cognitive load (1 hour).** Map current teams onto the candidate contexts. Classify each context simple/complicated/complex and apply the allocation heuristics (one complicated domain per team, etc.). This yields the target ownership map — and usually exposes one context too big for any team, which must itself be split before assignment.
**Step 5 — Mark the shared code (1 hour).** List code used by multiple candidate contexts: utility libraries, the auth module, the ORM layer, shared test fixtures. Tag each with its disposition (see shared-code options below). Do not leave any item untagged; untagged shared code defaults to shared ownership, which is the thing being eliminated.
**Step 6 — Choose interaction modes per seam (30 min).** For each dependency in the target map, declare the intended mode: which seams become X-as-a-Service (and need an interface invested in), which need a temporary collaboration during extraction, where an enabling team should assist.
**Step 7 — Sequence (1 hour).** Pick the first one or two extractions by: (a) high change rate (payoff is proportional to change frequency), (b) green seam score, (c) a willing, non-overloaded receiving team. Write down the sequence and the checkpoint dates. Resist sequencing more than two moves ahead — later moves should incorporate what the first ones teach.
**Output:** a one-page target map (contexts → owning teams → interaction modes), a shared-code disposition list, and a two-step sequenced plan.
## Aligning with DDD Bounded Contexts
Fracture planes and Domain-Driven Design are mutually reinforcing: a bounded context — the boundary within which a model and its ubiquitous language stay consistent — is the ideal team-sized unit of software. Practical correspondences:
- **One team per bounded context; a team may own more than one small context** (subject to load heuristics), but a context split across teams fractures its language and model
- **Context maps translate directly to interaction modes:** customer-supplier ≈ X-as-a-Service with a roadmap voice for the consumer; partnership ≈ collaboration (time-box it); conformist ≈ X-as-a-Service where the consumer adapts wholesale; anticorruption layer = the consumer protecting its model — a cheap, often-right default at new seams; shared kernel ≈ shared ownership — treat as a temporary state to engineer away
- **Ubiquitous language is a team API concern:** each team's glossary belongs in its team API page; translation happens at the seams, explicitly
If the org has no DDD practice, the mapping exercise above is a sufficient lightweight substitute; if it has one, reuse its context map as Step 2 input and spend the saved time on Step 3 evidence.
## Handling Shared Code
Every monolith split strands code that multiple contexts use. Four dispositions, in default order of preference:
1. **Single owner.** Assign the code to the team that changes it most (git history settles this); other teams become consumers via an internal package with semver releases. Cheap, honest, works for most utility code.
2. **Platform extraction.** When the shared code is infrastructure-shaped (auth, feature flags, messaging adapters) and several streams need it long-term, move it behind a platform team's product surface with docs, versioning, and support. Costs the most; pays off when consumer count is high.
3. **Inner source with a steward.** The code stays open to PRs from any team, but one named steward team reviews, releases, and owns quality. Suits slow-moving code with occasional cross-team needs. Requires real review capacity in the steward team's budget — unfunded stewardship is shared ownership in disguise.
4. **Duplicate and diverge.** Copy the code into each context and let the copies drift. Heretical and frequently right for small, stable code (validation helpers, DTOs): duplication is cheaper than coordination when the code is cheap and the coordination is not.
Decision guide: high change rate + many consumers → platform extraction; high change rate + few consumers → single owner; low change rate + many consumers → inner source; low change rate + few consumers → duplicate.
## Sequencing a Reorg with the Inverse Conway Maneuver
The inverse Conway maneuver means changing the team structure *first* so the desired architecture becomes the path of least resistance. Sequencing that works:
1. **Sketch the target architecture** at context-map granularity — boxes, owners, interaction modes. Resist detail; teams will discover it.
2. **Design the team topology to match:** team types, sizes against cognitive load, declared interaction modes. This is an architecture document and should be reviewed by the same people who review architecture.
3. **Communicate the why before the what.** Teams that understand "we are reshaping teams to get this architecture" cooperate; teams that experience an unexplained reorg resist by routing around it — and their old communication paths will faithfully rebuild the old architecture.
4. **Move one or two teams at a time.** Re-form the first new team (e.g., the future pricing team) *before* extracting its software, and let the team pull the extraction rather than receiving it.
5. **Re-point the supporting systems immediately:** repos and CODEOWNERS, CI pipelines, on-call rotations, dashboards, cost centers, and chat channels must match the new boundaries within days — every system still wired to the old structure is a Conway force pulling backward.
6. **Declare transition modes:** explicit, end-dated collaboration between the old and new owners of any moved code; facilitation from an enabling team where capability gaps would otherwise stall the move.
7. **Checkpoint on flow evidence:** at +6 and +12 weeks, check cross-team change frequency at the new seams, wait times, and the one-question load survey. Adjust the next move based on what these show.
**Pitfalls:** big-bang reorgs (all boundaries change, nothing works, no one can tell which change caused what); renaming teams without changing ownership (the communication paths — and therefore the architecture — stay exactly where they were); splitting the code but keeping one shared database (the monolith survives in the schema and every "service" still coordinates through it); and leaving incentives unmoved (if managers are still rewarded for component throughput, components are what you will get).
references/interaction-modes.md
# The Three Interaction Modes in Practice
Team Topologies allows exactly three ways for two teams to interact: collaboration, X-as-a-Service, and facilitating. Everything else — "alignment", "syncing", "working closely with" — is an undeclared mode, and undeclared modes are where organizational friction breeds. This reference covers the mechanics of each mode, how to declare modes explicitly, how to time-box collaboration, how to design service interfaces, a facilitation playbook for enabling teams, and the patterns and triggers for evolving modes over time.
## Mode 1: Collaboration
Two teams work closely together for a defined period to discover something neither could discover alone: a new technology approach, a missing interface, a novel product capability.
**Use when:**
- The boundary between the teams' responsibilities is genuinely unknown
- High-stakes discovery requires both teams' expertise simultaneously (e.g., a stream team and a platform team designing a new deployment model)
- Rapid innovation matters more than predictable delivery, for a bounded period
**Mechanics:**
- Define a joint goal and a hard end date before starting (see time-boxing below)
- Create one shared channel and, ideally, shared working sessions several times a week; partial overlap (a few people from each team) is the common form — full-team merging is rare and costly
- Make decisions jointly within the collaboration scope; do not route them up two management chains
- Capture what is being discovered continuously — especially any interface taking shape — because the artifact of a good collaboration is usually the contract that lets the teams stop collaborating
**Costs to budget for:** Both teams' cognitive load rises (each must absorb part of the other's context). Delivery predictability drops for both. Boundary blur means mistakes in either domain temporarily belong to both teams. This is why collaboration is powerful and why it must be rationed: one collaboration at a time per team, as a hard rule of thumb.
## Mode 2: X-as-a-Service
One team consumes something another team provides — a platform capability, a complicated subsystem's API, a data product — with minimal coordination. The provider owns the "X"; the consumer uses it without needing to know its internals.
**Use when:**
- The interface is well understood and reasonably stable (often the *output* of an earlier collaboration phase)
- Many teams need the same thing and per-consumer coordination would not scale
- Predictable delivery matters more than joint innovation
**Mechanics:**
- The provider treats the service as a product: documented, versioned, supported, with a feedback channel
- The consumer files no tickets for routine use — self-service is the defining property
- Coordination is limited to roadmap-level signals (what consumers need next) and incident-level communication
**Designing the service interface.** The interaction only stays cheap if the interface absorbs the coordination. Checklist for the provider:
- [ ] Quick-start that gets a new consuming team to "hello world" in under a day
- [ ] Reference docs generated from the source of truth (API spec, schema), not hand-maintained
- [ ] Versioning policy with explicit deprecation windows (e.g., N-1 supported for 6 months)
- [ ] Error messages that tell the consumer what to do, not just what failed
- [ ] Status page or equivalent, plus an incident communication channel
- [ ] A single, well-known request path for new needs — and a published triage SLA for it
- [ ] Usage metrics per consumer, so the provider can see adoption and pain without asking
**Failure smell:** if consuming the service routinely requires meetings with the provider, you do not have X-as-a-Service; you have collaboration with worse hygiene. Either invest in the interface or formally switch modes.
## Mode 3: Facilitating
One team (almost always an enabling team) helps another acquire a capability: a practice, a technology, a way of working. The facilitator's output is the other team's increased ability, not delivered software.
**Use when:**
- A stream-aligned team has a capability gap that would be slow or wasteful to close alone
- The organization is rolling out a new practice (observability, test automation, threat modeling) across many teams
- A team is about to take ownership of something new (e.g., absorbing a component) and needs a bridge
**Facilitation playbook** (for the enabling team):
1. **Assess (week 0):** observe the team's actual workflow; agree on the gap in the team's own words. Output: a one-page engagement brief — current state, target capability, exit criteria, end date.
2. **Agree the working pattern:** typically 2-3 pairing sessions per week plus one workshop, embedded in the team's real work. Never a parallel side project.
3. **Work on real tasks:** the stream team's backlog items are the training material. The facilitator pairs and coaches; the stream team's hands stay on the keyboard.
4. **Transfer artifacts deliberately:** templates, checklists, starter repos, runbooks — things that outlive the engagement.
5. **Taper:** halve facilitator involvement in the final third; the team runs the practice alone while support is still nearby.
6. **Exit and verify:** end on the agreed date. Four to six weeks later, check the exit criteria again (is the team still doing it unaided?). Publish what was learned for other teams.
**Hard rules:** the facilitator does not own deliverables, does not appear on the stream team's on-call, and does not extend the engagement without a new, explicit brief. Extensions by inertia are how enabling teams decay into dependencies.
## Declaring Modes: Team Interaction Contracts
Every pair of teams that interacts regularly should have a declared mode, recorded where both teams' members will see it (each team's team API page is the natural home). A lightweight contract template:
```markdown
## Team Interaction: <Team A> ↔ <Team B>
- Mode: collaboration | X-as-a-Service | facilitating
- Purpose: <what this interaction exists to achieve>
- Direction: <who provides / who consumes / who facilitates whom>
- Started: <date> Review/end date: <date — mandatory for collaboration & facilitating>
- Success criteria: <observable outcomes, e.g. "interface v1 published", "team deploys unaided">
- Channels: <shared channel, office hours, request path>
- Escalation: <named person per team>
```
Declaring modes does three things. It sets expectations (a team that knows it is a service consumer stops requesting design meetings). It bounds cost (collaboration has an end date by construction). And it creates a review point — every contract has a date at which the mode is deliberately re-chosen rather than drifting.
A team's full set of declared interactions is also a load check: a stream-aligned team with two collaborations, three service dependencies, and a facilitation underway is over budget regardless of how reasonable each item looks alone.
## Time-Boxing Collaboration
Collaboration without an end date converges on permanent mutual dependency. Defaults that work:
- **Discovery spike between two teams:** 2-4 weeks
- **New platform capability co-design:** 4-8 weeks
- **Major boundary change (component absorption, service extraction):** 6-12 weeks, reviewed at the midpoint
At the end of the box, there are exactly three legitimate outcomes: (1) switch to X-as-a-Service because the interface is now known; (2) end the interaction because the discovery is done; (3) renew the collaboration once, explicitly, with a new goal — renewal by silence is not an option. If a collaboration gets renewed twice, treat it as a topology signal: the team boundary is probably in the wrong place, and the teams may need merging or re-splitting along a different fracture plane.
**Ending well:** the last week of any collaboration is for hardening the artifacts that let the teams separate — the API contract, the runbook, the ownership map. A collaboration that ends without these will quietly restart within a month.
## Mode Evolution: Patterns and Triggers
Modes are temporary by design. The canonical evolution patterns:
**Collaborate → X-as-a-Service.** The standard maturation path. A stream team and a platform team collaborate to discover what a capability must do; once the interface stabilizes, the relationship drops to service mode and coordination cost falls by an order of magnitude. Trigger: change requests to the interface become rare and backward-compatible.
**X-as-a-Service → collaborate (temporarily).** When a consumer needs something qualitatively new from a provider — a new class of capability, a 10x scale change — service mode produces a frustrating ticket ping-pong. Declare a short collaboration to co-design the change, then drop back to service mode. Trigger: a consumer's requests keep being rejected as "not how the API works."
**Facilitating → nothing.** The enabling engagement ends and the teams stop interacting, by design. Trigger: exit criteria met. (If the relationship instead morphs into "just keep helping", return to the playbook's hard rules.)
**Collaboration as adoption accelerant.** When a platform ships a major new capability, briefly collaborating with the first one or two consuming teams beats documentation alone — the platform team learns where the friction is, and the early consumers become references for the rest.
**Triggers to switch, summarized:**
| Signal | Current mode | Move to |
|--------|--------------|---------|
| Interface change requests now rare and compatible | Collaboration | X-as-a-Service |
| Consumer needs are qualitatively new; tickets bounce | X-as-a-Service | Time-boxed collaboration |
| Provider attends consumer's planning every week | "X-as-a-Service" (nominal) | Real collaboration, or fix the interface |
| Exit criteria met; team performs practice unaided | Facilitating | None |
| Collaboration renewed twice | Collaboration | Re-examine the team boundary itself |
| Many consumers ask the provider for the same thing | Many 1:1 interactions | Platform capability + X-as-a-Service |
## Interaction Friction as Organizational Sensing
Treat recurring friction between two teams as data about the design, not about the people:
- **Collaboration feels endless** → the boundary between the teams is wrong; revisit the fracture plane
- **Service feels bureaucratic** → the provider lacks product discipline, or the thing should not be a service at all
- **Facilitation is resented** → the capability was imposed top-down rather than pulled by the team; fix the demand side first
- **No interaction where the architecture says there should be one** → an interface is being designed by accident; expect integration surprises
Review these signals on a regular cadence (a quarterly topology review works for most orgs) and make one deliberate change at a time — modes first, boundaries second, since mode changes are cheaper and often sufficient.
references/team-types.md
# The Four Team Types in Depth
Team Topologies restricts organizations to four fundamental team types. The restriction is the point: when every team is one of four well-understood types, every other team knows what to expect from it, gaps and overlaps become visible, and "miscellaneous" teams that quietly accumulate unowned work cannot hide. This reference covers each type's responsibilities, staffing, success metrics, and failure modes, then gives procedures for converting existing teams and a decision guide for classifying ambiguous ones.
## Stream-Aligned Teams
A stream-aligned team is aligned to a single, valuable stream of work: a product, a service, a user journey, a user persona, or a market segment. It is the primary team type — the other three exist only to reduce its load. In a healthy organization, the large majority of teams are stream-aligned (rough guide: six to nine stream-aligned teams for every other-type team).
**Responsibilities:**
- Own a slice of business change end to end: discovery, design, build, test, deploy, operate, support, and retire
- Ship safely, independently, and frequently without requiring handoffs to other teams
- Stay close to users: consume usage data, run experiments, talk to customers
- Carry the on-call rotation for what they build ("you build it, you run it")
- Continuously improve their own flow: reduce batch size, shorten feedback loops
**Staffing:** Cross-functional by definition. The team must contain — not have access to, contain — the capabilities its stream requires: application development, design/UX where relevant, testing and quality, operability and infrastructure literacy, security awareness, and product/metrics literacy. Typical size 5-9 people. Not every member is a specialist in everything; the team as a whole covers the set.
**Success metrics:** Flow of change. The four key metrics from *Accelerate* work well: deployment frequency, lead time for changes, change failure rate, and time to restore service. Add team health (regular survey) and the cognitive-load check ("can you respond effectively and in a timely fashion to the work you are asked to do?").
**Failure modes:**
- **Feature team in disguise** — builds features but throws them over a wall to ops or QA; the handoff makes it a component team with extra steps
- **Too many domains** — three products and a legacy system on one team; ownership goes shallow and reactive
- **Starved of operability skills** — "cross-functional" on paper, but no one can debug production, so an ops team gets pulled in for every incident
- **Backlog colonization** — other teams or stakeholders inject work directly, destroying the team's ability to manage its own flow
## Enabling Teams
An enabling team grows capabilities in stream-aligned teams. It is composed of specialists in a given technical or product domain who actively research ahead of need, then bridge the gap — through pairing, coaching, and short engagements — so stream-aligned teams acquire the capability without halting delivery to learn it from scratch.
**Responsibilities:**
- Understand the obstacles and missing capabilities of stream-aligned teams (by asking and observing, not by audit)
- Research new methods, tools, and practices before streams need them
- Run time-boxed engagements that transfer capability: pairing, workshops, starter kits, curated guidance
- Promote learning across teams: write up findings, maintain internal guidance, connect teams with similar problems
- Disengage on schedule and verify the capability stuck
**Staffing:** Senior practitioners with strong coaching instincts. The job is making other teams better, not being the best in the room. Small teams (2-5) are typical. People who need to own production systems to feel useful are a poor fit.
**Success metrics:** Capabilities transferred and engagements exited on time. Concretely: the stream team performs the practice unaided N weeks after exit; engagement NPS from the stream team; lead-time or quality improvement in the streams served. Never tickets closed, and never lines of code delivered into stream codebases.
**Failure modes:**
- **Permanent dependency** — the engagement never ends; the enabling team becomes a shared-services bottleneck wearing a nicer name
- **Doing instead of teaching** — the specialists implement the capability themselves; the stream learns nothing and the work decays after exit
- **Ivory tower** — produces standards documents and tech radars no stream asked for; measured by output, not uplift
- **Gatekeeping** — drifts into approval workflows ("all designs must be reviewed by..."), which inverts its purpose
## Complicated-Subsystem Teams
A complicated-subsystem team owns a part of the system that depends on deep specialist knowledge — heavy mathematics, machine learning, audio/video codecs, real-time trading logic, low-level hardware interfacing. The split exists to spare stream-aligned teams from having to grow and retain rare expertise, not to centralize anything that merely looks hard.
**Responsibilities:**
- Build and run the specialist subsystem behind the simplest possible interface
- Hide internal complexity: consumers should integrate in days, not quarters
- Prioritize according to the needs of the streams that consume the subsystem
- Keep the subsystem's scope tight; resist absorbing adjacent "hard" work
**Staffing:** A small number of genuine specialists (often PhD-level or long-tenured domain experts) plus engineers who productize their work. This is the rarest type — most organizations need zero or one.
**Success metrics:** Subsystem quality and the integration experience of consuming teams: correctness/performance of the subsystem, time for a stream team to integrate, and absence of the subsystem from stream teams' incident causes.
**Failure modes:**
- **Scope creep** — becomes "the hard problems team" and accumulates unrelated complexity, recreating a component-team bottleneck
- **Genius silo** — knowledge concentrated in one or two heads; no productization, so every consumer needs a meeting
- **Created by vanity** — formed because the technology is fashionable, not because the cognitive load is real; the test is whether stream teams could plausibly own it themselves
## Platform Teams
A platform team provides internal services and tooling that reduce the cognitive load of stream-aligned teams: deployment pipelines, environment provisioning, observability, identity, data infrastructure. The defining stance is *platform as a product*: internal teams are customers who choose to adopt it because it is the easiest, safest path — a paved road, not a toll gate.
**Responsibilities:**
- Provide self-service capabilities with clear APIs, docs, and onboarding — consumable without filing a ticket
- Treat developer experience as the product's UX: research user needs, watch teams use the platform, fix friction
- Publish a roadmap, SLAs, versioning and deprecation policies; support what is shipped
- Curate as much as build: a Thinnest Viable Platform can be a wiki page of vetted services and how to use them
- Measure adoption and load removed, not features shipped
**Staffing:** Engineers with strong product sensibility plus an actual product manager (this role is routinely skipped and routinely fatal to skip). Platform groups in larger orgs are themselves composed of stream-aligned-style teams per platform capability, fronted by one coherent platform experience.
**Success metrics:** Voluntary adoption rate; time-to-X for streams (time to first deploy, time to new environment, time to onboard a service); developer experience survey scores; reduction in stream-team extraneous load (fewer tools each stream must master); platform reliability against published SLAs.
**Failure modes:**
- **Mandate instead of merit** — adoption enforced by policy; quality feedback disappears and the platform decays into bureaucracy
- **Ops rebadged** — the old ticket queue with a new name; nothing is self-service
- **Build-it-and-they-will-come** — a year of platform construction with no internal user research; streams keep their shadow tooling
- **Bottomless scope** — the platform tries to serve every conceivable need; cognitive load moves into the platform team instead of being removed from the system
## Converting Existing Teams
Most adoptions of Team Topologies start from an existing org chart, not a blank page. Common conversions:
### Component team → stream-aligned team
1. **Identify the streams** the component currently serves and the change types it receives (use 6-12 months of ticket/PR history)
2. **Choose a destination per person, not per team** — component specialists usually disperse into the stream-aligned teams that consumed their component most
3. **Re-home the component itself:** give it one owning team (the stream that changes it most), extract it to the platform if several streams genuinely share it, or schedule it for absorption/deletion
4. **Run a transition period** with an explicit collaboration mode between old members and receiving teams (4-8 weeks), then dissolve the old channel and queue
5. **Verify with flow metrics:** cross-team tickets touching the old component should approach zero
### SRE/ops team → platform team or enabling team
Decide which based on what the org needs removed: if streams need *services* (pipelines, environments, observability), convert to a platform team; if streams need *skills* (operability, incident response, SLO thinking), convert to an enabling team. Often it is both, in sequence — enable first, productize the recurring needs second.
1. Inventory the ticket queue; classify each recurring request as automate (platform candidate), teach (enabling candidate), or stop doing
2. Stand up self-service for the top two or three request types before closing the queue
3. Move stream on-call responsibility to streams gradually, with facilitating support
4. Assign a product manager and publish the platform's team API
5. Track queue volume: it should trend toward zero as self-service and capability take over
### QA team → embedded + enabling
Disband the central gate; embed test-minded engineers into stream-aligned teams; keep a small enabling team that raises testing capability across streams for a few quarters, then re-evaluate whether it is still needed.
### Architecture team → enabling (mostly)
Standing architecture boards that approve designs are queue-based gatekeepers. Convert architects into a small enabling group that works *with* teams part-time, plus participation in topology design itself — deciding team boundaries is now a core architecture activity.
## Decision Guide: Which Type Is This Team Really?
Ask in order; the first "yes" usually classifies the team:
1. **Does the team own a slice of business value end to end, with its own users?** → Stream-aligned
2. **Do other teams consume what this team provides via self-service or an API?** → Platform (if via tickets and meetings instead: a shared-services team that needs converting)
3. **Is the team's main output other teams getting better at something, with engagements that end?** → Enabling (if engagements never end: a dependency, not an enabler)
4. **Does the team own a subsystem that genuinely requires rare specialist knowledge?** → Complicated-subsystem (if the knowledge is ordinary: a component team that should dissolve into streams)
5. **None of the above?** → It is a coordination artifact (project team, "alignment" team, ticket router). Plan its conversion or dissolution.
Cross-checks that catch common misclassifications:
| The team says | It is probably | Because |
|---------------|----------------|---------|
| "We build features, another team deploys them" | Component team, not stream-aligned | End-to-end ownership is missing |
| "We're the platform team" (but work arrives as tickets) | Shared services, not platform | No self-service product exists |
| "We help other teams" (engagement has lasted 2 years) | Dependency, not enabling | Capability transfer never completes |
| "Our system is too complex for normal teams" | Possibly component team | Test the specialism claim against hiring reality |
| "We own the API layer / the database / the frontend" | Component team | Technology layer, not a stream or true subsystem |
When in doubt, classify by *cognitive load effect*: a team that reduces other teams' load while staying out of their critical path is platform or enabling; a team that sits in other teams' critical path is either stream-aligned (fine) or a bottleneck (fix).