C4 Modeling. Show your Software Architecture that easy!
The C4 model is a software architecture visualization that provides a lightweight and scalable way to communicate software architecture effectively.
It consists of 4 main hierarchical diagrams:
- System Context Diagram: Provides a starting point, showing how the software system interacts with its external environment.
- Container Diagram: Zooms into the system, revealing the high-level containers and their interactions.
- Component Diagram: Focuses on an individual container, displaying the components within it.
- Code Diagram: At the most detailed level, it shows how a specific component is implemented.

On a previous post I showed you how to obtain your own docker image for PlantUML
https://darthseldon.net/plantuml-and-nginx-your-own-uml-designer/
And how to use the standard library
https://darthseldon.net/shiny-things-sell-so-embelish-your-plantuml-diagrams/
I will be focusing on the C4 standard library.
As an example, we will create a fictitious ecommerce site.
Including the standard library is as easy as to use the following directive.
!include <C4/C4_Container>
Creating the containers and Relationships are verbose and simple to follow.
Container(ecommerce, "E-Commerce Application")
Rel(customer, ecommerce, "Customer shops on the E-Commerce Application")
System Context Diagram
"Provides a starting point, showing how the software system interacts with its external environment." -c4model.com
@startuml
'Title
title System Context Sample E-Commerce with C4
'Standard libraries
!include <C4/C4_Container>
!include <azure/AzureCommon>
'Containers and components
Person(customer, "E-Commerce Customer")
Container(ecommerce, "E-Commerce Application")
Container(backend, "Backend Services")
'Relationships
Rel(customer, ecommerce, "Customer shops on the E-Commerce Application")
Rel(ecommerce, backend, "Application interacts with backend services to fulfill shopping experience")
'Footer
SHOW_LEGEND()
footer v1.0
@enduml

Container Diagram
"Zooms into the system, revealing the high-level containers and their interactions." -c4model.com
@startuml
'Title
title Container Diagram Sample E-Commerce with C4
'Standard libraries
!include <C4/C4_Container>
!include <azure/AzureCommon>
'Containers and components
Person(customer, "E-Commerce Customer", $tags="customer")
System_Boundary(ecommerceBoundary, "Ficticious E-Commerce") {
Container(frontend, "Web Application")
System_Boundary(backendBoundary, "Backend Services") {
Container(api, "API Backend Services", "Catalog, Orders, Customer, Shopping Cart, Checkout")
ContainerDb(db, "Document Database", "Collections")
}
}
'Relationships
Rel(customer, frontend, "Uses Application")
Rel(frontend, api, "Uses Services")
Rel(api, db, "Uses Database")
'Footer
SHOW_LEGEND()
footer v1.0
@enduml

