Skip to content

Diagramming Software Architecture in C4

This page is based off the C4 video on YouTube.

Poor communication slows teams down, so getting information delivered and understood as easily as possible is of vital importance. If the information can be understoord it will result in fewer bugs, faster development, and likely a product that best matches what is actually intended.

Diagramming is a key part of that, the foundation. With a good diagram all team members can move fast in the same direction.

We need to target our stories to different types of audiences. UML will more likely be understood by technical people, but will be difficult for Product owners or business representatives to understand.

One approach is to not think like an architect when creating diagrams, think like a developer.

Above all: The Diagrams must reflect reality.

A common set of abstractions is more important than common notation.

Overview of a software system at a conceptial level is something like this:

Software System Overview NOTE: Container doesn't refer to a Docker container, it is used to refer to a piece of the software, for example and Android application, Database, etc.

A good approach for diagramming is to use the C4 Model. C4 stands for:

C4 Model Meaning

Think of diagrams as maps. You zoom into and out of the diagrams to get different levels of detail.

Example 1

Level 1 - System Context Diagram

A "System Context Diagram" basically shows the thing you are working on/building, and the stuff around it such as other systems ot talks to and the people who use the system. So for an internet banking system we start with a single box:

IBS Example Start

Now we ask: Who is using this system? Add that information:

IBS Example Users

Where does this system get its information from (external systems):

IBS Example External Systems

And where does it interface out to:

IBS Example Additional External Systems

This is an example of a system context diagram, it shows:

  • What we are working on.
  • The environment/context around it.

Level 2 - Container Diagram

As developers and architectures we want more detail, this is where the container diagram is created. The container diagram will show the apps and datastores, and how they are related and run at runtime. We can also build this up piece by piece. This is like zooming into our internet banking system from the level 1 diagram showing the (mostly) separately deployable components:

IBS Example Empty Container Diagram

We start by adding a deployable web application:

IBS Example Container Web App

This Web App returns a SPA:

IBS Example Container SPA

But we can also have a mobile app too:

IBS Example Container Mobile App

Both the SPA and Mobile App get their data via an API endpoint which is seperately deployable:

IBS Example Container API

We might also need our own database to store app related data (such as login information) that is not contained in the mainframe backing system:

IBS Example Container Database

So this is a complete example container diagram showing the various applications and data stores, the technologies they are built with, a little about the responsibilities, and how they connect at runtime.

The components are mostly separately deployable, and the links are mostly interprocess container calls.

Level 3 - Component Diagram

This is a zoom in of a component to show more detail, in this example for the API shown above. We start in a similar way with an empty diagram:

IBS Example Component Empty Diagram

We show who it is used by initially.

To use the apps and API we first need to sign-in, so add this information first:

IBS Example Component Sign-In

Once signed in you get a list of accounts, so we assume an Account Summary Controller:

IBS Example Component Accounts Controller

And let's add a way to rest a password too:

IBS Example Component Password Reset

In a real world example there would be many more components on the diagram, but this is a good intro on how to show the components that sit inside this example API application.

Crucially, if we were to open the codebase for this project we would expect to find these six items. This diagram needs to reflect the code structure at a high level. There should be a 1-to-1 mapping between the concepts in this diagram and the codebase itself.

Level 4 - Code - Class Diagrams


NOTE: This level is not usually recommended, it's not worth it and can usually be generated automatically from the IDEs using the actual implemented code itself.


This is where UML is useful for documenting and diagramming the lower level aspects:

IBS Example Class UML

Level 4 could be useful for complicated components or where something of note should be called out, but is not required for 99% of use cases.

Notation

Notation is important. Here are some tips:

  • Put Titles on pictures. Type of diagram and scope.
  • Layout is important. Keep things clean. Use Post-It notes to help visually with this if other tools or a whiteboard are not available - but don't deliver this as things can fall off!
  • Visual Consistency. Try to use consistent notation, colour coding, shapes and element positioning across diagrams.
  • Take care with using Acronyms. Consider the target audience, for example using MVC with developers is fine, but consider business level terminology, acronyms and system codenames which can catch out new joiners.
  • Elements. Start with simple boxes containing the element name, type, technology (if appropriate) and description/responsibilities. The following are the only 4 types of elements expected on a diagram:

Element Types

- The system context diagram shows: People and Software System elements.
- The container diagram shows: People, Software Systems and container elements.
- The component diagram potentially shows all four element types.
  • A Short description can also be added to the elements. This isn't usual in architecture diagrams, but this can help understanding, as shown in the following diagram, but must be kept short:

No Description vs With Description

  • Lines give structure and glue the elements together. Prefer uni-directional lines. Prefer Thing A calls B, or A bepends on B. Make sure text on the arrow is consistent with the direction. For Bi-directional relationships show the intent, for example:

Relationship Initial Intent

Becomes:

Relationship Preferred Intent

- Avoid using the word "Uses".
- Use two arrows if the intents are different:

Relationship Differing Intent

- Beware of hiding the true story, for example with a hub and spoke diagram, for example this doesn't show the flow clearly:

Relationship Confusing Flow

Where as this is much cleaner:

Relationship Clear Flow

- Add words to make the intent explicit, Read the diagrams out aloud to see if they make sense!
- There are no hard and fast rules - focus on making the diagrams as clear and explicit as possible!
  • Add a Key/Legend to explain shapes, line styles, colours, borders, acronyms, etc. even if it seems obvious:

Key Diagram

  • Use shapes and colour to complement a diagram that already makes sense. Watch out for colourblindness and monochrome printers! If you remove the shapes and colours it should still make sense. Adding these should just make it clearer.
  • Use icons to supplement text, not replace it. Use to complement information, as with colours.

All this is to make the diagram readable and able to stand on their own. New joiners with limited context should be able to make sense of them. Any narrative should complement the diagram.

See the simple checklist at C4Model.com

Key Rule

Abstractions first, notation second.