Microservices Architecture and Service Decomposition Questions
Decomposing a system into services along bounded contexts, defining service boundaries and ownership, and managing the tradeoffs against a monolith. Covers cohesion, coupling, data ownership per service, the distributed-monolith anti-pattern, and when a modular monolith beats microservices. Emphasizes decomposition reasoning rather than any single framework.
How would you quantify and present the technical risk and business cost of having many microservices with overlapping responsibilities, versus consolidating some of them into fewer services? Describe the metrics you would gather (deployment coordination overhead, on-call load, infra cost per service, cross-service change frequency), any lightweight experiments you might run, and how you would present the trade-off to executives who are not engineers.
Sample Answer
Direct answer
To quantify the cost of too many overlapping-responsibility microservices, measure deployment coordination overhead (how often a single logical change requires touching multiple services in lockstep), on-call and incident load per service, infrastructure cost per service (even a nearly-idle service carries a fixed baseline cost), and cross-service change frequency (how often a change to one service requires a corresponding change to another); present the trend in those numbers to executives rather than an architectural opinion about service count.
Structured elaboration
Deployment coordination overhead is measurable directly: track how many recent releases required coordinating changes across two or more services that, if consolidated, would have been a single deploy, and how much calendar time that coordination added compared to a single-service change. On-call load is measurable from incident data: total pages per service per month, and specifically how many of those incidents were caused by an inter-service contract mismatch (a caller and callee disagreeing about a field's meaning or an API version) rather than a genuine bug in one service's own logic, since contract mismatches are a direct symptom of over-decomposition. Infrastructure cost is measurable from the cloud bill: baseline compute, monitoring, and logging cost per service, multiplied by the number of services that could plausibly be consolidated without losing a real scaling or ownership benefit. Cross-service change frequency is measurable from version-control history: how often a pull request in one service's repo is immediately followed by a corresponding pull request in another service's repo within a short window, a proxy for services that are more tightly coupled in practice than their separate deployability suggests.
Worked example
A lightweight experiment to gather this evidence without a large upfront investment: instrument the deploy pipeline to tag any release that required a coordinated multi-service change, and run that for a month before making a consolidation recommendation, rather than relying on anecdotes about "it feels like everything requires touching three services." Present the finding to executives in business terms: "N% of releases in the last quarter required coordinating three or more services, adding an average of X days to the release; consolidating these two specific services would remove that coordination cost for roughly Y% of those releases," rather than a purely technical argument about service-count aesthetics.
Trade-offs and pitfalls
The risk of presenting this case poorly is framing it as "we have too many microservices" in the abstract, which invites a debate about architectural philosophy instead of a decision grounded in measured cost; naming the SPECIFIC services with the worst coordination and incident numbers, and proposing a targeted consolidation of just those, is both more persuasive and less risky than a broad "let's reduce our service count" initiative. The countervailing risk is consolidating services that look similar on paper but actually have a real, measured difference in scaling or team ownership; the same data-gathering discipline that justifies a consolidation should also be used to rule one out when the signals don't actually support it.
Explain the operational impact of decomposing a monolith into many small services on deployment pipelines, incident management, and on-call rotations. As the service count grows, how would you design the operations model (paging policy, ownership routing, tooling) to limit alert fatigue while keeping reliability high?
Sample Answer
Direct answer
Decomposing a monolith into many small services shifts operational load from "deploy and operate one thing" to "deploy and operate N things," which multiplies the number of deployment pipelines, the number of places an incident can originate, and the number of services someone needs to be paged for, so the operations model needs to change deliberately (routing, on-call structure, alerting design) rather than simply scaling the old monolith-era practices across more services.
Structured elaboration
Deployment pipelines: a monolith has one pipeline to maintain and improve; N services means N pipelines unless there's a shared, templated deployment approach, so investing in a standard, reusable pipeline template early (rather than letting each service reinvent its own) is what keeps this from becoming N times the maintenance burden. Incident management: with a monolith, on-call needs deep familiarity with one large system; with many services, on-call needs either broad familiarity with many smaller systems (harder to maintain deep expertise in each) or a routing mechanism that pages the specific team owning whichever service is actually failing, which requires accurate service ownership metadata and alerting configured per service rather than one undifferentiated alert stream. On-call rotation: the natural model shifts from one shared rotation covering the whole monolith to per-team rotations, each covering the services that team owns, which requires clear, unambiguous ownership (no orphaned or ambiguously-owned services that nobody is actually on call for).
Worked example
As service count grows, avoiding alert fatigue specifically requires: routing alerts to the team that actually owns the failing service (rather than a single shared on-call rotation getting paged for every service in the fleet, most of which they don't know well), distinguishing service-level-objective (SLO) impacting alerts (a customer-facing symptom worth waking someone up for) from purely internal or low-severity signals (which can wait for business hours or go to a dashboard instead of a page), and periodically reviewing alert volume per service to catch and fix a chronically noisy alert rather than letting on-call engineers learn to ignore it, since an alert that's routinely ignored provides no real protection when it matters.
Trade-offs and pitfalls
The common failure as service count grows is not investing in the operational tooling (service ownership catalog, alert routing, shared pipeline templates) at the same time as the service count grows, so the org ends up with 50 services and still a single undifferentiated on-call rotation and alert stream, which reliably produces alert fatigue and slow incident response, since the person paged often isn't the person who actually understands the failing service. The fix is treating the operations model itself as something that needs deliberate investment alongside the architectural decomposition, not an afterthought that scales itself.
Explain the strangler fig pattern for migrating a monolith to microservices: the role of a routing/intercept layer, the role of anti-corruption layers when the new service must still talk to the old monolith's data, and how you would manage shared-database access during the transition period. Describe how you'd prioritize which components to extract first.
Sample Answer
Direct answer
The strangler fig pattern migrates a monolith to microservices incrementally: you place a routing layer in front of the monolith, redirect one slice of functionality at a time to a newly-built service behind that layer, and let the monolith's role shrink slice by slice until, eventually, it can be retired, rather than attempting a single big-bang rewrite.
Structured elaboration
The routing (or intercept) layer is the mechanism that makes this incremental: it sits in front of the monolith and inspects each incoming request, forwarding requests for the not-yet-migrated functionality to the monolith as before, and requests for the newly-extracted slice to the new service instead. Because the routing decision happens per-request, the cutover for any one slice can be gradual (a percentage of traffic, or a specific subset of users) and reversible (route back to the monolith if the new service misbehaves), rather than an all-at-once switch.
An anti-corruption layer handles the case where the new service still needs to talk to the old monolith, either because the monolith still owns some data the new service needs, or because other parts of the monolith still call into the functionality that's now been extracted. Rather than letting the new service's clean domain model get contaminated by the monolith's legacy data shapes and conventions, the anti-corruption layer translates between the two, so the new service's internal model stays coherent even while it's still dependent on the old system underneath.
Managing shared database access during migration is the trickiest part: in the transition window, both the monolith and the new service may need to read or write data that hasn't fully moved yet. A common approach is dual-write (the monolith continues writing to its tables while also publishing changes the new service consumes) with reconciliation to catch drift, or a change-data-capture stream from the monolith's database that the new service consumes without writing to the monolith's tables directly, avoiding a genuine two-way dependency on the same schema.
Worked example
Prioritizing which components to extract first: start with a slice that's relatively self-contained (few dependencies on the rest of the monolith), has a clear owning team ready to take it on, and delivers a visible win (either operational, like removing a frequent source of incidents, or business, like unblocking a team that's currently release-blocked by the monolith's shared deploy train). Extracting the riskiest, most deeply-entangled part of the monolith first, even if it's the part causing the most pain, tends to produce the highest-risk first migration when the team has the least experience running this pattern; a smaller early win builds the operational muscle (routing, dual-write, monitoring the new service) that the harder extractions will need later.
Trade-offs and pitfalls
The most common failure is leaving the routing layer and the dual-write/reconciliation logic in place indefinitely instead of treating them as temporary migration scaffolding; if a slice never gets fully cut over (the monolith keeps a code path alive "just in case"), the system ends up permanently carrying the complexity of both the old and new implementations, which is worse than either the original monolith or a clean microservice on its own.
For a 100-engineer organization, propose a team-ownership model for a large microservice landscape. Compare 'service-per-team', 'feature teams that share services', and a dedicated platform-team model, covering governance, shared libraries, and how cross-team changes get made under each.
Sample Answer
Direct answer
For a 100-engineer organization, the three common team-ownership models are service-per-team (each team owns a small, dedicated set of services end to end), feature teams sharing services (cross-functional teams that ship features but don't uniquely own the services they touch), and a dedicated platform team (owning shared infrastructure that every other team builds on); most organizations at this size end up needing a combination, service-per-team for product-facing services plus a platform team for shared concerns, rather than picking one model exclusively.
Structured elaboration
Service-per-team gives the clearest accountability (one team, one on-call rotation, one release cadence per service) and the strongest Conway's Law alignment, but it can lead to duplicated effort across teams solving similar infrastructure problems independently, and it struggles when a feature genuinely needs coordinated changes across several services owned by different teams. Feature teams sharing services optimize for shipping cross-cutting product features quickly, since a team can touch whatever services a feature needs without waiting on another team's roadmap, but they create ambiguous ownership (who's on-call when a shared service breaks, whose roadmap does a needed change compete against) and tend to erode the clean boundaries a service-per-team model would otherwise maintain. A platform-team model centralizes shared infrastructure (deployment pipelines, observability, core libraries) so product teams don't each reinvent it, but if under-resourced relative to demand, it becomes a bottleneck every other team is waiting on.
Worked example
A workable combination at 100 engineers: organize the majority of engineers into a handful of product-facing teams, each owning a small, clear set of services end to end (service-per-team for ownership and on-call clarity), carve out one platform team (perhaps 10-15% of headcount) providing the shared deployment, observability, and core-library tooling every product team depends on, and use temporary, cross-team "feature squads" only for genuinely cross-cutting initiatives that need coordinated changes across several product teams' services, disbanding them once the initiative ships rather than making shared, ambiguous ownership permanent.
Trade-offs and pitfalls
Governance needs to track which model a given piece of work actually fits: a well-understood, product-facing feature fits cleanly inside one team's service-per-team ownership; a genuinely cross-cutting initiative (say, adding a new compliance requirement across every service) needs either a temporary cross-team squad or, if it recurs often enough, its own dedicated team. Shared libraries are a common pitfall regardless of model: without a clear owner and a versioning discipline, a shared library becomes either everyone's problem (nobody prioritizes fixing it) or a de facto dependency that quietly recouples otherwise-independent services, since a breaking change to the shared library now has to be coordinated across every team using it, the same coordination cost service-per-team was meant to avoid.
Describe the step-by-step process to extract one backend module from a monolith into an independently deployable microservice in production. Address data ownership and migration, keeping API compatibility for existing callers, your testing strategy (unit, integration, canary), deployment sequencing (including a routing layer or feature toggle to shift traffic), and how you would roll back safely if something goes wrong.
Sample Answer
Direct answer
Extracting one backend module into an independently deployable service, in production, follows this sequence: define the new service's API contract first, stand it up against a copy or a read path into the existing data, migrate data ownership deliberately (not as an afterthought), route traffic gradually with the ability to roll back, and verify with a layered testing strategy (unit, integration, and canary) at each step before fully committing.
Structured elaboration
Data ownership and migration: decide upfront whether the new service will own its data from day one (with the monolith's data migrated or backfilled into it) or will read through to the monolith's database temporarily via an anti-corruption layer while a migration happens in the background; the second is lower-risk but requires a clear plan (and a deadline) for when the temporary dependency gets removed. API compatibility: the new service's external contract needs to match what existing callers expect, at least at first, so that extracting the implementation doesn't require every caller to change simultaneously; if the contract does need to differ, put a thin compatibility-shim in front of it rather than forcing a synchronized multi-team cutover. Testing strategy: unit tests validate the new service's own logic in isolation; integration tests validate its actual contract against real (or realistic) callers and dependencies; canary deployment routes a small percentage of production traffic to the new service while the rest still goes to the monolith's original code path, letting you compare real production behavior (error rates, latency, and, where possible, output correctness) before committing further. Deployment sequencing: stand up the new service dark first (deployed, but receiving no real traffic), then canary a small percentage, then ramp up gradually while watching the comparison metrics, only fully cutting over once the canary period has run long enough to build confidence. Rollback: keep the old code path in the monolith intact and routable-to until the new service has been fully cut over and stable for a defined period, since the fastest, safest rollback is simply routing traffic back to code that's still there and known to work.
Worked example
For extracting an Orders module using the strangler pattern specifically: put a routing layer in front of the order-related endpoints, implement the new Orders service, and use a feature toggle to control what percentage of order-related traffic each order type or user segment routes to; start with a low-risk subset (say, read-only order-status lookups) before migrating writes, since write-path bugs in a payments-adjacent flow are far more costly to get wrong than a stale read. Data migration in this case might use change-data-capture (CDC), streaming the monolith's writes to the new service without a two-way dependency, to backfill the new service's database, with a reconciliation job comparing the two periodically until the migration is confirmed complete and the CDC feed can be turned off.
Trade-offs and pitfalls
A minimal-viable extraction still needs to cover: the API contract (don't skip this even for a "small" extraction, since an undocumented implicit contract is exactly what breaks callers later), the data-ownership plan (explicit, not "we'll figure it out"), monitoring and observability on the new service from day one (not added after the first incident), and, critically, a genuine rollback path, not just a plan that assumes the cutover will go smoothly. The most common corner cut under time pressure is skipping the canary phase and cutting over 100% of traffic at once; canarying costs a bit more calendar time but catches the class of bug that only shows up under real production load and real data shapes, which unit and integration tests, however thorough, tend to miss.
Unlock Full Question Bank
Get access to all 34 Microservices Architecture and Service Decomposition interview questions and detailed answers.
Sign in to ContinueJoin thousands of developers preparing for their dream job.