Recently I stumbled across a model called ”C4” that is designed to help visualize software architecture. After reading through the C4 website, https://c4model.com/, and looking at the conference talk by Simon Brown, I felt that this was something I should explore more in depth. My, very personal, opinion is that we as software designers have lost our ability to communicate software architecture in clear and concise way. Maybe it was lost somewhere in our hunt for being ”Agile” and valuing Working Software over comprehensive documentation, as stated in the Manifesto for Agile Software Development, and we need to rediscover how it should be done.
Now, I don’t have anything against being agile, I’ve suffered through the test and integration phases of a large waterfall project and that is one experience I never wish to have again. However, valuing Working Software does not mean that our systems should not be documented, and in many cases claiming that The code is our documentation just does not cut it (if you don’t believe me, try telling your, not so tech-savvy, manager to clone the Git repo and look at the source code when you get a question about the system and see what happens).
What really spoke to me when I learned about the C4 model are the clear and distinct levels, Context, Containers, Components, and Code. These are ordered by level of abstraction. At the highest level, Context, the system is presented as a single box and the diagram shows people and external systems that in some way interact with the system. As an example I made up a used cars dealership backend system.
It should be easy to understand the role of the system and the context of which it functions. In the diagram there are two Persons, or roles, a Car Dealer and a System Admin. The dealer has access to a locally hosted system which in turn interacts with the backend system via REST. The system admin has direct access to the backend system via some sort of graphical user interface (GUI). The backend system also interacts with the National vehicle owner registry via remote procedure calls (RPC).
On the next level, the Container level, we open up the box of the Used Cars Dealership Backend system and take a look inside. Note that containers in this context have nothing to do with Docker. Containers in this context are different applications that makes up the system. You can imagine a Web API application that handles REST request and some sort of admin application that the system administrator has access to. There is probably also one or two databases that contains information about the cars and the connected dealers. It could look something like the diagram below.
On the third level, Components, we zoom in on a single container and peek inside. I didn’t go that deep in this example but you can imagine a component to correspond to a .NET project and the connections between components being project references. As you can imagine, the components level can change quite rapidly in new projects and it can be worth looking at ways to generate a diagram in this level instead of manually keeping it updated.
For the final level, Code, no diagrams should be manually constructed. The Code level is represented by classes and interfaces, which can be constructed using UML. These diagrams should either be skipped entirely or generated by a tool.
The C4 model can be really useful for describing a software system’s architecture from a high-level perspective. The first two levels, Context and Containers, should be quite stable during the lifetime of a system and creating and keeping those diagrams up to date should not add much work. The diagrams can be used when communicating the architecture both within a development team and with other parts of the organization.
The lower two levels, Components and Code, are more volatile and also more targeting software developers and architects actively working with developing the system. They should be generated from the existing code rather than being written manually by hand.
For documentation on Wiki pages, PDF files and the likes I would only use Context and Container diagrams. Components and Code can be generated when needed, or automatically generated as part of the build and automatically uploaded to a shared area.
There are pretty good tooling available for creating the diagrams using simple text and have the diagrams generated. For the diagrams above I used PlantUML (https://plantuml.com/) with a C4 add-on (https://github.com/RicardoNiepel/C4-PlantUML). The text files can be easily stored in the same source control repository as the system’s source code.