Microservices antipatterns for systems analyst interviews
Contents:
Why interviewers ask about antipatterns
When a systems analyst at Stripe or DoorDash is dropped into a microservices design round, the interviewer rarely wants a textbook diagram. They want to know whether the candidate can smell decay in an architecture before it ships. Antipatterns are the vocabulary of that smell test — terms like distributed monolith, shared database and sync RPC chain are the shorthand senior engineers use to flag "we are about to repeat 2018 here, please stop".
The reason these questions have crowded out greenfield design questions is that most candidates joining a mid-size company today are not building from zero. They are walking into a system with 40+ services, a shared Postgres instance nobody dares to touch, and three product squads blocked on a 9-step synchronous call chain. Recognizing the pattern is half the fix. If you can name the antipattern, point at the symptom set, and propose a containment strategy, you have already moved ahead of the candidate who only memorized "microservices = good, monolith = bad".
This guide walks through the six antipatterns that come up in roughly 80% of senior systems analyst loops at Stripe, Uber, Notion and similar shops. Each section gives you a one-line definition, the symptoms an interviewer wants to hear back, and the fix you propose without sounding dogmatic.
| Antipattern | One-line tell | Typical fix |
|---|---|---|
| Distributed monolith | Coordinated deploys of 5+ services | Event contracts, schema independence |
| Shared database | Schema change requires cross-team sign-off | One DB per service, CDC for read models |
| Sync RPC chains | Latency budget already blown at hop 3 | Async events, BFF aggregator, Saga |
| Nano-services | 50 services for a team of 5 | Merge to two-pizza-team granularity |
| Wrong boundaries | Single feature touches 5 services | Re-do DDD bounded contexts |
| Premature microservices | Startup with 3 devs and 20 services | Monolith first, split on real pain |
Distributed monolith
A distributed monolith is what you get when you take a monolith, slice it on the wrong seams, and now pay the network tax of microservices with the coupling tax of a monolith. Every release is a coordinated train across five services, a shared library carries domain logic, and one downstream failure cascades up the stack.
Gotcha: if the team needs a release-coordination spreadsheet, the architecture is a distributed monolith no matter what the slide deck claims.
The interview tell is when a candidate describes "microservices" but in the next breath says "we deploy them together". Push back. The fix is rarely "more services" — it is decoupling: replace shared libraries that carry business rules with explicit contracts (OpenAPI, AsyncAPI, protobuf), move from synchronous RPC to event-driven where the consumer can tolerate eventual consistency, and force each service to own its schema. A useful smoke test is to ask whether any single service can roll back independently. If the answer is no, the seam is wrong.
Shared database
Two services pointing at the same Postgres instance is the textbook violation of microservices ownership. It looks innocent — both teams need the users table, why duplicate? — but within a quarter the schema becomes a frozen contract nobody can evolve without a four-team meeting.
Symptoms an interviewer wants you to volunteer: Service A cannot add a column without Service B regression-testing, the database becomes the scaling bottleneck because everyone hits the same primary, and migrations turn into multi-team coordination ceremonies. Cross-service joins inside SQL are the most damning evidence — they pin the two services together at the storage layer, where you have no version negotiation.
The fix is one database per service, with cross-service data movement via three options. First, synchronous API calls when the consumer needs strong consistency and the read volume is modest. Second, asynchronous events on a broker like Kafka or Pulsar when eventual consistency is acceptable. Third, change data capture (Debezium, Snowflake streams) into a read-model store when you need reporting or search across domains. Pick by read pattern, not by team preference.
Sync RPC chains
Client → Service A → Service B → Service C → Service DA request that hops through four synchronous services has a latency budget equal to the sum of all four p99 latencies, plus the probability of failure equal to 1 − (product of all success rates). With 99% success per hop, four hops gives you 96% — a 4% failure rate that the user experiences as flaky.
| Hops | Success per hop | End-to-end success | p99 latency budget |
|---|---|---|---|
| 2 | 99.5% | 99.0% | ~200 ms |
| 4 | 99.5% | 98.0% | ~400 ms |
| 6 | 99.5% | 97.0% | ~600 ms |
| 8 | 99.5% | 96.1% | ~800 ms |
Three fixes earn full marks in an interview. The first is moving non-critical calls to async events — fire an order-placed event and let downstream services pick it up at their own pace. The second is introducing a Backend-for-Frontend (BFF) aggregator that fans out in parallel and merges responses, so the client sees one round trip instead of a serial chain. The third is choosing Saga choreography over orchestration when the workflow is long-running: each service reacts to events and emits its own, replacing the central coordinator that becomes a single point of failure.
Nano-services and wrong boundaries
The opposite trap from a distributed monolith is over-decomposition. A team of five owning 50 services spends 80% of its time on operational toil — building pipelines, rotating secrets, debugging traces across boundaries — and 20% on features. Each service is so small that almost every business operation needs to call three of them, which reintroduces all the sync-chain problems from the previous section.
Load-bearing trick: map services to two-pizza teams. If a team owns more services than people, merge.
Wrong boundaries is the sibling antipattern. The seams are not microscopic, but they cut across the domain in the wrong places — a single user-facing feature requires changes to five services because the underlying bounded context was split by technical layer (auth, profile, preferences, settings, notifications) instead of by business capability (user lifecycle). The repair is to revisit DDD bounded contexts with the actual domain experts, not the org chart. A useful diagnostic: pick the last 10 production tickets and check how many services each touched. If the median is above two, the boundaries are wrong.
Premature microservices
A startup with three engineers and 20 services is the loudest version of this antipattern. The founders read a Netflix engineering blog post, skipped the part where Netflix had 2,000 engineers, and now every new hire spends their first month learning the deployment topology instead of shipping product.
Martin Fowler's "monolith first" is still the right default. The mainstream signals that justify a split are roughly: team has grown past 10 engineers, the domain has clearly separable subdomains with different change rates, or a specific service has scale or compliance requirements that the rest of the system does not. None of these is "we want to use Kubernetes".
In an interview, the safe stance is to say: "I would start by isolating the part of the monolith that has the loudest pain — usually a high-traffic read path or a compliance-sensitive write path — and extract that into its own service while leaving the rest as is. The strangler fig pattern lets you do this incrementally, not as a big rewrite."
Common pitfalls
The most common candidate failure is confusing microservices with distributed systems hygiene. A senior interviewer will dock points if you propose splitting a monolith without first listing the consistency, observability and deployment investments required. Mention distributed tracing, idempotent handlers, retry budgets and circuit breakers in the same breath as the split, or your design will be flagged as naive.
A second pitfall is over-indexing on technology choices and under-indexing on contracts. Candidates sometimes spend ten minutes on Kafka versus RabbitMQ versus NATS and zero minutes on how the producer and consumer will agree on a schema, version it, and roll it forward without breaking the other team. Interviewers care more about AsyncAPI / protobuf schema registry than about broker brand names.
A third trap is treating shared database as a shortcut. Candidates often propose it as "temporary" — we will split later, promise. In practice, the shared schema becomes a frozen surface within a quarter because every downstream service starts depending on undocumented column semantics. The fix is to introduce the read model on day one, even if it is just a daily dump, so the contract is API or event, never SELECT *.
A fourth pitfall is ignoring the operational cost curve. Each new service costs roughly one engineer-week per quarter in ongoing toil — runbook updates, dashboard owners, on-call rotations, dependency bumps. Candidates who propose "let's split this into five services" without accounting for the five engineer-weeks per quarter they just signed up the team for will lose points with any platform-aware interviewer.
A fifth and quieter pitfall is forgetting the data plane. Most antipattern conversations focus on the request path, but the long tail of pain is in analytics, reporting and ML feature engineering. If every service owns its own database, the data team now needs CDC pipelines, schema registries and a warehouse layer to reassemble what used to be one JOIN. Mention this proactively — interviewers from companies like Snowflake or Databricks will reward it.
Related reading
- Monolith vs microservices for systems analysts
- DDD for systems analyst interviews
- API Gateway vs BFF for systems analysts
- 2PC vs Saga for systems analysts
- Distributed tracing for systems analysts
If you want to drill systems analyst design rounds with this exact pattern library, NAILDD ships with 1,500+ interview questions across architecture, SQL and product cases.
FAQ
When are microservices actually justified?
Microservices pay off when the organization has independent teams shipping at different cadences, the domain has clearly separable subdomains with their own data stores and change rates, or specific parts of the system have unique scale or compliance requirements. In an interview, anchor the answer to team size and domain separability, not technology preference. A useful rule of thumb: under 10 engineers, a modular monolith almost always wins on velocity.
How do I spot a distributed monolith in an existing codebase?
Three quick diagnostics. First, look at the release pipeline — if multiple services have to deploy in lockstep for most features, the seams are coupled. Second, grep for shared libraries that contain business logic; cross-cutting utilities are fine, shared domain rules are not. Third, check whether any single service can be rolled back independently without breaking peers. If two of these three fail, you are looking at a distributed monolith.
Is one database per service really mandatory?
It is the target state, not always day one. Many teams start by giving each service its own schema inside a shared cluster, then migrate to fully separate clusters as scale demands. The non-negotiable part is the contract — no service should ever read or write another service's tables directly. Cross-service data should flow through APIs, events, or CDC into a derived store.
How do I argue against premature microservices without sounding old-fashioned?
Frame it as risk-adjusted velocity, not nostalgia. Microservices add a fixed operational tax — typically one engineer-week per service per quarter — and compound interest on every new dependency. A startup paying that tax across 20 services with three engineers has effectively zero feature velocity. The pitch is "we will split when the pain of not splitting is higher than the operational cost, and we will measure that pain explicitly".
What is the difference between Saga choreography and orchestration?
In choreography, each service reacts to events and emits its own, with no central coordinator. It scales well and has no single point of failure, but the workflow becomes implicit and hard to debug. In orchestration, a central Saga coordinator drives the sequence and tracks state. It is easier to reason about and visualize but introduces a coordinator that must be highly available. For two or three steps, choreography is fine; for long workflows with compensation logic across five or more services, orchestration usually wins on operability.
How granular should a microservice be?
The widely cited heuristic is one service per two-pizza team (six to ten engineers). Smaller than that and the operational cost dominates; larger than that and ownership becomes ambiguous and changes start requiring cross-team coordination. If a team of five owns 15 services, you have nano-services; if a team of 20 owns one service, you have a hidden monolith. The right number sits between those extremes and shifts as the team grows.