Application Architecture
Application architecture is the arrangement of responsibilities, state, and communication—not a contest to draw the most boxes. Senior candidates choose boundaries that contain change and failure, keep invariants enforceable, and allow the organization to operate the system. A modular monolith can be more scalable and reliable than poorly divided microservices; an event-driven system can be more coupled through schemas and timing than a synchronous one.
How to use this chapter
- Read the mental model and mechanics without taking notes.
- Close the page and explain the topic aloud in five minutes.
- Work the quantitative example on paper.
- Answer the question ladder without revealing the answer signals.
- Complete one design drill and score yourself with the senior checklist.
Learning objectives
- Compare monoliths, modular monoliths, services, event-driven systems, and serverless functions without ideology.
- Identify domain, data, deployment, team, and failure boundaries.
- Choose synchronous versus asynchronous communication and manage their failure semantics.
- Separate stateless compute from durable state while recognizing genuinely stateful services.
- Design for evolution, migration, observability, and operational ownership.
- Explain control planes, data planes, and multi-tenant isolation at a senior level.
Mental model
Start with the domain and its invariants. Group behavior that changes together and data that must be updated atomically. Split when independent scaling, security isolation, ownership, or release cadence is worth the distributed-systems cost. Architecture should make the common path simple and the failure path explicit.
Core mechanics
Architecture styles and their real trade-offs
A monolith is one deployable unit; it may still have excellent internal modules. A modular monolith enforces dependency direction and ownership while retaining local transactions and simple debugging. Microservices create independently deployable processes around capabilities. Event-driven architecture uses durable or ephemeral events to decouple time and fan-out. Functions/serverless package short-lived handlers behind a managed runtime.
The style does not guarantee quality. A distributed monolith has many services that must deploy together, share databases, and call each other synchronously. A well-designed monolith can scale horizontally behind a load balancer and use queues for expensive work. Choose based on constraints, not fashion.
Bounded contexts, ownership, and invariants
A useful service boundary usually owns a coherent business capability, its code, and its data. It exposes contracts rather than tables. Strong invariants—such as “a payment capture cannot exceed the authorized amount”—are easiest to enforce inside one transactional boundary. Splitting that invariant across services requires a protocol, idempotency, compensation, and explicit intermediate states.
Data ownership does not mean no one else can read the data; it means changes flow through the owning contract and the owner defines semantics. Read models, change streams, and replicated views can serve other domains without giving them write access to internal tables.
Synchronous request paths
Synchronous calls are easy to understand and appropriate when a caller needs an immediate answer. They also compose latency and availability. A request that fans out to ten dependencies has more opportunities for a slow or failed branch, and retries can multiply load.
Senior designs use deadlines propagated end to end, bounded retries with jitter and budgets, circuit breaking, bulkheads, connection pooling, and fallbacks. They avoid deep call chains and distinguish required from optional dependencies. “Service A calls B” is incomplete without timeout, idempotency, overload, and failure behavior.
Asynchronous workflows
Queues and logs decouple producer rate from consumer rate and allow independent retries. They do not remove coupling: producers and consumers remain coupled through schema, meaning, ordering, retention, and operational expectations. Every handler should define its idempotency key, acknowledgment point, retry classification, dead-letter policy, and observability.
Long-running business transactions often use sagas: a sequence of local transactions with compensating actions or a central orchestrator. Compensation is not database rollback; it is a new business action that may itself fail. Explicit workflow state is usually safer than hiding a distributed transaction in ad hoc callbacks.
Stateless and stateful compute
Stateless request handlers are easy to replace and scale because durable truth lives elsewhere. Local caches and connection state can still exist, but the service must tolerate their loss. Session affinity may improve locality but should not become the only copy of important state.
Some components are inherently stateful: databases, stream processors, coordination services, and WebSocket gateways with live connections. They require placement, replication, recovery, and rebalancing plans. Calling everything stateless simply moves state into an undocumented place.
Control plane and data plane
The data plane handles the high-volume user or workload path. The control plane configures, schedules, discovers, authorizes, or manages the data plane. Keeping them separate can protect serving from administrative slowness and allow different consistency and availability goals.
A control-plane outage should not necessarily stop an already configured data plane. Cache last-known-good configuration, version changes, make rollouts idempotent, and design reconciliation. Conversely, stale control state can be dangerous, so define leases, expiry, and emergency disable paths.
Evolution and migration
Architecture is exercised most during change. Safe evolution uses backward-compatible contracts, expand-and-contract database migrations, dual reads/writes only with reconciliation, shadow traffic, canaries, and explicit rollback. A boundary that cannot be migrated independently is not truly independent.
Strangler migrations incrementally route capabilities from an old system to a new one. The hard parts are identity, duplicated state, source of truth, consistency windows, and retirement criteria—not the routing proxy itself.
Decision table
| Decision | Prefer the first option when… | Prefer the second option when… | Senior caveat |
|---|---|---|---|
| Modular monolith vs microservices | The domain/team is small, invariants span modules, and deployment independence has low value. | Teams need independent ownership/scaling or strong isolation justifies network boundaries. | Start with enforceable module boundaries; extraction should follow measured pain, not anticipated prestige. |
| Synchronous vs asynchronous | The caller needs an immediate result and the dependency is fast/reliable enough for the latency budget. | Work can complete later, bursts must be buffered, or fan-out/retry isolation matters. | Async shifts complexity to ordering, duplicates, lag, workflow state, and user-visible status. |
| Orchestration vs choreography | A workflow needs explicit state, auditability, deadlines, and centralized policy. | The flow is simple and independent subscribers react without global sequencing. | Unbounded choreography becomes hard to discover and reason about; orchestration can become a central bottleneck. |
| Shared database vs database per service | Atomic cross-module invariants and operational simplicity dominate. | Independent schema ownership, scaling, and isolation dominate. | A shared server with separate schemas can be an intermediate step; ownership rules matter more than slogans. |
| Serverless vs long-running service | Bursty, event-driven work fits execution limits and managed scaling reduces toil. | Steady traffic, long-lived connections, low latency, or runtime control matters. | Model cold starts, concurrency limits, state, observability, and provider-specific failure modes. |
| Single region vs multi-region active | RTO permits regional recovery and consistency/simplicity are more valuable. | Latency or availability requires serving through a regional loss. | Multi-region is a data-consistency and operations program, not merely duplicate compute. |
Quantitative reasoning
Failure modes and production signals
| Failure mode | What users see | Likely cause | Mitigation / design response | Useful signals |
|---|---|---|---|---|
| Cascading synchronous failure | Broad latency spike and timeouts | One dependency slows; callers retry and exhaust pools | Deadlines, retry budgets, circuit breakers, bulkheads, shed optional calls | Dependency latency, retry rate, pool saturation, request fan-out |
| Distributed monolith | Small change requires coordinated release; incidents span many teams | Tight runtime/data coupling despite many services | Clarify ownership, remove cycles, introduce contracts, merge or decouple services | Deployment coupling, call graph, shared-table access, change failure rate |
| Queue backlog | Delayed workflows and stale state | Consumer capacity loss, poison messages, traffic burst | Autoscale on age, isolate poison messages, backpressure producers, replay safely | Oldest message age, lag by partition, retry/DLQ rate |
| Split source of truth | Conflicting values and irreconcilable user state | Dual writes without transaction or reconciliation | Choose authority, outbox/change capture, idempotent repair, audit log | Mismatch counters, reconciliation lag, duplicate events |
| Control-plane outage | New changes fail; data plane may or may not continue | Central config/discovery unavailable | Last-known-good config, leases, local caching, degraded operations | Config freshness, reconciliation errors, lease expiry |
| Noisy tenant | One customer degrades others | Shared pools and unbounded per-tenant demand | Quotas, fair queues, isolated shards/pools, admission control | Per-tenant cost, saturation, queue age, throttles |
Senior-level lenses
Boundaries must align across dimensions
Code, data, deployment, on-call, and business ownership can disagree. A service owned by Team A but dependent on Team B’s table is not autonomous. During design, state who owns the contract, data, migrations, capacity, and incidents. Sometimes the right answer is organizational change rather than another API.
Localize invariants
Strong invariants that cross network boundaries become protocols. Before introducing a saga or distributed lock, ask whether the boundary should move so the invariant is local. When it cannot, model intermediate states and recovery as first-class domain concepts.
Design the degraded product
Reliability is often achieved by deciding what can be stale, omitted, queued, or read-only. A home page may omit recommendations; checkout may not omit payment authorization. Senior candidates classify dependencies by criticality and describe a user-coherent degraded mode.
Architecture includes operations
Every component adds dashboards, alerts, capacity models, deployments, security patches, and on-call paths. Estimate the operational surface area. Prefer a boring component when it meets requirements and the team can run it well.
Multi-tenancy is a policy problem
Isolation spans identity, authorization, data partitioning, encryption, quotas, billing, observability, and incident containment. Decide whether tenants share tables, shards, clusters, accounts, or regions and how they move between tiers without downtime.
Evolution is the proof of modularity
Ask how to change schemas, split a service, rotate an API, or migrate a tenant while both versions run. Backward compatibility and reconciliation are stronger evidence of architecture quality than a static diagram.
Interview question ladder
What is the difference between a monolith and a modular monolith?
Show strong-answer signals
A monolith is one deployable unit; a modular monolith additionally enforces internal boundaries, ownership, and dependency direction. It can still scale horizontally.
Why are stateless application servers easier to scale?
Show strong-answer signals
Any instance can handle a request; replacement and load balancing are simple. Clarify that durable/session state must live in a replicated store or recoverable layer.
When is asynchronous communication useful?
Show strong-answer signals
Burst absorption, decoupled timing, fan-out, retry isolation, and long work. Also mention duplicates, lag, ordering, and user-visible status.
What makes a microservice boundary good or bad?
Show strong-answer signals
Good boundaries align capability, data ownership, invariants, team ownership, scaling, and failure isolation. Bad boundaries are entity CRUD services, shared tables, chatty calls, and coordinated releases.
How do you prevent retries from causing a cascade?
Show strong-answer signals
End-to-end deadlines, retry only transient/idempotent operations, exponential backoff with jitter, retry budgets, circuit breakers, and load shedding.
Explain saga orchestration versus choreography.
Show strong-answer signals
Orchestrator stores workflow state and commands steps; choreography reacts to events. Compare auditability, coupling, discoverability, centralization, and compensation.
A company wants to split a checkout monolith into services. How would you choose the first extraction?
Show strong-answer signals
Map domain/invariants and change pain; choose a capability with clear ownership, low cross-transaction coupling, and measurable scaling or release benefit. Describe strangler routing, data ownership, compatibility, observability, and rollback.
Design a request path that depends on inventory, pricing, recommendations, and fraud. Which calls are synchronous?
Show strong-answer signals
Classify correctness-critical versus optional, define latency budget/deadlines, cache or precompute where possible, queue noncritical work, and give coherent degraded behavior.
How would you design a control plane so serving continues during its outage?
Show strong-answer signals
Versioned desired state, local cache/last-known-good, reconciliation, leases/expiry, idempotent rollout, scoped blast radius, emergency controls, and audit.
A queue-backed workflow occasionally executes a side effect twice. What architecture changes do you make?
Show strong-answer signals
Idempotency key and dedupe store, transactional outbox/inbox, atomic state transition with acknowledgment, effect-specific reconciliation, and clear exactly-once scope.
Propose a multi-tenant architecture that supports shared, isolated, and dedicated tiers.
Show strong-answer signals
Common identity/control plane; placement metadata; tenant-aware routing; shared shards with quotas; isolated clusters for higher tiers; encryption and observability; online migration and billing.
How do you decide whether to merge two services rather than further decouple them?
Show strong-answer signals
Use change/deploy coupling, cross-service invariants, synchronous chatter, incident ownership, scaling profiles, and team structure. Explain migration and contract simplification, not only organization preference.
Design drills
You inherit a 60-developer commerce monolith with weekly releases, a shared relational database, and frequent checkout regressions. Produce a target architecture and a two-stage migration plan. Identify which modules stay together because of invariants.
What the interviewer is testing
Boundary selection, incremental migration, data ownership, release safety, and avoidance of a distributed monolith.
Design a platform that accepts email, push, and SMS requests, supports scheduled delivery, per-tenant quotas, templates, retries, and delivery receipts. Decide which path is synchronous and where workflow state lives.
What the interviewer is testing
Sync/async decomposition, tenant isolation, idempotency, provider failure, control/data plane separation.
A user-profile service is globally read-heavy but writes must remain ordered per user. Design regional serving and describe behavior when the home region is unreachable.
What the interviewer is testing
Data ownership, consistency scope, routing, failover semantics, read staleness, and operational recovery.
Common weak answers and how to improve them
“Microservices scale better.”
Show the stronger answer
Name the independent scaling or isolation need and include network, data, deployment, and on-call costs.
“Use events to decouple everything.”
Show the stronger answer
Specify schema ownership, ordering, retention, replay, idempotency, and which business workflow observes completion.
“The app servers are stateless.”
Show the stronger answer
Identify connection state, caches, sessions, local files, in-flight jobs, and how loss is handled.
“We will do a saga if the transaction fails.”
Show the stronger answer
Model workflow states and compensation before implementation; compensation is a fallible business action, not automatic rollback.
“Put a circuit breaker around it.”
Show the stronger answer
Define thresholds, open/half-open behavior, fallback, retry interaction, observability, and how to avoid synchronized recovery.