C4 and UML with PlantUML
You are creating an awesome digital product. The software part shall work flawlessly over the years.
Technology changes will be added to the product. Legal changes and security improvements are implemented in a timely manner over the years.
This application will evolve to satisfy new needs and customer segments. The life span of your product is probably more than a decade.
How can you document critical cross-cutting design decisions and key mechanisms?
How to help new team members understand your architecture and key concepts?
We are convinced that arc42, C4 Model, UML and plantUML are approaches to better communicate your intent to team members.
Include C4 Templates in plantUML
The C4 Model notation is available as a template file [3]. Include the template in your plantUML diagram.
The following code generates the below diagram [1].
-
Diagram
-
Source
@startuml !include <C4/C4_Container> Person(personAlias, "Customer", "Optional Description") Container(containerAlias, "tangly", "Technology", "tangly open source components") Rel(personAlias, containerAlias, "use", "Cool Technology") @enduml
System Context Diagram
A System Context diagram is a good starting point for diagramming and documenting a software system, allowing you to step back and see the big picture. Draw a diagram showing your system as a box in the center, surrounded by its users and the other systems that it interacts with.
Detail is not important here as this is your zoomed-out view showing a big picture of the system landscape. The focus should be on people (actors, roles, personas, etc.) and software systems rather than technologies, protocols, and other low-level details.
-
Diagram
-
Source
@startuml !include <C4/C4_Component> LAYOUT_WITH_LEGEND() title Context Diagram for Voice Activated Door Control System Person(customer, "Person", "person walks to the door") System(VoiceActivatedDoorControl,"Voice Activated Door Control System","Receives realtime voice of person and makes recognition, then opens door if access permited") System_Ext(DoorControlHardware, "Door Control System", "Opens/Closes Door with electronics systems") System_Ext(MicrophoneSystem, "Microphone System", "Microphone for door control") Rel(customer, VoiceActivatedDoorControl, "Uses system to enter the house using own voice") Rel(VoiceActivatedDoorControl, DoorControlHardware, "Disceate IO","Commands to open/close door") Rel(VoiceActivatedDoorControl, MicrophoneSystem, "UDP","Gets voice data as UDP stream") @enduml
Container Diagram
Once you understand how your system fits in to the overall IT environment, a really useful next step is to zoom-in to the system boundary with a Container diagram. A "container" is something like a server-side web application, single-page application, desktop application, mobile app, database schema, file system, etc. Essentially, a container is a separately runnable/deployable unit (e.g., a separate process space) that executes code or stores data.
The Container diagram shows the high-level shape of the software architecture and how responsibilities are distributed across it. It also shows the major technology choices and how the containers communicate with one another. It is a simple, high-level technology focussed diagram that is useful for software developers and support/operations staff alike.
-
Diagram
-
Source
@startuml !include <C4/C4_Container> LAYOUT_WITH_LEGEND() title Container Diagram for Voice Activated Door Control System Person_Ext(customer, "Person", "person walks to the door") Container(VoiceActivatedDoorControl,"Voice Activated Door Control Microservice","c++","Receives realtime voice of person and makes recognition, then opens door if access permited") Container(VoiceTraining,"Voice Training Microservice","c++","Gets sample voices from rest sdervice and uses them for machine learing purpose") Container(WEBComponent,"WebComponent","React","User interface for management and monitoring of system") ContainerDb(DB, "DB", "PosgreeSQL", "Stores metadata for voice recognition") Rel_Down(customer,VoiceActivatedDoorControl,"audio") Rel_Down(customer,WEBComponent,"Trains own voice to system") Rel(VoiceActivatedDoorControl,DB,"Gets voice recognition data") Rel(VoiceTraining,DB,"Puts voice recognition data") Rel(WEBComponent,VoiceTraining,"Rest","Sends Voice Recognition Data")
Component Diagram
Next, you can zoom in and decompose each container further to identify the major structural building blocks and their interactions.
The Component diagram shows how a container is made up of a number of "components", what each of those components are, their responsibilities and the technology/implementation details.
-
Diagram
-
Source
@startuml !include <C4/C4_Component> LAYOUT_WITH_LEGEND() title Component Diagram for Voice Activated door control system Person_Ext(customer, "Person", "person walks to the door") Container(Service, "Service", "C++", "Main Service") Container(VoiceRecogniton, "VoiceRecogniton", "C++", "Voice Recognition Module") Container(DoorControl, "DoorControl", "C++", "Opens and Clsoeses door") Rel(customer,Service,"talks") Rel(Service,VoiceRecogniton,"Initiatesd Voice Recognition") Rel(Service,DoorControl,"Initiates Door control") @enduml
Code
Finally, you can zoom in to each component to show how it is implemented as code; using UML class diagrams, entity relationship diagrams, or similar.
This is an optional level of detail and is often available on-demand from tooling such as IDEs. Ideally, this diagram would be automatically generated using tooling, (e.g., an IDE or UML modeling tool), and you should consider showing only those attributes and methods that allow you to tell the story that you want to tell. This level of detail is not recommended for anything but the most important or complex components.
-
Diagram
-
Source
@startuml class Message<T> { int kind(); T data(); } abstract class ConcurrentQueue<T> abstract class Actor<T> Actor "1"*-"1" ConcurrentQueue : queue ConcurrentQueue "1"*-"n" Message : messages @enduml
Additional Diagrams
System Landscape diagram
The C4 model provides a static view of a single software system but, in the real-world, software systems never live in isolation. For this reason, and particularly if you are responsible for a collection/portfolio of software systems, it is often useful to understand how all of these software systems fit together within a given enterprise, organization, department, etc. Essentially this is a map of the software systems within the chosen scope, with a C4 drill-down for each software system of interest.
From a practical perspective, a system landscape diagram is really just a system context diagram without a specific focus on a particular software system.
Dynamic Diagram
A dynamic diagram can be useful when you want to show how elements in the static model collaborate at runtime to implement a user story, a use case, a feature, etc. This dynamic diagram is based upon a UML communication diagram (previously known as a "UML collaboration diagram"). It is similar to a UML sequence diagram, although it allows a free-form arrangement of diagram elements with numbered interactions to indicate ordering.
Deployment Diagram
A deployment diagram allows you to illustrate how instances of software systems and/or containers in the static model are deployed on to the infrastructure within a given deployment environment such as production, staging, development, etc. It is based upon UML deployment diagrams.
A deployment node represents where an instance of a software system/container is running; perhaps physical infrastructure (e.g., a physical server or device), virtualized infrastructure (e.g., IaaS, PaaS, a virtual machine), containerized infrastructure (e.g., a Docker container), an execution environment (e.g., a database server, Java EE web/application server, Microsoft IIS), etc. Deployment nodes can be nested.
You may also want to include infrastructure nodes such as DNS services, load balancers, firewalls, etc.
Feel free to use icons provided by Amazon Web Services, Azure, etc. to complement your deployment diagrams . Make sure any icons you use are included in your diagram legend.
Lessons Learnt
You should discuss intensively in your team and organization why you create diagrams. Each diagram has creation and maintenance costs.
If you decide to create a lot of diagrams for your system, consider using a full-fledged C4 or UML modeling tool instead of a diagramming tool. Be aware one team member shall be a power user. He will support the team and write utilities to simplify usage of the tool [2].
What are the purpose and goals of your diagrams?
I suggest using diagrams to document key design cross-cutting decisions.
Cross-cutting decisions are the backbone of your design. Document them extensively with graphical tools. Key architecture decisions are often tactical decisions and should be documented in Architecture Design Records ADR. Future team members will understand why you decided to use a specific technology or design pattern. Public API shall be documented with OpenAPI or a similar approach. Modules and classes are documented with JavaDoc. Maintainers will be thankful for high-quality documentation. |
New team members should understand the application design with the help of these diagrams and associated documentation.
Please do not try to document all classes and packages with diagrams. It is not worth the money.
Links
-
[1] Agile Visual Tools. Marcel Baumann. 2023.
-
[2] Creating a Technical Website with Hugo and AsciiDoc. Marcel Baumann. 2020.