This article highlights a critical gap in architectural documentation for asynchronous, queue-heavy systems: traditional C4 container diagrams often fail to represent the actual runtime execution flow. It argues that while C4 is useful for deployable units, dynamic sequence diagrams and end-to-end tracing are essential for understanding actual process hops, especially for incident response, where a simple three-box diagram can hide a complex seven-hop reality.
Read original on Dev.to #systemdesignArchitectural diagrams, such as those following the C4 model, are invaluable for visualizing system structure. However, this article presents a crucial insight: for systems leveraging asynchronous communication heavily (e.g., message queues, background jobs), a static container diagram may dangerously oversimplify the actual runtime execution flow of a single business transaction. This discrepancy can lead to significant challenges during incident troubleshooting, as the diagram doesn't reflect the "seven hops" behind a seemingly simple "three-box" view.
The core issue identified is that a C4 container diagram accurately depicts deployable units and their structural relationships, but it does not inherently answer the question of "what actually runs, in what order, for this one business action." When a request traverses multiple services, queues, and background jobs (e.g., Node.js Function -> Blob Storage -> Service Bus -> .NET Function -> Hangfire), each step represents an independent execution hop. Failing to visualize these individual hops obscures the true failure surface and makes diagnosing issues extremely difficult.
Diagrams are Not Just for Design, But for Incidents
The article emphasizes that the cost of incomplete diagrams becomes painfully clear during incidents. Without a clear understanding of the full execution path, incident resolution devolves into multiple teams manually searching logs across disparate systems, often based on imprecise timestamps. This significantly prolongs mean time to resolution (MTTR).
The practical solution implemented was distributed tracing using OpenTelemetry. This allowed for the propagation of a correlation ID across all services, queues, and background jobs involved in a transaction. A key challenge highlighted was ensuring context propagation across components that don't inherently support it, like Hangfire's Redis-backed queue, which requires explicit coding to carry the trace ID.
The core takeaway is that architectural documentation for asynchronous systems must evolve beyond mere structural views. By integrating dynamic flow diagrams and robust distributed tracing, teams can gain a far more accurate and actionable understanding of their systems' runtime behavior, drastically improving operational effectiveness and incident response.