Design and Decomposition Questions

How do you decide service boundaries?

  • Business capability: catalogue, ordering, payments, users, notifications.
  • DDD bounded context: the place where a word has one meaning. "Product" in catalogue (description, images) differs from "Product" in order (id, price at purchase time).
  • High cohesion inside, loose coupling outside: if two services always change together or call each other chattily, merge them.
  • Team ownership (Conway's law): one team can own a service end to end.

Why database per service? How do you query data owned by another service?

Shared databases couple services at the schema level: one team's migration breaks another service, and nobody owns the data. With database per service, only the owner touches its tables. To read others' data use:

  • API call (order-service calls product-service for the price).
  • API composition at the gateway/BFF for read screens.
  • Data replication by events: order-service keeps a local read copy of product names updated from ProductUpdated events (CQRS read model).

What is a distributed monolith and how do you avoid it?

Services that are split physically but still coupled: shared database, synchronous call chains (A → B → C → D) for every request, shared domain library, lock-step deployments. Avoid it with clear bounded contexts, own data, async events for side effects, backward-compatible API versions and consumer-driven contract tests.

How do you version microservice APIs without breaking clients?

  • Prefer backward-compatible changes: add optional fields, never rename or remove; consumers ignore unknown fields (Jackson FAIL_ON_UNKNOWN_PROPERTIES=false, Boot's default).
  • For breaking changes, run /api/v1 and /api/v2 side by side (URI or header versioning) and retire v1 after clients migrate.
  • Verify with consumer-driven contract tests (Spring Cloud Contract, Pact) in CI.

How would you migrate a monolith to microservices?

Use the strangler fig pattern: put a gateway in front of the monolith, build one new service (start with a low-risk, well-bounded module like notifications or catalogue), route its paths to the new service, sync data via events or CDC, and repeat until the monolith is gone or small.

client ─► gateway ─┬─ /api/products/** ─► product-service (new)
                   └─ everything else ─► monolith (shrinking)

What is the Backend for Frontend (BFF) pattern?

A separate gateway-like service per client type (web, mobile, partner). Each BFF aggregates and shapes data for its UI: the mobile BFF returns a lighter product card, the web BFF returns full details plus recommendations. It keeps client-specific logic out of the core services. Used by apps like Swiggy and Netflix where mobile and web screens differ a lot.