CH10-06: Microservices Architecture Scenario
Goal
This section applies the Chapter 10 model to a growing commerce product. The point is not to split everything into services. The point is to explain which boundaries deserve independence, which Azure services support the design, and which operating model must exist before production.
The durable idea is:
A strong microservices design explains why each service boundary deserves independent ownership, data, communication, and operations.
Scenario
A commerce company has outgrown a single application. The product supports catalog browsing, checkout, payments, inventory reservation, fulfillment, recommendations, and an admin back office.
The current application is becoming hard to change because:
Orders and inventory need independent deployment during peak sales periods.
Payments have different security, audit, and partner integration requirements.
Recommendations change frequently and should not block checkout.
Fulfillment work may continue after the customer request ends.
Back-office administration changes slowly and is owned by the same team as the core application.
The team wants to use Azure but does not yet have a large Kubernetes platform team.
Step 1: Choose Boundaries by Independence
Do not start by drawing ten services. Start with the independence pressure.
| Capability | Service Boundary? | Reasoning |
|---|---|---|
| Catalog | Maybe service | Changes often and has clear product-data ownership. Could start as a service if catalog ownership is distinct. |
| Orders | Strong service candidate | Checkout reliability, order lifecycle, and customer impact justify clear ownership. |
| Payments | Strong service candidate | Security, audit, partner integration, and risk profile differ from other capabilities. |
| Inventory | Strong service candidate | Reservation and availability need independent scaling and careful consistency. |
| Fulfillment | Strong service candidate | Long-running work and external warehouse integration fit asynchronous processing. |
| Recommendations | Service candidate | Can change frequently and degrade without blocking checkout. |
| Admin back office | Maybe keep modular | Lower change pressure and shared ownership may not justify a separate service yet. |
This design avoids the trap of turning every module into a microservice automatically. It separates the capabilities where independence has operational value.
Step 2: Choose a Runtime Platform
Because the team has container skills but not a dedicated Kubernetes platform team, Azure Container Apps is a reasonable starting runtime. It can run the service containers, support managed scaling, expose ingress where needed, and reduce the amount of platform machinery the team must operate directly.
AKS may become appropriate later if the organization builds a platform team and needs Kubernetes APIs, ecosystem tools, advanced networking patterns, service mesh control, or standardized multi-team platform operations.
The initial runtime decision could be:
Public API boundary
-> API Management
-> Container Apps environment
-> Catalog service
-> Orders service
-> Payments service
-> Inventory service
-> Fulfillment service
-> Recommendations service
API Management can protect and govern external or partner-facing APIs. Not every internal service must be public. Some services may expose only internal endpoints or consume messages from Service Bus.
Step 3: Design Communication
The platform needs both synchronous and asynchronous communication.
Synchronous APIs fit immediate questions:
The web or mobile frontend calls product and catalog APIs.
Checkout calls the orders API to create an order.
Orders may call payments when an immediate authorization result is required.
Asynchronous messaging fits durable workflow and decoupling:
Orders sends a durable command to reserve inventory.
Orders publishes an order-created event for interested services.
Fulfillment receives durable work after the order reaches the right state.
Recommendations consumes events but does not block checkout.
A simple flow might look like this:
Customer checkout
-> API Management
-> Orders service
-> Payments service for authorization
-> Service Bus: ReserveInventory command
-> Service Bus: StartFulfillment command
-> Event: OrderCreated
Inventory service processes reservation.
Fulfillment service processes warehouse work.
Recommendations service reacts when useful, but checkout does not wait.
This is not a claim that every message must use the same Azure service. The design should choose Service Bus queues or topics for durable work and fan-out where appropriate, and event-routing options where notification semantics fit. The important point is that each path has a clear meaning.
Step 4: Own Data by Service
Each service should own its operational data where practical:
| Service | Owned Data |
|---|---|
| Catalog | Product information, categories, merchandising attributes. |
| Orders | Order records, order state, customer order history snapshots. |
| Payments | Payment attempts, authorization state, partner references, audit details. |
| Inventory | Stock availability, reservations, adjustment history. |
| Fulfillment | Shipment work, warehouse handoff state, fulfillment exceptions. |
| Recommendations | Recommendation models, feature snapshots, behavior signals. |
Azure SQL Database may fit services that need relational integrity and transactions. Azure Cosmos DB may fit services with document-style access patterns, high scale, or globally distributed read needs. The choice should follow the service's data model and access pattern, not a desire to use a different database for every service.
Cross-service reporting should avoid direct shared writes to operational tables. The team can build separate read models, analytics pipelines, or event-fed projections for reporting and customer support views.
Step 5: Design Security and Configuration
Each service needs secure access to the Azure resources it owns. Managed identities can let services access Azure resources without storing credentials in code. Azure Key Vault can hold secrets, certificates, and keys when secrets are still needed.
At a high level:
API Management handles external API boundary concerns such as routing, policies, and throttling.
Microsoft Entra ID or another identity provider authenticates users, applications, or partners depending on the scenario.
Managed identities help services access databases, messaging, Key Vault, and other Azure resources.
Azure RBAC and network controls limit what each service can reach.
Tags, budgets, and resource groups make ownership and cost visible.
Security should follow service ownership. The payments service should not have broad access to catalog data, and the recommendations service should not gain payment permissions because it runs in the same platform.
Step 6: Make Operations Real
Before production, the team needs an operating model:
| Operational Need | Design Response |
|---|---|
| Deployment | Independent pipelines with environment promotion and rollback. |
| Observability | Azure Monitor, Application Insights, logs, metrics, traces, and correlation IDs. |
| Messaging health | Service Bus backlog, dead-letter queues, retry counts, and processing latency. |
| Incident ownership | Each service has an owning team and escalation path. |
| Failure behavior | Timeouts, retries, idempotent handlers, fallbacks, and graceful degradation. |
| Cost visibility | Tags, budgets, dashboards, and per-service cost review. |
For example, if recommendations fails, product browsing should continue with a fallback. If inventory reservation is delayed, orders should show a clear pending state rather than pretending the reservation is complete. If Service Bus dead-letter queues grow, the owning team should know before customers report missing fulfillment.
A Reasonable First Architecture
The first version might be:
Users and partners
-> API Management
-> Catalog service + catalog data
-> Orders service + order data
-> Payments service + payment data and partner integration
-> Inventory service + inventory data
-> Fulfillment service + fulfillment data
-> Recommendations service + recommendation data
Orders service
-> Service Bus commands for inventory and fulfillment
-> events for downstream reactions
Platform foundation
-> Container Apps runtime
-> Managed identities and Key Vault
-> Azure Monitor and Application Insights
-> Azure Policy, RBAC, tags, budgets, and resource groups
The admin back office can remain a modular application for now. That is not inconsistent. It is disciplined. It keeps the design focused on independence where independence has value.
Common Mistakes
Splitting every module into a service on day one.
Choosing AKS before the organization can operate a Kubernetes platform.
Sharing one database across all services while claiming independent ownership.
Making checkout depend synchronously on every downstream capability.
Ignoring event contracts, duplicate messages, dead-letter handling, and cross-service troubleshooting.
Treating observability and incident ownership as post-launch tasks.
If Someone Asks You
How would you design Azure microservices for a commerce platform?
A good answer is:
I would start by identifying which capabilities need independent ownership and operations. Orders, payments, inventory, fulfillment, and possibly recommendations are strong service candidates because they have different change, reliability, security, and workflow needs. I would avoid splitting every module immediately. For a team without mature Kubernetes operations, I might start with Container Apps, use API Management for API boundary controls, Service Bus for durable workflow messages, service-owned data stores such as Azure SQL or Cosmos DB where they fit, managed identities and Key Vault for secure access, and Azure Monitor/Application Insights for observability. I would also define ownership, retries, idempotency, failure behavior, and cost visibility before production.
What You Should Remember
Justify each service by independence, ownership, and operational value.
Questions to Check Understanding
Which services in the scenario deserve independent ownership?
Which communication paths should be asynchronous?
What operating model must exist before production?