Further decomposing a single container into its logical building blocks (modules, services, namespaces)
The Component Diagram (Level 3) takes one specific container from the Level 2 Container Diagram and decomposes it further — revealing the logical building blocks that collectively implement the container’s responsibilities.
This is not about listing classes, methods, or code files. Instead, it’s about identifying meaningful, cohesive groupings of functionality that represent higher-level design decisions: modules, services, subsystems, layers, bounded contexts, or other conceptual units that give the container its internal structure.
Think of it as answering: “If I were to explain how this container actually works internally — without showing code — what are the major logical pieces and how do they fit together?”
What Qualifies as a Component?
A component in the C4 Model is:
- A logical, cohesive unit of functionality with a clear responsibility
- Something that has (or could have) well-defined interfaces (e.g., public methods, API endpoints, event handlers, message consumers)
- A grouping that makes architectural sense — often aligned with domain concepts, layers, or technical concerns
- Independent enough that it could theoretically be extracted, replaced, mocked, or tested in isolation
Common component types you’ll identify when zooming into a container:
- Domain / Business Logic Components
- “Order Placement Service”
- “Pricing Engine”
- “Customer Profile Manager”
- “Inventory Reservation Aggregate”
- “Payment Orchestrator”
- These often map to DDD concepts: entities, aggregates, domain services, application services, anti-corruption layers, or bounded contexts.
- Technical / Infrastructure Components
- “REST API Controller Layer”
- “Event Publisher”
- “Notification Sender”
- “Audit Logger”
- “Configuration & Secrets Manager”
- “Metrics & Observability Adapter”
- Integration / Adapter Components
- “Database Repository / Data Access Layer”
- “External Payment Gateway Adapter”
- “Email Service Adapter”
- “Legacy System Anti-Corruption Layer”
- “Message Consumer / Event Handler”
- Cross-Cutting or Utility Components (use sparingly)
- “Authentication & Authorization Service”
- “Validation & Business Rule Engine”
- “Caching Layer”
- “Error Handling & Retry Policies”
How to Identify and Name Components Systematically
Use these practical heuristics to decompose a container:
- Follow responsibility & cohesion
- Group code that changes together for the same reason (Single Responsibility Principle at a higher level).
- Ask: “If I change how orders are priced, which parts are affected?” → Those parts belong in the same component.
- Apply domain-driven design lenses
- Look for bounded contexts, aggregates, domain events, subdomains.
- Example: In an “Order Service” container → components might be “Order Placement”, “Order Fulfillment”, “Order History Query”, “Order Event Publisher”.
- Use layering or hexagonal/ports-and-adapters patterns
- Common in many codebases:
- “API Layer / Controllers”
- “Application Services / Use Cases”
- “Domain Model / Business Logic”
- “Infrastructure / Adapters / Repositories”
- This works well for traditional layered architectures.
- Common in many codebases:
- Consider namespaces or modules in the codebase
- If your code is already organized into namespaces/folders like src/orders/placement, src/orders/fulfillment, src/payments/gateway, these are strong hints for component boundaries.
- Focus on interfaces and dependencies
- Each component should have clear incoming and outgoing dependencies.
- Ask: “What does this component need from others? What does it provide?”
Guidelines for Good Component Naming & Granularity
- Name with responsibility + type when helpful:
- “Order Placement Service”
- “Customer Domain Model”
- “Payment Gateway Adapter”
- Avoid generic names like “Service1”, “ModuleA”, “Helper”.
- Aim for 4–10 components per container
- Too few → you’re still at Container level or the container is too simple.
- Too many → you’re drifting toward code-level detail (Level 4).
- Keep it conceptual
- No class names, no Java annotations, no Spring @Component/@Service tags.
- Focus on “what it does”, not “how it’s implemented”.
Visualizing the Decomposition
In the diagram:
- The container itself becomes the boundary box (optional — some notations show components floating inside an implied container).
- Components are boxes inside it.
- Arrows show dependencies and interfaces (e.g., “Order Placement Service” depends on “Inventory Reservation”, “Payment Orchestrator” depends on “External Payment Adapter”).
- Label arrows with the nature of the interface if helpful (e.g., “calls”, “publishes events to”, “queries via”).
This zoomed-in view makes hidden complexity visible: tight coupling between components, god-classes masquerading as single responsibilities, missing abstractions, or opportunities for better separation of concerns.
In the hands-on section ahead, you’ll take a real container example (e.g., a monolithic backend or a complex microservice), apply these decomposition techniques, and iteratively build and refine a Component Diagram — using AI conversational refinement to explore alternatives, spot inconsistencies, and arrive at a clean, meaningful internal structure.
This level is where architecture meets design — and where the C4 Model helps turn vague “it’s complicated inside” feelings into clear, communicable structure. Let’s start breaking that container open, one logical block at a time.