Diagrams: Dependency Visualization¶
Drydock generates four kinds of Mermaid diagrams, each answering a different architectural question. All output is deterministic, safe to share, and bounded to stay legible.
Four Diagram Kinds¶
Layer Diagrams — "How are modules stacked?"¶
Renders topological dependency levels as horizontal bands. Modules sink to lower levels if they have no load-time dependencies; modules rise if they import from others. Edges flow downward, showing stability order.
What it shows: - Depth 0 (foundation) → most stable, least dependent - Depth 1 → depends on depth 0 - Depth N → depends on earlier levels
Good for: Spotting inversions ("a core module importing application code"), understanding build order, finding layers that are too deep (overly stratified design).
Constraints: - Bounded to 60 most-connected modules; rest truncated with "N more" label - Only load-time edges; deferred imports (type-only, test fixtures) are ignored - Deterministic: same graph always produces byte-identical output
Example:
graph TD
layer0["Depth 0 (3 modules)"]
id1["models.py"]
id2["config.py"]
layer1["Depth 1 (2 modules)"]
id3["db.py"]
id3 --> id1
id3 --> id2
omitted["1 of 6 modules omitted; showing the most connected"]
Package Diagrams — "How do packages couple?"¶
Collapses modules into directories (packages). Shows cross-package dependencies, not within-package. Each node is a directory; edges represent one package depending on another.
What it shows: - Package instability (Ce / (Ca + Ce), where 0 = stable, 1 = unstable) - Afferent coupling (Ca) — how many packages depend on this one - Efferent coupling (Ce) — how many packages this depends on - Dependency violations (unstable package depending on stable one)
Good for: Refactoring decisions ("should this package be split?"), spotting circular dependencies between packages, understanding high-level architecture.
Constraints: - Bounded to 40 most-coupled packages - Node color by instability (not yet implemented; currently monochrome)
Example:
Seam Diagrams — "Which modules implement this contract?"¶
Shows a single contract and all its implementations, plus their dependencies. Arrows point at the contract, not the reverse — implementers depend on the seam, not the other way around.
What it shows: - Contract (interface, protocol, abstract base) - All implementations - Public symbols in each - Dependencies between implementations
Good for: Understanding plugin architecture, verifying contract compliance, planning extraction.
Constraints:
- Focused on one seam; pass --seam CONTRACT to specify
- Arrows point at the contract (correct dependency direction for plugins)
- Truncated to 50 nodes if very large
Example:
graph TD
contract["IProcessor (contract)"]
impl1["FastProcessor"]
impl2["SlowProcessor"]
impl1 -->|implements| contract
impl2 -->|implements| contract
impl1 -->|uses| impl2
Component Diagrams — "What's inside this component?"¶
Shows modules and dependencies within a single extracted component. Useful for verifying that extraction didn't miss dependencies or inadvertently included external modules.
What it shows: - All modules in the component - Internal dependencies only - External dependencies marked separately (truncated list)
Good for: QA after extraction, verifying component boundaries, spotting missed dependencies.
Constraints: - Scoped to one component - Bounded to prevent massive graphs
Key Constraints (Why They Matter)¶
Mermaid has no backslash escape¶
Problem: A label with a quote " cannot be escaped as \" — Mermaid treats backslash as literal.
Solution: Labels use HTML entities (#quot; for quotes, #lt; and #gt; for angle brackets). Verified against mermaid-cli 11.16.
Node ids carry a content hash¶
Problem: Path segments like a/b.py, a-b.py, a.b.py, and a_b.py all normalize to the same Mermaid id when translated naively. The diagram silently merges unrelated modules.
Solution: Each node id includes a digest of the full path, ensuring distinct modules always map to distinct ids.
Every edge is real¶
Problem: Inferred or fabricated edges (e.g., "module X might depend on module Y based on naming patterns") make diagrams misleading.
Solution: Every arrow represents an actual import statement in the source code. No inference, no guesses. If an edge isn't in the diagram, the dependency doesn't exist.
Output is bounded¶
Problem: A layer diagram of a 300-module project produces 1,000+ lines and is unreadable.
Solution: Only the most-connected modules survive the cap (60 for layers, 40 for packages). Truncation is stated in the diagram rather than applied silently:
You still get the essential structure; less-connected modules aren't shown but their absence is clear.
Seam arrows point at the contract¶
Problem: If arrows pointed from the contract to implementations, the diagram would suggest that adding a new implementation requires modifying the contract. That's backwards.
Solution: Arrows point at the contract. Implementations depend on the seam; the seam doesn't depend on them. The direction correctly conveys that implementations can be added or removed without changing the contract.
Determinism¶
Problem: Non-deterministic output makes diagrams hard to version-control, review, or reproduce in CI.
Solution: Same input graph always produces byte-identical Mermaid output. Sorted edge lists, sorted node lists, no randomness or threshold-based variation.
Using Diagrams¶
Generate and view locally¶
# Output Mermaid source
drydock diagram /project --kind layers --markdown
# Pipe to mermaid-cli for PNG
drydock diagram /project --kind layers --markdown | mmdc -i /dev/stdin -o diagram.png
# Or paste into GitHub Markdown / Notion / Mermaid Live Editor
Export to PDF/SVG¶
# Install mermaid-cli if you haven't
npm install -g @mermaid-js/mermaid-cli
# Generate and export
drydock diagram /project --kind layers --markdown | \
mmdc -i /dev/stdin -o diagram.svg
Share with non-technical stakeholders¶
Layer diagrams work well for explaining build order and dependencies to product managers or stakeholders. Seam diagrams are great for showing plugin architecture in design reviews.
Integrate into documentation¶
Embed diagram Mermaid in your project README or Wiki:
Common Pitfalls¶
"The diagram is too big"¶
If output is truncated, you have more than 60–40 of the most-connected nodes. This often means:
- Too coarse a granularity — Try the package diagram instead of the layer diagram
- Too fine a granularity — Consider merging small utility modules
- Missing components — You have a large monolith; use
drydock boundariesto find natural extraction points
"The diagram looks wrong"¶
Before assuming a bug:
- Check the source — Are the imports really there? Run
drydock codemapto see what the dependency analyzer found - Check the filter — Layer diagrams exclude deferred imports by default (type hints, test fixtures). Might your dependencies be deferred?
- Check for cycles — Run
drydock architecture --markdownto see if dependency cycles are causing unexpected layer assignment
"I see modules that shouldn't be there"¶
Module inclusion is based on the dependency graph, not your mental model. If a module appears:
- Verify the import — Search the source code for the import statement
- Check if it's a test — Did you exclude test files? Use
--include-tests=false - Check scope — Is it in a language you disabled? Run
drydock languagesto see what's included
Technical Details¶
Rendering Pipeline¶
- Build graph — Walk source tree, extract imports, resolve to modules
- Compute metrics — Afferent/efferent coupling, instability, depth
- Render diagram — Call layer/package/seam/component function, emit Mermaid
- Escape labels — HTML-entity-escape special characters
- Validate — Ensure all edges reference declared nodes (test mode only)
Performance¶
Diagram generation is typically sub-second for projects up to 500 modules. Larger projects may take a few seconds (mostly time spent computing metrics, not rendering Mermaid).
Diagram Kinds in API¶
For programmatic use (building a GUI, composing with other tools):
from drydock.diagram.mermaid import (
layer_diagram,
package_diagram,
seam_diagram,
component_diagram,
)
from drydock.arch.graph import DependencyGraph, build_graph
from drydock.core.registry import AnalysisContext
ctx = AnalysisContext("/path/to/project")
graph = build_graph(ctx)
# Generate diagrams
layers = layer_diagram(graph, max_nodes=60)
packages = package_diagram(graph, max_nodes=40)
# For seams, you need the analysis context and a Seam object
# (typically obtained from architecture analysis results)
All functions return Mermaid source as a string (no fences).
Validation¶
All 48 generated diagrams in Drydock's regression suite (four diagram kinds, across eleven adversarial fixtures with cycles, empty modules, deep nesting, etc.) render cleanly through mermaid-cli 11.16.
See Also¶
- Catalog — Store and query generated diagrams
- Architecture Analysis — Principles that complement diagrams
- Boundary Detection — Find extraction candidates