Writing good software architecture diagrams

Jan Christian Alvestad
5 min readFeb 22, 2023

--

Software architecture diagrams come in all shapes and sizes.

Since early in my career I have been subjected to many different diagrams which certainly did not lack in creativity.

However, most (all?) of them failed to capture and communicate what is important in a clear and concise manner.

Some started out at a high level and suddenly boiled down to a low level view of what it was trying to communicate — or they used different color coding schemes to emphasize significance. Others had the opinion of “size matters” and used bigger boxes for important things (yet over time — those small boxes grew to bigger components and it lost all relevance).

I have done many of the same sins — In many different tools. Whiteboard, MS Paint, Photshop, Gliffy, draw.io, Visio — you name it, I’ve done it.

Countless hours have been spent updating these diagrams, and many more trying to align arrows and angles in perfect orientation (to scratch my inner feng shui alignment OCD).

So what has been my redemption?

The “C4 model

Being less destructive than it might initially sound — A C4 model is represented by a set of diagrams that each describe a different level of detail about your software code. These different levels help you to communicate abstract ideas in a visual way and from different points of view.

Shameless plug from wikipedia:

The C4 model documents the architecture of a software system, by showing multiple points of view that explain the decomposition of a system into containers and components, the relationship between these elements, and, where appropriate, the relation with its users.

The viewpoints are organized according to their hierarchical level:

Context diagrams (level 1): show the system in scope and its relationship with users and other systems;

Container diagrams (level 2): decompose a system into interrelated containers. A container represents an application or a data store;

Component diagrams (level 3): decompose containers into interrelated components, and relate the components to other containers or other systems;

Code diagrams (level 4): provide additional details about the design of the architectural elements that can be mapped to code. The C4 model relies at this level on existing notations such as Unified Modelling Language (UML), Entity Relation Diagrams (ERD) or diagrams generated by Integrated Development Environments (IDE).

For level 1 to 3, the C4 model uses 5 basic diagramming elements: persons, software systems, containers, components and relationships. The technique is not prescriptive for the layout, shape, colour and style of these elements. Instead, the C4 model recommends using simple diagrams based on nested boxes in order to facilitate interactive collaborative drawing. The technique also promotes good modelling practices such as providing a title and legend on every diagram, and clear unambiguous labelling in order to facilitate the understanding by the intended audience.

The C4 model facilitates collaborative visual architecting and evolutionary architecture in the context of agile teams where more formal documentation methods and up-front architectural design are not desired.

I am a big fan of evolutionary architecture so this fits the bill perfectly.

As an example — See how easy it is to read and understand each of these diagrams.

Level 1 — System context

Level 2 — Container diagram

Level 3 — Component diagram

Still — this alone does not solve the problem of spending (wasting?) hours to update the model after some time. This is inevitable — especially as the architecture evolves.

Enter PlantUML

What is so great about this tool?

Well — PlantUML is an open-source tool allowing users to create diagrams from a plain text language. This means you no longer have to fire up some heavy program / plugin to update your diagrams — you can model it in code.

Compared to other tools (such as Structurizr) — PlantUML is mature, battle-tested and free to use.

And what do we usually do with code?

We store it in version control such as GIT — which in turn facilitates collaboration and gives us the added benefit of knowing what changed when — giving us the complete evolutionary history of an application!

For instance — here is the code for the Level 1 diagram:

@startuml
!include C4_Context.puml

LAYOUT_WITH_LEGEND()

title System Context diagram for Internet Banking System

Person(customer, "Personal Banking Customer", "A customer of the bank, with personal bank accounts.")
System(banking_system, "Internet Banking System", "Allows customers to view information about their bank accounts, and make payments.")

System_Ext(mail_system, "E-mail system", "The internal Microsoft Exchange e-mail system.")
System_Ext(mainframe, "Mainframe Banking System", "Stores all of the core banking information about customers, accounts, transactions, etc.")

Rel(customer, banking_system, "Uses")
Rel_Back(customer, mail_system, "Sends e-mails to")
Rel_Neighbor(banking_system, mail_system, "Sends e-mails", "SMTP")
Rel(banking_system, mainframe, "Uses")
@enduml

Neat.

There are some supplementary diagrams as well such as:

As for tooling support, there are plugins available for Visual Studio Code and IntelliJ IDEA.

Most of these plugins default to an open PlantUML server, but have the option of using a local PlantUML server which is as easy as..

docker run -d -p 8080:8080 plantuml/plantuml-server:tomcat

Now there are some drawbacks.

  • PlantUML (and other similar tools) can be tricky to position with regards to arrows, boxes etc. when diagrams get complex.
  • Generating these diagrams require a server component whereas others (such as MermaidJS) are more smooth to integrate into ex. a Github page.

But all in all it is a fair tradeoff. I think it does a decent job positioning stuff most of the time and generating updated diagrams on the fly could easily be achieved by a simple Jenkins job / GitHub action.

And there you have it! May your diagrams be blessed from this day on.

--

--

Jan Christian Alvestad

A 38 year old father-of-two Java developer with interests in how to architect apps, work smart, efficient and have fun trying out new stuff.