Component Diagram
"Focuses on an individual container, displaying the components within it." -c4model.com
This is the diagram that usually (at least how I represent it) has the most detail at "high" level. It shows the major components, protocols and the system that starts the relationship to the other components.
Some people like to add numbers to show the sequence of interactions, I prefer sequence diagrams. :)
@startuml
'Title
title Component Diagram Sample E-Commerce with C4
'Standard libraries
!include <C4/C4_Container>
!include <azure/AzureCommon>
!include <azure/Web/AzureWebApp>
!include <azure/Databases/AzureRedisCache>
!include <azure/Databases/AzureCosmosDb>
!include <azure/Networking/AzureFrontDoor>
!include <azure/Compute/AzureFunction>
!include <azure/Identity/AzureActiveDirectoryUser>
!include <office/Concepts/firewall>
'Custom tags
AddPersonTag("customer", $sprite="AzureActiveDirectoryUser", $legendText="User")
AddContainerTag("webApp", $sprite="AzureWebApp", $legendText="Web App/SPA(React)")
AddContainerTag("db", $sprite="AzureCosmosDb", $legendText="Cosmos Document DB")
AddContainerTag("cache", $sprite="AzureRedisCache", $legendText="Redis Cache")
AddContainerTag("frontdoor", $sprite="AzureFrontDoor", $legendText="Front Door")
AddContainerTag("microservice", $sprite="AzureFunction", $legendText="Microservice/Azure Function")
AddRelTag("firewall", $textColor="$ARROW_FONT_COLOR", $lineColor="$ARROW_COLOR", $sprite="firewall,scale=0.3,color=red", $legendText="firewall")
'Containers and components
Person(customer, "E-Commerce Customer", $tags="customer")
System_Boundary(ecommerceBoundary, "Ficticious E-Commerce") {
Container(frontend, "SPA", "Web App/React", $tags="webApp")
Container(frontdoor, "CDN", "Front Door", $tags="frontdoor")
Container(cache, "Cache", "Azure Redis", $tags="cache")
System_Boundary(backendBoundary, "Backend Services") {
Container(saga, "SAGA Orchestrator", "Azure Durable Function", $tags="microservice")
ContainerDb(cosmos, "Cosmos", "Cosmos Document DB", $tags="db")
Container(orders, "Orders Microservice", "Azure Function", $tags="microservice")
Container(catalog, "Catalog Microservice", "Azure Function", $tags="microservice")
Container(shoppingcart, "Shopping Cart Microservice", "Azure Function", $tags="microservice")
Container(customerms, "Customer Microservice", "Azure Function", $tags="microservice")
Container(checkout, "Checkout and Payments Microservice", "Azure Function", $tags="microservice")
}
}
'Relationships
Rel(customer, frontdoor, "Uses", "HTTPS", "Depending on Region, the CDN will resolve to the closest data center")
Rel(frontdoor, frontend, "Resolves", "HTTPS", "Depending on Region, load balancer resolve to the closest data center")
Rel(frontend, cache, "Retrieves/Updates", "TCP/6379", "Cached catalog, localizations, customer information and shopping carts", , $tags="firewall")
Rel(frontend, saga, "Creates SAGA (Via function chaining and correlation)", "HTTPS", "Creates SAGA for Customer Journey", $tags="firewall" )
Rel(saga, catalog, "Retrieves Catalog", "REST HTTPS", "Retrieves Catalog in ODATA", $tags="firewall")
Rel(saga, customerms, "Retrieves Customer Information", "REST HTTPS", "Retrieves Customer Information in ODATA", $tags="firewall")
Rel(saga, shoppingcart, "Retrieves Customer Shopping Cart", "REST HTTPS", "Retrieves Customer Shopping Cart Information in ODATA", $tags="firewall")
Rel(saga, checkout, "Perform payments", "REST HTTPS", "Perform payments", $tags="firewall")
Rel(saga, orders, "Creates/Updates Orders", "REST HTTPS", "Creates/Updates Orders Information in ODATA", $tags="firewall")
Rel(catalog, cosmos, "Upsert catalog collection", "HTTPS", "Upsert Document")
Rel(orders, cosmos, "Upsert orders collection", "HTTPS", "Upsert Document")
Rel(shoppingcart, cosmos, "Upsert shopping cart collection", "HTTPS", "Upsert Document")
Rel(customerms, cosmos, "Upsert customer collection", "HTTPS", "Upsert Document")
Rel(checkout, cosmos, "Upsert checkout collection", "HTTPS", "Upsert Document")
'Footer
SHOW_LEGEND()
footer v1.0
@enduml

Since we are using microservices, it is important to have a SAGA orchestrator.
The Saga pattern is a design pattern used in microservices architectures to manage data consistency across distributed transaction scenarios.
I will try to post on how to implement this pattern with an azure durable function. It is complex but not that difficult, it will have eventual consistency.
Code Diagram
"At the most detailed level, it shows how a specific component is implemented" -c4model.com
Since the project can get really detailed, I usually describe each component separately. In this case Catalog Micro Service, but you get the idea.
@startuml
!theme carbon-gray
title Catalog Micro Service
set separator none
package Fictional.ECommerce.Web {
class Program {
Main()
}
class Catalog {
GET()
POST()
PUT()
PATCH()
DELETE()
}
}
package Fictional.ECommerce.Business {
package Models {
class CatalogDbContext {
}
class Product {
}
}
}
package Fictional.Services.DataAccess {
package Abstractions {
interface IRepository {
Create()
Retrieve()
Update()
Delete()
}
class DbContextAbstractFactory {
CreateContext()
}
}
package Cosmos {
class CosmosRepository {
}
}
}
package Microsoft.Azure.Cosmos {
package Azure.Cosmos {
class CosmosClient {
}
}
package Extensions.Hosting {
class HostBuilder {
}
}
}
package System.Data.Entity {
class DbContext {
}
}
IRepository <|-- CosmosRepository
DbContext <|-- CatalogDbContext
CosmosRepository --o CatalogDbContext
CosmosRepository --> Product
Program --> HostBuilder
Catalog <-- Program
Catalog ..> DbContextAbstractFactory
Catalog --> IRepository
CosmosRepository --> CosmosClient
IRepository --> DbContext
DbContextAbstractFactory --> CatalogDbContext
footer v1.0
@enduml

That's it, following these principles and agreeing in some standards will make your life easier on communicating your architecture.
Happy coding and designing!