The day after the Event Storming an Architecture session that carved Greenbox into four contexts, the team walks into the office and discovers the wall is already starting to betray them.
It’s Friday. The sticky notes from yesterday’s session are still on the wall, mostly, three have come loose overnight and are lying on the floor in front of the heater. Maya picks them up and sticks them back where she thinks they belong. She’s about eighty percent sure. She takes a photograph with her phone and frowns at it.
“Can you read that?” she asks Tom, showing him the photo.
Tom squints. The overhead fluorescents are reflecting off the laminated photographs on the adjacent wall, the ones Charlotte has been calling “the smartest thing Greenbox ever laminated”, and the new session wall is a mess of orange, pink, yellow, and blue notes that the phone camera has turned into a blur of warm tones.
“I can read it if I know what it says.”
“That’s not the same as being able to read it.”
“Agreed.”
Priya comes in with coffees. She looks at the wall, then at the photograph on Maya’s phone, then at the wall again.
“We’re not going to keep the wall,” she says. It’s not a question.
“No,” Maya says. “The office is being painted next week.”
“So what are we going to do with this?” Priya gestures at the whole thing, the four clusters, the pink hotspot notes, the arrows Charlotte drew in red marker, the words “gift activation is still wrong” in Tom’s handwriting near the Subscription cluster.
Nobody has an answer. The wall told them where the boundaries were. The wall is about to not exist. And in a week Kai is going to onboard someone new to the Supply Matching context and they will have no idea what any of this means, because none of it will be on the wall any more.
The Slack problem
By mid-morning the problem has surfaced in Slack, which is where all of Greenbox’s problems surface eventually.
Anika has a question about the Melbourne launch. She joined two weeks ago to run Melbourne operations and she’s trying to understand how the substitution logic will talk to the farm availability data when Melbourne farms start appearing in the system. She can’t see the wall. She can’t see the photograph of the wall. She has read the session notes Tom typed up at midnight, which are reasonably clear about what the contexts are, but which say nothing about how they connect.
Her question, verbatim: “Does the thing that decides substitutions live inside the thing that matches farms to boxes, or is it a separate thing that reads from it? Asking because Jack from the Melbourne farm co-op just asked me how their availability data gets from their portal to our substitution decisions and I gave him an answer that I am now fairly certain is wrong.”
Tom reads it twice. He knows the answer. He was at the session yesterday. He could write a paragraph explaining it. But the paragraph would be wrong, in the sense that Anika would read it and nod and then have the same question again in three days because paragraphs are not how humans understand system shapes.
He Slacks Charlotte: “Remember when you said we needed a way to keep the wall alive after the wall is gone? We need that now.”
Charlotte responds four minutes later: “I’ll be in at 1.”
Charlotte brings a book
Charlotte arrives at 1:15 carrying two things: a laptop and a book. The book is battered, with a coffee ring on the front cover and a cracked spine from being opened too many times at the same page.
She puts the book on the table. Software Architecture for Developers by Simon Brown.
“Before we start,” she says, “I want to be clear about one thing. What we did yesterday. Event Storming, finding the contexts, drawing boundaries on the wall, that was modelling. We were discovering what the system should be. What we’re about to do is documentation. We’re capturing what we discovered so other people can understand it without being in the room. These are different activities. Don’t confuse them.”
Tom leans back. “So we’re writing docs.”
“Sort of. But not Confluence-page-with-a-diagram-somebody-made-in-2019 docs. Living diagrams. Diagrams that live in the code repository and change when the architecture changes.”
“Architecture diagrams in version control.”
“Yes.”
“Huh.”
Charlotte opens the book to a page she’s clearly opened many times before. She puts it on the table and lets the team see.
“This is the C4 model. Simon Brown wrote it, around 2018, as a reaction to exactly the problem you had this morning. He’d watched hundreds of teams draw architecture diagrams that were either too detailed to understand, too abstract to be useful, or different every time a different person drew them. C4 is his answer. Four levels of zoom, each one with a fixed meaning.”
She writes them on the whiteboard:
| Level | Name | Answers |
|---|---|---|
| C1 | System Context | What is this system, who uses it, and what does it talk to? |
| C2 | Container | What are the big independently-runnable pieces inside it? |
| C3 | Component | What's inside one of those pieces, in enough detail to explain it? |
| C4 | Code | What does the actual class / function layout look like? |
“Four levels. You don’t draw all four. Most teams draw one or two. The C4 level is usually a waste of time, your IDE already shows you the code. The useful ones are C1 and C2, most of the time. And you draw them by starting at the top, because that’s how the brain works: first you want to know what the thing is, then you want to know what’s inside it.”
Priya is already nodding. She’s nodded at everything Charlotte said. She loves this. Priya has always wanted the team to write its intentions down in structured ways and be able to refer to them later. She was the one who pushed for conventions around Go package layout back in the 200-subscriber days, and she’s been quietly mourning the loss of that clarity ever since Kai’s 47-file PR.
Tom is not nodding. Tom is looking at the book.
“Simon Brown,” Tom says. “Is this the guy who does those diagrams that look like PowerPoint?”
“Yes.”
“The ones with the boxes and the arrows and the labels on the arrows.”
“Yes.”
“I thought we weren’t drawing UML.”
“It’s not UML. UML has fifty-seven diagram types and none of them mean the same thing to two different people. C4 has four types, and they all mean the same thing every time. That’s the whole point.”
Tom grunts. Charlotte can tell it’s the kind of grunt that means I’m not convinced but I’m willing to watch. That’s fine. She’s not here to convince him with speeches.
Drawing the first C1
Charlotte draws the first C1 on the whiteboard. It’s a square. Inside the square, she writes Greenbox. Around the outside, she draws stick figures and rectangles.
“This is the least detailed diagram you’ll ever see. It says: there is a system called Greenbox. Subscribers talk to it. Farm partners talk to it. Couriers talk to it. Stripe processes our payments. Mailgun sends our email. That’s it.”
She labels the connections:
- Subscriber → Greenbox: manages subscription, views deliveries, updates preferences
- Farm partner → Greenbox: submits weekly availability
- Courier → Greenbox: collects delivery manifests, confirms drop-offs
- Ops team (Sam, Anika, Maya) → Greenbox: runs weekly matching, handles exceptions
- Greenbox → Stripe: charges subscribers
- Greenbox → Mailgun: sends transactional emails
Tom looks at the diagram and his first reaction is that it’s obvious.
“This tells me nothing I don’t already know.”
“Correct,” Charlotte says.
“Then what’s the point?”
“The point is Anika. You knew this. I knew this. Maya knew this. But Anika has been here two weeks and she’s been piecing it together from Slack messages. This diagram tells her, in thirty seconds, what Greenbox is and what it talks to. It’s not for you. It’s for everyone who isn’t you.”
Tom considers that. He has Ava and Leo at home, ten and seven, and he thinks about how often he tells his kids things he thinks are obvious and then discovers they aren’t, because the kids didn’t grow up in his head. The team is growing. Most of them didn’t grow up in Tom’s head either.
“Okay,” he says. “Fine. But obvious is still obvious. What about the stuff that isn’t?”
“That’s C2.”
Drawing the first C2
Charlotte redraws on a fresh section of whiteboard. This time, the Greenbox square is much bigger, and inside it she draws four smaller boxes.
“C2 is the container diagram. A ‘container’ in C4 is anything that runs as a separate process or has independent data, a web application, an API service, a database, a mobile app, a background worker, a message bus. It is not a Docker container, even though Docker came along later and stole the word. Simon Brown was using ‘container’ in this sense before Docker existed.”
Tom snorts. “That’s going to confuse everyone forever.”
“It already does. Move on.”
She draws the four boxes and labels them:
- Subscription, handles signups, pauses, gifts, box size changes, cancellations
- Billing, handles Stripe integration, invoices, refunds, retries
- Supply Matching, handles weekly farm availability, subscriber preferences, substitution decisions
- Fulfilment, handles box packing lists, courier manifests, delivery confirmations
Each box also gets a database cylinder underneath it. Each box also gets notes about the technology, Go service, PostgreSQL, because that’s the level of detail C2 is for.
Then she draws the arrows. The arrows are the important part. Each one is labelled with what crosses it.
- Subscription → Supply Matching: SubscriptionCreated, SubscriptionCancelled events
- Subscription → Billing: SubscriptionCreated, SubscriptionPaused, SubscriptionCancelled events
- Supply Matching → Fulfilment: BoxAllocated, SubstitutionApplied events
- Billing → Fulfilment: PaymentConfirmed event
- Fulfilment → Courier (external): daily manifest upload
- Subscription → Stripe (external, via Billing): (no direct edge)
Priya is staring at the diagram. She takes out her phone, takes a photo, then takes it again with a different framing.
“Charlotte. This is the context map. The one you drew yesterday on the wall. But it’s readable.”
“Yes.”
“Why didn’t we just start here?”
“Because yesterday we didn’t know what the boxes were. You can only draw C2 once you’ve done the Event Storm and decided on the contexts. C4 is downstream of the modelling work. It’s not a substitute for it.”
Priya nods again. Tom looks at the diagram and it clicks for him in a different way than it clicked for Priya.
“Anika’s question,” he says.
“What about it?”
“She asked whether the substitution logic lives inside the farm matching or is a separate thing. If I could have sent her this diagram, she would have seen that substitution lives inside Supply Matching and that Supply Matching publishes SubstitutionApplied to Fulfilment. Done. Thirty seconds.”
“Yes.”
“But the diagram wouldn’t have existed if we hadn’t drawn it.”
“Correct.”
“So we need to draw it, and we need it to be somewhere Anika can find it, and we need it to stay correct as the system changes.”
“Yes. That’s the interesting problem.”
The problem with whiteboards
Tom, who has spent his entire career using whiteboards for architectural conversations and then taking photographs and forgetting about them, says the obvious thing.
“So I take a photograph of this diagram and put it in the repo.”
Charlotte makes a face. Priya makes the same face a fraction of a second later, because Priya always catches on first when structured thinking is about to be needed.
“Two problems,” Charlotte says. “First, the photograph goes stale. The Subscription container split into two sub-containers six months from now and the photograph still shows one box. Second, if someone wants to fix the diagram they have to find a whiteboard, redraw it, and photograph it again. The cost of updating is high, so nobody updates. The diagram stops matching the code. The diagram stops being useful. Everyone stops looking at it. The diagram dies.”
“Okay, so I draw it in Miro.”
“Same problem. It’s out of the repo. It’s owned by whoever had the Miro login. When that person leaves, the diagram is a dead artefact in an account nobody can edit.”
Priya says, quietly, “Diagrams as code.”
“Yes,” Charlotte says. “That’s what we need. Diagrams that are text files that live in the repository next to the code they describe. When you change the code, you change the diagram in the same pull request. The diagram is reviewed alongside the code. When the diagram gets out of date, someone notices in code review, the same way they notice a comment that lies.”
Tom’s ears perk up. Text file. He likes text files. Text files live in repositories. Text files go through pull requests. Text files can be diffed. Text files don’t get deleted when someone’s Miro subscription lapses.
“What’s the text file look like?”
Charlotte opens her laptop.
Structurizr
“There’s a few tools that do this,” she says. “The one Simon Brown built is Structurizr. There’s also Mermaid, which has a C4 mode these days, and there’s Likec4, and there’s diagrams.net with an export. They all have trade-offs. What matters is that the source is text and lives in Git.”
She shows them Structurizr DSL, the domain-specific language Simon Brown built for describing C4 models in text.
workspace "Greenbox" "Produce box subscription service" {
model {
subscriber = person "Subscriber" "Signs up, manages subscription, receives boxes"
farmPartner = person "Farm Partner" "Submits weekly availability"
courier = person "Courier" "Collects manifests, confirms deliveries"
opsTeam = person "Ops Team" "Runs weekly matching, handles exceptions"
greenbox = softwareSystem "Greenbox" "Produce box subscription platform" {
subscription = container "Subscription" "Signups, pauses, gifts, cancellations" "Go, PostgreSQL"
billing = container "Billing" "Invoices, charges, refunds, retries" "Go, PostgreSQL"
supplyMatching = container "Supply Matching" "Farm availability, preferences, substitutions" "Go, PostgreSQL"
fulfilment = container "Fulfilment" "Packing lists, manifests, delivery confirmations" "Go, PostgreSQL"
subscription -> supplyMatching "publishes SubscriptionCreated, SubscriptionCancelled"
subscription -> billing "publishes SubscriptionCreated, SubscriptionPaused, SubscriptionCancelled"
supplyMatching -> fulfilment "publishes BoxAllocated, SubstitutionApplied"
billing -> fulfilment "publishes PaymentConfirmed"
}
stripe = softwareSystem "Stripe" "Payment processing" "External"
mailgun = softwareSystem "Mailgun" "Transactional email" "External"
subscriber -> greenbox "manages subscription, views deliveries"
farmPartner -> greenbox "submits availability"
courier -> greenbox "collects manifests, confirms drop-offs"
opsTeam -> greenbox "runs matching, handles exceptions"
billing -> stripe "charges via API"
subscription -> mailgun "sends lifecycle email"
fulfilment -> mailgun "sends delivery notifications"
}
views {
systemContext greenbox "Context" {
include *
autolayout lr
}
container greenbox "Containers" {
include *
autolayout lr
}
}
}
Tom reads it. It’s about forty lines. It describes the whole diagram.
“Huh.”
“That’s your ‘I can see how this works’ noise.”
“Yeah.”
“Good. The DSL compiles to a rendered diagram. PNG, SVG, whatever, and the source is what lives in Git. When someone adds a new container, they edit the DSL, the diagram regenerates, and the PR shows both the code change and the diagram change together. If someone deletes a container from the code but forgets to update the DSL, you can catch that in review.”
Priya is already thinking two steps ahead. “We can put the rendered diagram in the README. Or in a docs/ directory. Or generate it on every merge to main and push it to an internal site.”
“Yes. All of those. Teams I’ve worked with do all three. The point is that the rendered output lives wherever it’s needed, and the source of truth is the text file.”
Tom’s moment
Tom does a thing Tom does when he’s working something out. He picks up a blue marker and starts drawing on the corner of the whiteboard, away from Charlotte’s diagram. He writes:
- Event Storm → contexts
- Contexts → C2 container diagram
- C2 in DSL → rendered diagram
- Diagram in repo → anyone can find it
- Diagram in PRs → stays accurate
He underlines step 5. Then he underlines it again.
“The wall told us where the boundaries are,” he says. “The C4 diagram lets anyone who wasn’t in the room understand them. And the diagram-as-code thing is the part that makes it not die.”
“Yes,” Charlotte says.
“Okay. I was ready to push back on this. I’m not going to. Let’s do it.”
Maya, who has been quiet for most of this, looks genuinely surprised.
“That’s the fastest you’ve ever agreed to a process change,” she tells Tom.
“It’s not a process change. It’s a tool change. Process changes slow me down. Tool changes make me faster. This is the second one.”
Charlotte doesn’t ask what the first one was. She has a guess. (BDD feature files, probably. Tom came round to those for the same reason, text files, Git, diffable.)
Doing the work
They spend the afternoon on it. Priya writes the Structurizr DSL for the C1 and C2 views. Tom sets up a GitHub Action that renders the DSL into SVG on every push and commits the result to a docs/architecture/ directory. Charlotte writes a one-page README explaining the two diagrams and what each container is for.
The first rendered C1 looks clean, cleaner than the whiteboard version, because Structurizr’s auto-layout is better at spacing than Charlotte’s freehand. The C2 is dense but readable. The arrows all have labels. The colours match the Event Storm legend from yesterday, green for fulfilment, blue for subscription, orange for billing, purple for supply matching.
Priya puts the link in the team channel in Slack, pinned.
Anika, who has been patiently waiting all day for an answer to her substitution question, clicks the link. Two minutes later she messages Tom: “Okay. I see it now. The substitution logic is inside Supply Matching. It publishes SubstitutionApplied which Fulfilment consumes. That’s what I needed. Thank you.”
Tom shows Charlotte the message. Charlotte smiles.
“That’s the whole game. One question, one diagram, one minute to an answer. Multiply that by fifty onboarding questions a year and you’ve saved a working week.”
Where this stops
Charlotte is careful to bound the claim.
“I want to be clear about what C4 is not. It is not a replacement for the Event Storm. It is not a replacement for the boundary conversation we had yesterday. It is not the thing that tells you what to build. It is the thing that captures what you decided to build in a form other people can understand.
“And you should not draw every level. Most of the time, for a team your size, C1 and C2 are all you need. The C3 component diagram is for when a container is internally complex enough to deserve its own zoom, and most containers aren’t. The C4 code-level diagram is almost always a waste. Your IDE is the C4 diagram.
“Do the minimum. Draw it for the same reason you write code comments: because the next person to read it needs the help. If you’re drawing diagrams nobody looks at, stop drawing them. Diagrams that are not read are worse than no diagrams, because they give the impression that the system is documented when it isn’t.”
Tom nods at this. It’s the kind of rule Tom respects, do the thing, but only as much as the thing earns.
What the wall said, and what the diagram says
Late afternoon. The office is thinning out. Kai has gone to pick up his kid. Sam is out at the Perth packing shed. Maya is on a call with a potential Melbourne farm partner.
Priya is still at the diagram. She’s adjusting the DSL to get the layout exactly right, moving Supply Matching slightly so the arrow to Fulfilment doesn’t cross the arrow from Billing. It’s the kind of polish Priya does because it makes the thing work better for the next reader, and Priya always thinks about the next reader.
Tom watches her.
“You’re enjoying this.”
“I am.”
“Why?”
Priya thinks for a moment. “Because I like it when the thing I know how to explain out loud is also a thing that exists as a file. I’ve been explaining this architecture to people for three months. Now I can send them a link. That’s freedom.”
Tom nods. He gets that. Freedom from explaining the same thing over and over. Freedom from being the bottleneck between the code and the understanding. That’s why he likes text files, too.
Charlotte packs up her laptop and the book. The coffee-ringed book. As she walks out she stops by the door.
“One more thing. The wall is going to be painted over next week. Before that happens, take good photographs. Store them in the repository too. They’re not canonical any more, the DSL is canonical, but they’re historical. They’re the record of the conversation that produced the architecture. That matters.”
Maya, who has just come off her call, nods and makes a note.
What comes next
The diagrams are in the repo. Anika has her answer. The wall can be painted over on Monday without the architecture disappearing with it. The team has a new tool in the kit: documentation that travels at the speed of code.
They’ll use it more than they expect. Not every container will earn a C3 zoom, but the one that does will earn it emphatically, and the team will draw it without being asked, because they’ll have learned by then what C4 is actually for.
Next in the story: what Domain-Driven Design actually looks like in Go. For the workshop pattern behind this post, how to run a C4 modelling session from scratch, see The Workshop: C4 Modelling.
The next chapter, Domain-Driven Design: Modelling the Subscription Context in Go, publishes around 10 Jun.