DEV Community

loading...
Cover image for Diagramming distributed architectures with the C4 model

Diagramming distributed architectures with the C4 model

Simon Brown
Author "Software Architecture for Developers" | Creator of the "C4 model for visualising software architecture" | Founder at Structurizr | Software architecture training at architectis.je
・5 min read

"I read that C4 is best suited for monolithic architectures and less suited to distributed architectures" ... this is a statement I see frequently, and it isn't true. The C4 model is a hierarchical collection of diagrams based upon a small set of abstractions. There's nothing here that makes it more or less suitable for distributed architectures than UML, ArchiMate, or ad hoc whiteboard sketches. The problem is really one of tooling, and our inability to think past static PNG files.

If you're following Conway's Law, and have different teams owning different parts of your distributed architecture, this post likely isn't for you. This post is really aimed at teams building a distributed monolith - one team, lots of separately deployable microservices and/or lambdas, lockstep deployment, etc. These architectures tend to have lots of elements and relationships at the C4 model container level, making it difficult to create a comprehensive container diagram that's not cluttered, and easy to understand. This tweet sums up the situation well.

"with serverless, you are deploying your UML collaboration diagram!"

Any diagram with 20+ elements (perhaps fewer) starts to get complicated quickly, making it harder to tell the story you want to tell. A complicated architecture will lead to a complicated diagram.

An example

This is an oversimplified example, (and please don't create a distributed architecture that's really just a fragile chain of synchronous services communicating with each other!), but I want to use this example to illustrate some points about diagramming. Many teams would initially approach this by drawing a diagram showing the entirety of their architecture - perhaps showing all of the containers that make up the software system, plus their external dependencies.

Granted this diagram isn't too bad, and this approach will work fine for smaller software systems. It falls apart very quickly once you start getting to 10 services, or 20 services, or 100 services. Although we'd ideally like to create a single diagram that shows everything, it's just not feasible in many cases. That approach to diagramming doesn't scale. You do have some options though.

Option 1: Create a number of smaller diagrams

One of those options is to create multiple diagrams showing a subset of the overall story. You could create diagrams to show a single domain, a bounded context, a business capability, a feature, and so on. Alternatively, you could create diagrams to focus on a single service plus its direct afferent/efferent couplings. Here's an example that focusses on "Service 1" rather than showing all containers.

We do lose some of the "big picture" by doing this, but this diagram is much easier to understand because it has a much more confined scope. A problem with this approach is the same one I outlined in Diagrams as code 2.0 ... we're going to need to repeat elements/relationships across multiple diagrams, and we need a strategy for keeping them all in sync when things change.

And that leads to tooling, and diagramming vs modelling. I've said this before: we need to stop using general purpose diagramming tools for software architecture diagrams (Visio, etc), and we should think carefully before handcrafting diagrams with PlantUML, C4-PlantUML, Mermaid, etc too.

The above diagram that focusses on "Service 1" is trivial to create with any "model + views" tooling. For example, with the Structurizr DSL, once you've defined your overall model, you can create the above diagram like this:

views {
  container softwareSystem {
    include user ->service1->
  }
}
Enter fullscreen mode Exit fullscreen mode

This says, "create a container view showing the user, service 1, and anything directly connected to service 1". It's compatible with a number of diagramming formats too via the Structurizr CLI export command. Here's a PlantUML version of the above diagram, created from the same Structurizr DSL code.

A "model + views" tool provides a quick and easy way to tell different stories from the model, while keeping all resulting diagrams in sync. The Structurizr DSL and CLI are free and open source, plus any good UML tool from the past 20+ years should offer this functionality too, albeit with a very different user experience. Modelling is not new, and we really shouldn't have thrown it away in our haste to become "agile".

Option 2: Use a different visualisation format

With all the computing power available to us, it still amazes me that teams "just want a PNG image to embed in Confluence". Other documentation tools are available, of course.

Traditional static diagrams are fabulous for communication, but they should not be the only tools in your toolbox. Once you relinquish your obsession with static PNG images and jump across the chasm, you might find there are other visualisation formats that are more suited to helping you tell a story.

For example, an interactive force-directed graph is better suited to showing and exploring larger quantities of data. Something like D3.js admittedly has a steep learning curve, but makes this relatively straightforward.

(yes, the irony of posting a static screenshot of an interactive graph is not lost on me, so here's a link to the interactive version)

Alternatively, there are tools like Ilograph, which provides a way to navigate a model using an interactive UI.

(a Structurizr DSL to Ilograph export is available if you don't like writing Ilograph's YAML definition by hand)

Summary

In summary, the C4 model is not less suitable than any of the other alternatives for diagramming distributed architectures. And you have the same set of problems diagramming the components inside a larger monolithic application too. Those problems are related to the size and complexity of the diagram. If a diagram with a dozen boxes is hard to understand, don't draw a diagram with a dozen boxes!

Instead, switch from diagramming to modelling, think about what the story is you're trying to tell, and look at how technology can help you achieve that goal. Diagrams as code 2.0 is a very powerful approach if you're willing to jump across the chasm away from diagramming.

Discussion (0)