Architecture as Code: Tools
published: ⏰ 12Implementing the Architecture as Code approach requires convenient tools that allow one to describe the architecture in text or code, and then, using CI/CD processes, update and automatically generate documentation based on these descriptions. In this article, I wanted to provide an example of some of these tools.
Introduction
The introductory article already covered what Architecture as Code is and why it’s needed. This article will cover the tools used in more detail.
Naturally, this article will primarily cover tools I’ve personally used or at least tried. This isn’t a complete list, but it may be useful for those looking to get started with the AaC approach.
General Requirements
The requirements for tools are primarily determined by the goals of the AaC approach itself:
- The architectural artifact description format should be primarily text-based and editable in any convenient editor.
- Architectural models can be described as code that can be entered into a version control system (git).
- This description should support the automatic generation of diagrams and other graphical representations.
- Ability to integrate into CI/CD processes, for example, to automatically update documentation when changes are made.
- It should be possible to organize component libraries for reuse to minimize duplication and repetition of similar work.
- The description format should be understandable for GenAI (e.g., LLM) so that they can be used for analysis or documentation generation. It should also serve as a knowledge base for training and integrating GenAI into the design and development process.
It is highly desirable for the tools to be free and open source, but this is not a requirement. Open source code allows you to customize it to suit your needs, as internal documentation requirements and processes within companies may differ, and as we know, there is no one-size-fits-all solution.
Which tools should I use?
Below are a few tools that can be used. Of course, there are other options for creating in-house solutions, but they are not covered here.
| Tool | Main Functionality | Best for… | Less Suitable for… | Complexity | CI/CD | OSS |
|---|---|---|---|---|---|---|
| Structurizr | C4 model, automation from code | Complex systems, teams using C4, “living” documentation | Simple diagrams, teams not using C4 | Average | Excellent | Partial (CLI/Lite) |
| Mermaid | Simplicity, versatility, mass support | Quick integration in Markdown, small/medium projects | Detailed or custom architectural diagrams | Low | Excellent | Yes |
| PlantUML | Convenience and variety of diagram types | Detailed and mixed diagrams, complex interactions | Simple diagrams where automatic layout is needed | Medium/High | Excellent | Yes |
| Graphviz | Automatic layout of complex graphs | Dependency generation, visualization of large relationships via scripts | Manual description of the entire architecture, simple diagrams | Low/Medium | Good (via scripts) | Yes |
Structurizr
Structurizr is a comprehensive solution for documenting architecture based on the C4 model. It allows you to describe architecture in code (JSON/YAML) and generate interactive diagrams of different levels (context, container, component, code) in a web portal.
Key benefits:
- Built using C4 notation, one of the simplest and most popular for describing architecture.
- Supports automatic integration with code for description generation.
- Two deployment options – Structurizr Lite (for local development) and Structurizr On-Premises (for collaboration).
- Ability to export diagrams in various formats: PNG, SVG. Useful for transferring diagrams to other systems.
- CI/CD integration possible using the Structurizr CLI.
- Open source (plugins can be developed and written)(/devmix/structurizr-plugin-diagrams/structurizr-plugin-diagrams-0.1)
- Integrations with documentation systems, such as Confluence, are available.
Additionally, it allows for organizing internal architecture documentation, for example, in Markdown or AsciiDoc format, with the ability to insert links to diagrams. ADR is also available in a separate section.
Potential disadvantages:
- Requires training to use the DSL.
- Complex integration with existing documentation systems.
- Performance may decrease with large models and a large number of diagrams, especially when using the web interface and increasing documentation volume.
Use cases:
- Developing architectural models using the C4 model.
- Automatic generation of diagrams and documentation from code or DSL.
- Integrating with CI/CD for automatic updating of architectural documentation.
- Collaborating on architecture and documentation within a development team.
- Publishing architectural documentation as a static website.
Examples
System Architecture (High-Level Overview)
workspace "Online Shop Architecture" {
model {
user = person "Customer"
onlineShop = softwareSystem "Online Shop" "Allows customers to browse and buy products" {
webApp = container "Web Application" "Allows customers to browse and buy via browser" {
technology "React"
}
mobileApp = container "Mobile App" "Allows customers to browse and buy via phone" {
technology "iOS/Android"
}
api = container "Backend API" "Handles business logic and requests" {
technology "Java/Spring Boot"
}
db = container "Database" "Stores customer, order, and product data" {
technology "PostgreSQL"
}
cache = container "Cache" "Improves API response times" {
technology "Redis"
}
paymentGateway = container "Payment Gateway" "External payment processing" {
technology "Stripe/PayPal API"
tag external
}
}
user -> webApp "Uses"
user -> mobileApp "Uses"
webApp -> api "Makes API calls [HTTPS]"
mobileApp -> api "Makes API calls [HTTPS]"
api -> db "Reads/Writes [JDBC]"
api -> cache "Caches results"
api -> paymentGateway "Processes Transactions"
}
views {
styles {
element "external" {
background gray
color #ffffff
}
element "Web Browser" {
shape WebBrowser
}
element "database" {
shape Cylinder
}
element Component {
shape Component
}
}
theme default
}
}PlantUML
PlantUML (https://plantuml.com/) is a diagramming tool using structured text descriptions. This allows you to create diagrams from text descriptions, which is consistent with the AaC concept. There are also numerous plugins that allow you to integrate PlantUML into various IDEs and generate diagrams automatically from source code. It supports various diagram types, including UML, C4, Archimate, BPMN, Deployment, Network, WBS, MindMap, Gantt, Timeline, and more.
Key Benefits:
- Large library of supported diagram types: architectural, class, sequence, state, BPMN, and more.
- Allows you to create fairly complex and detailed diagrams. There are some limitations, but they are not critical.
- You can customize styles, presentation themes, colors, fonts, relationship styles, block views, and more. - A very common diagram description format supported by all popular editors and IDEs.
- Easily integrated into CI/CD processes.
- Supported by most documentation generators (AsciiDoc, Markdown via extensions, Confluence).
- Open source.
Potential Disadvantages:
- Requires learning the diagram description language (DSL) and its syntax.
- Some complex diagrams can be difficult to edit manually, especially if they contain many elements. For example, it’s not always easy to establish the correct relationships between elements so they appear correctly in the final diagram.
Use Scenarios:
- Description of various types of architectural diagrams and other types that will later be used in project documentation.
- Creation of automatically generated diagrams from code (e.g., via annotations or metadata) in the form of diagrams. Eliminates the need for manual diagram description and maintenance.
- Use in CI/CD for automatic diagram generation with each code change.
Examples
System Architecture (High-Level Overview)
@startuml
!theme vibrant
!define RECTANGLE class
' Define Styling
skinparam componentStyle rectangle
skinparam backgroundColor #FEFEFE
actor "User" as User
package "Client Layer" {
component "Web Application" as Web
component "Mobile App" as Mobile
}
package "Infrastructure" {
component "Load Balancer" as LB
component "Backend API" as API
}
component "Auth Service" as Auth
database "Primary DB" as DB
database "Redis Cache" as Cache
cloud "Payment Gateway" as Payments
cloud "Shipping Provider" as Ship
' Connections
User --> Web : HTTPS
User --> Mobile : HTTPS
Web --> LB
Mobile --> LB
LB --> API
API --> Auth
API --> Cache
API --> DB
API --> Payments : REST API
API --> Ship : API
@endumlCheckout Process (Sequence Diagram)
@startuml
!theme vibrant
autonumber
actor "Customer" as C
participant "Website/App" as UI
participant "Server" as S
database "Database" as DB
participant "Payment Gateway" as P
C -> UI: View Cart & Checkout
UI -> S: POST /api/create-order
S -> DB: Verify Inventory & Reserve Items
DB --> S: Items Reserved
S --> UI: Order ID & Payment Token
UI -> C: Request Credit Card Details
C -> UI: Submit Payment Details
UI -> P: Charge Card (with Token)
P --> UI: Payment Success/Fail
alt Payment Successful
UI -> S: POST /api/confirm-payment
S -> DB: Update Order Status to "Paid"
S --> UI: Confirmation Receipt
UI --> C: Display "Thank You" Page
else Payment Failed
S -> DB: Release Reserved Inventory
UI --> C: Display Error Message
end
@endumlOrder Lifecycle (State Diagram)
@startuml
[*] --> Cart
state Cart {
[*] --> Active
}
state "Payment Failed" as Failed
state "Payment Successful" as Paid
Cart --> Processing: Checkout
note right of Cart
User fills details
and clicks "Pay"
end note
Processing --> Failed: Payment Declined
Processing --> Paid: Payment Success
Paid --> Shipped: Order Picked & Packed
note right of Paid
Warehouse handles
physical goods
end note
Shipped --> Delivered: Customer Receives
Delivered --> Returned: Refund Requested
Delivered --> [*]: Order Complete
Returned --> Refunded: Item Received
Refunded --> [*]: Process Complete
Failed --> Cart: Try Again
Failed --> [*]: Abandoned
@endumlMermaid
Mermaid is a tool for generating diagrams from text descriptions. Similar to PlanUML, but with a simpler syntax and the ability to integrate with Markdown. It supports many diagram types, including UML, C4, Flowcharts, Gantt, User Journey, Pie Charts, Timeline, Git Graphs, and more.
Key advantages:
- Easily integrates into Markdown documents (GitHub, GitLab, Notion, etc.), as it is supported by virtually all modern editors.
- Native support on GitHub, GitLab, VS Code, Confluence, and other platforms.
- Large library of supported diagram types.
- New diagram types and improvements are constantly being added, including support for architectural descriptions (C4).
- Can draw diagrams directly in the browser, as it is a JS library.
- Open source.
Potential drawbacks (I rarely used it, so I may have missed something):
- There are often problems displaying diagrams in some editors or on certain platforms—you need to select the correct diagram description.
- IDE support seems worse than for PlantUML.
Use scenarios:
- Similar to PlantUML.
- Can be used in a browser without installing additional software.
Examples
System Architecture (High-Level Overview)
graph TD
%% Nodes
User((User))
Web[Web Application]
Mobile[Mobile App]
LB[Load Balancer]
API[Backend API Server]
Auth[Auth Service]
DB[(Primary Database)]
Cache[(Redis Cache)]
Payments[Payment Gateway]
Ship[Shipping Provider]
%% Relationships
User -->|HTTPS| Web
User -->|HTTPS| Mobile
Web --> LB
Mobile --> LB
LB --> API
API --> Auth
API --> Cache
API --> DB
API -->|REST API| Payments
API -->|API| Ship
%% Styling
style User fill:#f9f,stroke:#333,stroke-width:2px
style DB fill:#ff9,stroke:#333,stroke-width:2pxCheckout Process (Sequence Diagram)
sequenceDiagram
autonumber
actor C as Customer
participant UI as Website/App
participant S as Server
participant DB as Database
participant P as Payment Gateway
C->>UI: View Cart & Checkout
UI->>S: POST /api/create-order
S->>DB: Verify Inventory & Reserve Items
DB-->>S: Items Reserved
S-->>UI: Order ID & Payment Token
UI->>C: Request Credit Card Details
C->>UI: Submit Payment Details
UI->>P: Charge Card (with Token)
P-->>UI: Payment Success/Fail
alt Payment Successful
UI->>S: POST /api/confirm-payment
S->>DB: Update Order Status to "Paid"
S-->>UI: Confirmation Receipt
UI-->>C: Display "Thank You" Page
else Payment Failed
S->>DB: Release Reserved Inventory
UI-->>C: Display Error Message
endOrder Lifecycle (State Diagram)
stateDiagram-v2
[*] --> Cart
Cart --> Processing: Checkout
note right of Cart
User fills details
and clicks "Pay"
end note
Processing --> PaymentFailed: Payment Declined
Processing --> Paid: Payment Success
Paid --> Shipped: Order Picked & Packed
note right of Paid
Warehouse handles
physical goods
end note
Shipped --> Delivered: Customer Receives
Delivered --> Returned: Refund Requested
Delivered --> [*]: Order Complete
PaymentFailed --> Cart: Try Again
PaymentFailed --> [*]: Abandoned
Returned --> Refunded: Item Received
Refunded --> [*]: Process CompleteGraphviz
Graphviz is a powerful graph visualization tool that uses the DOT graph description language to create diagrams. It can be useful for visualizing complex architectural diagrams and component relationships. I haven’t personally used it, but it’s worth mentioning.
Key Advantages:
- Graphviz’s algorithms handle complex graph layouts well without manual arrangement.
- Minimalistic DOT syntax.
- Can be used both independently and with other tools. For example, PlantUML uses it to generate certain diagram types.
- Efficiently processes large graphs.
- Full control over diagram appearance and layout.
Potential Disadvantages:
- Requires knowledge of DOT syntax.
- Does not support visual editing.
- No ready-made templates or blocks for different diagram types.
Use Scenarios:
- Creating your own visualization tools. - Work with complex schemas not supported by other tools.
Examples
System Architecture (High-Level Overview)
digraph OnlineShopArch {
// Graph Settings
rankdir=TB; // Top to Bottom layout
newrank=true;
splines=ortho; // Straight lines
node [shape=box, style="filled,rounded", fontname="Arial", fontsize=10];
// External Nodes
User [label="Customer", shape=oval, fill="#f9f"];
// Cluster for Server Side
subgraph cluster_backend {
label = "Infrastructure";
style=filled;
color=lightgrey;
Web [label="Web App", fill="#dodgerblue3"];
Mobile [label="Mobile App", fill="#dodgerblue3"];
LB [label="Load Balancer", fill="#gold"];
API [label="Backend API", fill="#limegreen"];
DB [label="Database", shape=cylinder, fill="#ff9"];
Cache [label="Redis Cache", fill="#ff9"];
}
// External Services
Payments [label="Payment Gateway", shape=cloud, fill="#e0e0e0"];
Ship [label="Shipping Provider", shape=cloud, fill="#e0e0e0"];
// Connections
User -> Web [label="HTTPS"];
User -> Mobile [label="HTTPS"];
Web -> LB;
Mobile -> LB;
LB -> API;
API -> Cache [label="Read/Write"];
API -> DB [label="SQL"];
API -> Payments [label="REST API"];
API -> Ship [label="API"];
}Checkout Process (Flow Diagram)
digraph CheckoutFlow {
rankdir=TB;
node [shape=rectangle, style="filled,rounded", fontname="Arial"];
// Start
Start [shape=oval, label="Customer Checkout", fill="#f9f"];
// Process Steps
UI [label="Web/App Interface"];
CreateOrder [label="API: Create Order\n& Verify Inventory"];
// Decision Diamond
PayCheck [shape=diamond, label="Payment Success?"];
// Success Path
Confirm [label="API: Update Status\nto 'Paid'"];
Receipt [label="Show Thank You"];
// Failure Path
Release [label="API: Release\nInventory"];
Error [label="Show Error Message"];
// Logic Flow
Start -> UI;
UI -> CreateOrder;
CreateOrder -> PayCheck;
PayCheck -> Confirm [label="Yes"];
Confirm -> Receipt;
PayCheck -> Release [label="No"];
Release -> Error;
// Styling
Start [fill="#f9f"];
UI [fill="#dodgerblue3"];
CreateOrder [fill="#limegreen"];
PayCheck [fill="orange"];
Confirm [fill="#limegreen"];
}Order Lifecycle (State Diagram)
digraph OrderLifecycle {
rankdir=TB; // Top to Bottom
// Node Styles
node [shape=ellipse, style="filled", fontname="Arial"];
Start [shape=point, label=""];
// States
Cart [fill="#add8e6", label="Cart"];
Processing [fill="#add8e6", label="Processing"];
Paid [fill="#add8e6", label="Paid"];
Shipped [fill="#add8e6", label="Shipped"];
Delivered [fill="#add8e6", label="Delivered"];
Returned [fill="#ffcccb", label="Returned"];
Refunded [fill="#ffcccb", label="Refunded"];
Abandoned [shape=doublecircle, fill="#d3d3d3", label="Abandoned"];
Complete [shape=doublecircle, fill="#90ee90", label="Complete"];
// Transitions
Start -> Cart;
Cart -> Processing [label="Checkout"];
Processing -> Paid [label="Success"];
Processing -> Abandoned [label="Fail/Quit"];
Paid -> Shipped [label="Pack & Ship"];
Shipped -> Delivered [label="Receive"];
Delivered -> Complete [label="Done"];
Delivered -> Returned [label="Refund Req"];
Returned -> Refunded [label="Item Received"];
Refunded -> Complete [label="Done"];
// Layout Optimization (Keep certain levels aligned)
ranksep=1.0;
}DocHub
DocHub (https://dochub.info) is a tool for creating and managing documentation in Markdown format. It allows you to create documentation using Markdown and automatically generates static web pages from Markdown files. It also supports diagram visualization using Mermaid and PlantUML.
I haven’t personally used DocHub, but I know it exists. Its functionality is closer to Structurizr. It also has a built-in technical radar (blog/arch/technical-radar/), which is very convenient.
Conclusion
For a long time, the primary documentation tool was various systems like Confluence, which required manual entry and updating of information. The updating process itself was, to put it mildly, inconvenient – edit the diagram, export it as an image, upload it to Confluence, and so on, endlessly repeating the process for each minor edit. It’s understandable that not everyone takes such a process seriously, and to some extent, their lack of commitment is understandable. We gradually abandoned this process because it was time-consuming, resulting in outdated documentation that hadn’t been updated for years.
As practice shows, at least for me, automating this process significantly simplifies and speeds up keeping architectural artifacts and documentation up to date. I don’t want to go back to manual documentation. Most importantly, the architecture always remains up-to-date and consistent with the actual state of the system.
An additional benefit is that with this approach, some of the documentation can be used with GenAI tools, at least for analyzing architectural decisions to identify potential problems and vulnerabilities.