Component & Integration Design
Component and integration design draws the boxes — the services, databases, and external systems — and decides how the arrows between them actually talk.
At a glance
Section titled “At a glance”- What it is: Identifying the components (services, databases, external systems) a solution needs and deciding the integration pattern between each pair — a synchronous API call, an asynchronous message, or a batch data transfer.
- Why it matters: this is the part of the design every downstream team inherits — get the arrows wrong and the pain (cascading failures, tight coupling, unclear ownership) shows up long after launch.
- For developers: this is the actual architecture diagram you’ll be handed before writing code — if an integration is drawn as a plain arrow with no pattern noted, ask whether it’s meant to be sync or async before you build against it.
- When to use it: after Non-Functional Requirements are known, since the NFRs often determine which integration pattern is viable.
- When not to use it: to over-decompose a simple problem into many components “for flexibility” it doesn’t need yet.
- Prerequisites: a chosen solution option and its NFR targets.
Mental model
Section titled “Mental model”flowchart LR
A[Web Storefront] -- sync API call --> B[Checkout Service]
B -- async event --> C[Analytics Store]
B -- sync call --> D[Payment Gateway]
Each arrow is a deliberate choice, not a default. Synchronous calls are simple but couple the caller to the callee’s availability; asynchronous messaging decouples them at the cost of added complexity (queues, eventual consistency).
Step-by-step walkthrough
Section titled “Step-by-step walkthrough”- List the components the scoped solution needs — existing systems it must touch, and any new ones the chosen option requires.
- For each pair of components that need to exchange data, decide: does the caller need an immediate response (sync), or can it continue without waiting (async)?
- Check each integration choice against the relevant Non-Functional Requirements — a hard availability target usually rules out tight synchronous coupling to a less-reliable system.
- Draw the component diagram with the pattern labeled on each arrow, not just the direction.
- Flag any new dependency on a system outside the initiative’s control as an input to Risk & Constraint Management.
Worked example
Section titled “Worked example”A marketing team wants live dashboards of site activity without slowing down the production storefront.
- Input: a requirement to add real-time analytics to an existing e-commerce platform.
- Process: querying the production database directly for dashboards would compete with checkout traffic for the same resources, risking the storefront’s own NFRs; instead, the design streams events asynchronously through a message queue to a separate analytics store.
- Output: the storefront publishes events without waiting for the analytics side to process them; the analytics store and dashboards read from the queue independently, so a slowdown on the analytics side never affects checkout.
- On Azure, this is typically an Azure Service Bus topic between the storefront and an independent analytics consumer writing to its own Azure Cosmos DB store:
// Storefront: fire-and-forget publish — checkout never waits on the analytics sideawait using var client = new ServiceBusClient(connectionString);ServiceBusSender sender = client.CreateSender("site-activity");
var message = new ServiceBusMessage(JsonSerializer.SerializeToUtf8Bytes(activityEvent)){ ContentType = "application/json"};
await sender.SendMessageAsync(message);Alternative: a serverless consumer. Instead of an always-on Container Apps consumer, the analytics side can be an Azure Function with a Service Bus trigger — useful when the consumer’s workload is bursty and paying for idle capacity isn’t worth it. Martin Fowler’s Serverless Architectures article frames the trade-off: less operational overhead and pay-per-execution cost, at the price of cold-start latency and tighter coupling to the platform’s runtime model.
[Function("ProcessSiteActivity")]public async Task Run( [ServiceBusTrigger("site-activity", Connection = "ServiceBusConnection")] string message, FunctionContext context){ var activityEvent = JsonSerializer.Deserialize<SiteActivityEvent>(message); await _cosmosContainer.UpsertItemAsync(activityEvent, new PartitionKey(activityEvent.SessionId));}Choosing between the two isn’t about which is “better” in the abstract — it’s another entry for Technology Selection: an Azure Function is cheaper at low or bursty volume, a Container Apps consumer is cheaper and more predictable at sustained high volume.
Common use cases
Section titled “Common use cases”| Use case | When to use | Notes |
|---|---|---|
| Adding a reporting/analytics feature | The new feature shouldn’t affect an existing system’s performance | Prefer async streaming over direct production-database queries |
| Calling an external payment or identity provider | The caller needs to know the outcome before continuing | Sync call is usually required, but combine with the provider’s SLA in your own NFRs |
| Connecting two systems owned by different teams | Coupling one team’s deploys to another’s availability is a risk | Async messaging reduces the blast radius of one side being down |
| Bursty, unpredictable consumer workload | Traffic is spiky rather than steady | An Azure Function (consumption plan) avoids paying for idle capacity; an always-on consumer suits steady, high-throughput streams |
Advanced details
Section titled “Advanced details”- Sync vs. async is a trade-off, not a preference: sync is simpler to reason about but couples availability; async decouples availability at the cost of eventual consistency and operational complexity (queues, retries, dead-letter handling).
- Label the pattern, not just the arrow: a diagram arrow without a stated pattern (sync/async/batch) leaves the actual behavior to be discovered during implementation.
- New external dependencies are new risks: every arrow to a system outside the initiative’s control should show up in Risk & Constraint Management.
- One diagram usually isn’t enough — use separate views: arc42 splits this concern into three distinct views answering three different questions — the Building Block View (static structure: what components exist and how they’re nested), the Runtime View (behavior: the sequence of calls for a specific scenario, like the payment confirmation flow), and the Deployment View (infrastructure: which building block runs on which node). A single “boxes and arrows” diagram that tries to answer all three at once tends to leave out the information a specific stakeholder actually needs.
- This work spans TOGAF ADM Phases C and D: component identification and data flows correspond to Phase C (Information Systems Architecture — data and application), while the technology and platform choices behind each component correspond to Phase D (Technology Architecture).
Quick reference
Section titled “Quick reference”| Term | Meaning |
|---|---|
| Component | A service, database, or system that is a distinct part of the solution |
| Synchronous (sync) integration | The caller waits for a response before continuing |
| Asynchronous (async) integration | The caller continues without waiting; the response (if any) arrives later, often via a queue or event |
| Eventual consistency | Data across components converges to the same state over time, not instantly, as a consequence of async integration |
| Building Block View / Runtime View / Deployment View | arc42’s three structural, behavioral, and infrastructure views of a design — a component diagram is usually a mix of these that’s clearer when split apart |
Troubleshooting
Section titled “Troubleshooting”| Symptom | Likely cause | Fix |
|---|---|---|
| A new feature slows down an unrelated existing system | They share a synchronous dependency (often a database) under new load | Move the new feature to an async integration against its own data store |
| Diagram looks fine but nobody knows if a call is sync or async | Integration pattern wasn’t labeled on the arrow | Annotate every arrow with its pattern before implementation starts |
| One team’s outage cascades into another’s | Tight synchronous coupling between independently-deployed systems | Introduce a queue or async boundary, or add a fallback/circuit breaker |
Check your understanding
Section titled “Check your understanding”- Why might querying a production database directly for a new reporting feature be risky?
- Take an integration you’ve built and decide whether it should have been sync or async, and why.
Related pages
Section titled “Related pages”Part of Introduction to Solution Architecture. Follows Non-Functional Requirements; feeds into Technology Selection and Risk & Constraint Management. See also the Glossary.