Overview
Chapter 02: Architecture Diagramming-as-Code (Mermaid, PlantUML & D2)
Playbook Track: 05 – Presentation Slides & Architecture Diagrams (Visual Systems, Claude Code & Antigravity Workflows)
Target Audience: Year 1 Computer Science & Software Engineering Students Core Tooling Stack: Mermaid.js, D2 (Terrastruct), PlantUML / Graphviz, Gemini 2.5 Flash (DSL Code Gen), Python 3.11+
Delivery Status: 🔍 Ready for Review (Tier 1 Markdown)
1. The Big Picture & Real-World Analogy
Writing in Markdown vs. LaTeX vs. HTML
When writing technical documents, software engineers use different markup languages depending on where the document will live:
- Markdown: Lightweight, human-readable, and renders natively in GitHub, Notion, and Slack. Great for quick notes and READMEs.
- LaTeX: The formal academic and mathematical standard with 30 years of history. Requires a heavy compiler, but produces pixel-perfect textbook typography.
- HTML/CSS: Highly flexible, responsive, and modern.
The "Big Three" Diagramming-as-Code engines share this exact same dynamic:
- Mermaid.js (The Markdown of Diagrams): Renders natively inside GitHub READMEs, Notion, and Discord without installing anything. If you need a diagram visible in a Git pull request, Mermaid is king!
- PlantUML (The LaTeX of Diagrams): The 20-year enterprise workhorse. Requires Java and Graphviz, but supports every formal UML diagram type and the entire C4 architecture standard library.
- D2 (The Modern Next-Gen DSL): Created by Terrastruct to fix the flaws of Mermaid and PlantUML. Features clean modern syntax, superior layout algorithms (TALA), and beautiful default typography.
By representing your system as an abstract intermediate model, you can write once and transpile to whichever engine your team or slide deck requires!
2. Engineering Jargon Demystifier Table
| Industry Term | What It Actually Means | Freshman Student Analogy |
|---|---|---|
| Mermaid.js | A lightweight JavaScript library that turns simple text into flowcharts and sequence diagrams natively in GitHub. | Typing Markdown # Header instead of opening Word and setting font size to 24pt. |
| PlantUML | An open-source tool that uses Graphviz to generate formal UML diagrams from text descriptions. | A rigorous compiler like javac that checks and builds formal software blueprints. |
| D2 (Declarative Diagramming) | A modern diagramming language built specifically for software architecture with advanced layout algorithms. | A modern styling system like Tailwind CSS compared to 1990s HTML table styling. |
| Layout Engine (Dagre / Graphviz / TALA) | The underlying math algorithm that calculates where boxes sit on the canvas and routes connecting lines without overlaps. | A GPS navigation app that calculates the shortest route between points with zero traffic jams. |
| Transpiler | A program that translates source code from one language to another (e.g. converting a Python dictionary into Mermaid and D2). | An automated translator converting an English essay into French and Spanish. |
| Orthogonal Routing | Drawing connecting arrows using only 90-degree right angles (horizontal and vertical lines) instead of diagonal slants. | Driving on grid-based city streets (like Manhattan) rather than cutting diagonally through parks. |
3. The 5-Minute Micro-Lab: The Multi-Engine Transpiler
Run this zero-dependency Python script to see how an in-memory graph is transpiled into both Mermaid.js and D2 formats in under 20 lines of code:
"""
Micro-Lab: Multi-Engine Diagram Transpiler
PB-05 Chapter 2 Micro-Lab (Zero External Dependencies)
"""
def transpile_graph(nodes: list, edges: list) -> dict:
# 1. Generate Mermaid Flowchart (direction LR)
mermaid_lines = ["flowchart LR"]
for src, dst, label in edges:
mermaid_lines.append(f" {src} -->|{label}| {dst}")
mermaid_output = "\n".join(mermaid_lines)
# 2. Generate D2 Diagram
d2_lines = ["direction: right"]
for src, dst, label in edges:
d2_lines.append(f'{src} -> {dst}: "{label}"')
d2_output = "\n".join(d2_lines)
return {"mermaid": mermaid_output, "d2": d2_output}
if __name__ == "__main__":
nodes = ["WebClient", "APIGateway", "Database"]
edges = [
("WebClient", "APIGateway", "HTTPS REST"),
("APIGateway", "Database", "SQL Query")
]
result = transpile_graph(nodes, edges)
print("=== Transpiled Mermaid.js Code ===")
print(result["mermaid"])
print("\n=== Transpiled D2 Code ===")
print(result["d2"])
4. Comparative Syntax Mechanics & Layout Algorithms
In enterprise software engineering, architectural diagrams serve distinct audiences with varying requirements:
- Developers reading GitHub pull requests need lightweight, inline diagrams that render natively in Markdown without external dependencies.
- Enterprise Architects designing multi-region cloud infrastructures require hierarchical container nesting, cloud provider icons, and strict layout routing.
- Security & Reliability Engineers auditing distributed failure domains need sequence diagrams with explicit synchronous calls, asynchronous event streams, and circuit breaker fallbacks.
To satisfy these demands without manual redrawing, architects must master the "Big Three" declarative diagramming engines: Mermaid.js, PlantUML, and D2.
+---------------------------------------------------------------------------------------------------+
| THE BIG THREE DECLARATIVE DIAGRAMMING ENGINES |
+---------------------------------------------------------------------------------------------------+
| |
| 1. MERMAID.JS 2. PLANTUML 3. D2 (TERRASTRUCT) |
| - Native in GitHub/Notion - Enterprise standard - State-of-the-art modern DSL |
| - Zero install (JS in browser) - C4-PlantUML standard library - TALA / ELK / Dagre pluggable |
| - Dagre layout engine - Graphviz Dot layout engine - Native container nesting |
| - Ideal for READMEs & PRDs - Ideal for formal UML & C4 - Ideal for complex cloud arch |
| |
| SYNTAX CONTRAST: |
| |
| Mermaid: PlantUML: D2: |
| flowchart LR @startuml direction: right |
| A[Client] -->|HTTP| B[(DB)] [Client] --> [DB] : HTTP client: "Client" -> |
| @enduml db: "DB" { shape: cylinder |
| } : "HTTP" |
| |
+---------------------------------------------------------------------------------------------------+
1.1 Layout Engine Mechanics: Dagre vs. Graphviz vs. TALA
A declarative diagram is only as readable as the algorithmic layout engine that positions its vertices and routes its edges:
- Dagre (JavaScript / Mermaid):
- Uses a simplified adaptation of the Sugiyama hierarchical graph drawing algorithm.
- Computes node ranks, orders vertices within ranks to minimize edge crossings, and calculates B-spline curves.
- Limitation: Struggles with bidirectional feedback loops and dense non-hierarchical topologies, frequently resulting in awkward line overlaps.
- Graphviz Dot (PlantUML):
- The battle-tested C-based industry standard for hierarchical layout.
- Extremely rigorous ranking and edge routing with configurable subgraphs and clustering.
- Limitation: Requires an underlying C/Java runtime; sensitive to minor node additions (can cause entire diagram layouts to jitter or invert).
- TALA & ELK (D2):
- TALA (Terrastruct Architecture Layout Algorithm): The first layout engine designed specifically for software architecture diagrams rather than mathematical trees.
- Minimizes line bends, handles nested containers naturally, and preserves semantic flow without reversing arrows.
- ELK (Eclipse Layout Kernel): Open-source force-directed and layered layout engine supporting complex orthogonal routing.
6. Multi-Engine Transpilation & Layout Pipeline State Machine
flowchart TD
A["Canonical Architecture Model: G = (V, E, Clusters)"] --> B["Multi-Engine Transpiler"]
B --> C["Mermaid Target: flowchart TD / LR, subgraphs, cylinder shapes"]
B --> D["D2 Target: direction down / right, nested objects, shape declarations"]
B --> E["PlantUML Target: @startuml, components, databases, sequence flows"]
C --> F["Headless Renderer: mmdc CLI -> Scalable SVG"]
D --> G["D2 Compiler: d2 CLI (TALA / ELK engine) -> Interactive SVG"]
E --> H["PlantUML Java CLI -> Vector PDF / EPS"]
F & G & H --> I["Visual QA & Bounding Box Inspection"]
style A fill:#f5f5f5,stroke:#9e9e9e,stroke-width:2px;
style B fill:#e8f5e9,stroke:#4caf50,stroke-width:2px;
style I fill:#e1f5fe,stroke:#03a9f4,stroke-width:2px;
3. Gate 2: Mandatory Manual vs. Programmatic Contrasts
Migrating from manual diagramming to multi-engine Diagramming-as-Code transforms engineering workflows:
| Architectural Dimension | Manual Dragging (Draw.io, Lucidchart) | Programmatic DaC (Mermaid, D2, PlantUML) | Operational Consequence |
|---|---|---|---|
| Multi-Format Export | Must redraw the entire diagram if switching between a technical wiki and an executive deck. | Single canonical model transpiles to Mermaid for GitHub and D2/PPTX for presentations. | Huge time savings; zero redundant redrawing across document formats. |
| Edge Routing Stability | Human manually drags Bezier curve handles around boxes to avoid collisions. | Algorithmic routing engines (Dagre, Graphviz, TALA) calculate mathematical edge paths automatically. | Eliminates human visual fatigue and inconsistent crooked connector lines. |
| Asynchronous Distinctions | Author forgets to change line style; synchronous REST and async Kafka events look identical. | Formal syntax guarantees: --> for synchronous blocking calls; -.-> or ->> for async events. |
Prevents critical distributed systems misunderstandings and race conditions. |
| Automated Translation | Impossible: manual diagrams cannot be automatically translated or ported. | Programmatic transpilation via Python AST engines bridges Mermaid, PlantUML, and D2 seamlessly. | Enables autonomous AI agents to refactor documentation across enterprise toolchains. |
| CI/CD Build Automation | Broken links in wikis when images are deleted or renamed. | Headless CLI compilation validates diagram syntax during Git pre-commit hooks and GitHub Actions. | Zero broken diagram images or syntax errors ever reach production branches. |
4. Gate 3: Frontier AI Prompts & Transpilation Schemas
Frontier models like Gemini 2.5 Flash excel at generating and transpiling declarative diagram code when guided by rigorous structural rules.
4.1 Multi-Engine Architecture Generator Prompt (gemini-2.5-flash)
SYSTEM INSTRUCTION: You are a Principal Systems Architect and Diagramming-as-Code Specialist.
TASK: Generate both Mermaid and D2 declarative source code for the provided distributed system architecture.
CONSTRAINTS:
1. Identify all services, datastores, queues, and gateways.
2. For Mermaid:
- Use 'flowchart LR' for horizontal pipelines; 'flowchart TD' for layered tiers.
- Use [("Datastore")] for databases; (["Gateway"]) for gateways; [["Queue"]] for message brokers.
- Use dotted lines (-.->) for asynchronous messages; solid lines (-->) for synchronous calls.
3. For D2:
- Define nested containers with curly braces {}.
- Explicitly assign shapes: shape: cylinder, shape: queue, shape: cloud, shape: person.
- Use ->> for asynchronous messaging; -> for synchronous requests.
4. Output structured, compilable DSL code blocks without conversational filler.
4.2 Structured JSON Schema for Architecture Graphs (MultiEngineArchitectureGraphSchema)
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"title": "ArchitectureSystemGraph",
"type": "object",
"properties": {
"system_name": { "type": "string" },
"direction": { "type": "string", "enum": ["TD", "LR"] },
"clusters": {
"type": "object",
"additionalProperties": { "type": "string" }
},
"nodes": {
"type": "object",
"additionalProperties": {
"type": "object",
"properties": {
"node_id": { "type": "string" },
"label": { "type": "string" },
"node_type": { "type": "string", "enum": ["SERVICE", "DATABASE", "QUEUE", "GATEWAY", "USER", "EXTERNAL"] },
"technology": { "type": ["string", "null"] },
"cluster": { "type": ["string", "null"] }
},
"required": ["node_id", "label", "node_type"]
}
},
"edges": {
"type": "array",
"items": {
"type": "object",
"properties": {
"source_id": { "type": "string" },
"target_id": { "type": "string" },
"label": { "type": "string" },
"protocol": { "type": ["string", "null"] },
"is_async": { "type": "boolean" }
},
"required": ["source_id", "target_id", "label", "is_async"]
}
}
},
"required": ["system_name", "direction", "clusters", "nodes", "edges"]
}
5. Gate 4: Quantitative Visual & Tooling Trade-Off Matrix
The following matrix compares the core technical capabilities, CLI dependencies, and layout mechanics across Mermaid, PlantUML, and D2:
| Feature / Capability | Mermaid.js | PlantUML | D2 (Terrastruct) |
|---|---|---|---|
| Compilation Dependencies | Node.js (@mermaid-js/mermaid-cli) or browser JS |
Java JRE + Graphviz binaries | Single self-contained Go binary (d2) |
| CLI Compilation Latency | Moderate (1.2s – 2.5s via headless Chromium) | Moderate (0.8s – 1.8s via Java/Graphviz) | Ultra-Fast (0.05s – 0.2s via Go binary) |
| Native GitHub Markdown Support | Universal (Native code blocks in GitHub/GitLab) | [FAIL] Requires external rendering proxy or Action | [FAIL] Requires GitHub Action or pre-compiled SVG |
| Nested Subgraph Ergonomics | Moderate (subgraphs cannot easily cross boundaries) | Good (packages and components) | Superior (Arbitrary nested objects {} with scoped IDs) |
| Layout Engine Support | Dagre (Default), ELK (Experimental) | Graphviz Dot, Neato, Fdp, Sfdp | TALA (Proprietary), ELK, Dagre |
| Cloud Icons Ecosystem | Community font-awesome icons | Comprehensive AWS/Azure/GCP sprite libraries | Native icon support (icon: https://...) |
| Interactive HTML Outputs | Clickable links only | Clickable SVG links | Pan, zoom, animated connections, tooltips |
6. Gate 5: The 10 Methodological Threats to Validity & Diagramming Pitfalls
When authoring multi-engine architecture diagrams, engineers must avoid ten technical pitfalls:
1. Unescaped Delimiters in Node Labels
- Threat: In Mermaid, using parentheses or brackets inside a label (e.g.,
A[Order Service (v1.0)]) breaks the regex parser and causes rendering failure. - Defense: Always wrap label strings in double quotes inside the shape brackets:
A["Order Service (v1.0)"].
2. Phantom Dependency Inversion
- Threat: In Dagre/Graphviz layout, adding an upward arrow can inadvertently flip the vertical ranking of the entire diagram, placing the database at the top and the client at the bottom.
- Defense: Use non-constraining invisible edges or specify explicit rank constraints; in D2, use
direction: down.
3. Duplicate Node IDs Across Subgraphs
- Threat: Defining node
dbinside Subgraph A and another nodedbinside Subgraph B creates an unintended merged node in Mermaid. - Defense: Namespace all node IDs prefixed with their container or cluster ID (e.g.,
cluster_a_db,cluster_b_db).
4. Over-Constrained Graphviz Spline Spaghetti
- Threat: Connecting every microservice to a shared telemetry daemon creates a visual web of crossing lines that obscures system causality.
- Defense: Omit cross-cutting infrastructure (logging, metrics, tracing) from the core topology diagram and document it in an ADR footnote or dedicated observability view.
5. Asynchronous vs. Synchronous Confounding
- Threat: Drawing synchronous HTTP REST calls with the same arrow as asynchronous Kafka events, misleading engineers into assuming blocking consistency.
- Defense: Strict visual contract: solid arrows
-->for synchronous blocking; dotted arrows-.->for asynchronous events.
6. Java Runtime Dependency Failures in CI/CD
- Threat: PlantUML build jobs failing on minimal Alpine Linux CI containers due to missing
graphvizoropenjdksystem packages. - Defense: Use modern single-binary tools like
d2or containerized renderers with pinned digest hashes.
7. Layout Jitter in Git Diff Reviews
- Threat: A developer adds a single node to a PlantUML diagram, causing Graphviz to calculate a completely different global layout, making the visual diff unreviewable.
- Defense: Adopt D2's TALA engine, which guarantees localized incremental routing without scrambling existing node positions.
8. Hardcoded Dimension Inflexibility
- Threat: Specifying fixed pixel widths on nodes that clip long service names or wrap awkwardly on mobile viewports.
- Defense: Rely on dynamic text-wrapping engines; set standard maximum label character lengths ($\le 32$ chars).
9. Broken Relative Image Links in Exported SVGs
- Threat: Embedding external icon URLs (
http://...) that fail to render when SVG diagrams are viewed in offline PDF reports. - Defense: In-line all icon assets as base64 data URIs during the compilation build step.
10. Missing Semantic Legends
- Threat: Presenting a diagram with 4 different line colors and 3 dashed line patterns without an explanatory legend.
- Defense: Automatically generate a standardized architectural legend defining all shapes, line styles, and protocol markers.
11. Gate 6: Mandatory Hands-On Lab (Visual Engineering Challenge)
Objective
You will engineer an automated Multi-Engine Diagram Transpiler & Syntax Validator in Python 3.11+, transforming a canonical distributed system graph into idiomatic, validated Mermaid.js and D2 source code.
Experimental Protocol
- Model Formulation: Define an e-commerce microservices architecture containing 7 nodes (Web Client, Kong Gateway, Order Service, Payment Service, Kafka Bus, PostgreSQL DB, and Stripe API) distributed across two Kubernetes clusters.
- Mermaid Transpilation: Transpile the system model into
flowchart LRMermaid syntax, formatting clustered subgraphs, semantic shapes ([("...")],(["..."])), and explicit protocol labels. - D2 Transpilation: Transpile the same model into modern D2 syntax, verifying nested container scoping (
{}), shape properties (shape: cylinder,shape: queue), and asynchronous connectors (->>). - Parity Validation: Programmatically verify that every node and edge in the canonical model is faithfully preserved across both output languages.
12. Gate 7: Mandatory Recommended Answer & Executable Solution
The following zero-dependency Python 3.11+ script provides the complete reference implementation of the Multi-Engine Diagram Transpiler & Syntax Validator.
"""
test_ch02_diagram_engine.py
Zero-dependency Python 3.11+ engine for PB-05 Chapter 2:
MultiEngineDiagramTranspiler & SyntaxValidator
"""
from dataclasses import dataclass, field
from enum import Enum
from typing import List, Dict, Any, Optional
class ArchNodeType(str, Enum):
SERVICE = "SERVICE" # Box / Rectangle
DATABASE = "DATABASE" # Cylinder
QUEUE = "QUEUE" # Queue / Buffer
GATEWAY = "GATEWAY" # Rounded / Hexagon
USER = "USER" # Person / Actor
EXTERNAL = "EXTERNAL" # Cloud / Third-Party
@dataclass
class ArchNode:
node_id: str
label: str
node_type: ArchNodeType = ArchNodeType.SERVICE
technology: Optional[str] = None
cluster: Optional[str] = None
@dataclass
class ArchEdge:
source_id: str
target_id: str
label: str
protocol: Optional[str] = None
is_async: bool = False
@dataclass
class ArchSystemGraph:
system_name: str
direction: str # "TD" or "LR"
nodes: Dict[str, ArchNode] = field(default_factory=dict)
edges: List[ArchEdge] = field(default_factory=list)
clusters: Dict[str, str] = field(default_factory=dict) # cluster_id -> cluster_label
class MultiEngineDiagramTranspiler:
"""Transpiles generic architectural graph models into idiomatic Mermaid and D2 source code."""
@classmethod
def to_mermaid(cls, graph: ArchSystemGraph) -> str:
lines = [f"flowchart {graph.direction}"]
# Group nodes by cluster
clustered_nodes: Dict[Optional[str], List[ArchNode]] = {}
for n in graph.nodes.values():
clustered_nodes.setdefault(n.cluster, []).append(n)
# Render clusters
for cid, nodes in clustered_nodes.items():
indent = " "
if cid:
clabel = graph.clusters.get(cid, cid)
lines.append(f" subgraph {cid}[\"{clabel}\"]")
indent = " "
for n in nodes:
full_label = f"{n.label}<br/>[{n.technology}]" if n.technology else n.label
if n.node_type == ArchNodeType.DATABASE:
node_def = f"{n.node_id}[(\"{full_label}\")]"
elif n.node_type == ArchNodeType.GATEWAY:
node_def = f"{n.node_id}([\"{full_label}\"])"
elif n.node_type == ArchNodeType.QUEUE:
node_def = f"{n.node_id}[[\"{full_label}\"]]"
elif n.node_type == ArchNodeType.USER:
node_def = f"{n.node_id}((\"{full_label}\"))"
elif n.node_type == ArchNodeType.EXTERNAL:
node_def = f"{n.node_id}{{\"{full_label}\"}}"
else:
node_def = f"{n.node_id}[\"{full_label}\"]"
lines.append(f"{indent}{node_def}")
if cid:
lines.append(" end")
# Render edges
for e in graph.edges:
edge_desc = f"{e.label} ({e.protocol})" if e.protocol else e.label
if e.is_async:
arrow = f"-.->|\"{edge_desc}\"|"
else:
arrow = f"-->|\"{edge_desc}\"|"
lines.append(f" {e.source_id} {arrow} {e.target_id}")
return "\n".join(lines)
@classmethod
def to_d2(cls, graph: ArchSystemGraph) -> str:
lines = [
f"# D2 Architecture Model: {graph.system_name}",
f"direction: {'down' if graph.direction == 'TD' else 'right'}",
""
]
# Group by cluster
clustered_nodes: Dict[Optional[str], List[ArchNode]] = {}
for n in graph.nodes.values():
clustered_nodes.setdefault(n.cluster, []).append(n)
for cid, nodes in clustered_nodes.items():
indent = ""
if cid:
clabel = graph.clusters.get(cid, cid)
lines.append(f"{cid}: \"{clabel}\" {{")
indent = " "
for n in nodes:
full_label = f"{n.label}\\n[{n.technology}]" if n.technology else n.label
lines.append(f"{indent}{n.node_id}: \"{full_label}\" {{")
if n.node_type == ArchNodeType.DATABASE:
lines.append(f"{indent} shape: cylinder")
elif n.node_type == ArchNodeType.QUEUE:
lines.append(f"{indent} shape: queue")
elif n.node_type == ArchNodeType.USER:
lines.append(f"{indent} shape: person")
elif n.node_type == ArchNodeType.EXTERNAL:
lines.append(f"{indent} shape: cloud")
else:
lines.append(f"{indent} shape: rectangle")
lines.append(f"{indent}}}")
if cid:
lines.append("}")
lines.append("")
# Edges in D2
for e in graph.edges:
edge_desc = f"{e.label} ({e.protocol})" if e.protocol else e.label
conn = "->>" if e.is_async else "->"
lines.append(f"{e.source_id} {conn} {e.target_id}: \"{edge_desc}\"")
return "\n".join(lines)
# ==========================================
# Self-Test Verification Suite
# ==========================================
if __name__ == "__main__":
import unittest
class TestMultiEngineTranspiler(unittest.TestCase):
def setUp(self):
self.graph = ArchSystemGraph(
system_name="ECommercePlatform",
direction="LR",
clusters={
"k8s_cluster": "Kubernetes Microservices Mesh",
"data_tier": "Managed Data Storage"
}
)
# Add Nodes
self.graph.nodes["client"] = ArchNode("client", "Shopper Web App", ArchNodeType.USER)
self.graph.nodes["gateway"] = ArchNode("gateway", "Kong API Gateway", ArchNodeType.GATEWAY, technology="Envoy/Kong", cluster="k8s_cluster")
self.graph.nodes["order_svc"] = ArchNode("order_svc", "Order Service", ArchNodeType.SERVICE, technology="Go / Gin", cluster="k8s_cluster")
self.graph.nodes["payment_svc"] = ArchNode("payment_svc", "Payment Gateway Proxy", ArchNodeType.SERVICE, technology="Node.js / TS", cluster="k8s_cluster")
self.graph.nodes["kafka"] = ArchNode("kafka", "Event Streaming Bus", ArchNodeType.QUEUE, technology="Apache Kafka", cluster="data_tier")
self.graph.nodes["order_db"] = ArchNode("order_db", "Order Datastore", ArchNodeType.DATABASE, technology="PostgreSQL 16", cluster="data_tier")
self.graph.nodes["stripe"] = ArchNode("stripe", "Stripe SaaS API", ArchNodeType.EXTERNAL)
# Add Edges
self.graph.edges.append(ArchEdge("client", "gateway", "Browse & Checkout", protocol="HTTPS / TLS 1.3"))
self.graph.edges.append(ArchEdge("gateway", "order_svc", "Dispatch Order", protocol="gRPC"))
self.graph.edges.append(ArchEdge("order_svc", "payment_svc", "Process Charge", protocol="gRPC"))
self.graph.edges.append(ArchEdge("order_svc", "order_db", "Persist Order State", protocol="SQL"))
self.graph.edges.append(ArchEdge("order_svc", "kafka", "Publish OrderCreated", protocol="TCP", is_async=True))
self.graph.edges.append(ArchEdge("payment_svc", "stripe", "Execute Payment", protocol="HTTPS REST"))
def test_mermaid_transpilation_validity(self):
mmd = MultiEngineDiagramTranspiler.to_mermaid(self.graph)
self.assertIn("flowchart LR", mmd)
self.assertIn("subgraph k8s_cluster[\"Kubernetes Microservices Mesh\"]", mmd)
self.assertIn("subgraph data_tier[\"Managed Data Storage\"]", mmd)
self.assertIn("order_db[(\"Order Datastore<br/>[PostgreSQL 16]\")]", mmd)
self.assertIn("-.->|\"Publish OrderCreated (TCP)\"| kafka", mmd)
self.assertIn("-->|\"Dispatch Order (gRPC)\"| order_svc", mmd)
def test_d2_transpilation_validity(self):
d2 = MultiEngineDiagramTranspiler.to_d2(self.graph)
self.assertIn("direction: right", d2)
self.assertIn("k8s_cluster: \"Kubernetes Microservices Mesh\" {", d2)
self.assertIn("shape: cylinder", d2)
self.assertIn("shape: queue", d2)
self.assertIn("shape: cloud", d2)
self.assertIn("order_svc ->> kafka: \"Publish OrderCreated (TCP)\"", d2)
self.assertIn("gateway -> order_svc: \"Dispatch Order (gRPC)\"", d2)
def test_node_and_edge_parity(self):
mmd = MultiEngineDiagramTranspiler.to_mermaid(self.graph)
d2 = MultiEngineDiagramTranspiler.to_d2(self.graph)
# Check that all 7 node IDs are present in both
for nid in self.graph.nodes:
self.assertIn(nid, mmd)
self.assertIn(nid, d2)
suite = unittest.TestLoader().loadTestsFromTestCase(TestMultiEngineTranspiler)
runner = unittest.TextTestRunner(verbosity=2)
test_result = runner.run(suite)
if not test_result.wasSuccessful():
exit(1)
print("\n[PASS] All PB-05 Chapter 2 Unit Tests Passed Successfully (100% Conformance).")
Verification & Execution Output
When executed in Python 3.11+, this engine confirms Mermaid and D2 transpilation validity and node-edge parity:
test_d2_transpilation_validity (__main__.TestMultiEngineTranspiler.test_d2_transpilation_validity) ... ok
test_mermaid_transpilation_validity (__main__.TestMultiEngineTranspiler.test_mermaid_transpilation_validity) ... ok
test_node_and_edge_parity (__main__.TestMultiEngineTranspiler.test_node_and_edge_parity) ... ok
----------------------------------------------------------------------
Ran 3 tests in 0.001s
OK
[PASS] All PB-05 Chapter 2 Unit Tests Passed Successfully (100% Conformance).
9. Summary & Visual Engineering Milestone Checklist
Before moving to Chapter 03 (C4 Model Visual Ontology & Structurizr Automation):
- Analyzed layout engine mechanics: Dagre vs. Graphviz vs. TALA.
- Contrasted manual diagramming with multi-engine Diagramming-as-Code.
- Calibrated Gemini 2.5 Flash prompts for dual-target Mermaid and D2 code generation.
- Compiled the Quantitative Trade-Off Matrix across Mermaid, PlantUML, and D2.
- Analyzed and mitigated the 10 Technical Diagramming Failure Modes.
- Executed and validated the zero-dependency Python 3.11+ multi-engine transpiler engine.