1. What a Component Diagram Shows
A component diagram shows independently deployable units and the interface contracts
they expose or depend on. Each component is a black box: its internal structure is
hidden, and it interacts with the world only through named interfaces. One interface
is provided - the component implements it and offers it to any caller.
Another is required - the component depends on some other unit to supply it.
The pairing of a provided interface on one component with a required interface on
another is an assembly connector. It says: these two components can be
wired together because one's output matches the other's input. The diagram does not
say which concrete type satisfies the requirement - that is a deployment or
configuration decision, not a design constraint.
Component diagrams sit between package diagrams and deployment diagrams in the UML
structural hierarchy. Package diagrams show compilation units; component diagrams
show runtime-substitutable units with explicit interface contracts; deployment
diagrams show which hardware nodes host which components. A system can be described
usefully at any of those levels without touching the others.
2. Notation
The core vocabulary is small: components, two kinds of interface symbol, and the
assembly connector that joins them.
| Element | Meaning |
| Component |
A rectangle labeled <<component>> or carrying the
component icon (a small rectangle with two tabs on its left edge). The body
may list internal parts or be left empty when only the interface matters.
|
| Provided interface (lollipop) |
A filled circle on a short line extending from the component boundary.
The component implements this interface and makes it available to any
requirer. Named on or beside the circle.
|
| Required interface (socket) |
A half-circle (open arc) on a short line extending from the component
boundary. The component depends on some other component to supply this
interface at runtime.
|
| Assembly connector |
A line connecting a provided lollipop to a required socket. The lollipop
fits inside the socket, forming a visual "ball-and-socket" joint. It asserts
that the provider's interface satisfies the requirer's contract.
|
| Port |
A small square on the component boundary through which a specific interface
is exposed or consumed. Ports name the interaction point independently of
the interface type, allowing one component to expose the same interface
through different ports for different clients.
|
| Dependency arrow |
A dashed arrow when a full assembly connector is not warranted - for example,
when the interface contract is informal or when the diagram is at a sketch level.
|
Mermaid has no native component diagram renderer. The diagrams on this page use
flowchart with labeled edges to approximate the assembly connector,
and <<component>> stereotypes in node labels to mark
each component. Arrow direction follows the convention: provider → requirer.
3. Notation in Practice
The diagram below shows two components wired by an assembly connector and one
component with a required interface that has no provider in scope - a deliberately
unresolved dependency, signaling that a third component must be supplied at
deployment time.
flowchart LR
CompA["<<component>>\nComponentA"]
CompB["<<component>>\nComponentB"]
CompC["<<component>>\nComponentC"]
CompA -->|"«provides» IServiceA"| CompB
CompC -.->|"«requires» ILogger\n(unresolved)"| ext["<<external>>\nLogger"]
Figure 1. Assembly connector notation.
A solid labeled edge links ComponentA's provided IServiceA to ComponentB's required
interface. ComponentC has an unresolved required interface shown as a dashed
dependency to an external placeholder.
4. TextFinder Interface Contracts
TextFinder has four components. Three are library components with a single provided
interface each. EntryPoint is the wiring component: it requires all three library
interfaces and additionally provides the callback interface that DirNav requires.
The callback provision is the structurally interesting point - it reverses the
usual direction and makes DirNav a client of EntryPoint at runtime.
| Component |
Provided interface |
Required interface |
| CommandLine |
ICmdLine - parse(args),
get(key) → Option,
get_all(key) → Vec
|
none |
| DirNav |
IDirNav - add_pattern(ext),
search(path, callback)
|
IDirEvent - do_dir(dir),
do_file(file)
|
| Output |
IOutput - set_regex(pattern),
find(path) → bool
|
none |
| EntryPoint |
IDirEvent (via TfAppl) - do_dir(dir),
do_file(file)
|
ICmdLine, IDirNav, IOutput
|
5. TextFinder Component Diagram
Four assembly connectors wire the system. Three flow from library components
toward EntryPoint - the libraries provide, EntryPoint consumes. The fourth runs
in the opposite direction: EntryPoint provides IDirEvent, which DirNav requires.
That reversed edge is the callback pattern made structurally explicit.
flowchart TD
CL["<<component>>\nCommandLine"]
DN["<<component>>\nDirNav"]
EP["<<component>>\nEntryPoint\n(hosts TfAppl)"]
OUT["<<component>>\nOutput"]
CL -->|"«ICmdLine»"| EP
OUT -->|"«IOutput»"| EP
DN -->|"«IDirNav»"| EP
EP -->|"«IDirEvent»"| DN
Figure 2. TextFinder component diagram.
Three arrows converge on EntryPoint from the library components. One arrow leaves
EntryPoint toward DirNav - the callback interface IDirEvent that DirNav requires
and EntryPoint provides via TfAppl.
6. Reading the Diagram
Two structural facts stand out that are not visible in the package diagram of the
same system.
DirNav has two edges, pointing in opposite directions. The
IDirNav edge points toward EntryPoint: DirNav provides, EntryPoint
consumes. The IDirEvent edge points away from EntryPoint: EntryPoint
provides, DirNav consumes. DirNav is simultaneously a service provider and a
service consumer in this assembly. The package diagram shows only the
IDirNav direction - the import - and hides the callback requirement
entirely.
CommandLine and Output are pure providers. No edge leaves them.
They have no required interfaces - they depend on nothing outside themselves. This
makes them the easiest components to test in isolation and the first candidates for
reuse in a different assembly. The component diagram makes that substitutability
visible without reading any source.
EntryPoint is the only component that appears on both ends of multiple
edges. It is the assembly hub - the component whose job is precisely to
connect the others. Identifying the assembly hub in a component diagram is useful:
it is the component most likely to need updating when an interface changes, and
the component that has the broadest test surface.
7. Component vs. Package Diagrams
Both diagram types are structural, and for a simple tool like TextFinder the two
views look similar. The distinction becomes important in larger systems.
| Concern |
Package diagram |
Component diagram |
| Primary question |
Which compilation unit imports which? |
Which runtime unit provides or requires which interface? |
| Dependency edge means |
A imports B - direct type dependency. |
A provides an interface that B requires - contract dependency. |
| Substitutability |
Not expressed. A depends on B, not on a B substitute. |
Explicit. Any component satisfying the interface can fill the slot. |
| Callback / inversion |
Hidden. Import arrows all point one way. |
Visible. A reversed assembly edge shows who provides the callback. |
| Granularity |
One package = one namespace or module. |
One component = one deployable unit, which may span multiple packages. |
| TextFinder fit |
Shows that EntryPoint imports all three library packages. |
Shows that DirNav both provides IDirNav and requires IDirEvent from EntryPoint. |
In a plugin system, a microservice mesh, or any architecture where components are
loaded or replaced at runtime, the component diagram is the more useful document.
In a statically compiled monolith where substitution never happens in practice,
the package diagram is often sufficient.
8. When to Draw One
Draw a component diagram when the question involves interface contracts and
substitutability rather than import structure or type detail. Specific
triggers:
-
Designing a plugin or extension point: the component diagram shows which
interface a plugin must provide and which the host will supply, without
committing to any concrete plugin type.
-
Documenting a service boundary in a distributed system: each service is a
component; the diagram shows the API contracts between services and makes
unresolved dependencies visible before deployment.
-
Planning a test strategy: components with no required interfaces (pure
providers) can be tested in isolation without mocking. The diagram identifies
them immediately.
-
Evaluating a design for replaceability: if a component can be swapped without
changing the rest of the assembly, the component diagram proves it by showing
that all connections go through named interface contracts.
When the interesting question is about compilation boundaries and import rules,
use a package diagram. When it is about type hierarchies and member relationships,
use a class diagram. Component diagrams earn their place when interface contracts
and runtime substitution are the design concern.
9. References
| Resource | Description |
|
Project Story: TextFinder
|
Architecture, CLI, performance, and code metrics for all five implementations. |
|
UML Package Diagrams
|
The compilation-boundary view of the same TextFinder structure - the closest structural diagram to compare against. |
|
UML Class Diagrams
|
The type-level view showing the members and relationships inside each component. |
|
Mermaid flowchart syntax
|
Full syntax reference for the Mermaid notation used to approximate component diagrams on this page. |
|
UML Component Diagrams Overview
|
Formal UML notation reference covering components, ports, interfaces, connectors, and substitution rules. |