<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Diagrams-as-Code | DerekArmstrong.Dev</title><link>https://derekarmstrong.dev/tags/diagrams-as-code/</link><atom:link href="https://derekarmstrong.dev/tags/diagrams-as-code/index.xml" rel="self" type="application/rss+xml"/><description>Diagrams-as-Code</description><generator>Hugo Blox Builder (https://hugoblox.com)</generator><language>en-us</language><lastBuildDate>Wed, 18 Sep 2024 00:00:00 +0000</lastBuildDate><image><url>https://derekarmstrong.dev/media/sharing.png</url><title>Diagrams-as-Code</title><link>https://derekarmstrong.dev/tags/diagrams-as-code/</link></image><item><title>PlantUML: Powerful Diagrams with Code</title><link>https://derekarmstrong.dev/blog/plantuml-powerful-diagrams-with-code/</link><pubDate>Wed, 18 Sep 2024 00:00:00 +0000</pubDate><guid>https://derekarmstrong.dev/blog/plantuml-powerful-diagrams-with-code/</guid><description>&lt;p&gt;At some point in most software projects, someone opens a Visio or Lucidchart file, updates three boxes, screenshots it, uploads the image to Confluence, and calls it &amp;ldquo;documentation.&amp;rdquo; Six months later that diagram is wrong, the person who knew how to update it has left, and nobody can remember what the arrows mean. I have lived this. PlantUML is the answer I landed on, and it&amp;rsquo;s been part of my workflow ever since.&lt;/p&gt;
&lt;p&gt;The core idea is simple: you write a text description of your diagram, and PlantUML generates the image. Because it&amp;rsquo;s text, it lives in your repository, diffs cleanly in pull requests, and can be regenerated in CI. No proprietary file formats. No &amp;ldquo;you need to install this app.&amp;rdquo; No screenshot-and-pray documentation workflows.&lt;/p&gt;
&lt;h2 id="key-takeaways"&gt;Key Takeaways&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;PlantUML diagrams are plain text — they belong in version control, not in a shared drive folder nobody remembers&lt;/li&gt;
&lt;li&gt;Supports sequence, class, component, state, activity, use case, and entity-relationship diagrams out of the box&lt;/li&gt;
&lt;li&gt;Integrates directly with VS Code, IntelliJ, and most CI/CD pipelines — low friction to add to an existing workflow&lt;/li&gt;
&lt;li&gt;Text-based means diagrams &lt;em&gt;can&lt;/em&gt; stay in sync with code; whether they &lt;em&gt;do&lt;/em&gt; stay in sync is still up to you&lt;/li&gt;
&lt;li&gt;It&amp;rsquo;s not the prettiest output by default, but skinparam and themes give you enough control to make it presentable&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="-what-is-plantuml"&gt;🧩 What is PlantUML?&lt;/h2&gt;
&lt;p&gt;PlantUML is a text-based diagramming tool created by Arnaud Roques in 2009. You write a description of your diagram using a purpose-built syntax, and PlantUML converts it to an image. That&amp;rsquo;s it. The genius is in what that enables downstream: version control, code review, CI automation, and a documentation workflow that doesn&amp;rsquo;t depend on anyone having the right desktop app installed.&lt;/p&gt;
&lt;p&gt;It supports a wide range of diagram types — more on that below — and has plugins for VS Code, IntelliJ, Eclipse, and several others.&lt;/p&gt;
&lt;h2 id="-how-plantuml-works"&gt;⚙️ How PlantUML Works&lt;/h2&gt;
&lt;p&gt;You write a text file, PlantUML generates the image. Here&amp;rsquo;s a minimal sequence diagram:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-plaintext" data-lang="plaintext"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;@startuml
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Alice -&amp;gt; Bob: Hello Bob, how are you?
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Bob --&amp;gt; Alice: I am good thanks!
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;@enduml
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;![PlantUML diagram](
align=&amp;ldquo;left&amp;rdquo;)&lt;/p&gt;
&lt;p&gt;That’s seven lines of text to produce a readable sequence diagram. No clicking, no dragging arrows around on a canvas, no wondering if your exported image is current.&lt;/p&gt;
&lt;h3 id="supported-diagram-types"&gt;Supported Diagram Types&lt;/h3&gt;
&lt;p&gt;PlantUML covers most of what you’ll need day to day:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Sequence Diagrams&lt;/strong&gt;: Interactions between components over time — great for API flows and auth sequences&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Class Diagrams&lt;/strong&gt;: Static structure, relationships, inheritance&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Component Diagrams&lt;/strong&gt;: System topology, dependencies, service boundaries&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;State Diagrams&lt;/strong&gt;: State machines and object lifecycle&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Activity Diagrams&lt;/strong&gt;: Workflows and process flows&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Entity-Relationship Diagrams&lt;/strong&gt;: Database schema — useful when you’re designing or debugging a data model&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="-why-plantuml-over-the-alternatives"&gt;🤔 Why PlantUML (Over the Alternatives)?&lt;/h2&gt;
&lt;p&gt;Let me actually answer this rather than just list features.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;It’s text.&lt;/strong&gt; That means diffs. That means code review. That means you can see when a diagram was last touched and who touched it. None of the GUI tools give you this — they give you a binary blob that either isn’t in version control at all or commits as “diagram.vsdx changed” with no useful diff.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;It runs in CI.&lt;/strong&gt; You can regenerate every diagram in your docs as part of a build. If something breaks, the build breaks. This is how documentation rot gets caught before it spreads.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;It’s not vendor-locked.&lt;/strong&gt; PlantUML is open source, runs on Java, and can be self-hosted. The syntax files are just text. If PlantUML ever disappears, your diagrams don’t — you still have the source and can render them with any compatible tool.&lt;/p&gt;
&lt;p&gt;The tradeoff is real though: &lt;strong&gt;it produces functional diagrams, not beautiful ones by default.&lt;/strong&gt; If you need polished, presentation-quality visuals for a pitch deck or an executive briefing, there are better tools. PlantUML is a documentation tool, not a design tool. Know the difference before you commit to it.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="-a-quick-comparison-with-other-tools"&gt;⚖️ A Quick Comparison with Other Tools&lt;/h2&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Tool&lt;/th&gt;
&lt;th&gt;Good for&lt;/th&gt;
&lt;th&gt;Watch out for&lt;/th&gt;
&lt;th&gt;In version control?&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;PlantUML&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Developer docs, CI-generated diagrams, anything that needs to evolve with code&lt;/td&gt;
&lt;td&gt;Not pretty by default; learning curve on the syntax&lt;/td&gt;
&lt;td&gt;✅ Native — it&amp;rsquo;s just text&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Mermaid&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Same use cases as PlantUML, native GitHub/GitLab rendering&lt;/td&gt;
&lt;td&gt;Fewer diagram types; complex diagrams get unwieldy fast&lt;/td&gt;
&lt;td&gt;✅ Native — also just text&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Draw.io&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Quick one-offs, whiteboard-style collaboration&lt;/td&gt;
&lt;td&gt;Manual export cycle; XML diffs are not human-readable&lt;/td&gt;
&lt;td&gt;⚠️ Technically yes, practically no&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Lucidchart&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Stakeholder-facing diagrams, polished outputs&lt;/td&gt;
&lt;td&gt;SaaS-only, subscription cost, no meaningful versioning&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Microsoft Visio&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Enterprise environments where everyone has it licensed&lt;/td&gt;
&lt;td&gt;Expensive, old-feeling, collaboration is painful&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;blockquote class="border-l-4 border-neutral-300 dark:border-neutral-600 pl-4 italic text-neutral-600 dark:text-neutral-400 my-6"&gt;
&lt;p&gt;&lt;strong&gt;Aside:&lt;/strong&gt; Mermaid is worth calling out specifically because it renders natively inside GitHub and GitLab markdown. If your audience is primarily reading diagrams on a git host rather than in built documentation, Mermaid has a real convenience edge. PlantUML requires a running server or a build step to produce images. Both are valid — the right answer depends on where your diagrams actually get read.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr&gt;
&lt;h2 id="-practical-tips"&gt;🛠️ Practical Tips&lt;/h2&gt;
&lt;p&gt;A few things I’ve learned using PlantUML on real projects:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Keep individual diagrams focused.&lt;/strong&gt; A sequence diagram that tries to show every variant of a flow is unreadable. Draw the happy path first. Then draw the error case separately. Two clear diagrams are better than one that requires a legend.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Use &lt;code&gt;!include&lt;/code&gt; to share common definitions.&lt;/strong&gt; If you have a set of actors, participants, or skinparam settings used across multiple diagrams, pull them into a shared &lt;code&gt;.iuml&lt;/code&gt; file and include it. This is especially useful when you’re generating docs from a repository — one skin change updates everything.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Use annotations and notes.&lt;/strong&gt; PlantUML supports &lt;code&gt;note left of&lt;/code&gt;, &lt;code&gt;note right of&lt;/code&gt;, and inline block notes. Use them for the decisions you want to preserve — the &lt;em&gt;why&lt;/em&gt; behind a sequence, not just the what. Diagrams without notes tend to lose their meaning faster than you’d expect.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Group and package related elements.&lt;/strong&gt; The &lt;code&gt;package&lt;/code&gt;, &lt;code&gt;node&lt;/code&gt;, and &lt;code&gt;rectangle&lt;/code&gt; groupings do a lot to make component diagrams legible at a glance. Here’s a simple example:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-plaintext" data-lang="plaintext"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;@startuml
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;package &amp;#34;Frontend&amp;#34; {
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; [Login Page] --&amp;gt; [Dashboard]
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; [Dashboard] --&amp;gt; [Profile Page]
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;package &amp;#34;Backend&amp;#34; {
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; [API Gateway] --&amp;gt; [Authentication Service]
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; [API Gateway] --&amp;gt; [Data Service]
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;[Login Page] -&amp;gt; [API Gateway]
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;@enduml
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;![PlantUML diagram](
align=&amp;ldquo;left&amp;rdquo;)&lt;/p&gt;
&lt;p&gt;This diagram clearly separates frontend and backend components. Anyone reading this immediately knows where the API boundary is, without needing to read the surrounding text.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="-examples"&gt;📋 Examples&lt;/h2&gt;
&lt;p&gt;Here are examples of the main diagram types, with context for when you&amp;rsquo;d actually reach for each one.&lt;/p&gt;
&lt;h3 id="sequence-diagram"&gt;Sequence Diagram&lt;/h3&gt;
&lt;p&gt;&lt;em&gt;Use for: API flows, auth sequences, anything where the order of messages between systems matters.&lt;/em&gt;&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-plaintext" data-lang="plaintext"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;@startuml
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;autonumber
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;actor User as user
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;participant &amp;#34;Browser UI&amp;#34; as browser
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;participant &amp;#34;Reseller UI&amp;#34; as reseller_ui
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;user -&amp;gt; browser : Visit the Reseller UI login page
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;browser -&amp;gt; reseller_ui : Retrieve the Reseller UI login page
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;browser &amp;lt;- reseller_ui : Return the login page with form field \nusername, password, and One Time Password(OTP)
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;user &amp;lt;- browser : Display the page, wait for user input
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;user -&amp;gt; user: Recall username and password \nfrom memory
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;user -&amp;gt; browser : Fill in the username and password field
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;user -&amp;gt; user: Open Google Authenticator, \nread the OTP
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;user -&amp;gt; browser : Fill in the OTP, and hit the send button
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;browser -&amp;gt; reseller_ui : Send the username, password and OTP
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;reseller_ui -&amp;gt; reseller_ui : Verify the information is valid
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;alt Login valid
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; browser &amp;lt;- reseller_ui : Return the logged in page
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; user &amp;lt;- browser : Display the logged in page
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;else Login invalid
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; browser &amp;lt;- reseller_ui : Return login failure page
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; user &amp;lt;- browser : Display the login failure page
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;end
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;@enduml
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;![PlantUML diagram](
align=&amp;ldquo;left&amp;rdquo;)&lt;/p&gt;
&lt;h3 id="class-diagram"&gt;Class Diagram&lt;/h3&gt;
&lt;p&gt;&lt;em&gt;Use for: modeling object relationships, documenting inheritance hierarchies, or producing a quick reference for an existing codebase.&lt;/em&gt;&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-plaintext" data-lang="plaintext"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;@startuml
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;hide circles
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Magic : numberActiveSpells : integer
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Magic : totalManaCostPerTurn : integer
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Magic &amp;lt;|-- Spells
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Spells : spellNumber[]: integer
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Spells : powerLevel: integer
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Spells : mannaPerTurn: bool
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Spells : mannaPerTarget: bool
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Spells : castSpell()
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Magic &amp;lt;|-- CounterSpells
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;CounterSpells : spellNumber[]: integer
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;CounterSpells : powerLevel: integer
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;CounterSpells : castCounterSpell()
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Magic &amp;lt;|-- MagicSupport
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;MagicSupport : mannaExpending: integer
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;MagicSupport : powerLevel: integer
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;MagicSupport : expendManna()
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;MagicSupport : getPowerLevel()
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;@enduml
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;![PlantUML diagram](
align=&amp;ldquo;left&amp;rdquo;)&lt;/p&gt;
&lt;h3 id="use-case-diagram"&gt;Use Case Diagram&lt;/h3&gt;
&lt;p&gt;&lt;em&gt;Use for: capturing what actors can do in a system — particularly useful early in requirements gathering when you need to communicate scope without getting into implementation details.&lt;/em&gt;&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-plaintext" data-lang="plaintext"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;@startuml
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;skinparam packageStyle rect
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;(Start) &amp;lt;|-- :Player_1:
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Player_1 &amp;lt;|-right- :Player_2:
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;(GamePlay) &amp;lt;-right-(Start)
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;(Movement) &amp;lt;-- (GamePlay)
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;(Move) &amp;lt;-- (Movement)
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Note top of (Move): Player moves in given direction
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;(Combat) &amp;lt;-- (GamePlay)
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Rectangle {
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; (Attack) &amp;lt;-- Combat
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; (Defend) &amp;lt;-- Combat
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;usecase (Access Menus) as Menus
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Menus &amp;lt;-- (GamePlay)
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;(Upgrades) &amp;lt;-- Menus
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Rectangle {
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; (Purchase) &amp;lt;-- Upgrades
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; (Utilize) &amp;lt;-- Upgrades
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;(Inventory) &amp;lt;-- Menus
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Rectangle {
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; (Use Item) &amp;lt;-- Inventory
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; (Drop Item) &amp;lt;-- Inventory
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; (Info) &amp;lt;-- Inventory
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Note right of Info: Short description of item
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;(Purchasing) &amp;lt;-- Menus
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Rectangle {
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; (Spend) &amp;lt;-- (Purchasing)
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; (Receive) &amp;lt;-- (Purchasing)
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;(Purchasing) &amp;lt;-- Purchase
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;@enduml
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;![PlantUML diagram](
align=&amp;ldquo;left&amp;rdquo;)&lt;/p&gt;
&lt;h3 id="activity-diagram"&gt;Activity Diagram&lt;/h3&gt;
&lt;p&gt;&lt;em&gt;Use for: process flows and decision logic. I reach for these when I need to document a workflow with branching paths — onboarding sequences, approval processes, retry logic.&lt;/em&gt;&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-plaintext" data-lang="plaintext"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;@startuml
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;start
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;:Open and Read Layout Configuration XML;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;repeat
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; :**Read Process**;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; repeat
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; :**Read Thread**;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; note: at least one should be there, the main thread
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; repeat
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; :**Read Component**;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; repeat
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; : **Read Interface**;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; repeat while(interfaces?)
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; : **Generate Interfaces Code**;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; repeat while(components?)
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; : **Generate Components Code**;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; repeat while(threads?)
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; : **Generate Threads Code**;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;repeat while(processes?)
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;:**Generate Processes Code**;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;stop
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;@enduml
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;![PlantUML diagram](
align=&amp;ldquo;left&amp;rdquo;)&lt;/p&gt;
&lt;h3 id="component-diagram"&gt;Component Diagram&lt;/h3&gt;
&lt;p&gt;&lt;em&gt;Use for: high-level system topology — which services exist, how they connect, where the data flows. Good for onboarding new engineers or explaining a system to someone who doesn&amp;rsquo;t need to see the code.&lt;/em&gt;&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-plaintext" data-lang="plaintext"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;@startuml
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;skinparam backgroundcolor transparent
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;node Backend
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;database Database
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;node Frontend
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;component Collectd
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;agent Client1
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;agent Client2
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;agent Client3
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;agent Client4
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Frontend -- Backend
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Backend -- Database
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Backend -- Collectd
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Collectd .. Client1
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Collectd .. Client2
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Collectd .. Client3
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Collectd .. Client4
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;@enduml
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;![PlantUML diagram](
align=&amp;ldquo;left&amp;rdquo;)&lt;/p&gt;
&lt;h3 id="state-diagram"&gt;State Diagram&lt;/h3&gt;
&lt;p&gt;&lt;em&gt;Use for: modeling object or entity lifecycle — order status, user account states, connection states. Anywhere you have a defined set of states and specific triggers that move between them.&lt;/em&gt;&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-plaintext" data-lang="plaintext"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;@startuml
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;title performing I/O
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;[*] --&amp;gt; Client
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Client: Process uri in Client
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Client -&amp;gt; Server : uri-data
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;state Server {
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; [*] -&amp;gt; monitor
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; monitor: Server starts monitoring
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; monitor: Stops at end of Server life
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Client -&amp;gt; Database: Client
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Database: database operations
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;state runcommand {
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; Database -&amp;gt; command: Database
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; command -&amp;gt; find: query
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; command: send command to server
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; monitor -&amp;gt; select: server-data
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; find --&amp;gt; select
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; select: select process to find proper server
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; select --&amp;gt; find: Server
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; find --&amp;gt; query: server
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; query: encodes query and send to server
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; query: decodes result
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; query --&amp;gt; find: result
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;find -&amp;gt; Cursor: cursor-data
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Cursor: stores docs
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Cursor: retrieves new docs
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Cursor -&amp;gt; fetch: document
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;fetch --&amp;gt; getmore
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;getmore: encodes query and send to server
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;getmore: decodes result
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;getmore --&amp;gt; fetch: new-documents
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;fetch -&amp;gt; [*]
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;@enduml
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;![PlantUML diagram](
align=&amp;ldquo;left&amp;rdquo;)&lt;/p&gt;
&lt;h2 id="-wrapping-up"&gt;🏁 Wrapping Up&lt;/h2&gt;
&lt;p&gt;PlantUML won&amp;rsquo;t make your documentation problems disappear — but it will make them much harder to ignore. When diagrams live in the same repository as the code they describe, the friction of keeping them current drops enough that people actually do it. That&amp;rsquo;s the real win here.&lt;/p&gt;
&lt;p&gt;If this saved you some research time, pass it on.&lt;/p&gt;</description></item></channel></rss>