skip to content

What are the concrete costs of a microservice architecture that's too coarse-grained ('macroservices' or mini-monoliths) versus one that's too fine-grained, and how do you decide which risk to accept for a given team and system?

level: seniorimportance: should knowfreq 60%

answer

  1. macro = mini-monolith, shares blast radius
  2. micro = op overhead x N
  3. same axis, opposite currencies
  4. size to a two-pizza team
  5. monolith-first, split on real evidence

basics

~20 s

Too coarse means services are basically small monoliths - hard to scale or deploy independently, one team's bug blocks everyone. Too fine means way too many tiny services - huge operational overhead, slow chatty calls, hard to reason about the whole system. The right size depends on team size, how independently pieces need to change, and how much operational complexity the team can actually handle.

solid answer

~50 s

A macroservice - a service that bundles several unrelated capabilities that don't share a real business or data reason to be together - keeps monolith-style coupling: unrelated features share a deploy pipeline and blast radius, different parts can't scale or be owned independently, and the codebase can still grow tangled internally even though it's technically 'a microservice.' A too-fine architecture pays the opposite cost: per-service operational overhead multiplied across many services, chatty cross-service calls, and distributed-transaction complexity for what used to be simple local operations. The deciding factors are team size and topology (can each proposed service actually be owned end-to-end by one small team?), operational maturity (does the org have the platform tooling to make many small services cheap to run?), and the system's actual scaling/consistency needs. Early-stage systems and small teams should generally err coarser and split later once real seams show up under load.

go deeper

for a junior

Should describe in plain terms that both 'too big' and 'too small' services cause problems, without necessarily naming the trade-off drivers.

for a middle

Should name at least one concrete cost of each extreme (e.g., shared blast radius for macro, operational overhead for micro) and recognize granularity as a spectrum, not two categories.

for a senior

Should apply concrete deciding factors (team size/topology, operational maturity, real scaling/consistency needs) to recommend a direction for a given scenario, and cite observable signals for when to split or merge.

for a principal

Should discuss 'monolith-first' as a deliberate strategy, weigh how platform investment shifts the break-even point over time, and describe how to govern granularity decisions as the org and system evolve rather than as a one-time call.

## Two directions of the same mistake A 'macroservice' (sometimes called a 'mini-monolith') is a service that's nominally one deployable unit in a microservices architecture but internally bundles several loosely related business capabilities that don't actually share a strong reason to live together — for instance, one 'Commerce' service that handles catalog browsing, checkout, and returns processing, three capabilities with different owners, different scaling profiles, and different change cadences, all shipped as one artifact. At the other extreme, an over-fine architecture splits a single cohesive capability into many small services (nanoservices, entity services). Both are granularity mistakes in opposite directions along the same spectrum: | Direction | Where it lands | |---|---| | coarse services | under-decompose relative to where the real seams in the business domain are | | fine services | over-decompose past those seams | ## What a macroservice costs A macroservice retains most of the coordination costs of a monolith while giving up some of a monolith's benefits. - **Unrelated features share one deployment**: a risky change to the returns-processing code can delay or block a routine catalog update because they ship in the same release, and a bug in one capability can degrade or crash the whole service (a shared in-process failure domain — an out-of-memory error in the returns module can crash the whole process, including checkout). - **Independent scaling is lost**: if catalog-browsing traffic is 100x checkout traffic, you can't scale them separately, so you either over-provision the whole service for the noisy neighbor's peak load or under-provision and let it degrade shared capacity. - **Team ownership blurs**: if three teams each own one capability inside the same deployable, they have to coordinate releases, share an on-call rotation for a codebase where two-thirds of it isn't theirs, and code review/merge conflicts increase because unrelated features touch a shared codebase and shared CI pipeline. ## What the opposite extreme costs The opposite extreme pays a different bill: - fixed per-service operational overhead (pipeline, monitoring, on-call, versioning) multiplied by a much larger service count - network calls replacing in-process calls with associated latency and failure modes - distributed-transaction/saga complexity for operations that used to be simple local writes It's important to see these as opposite failure modes on the same axis rather than 'micro good, macro bad' — the actual goal is matching service boundaries to real business/data seams, and both directions of mismatch are costly, just in different currencies: coordination cost for macro, operational/network cost for micro. ## Three factors that place a team on the spectrum Three factors should drive where on this spectrum a given team lands. 1. **First, team topology**: the 'two-pizza team' idea and the broader 'you build it, you run it' principle suggest a service should be sized to what one small team (roughly 5-9 people) can own end-to-end — smaller than that and you're probably too fine, larger than that and you're probably too coarse. 2. **Second, operational maturity**: an org with mature platform tooling — templated CI/CD, a service mesh handling retries/circuit-breaking/observability uniformly, centralized distributed tracing — can afford to run many more small services cheaply than an org where every new service means hand-rolling its pipeline and dashboards from scratch; the 'right' granularity for the same business domain genuinely differs by platform maturity. 3. **Third, actual (not theoretical) scaling and consistency needs**: if two capabilities really do have wildly different load profiles or need to release on independent cadences for business reasons, that's real evidence for splitting; if the justification for splitting is 'it feels cleaner' without a concrete scaling or ownership reason, that's a sign to stay coarser. ## Err coarser, split later The pragmatic, widely-cited industry guidance (echoing Martin Fowler's and Sam Newman's writing on this) is to err coarser early and split later: start with fewer, larger services aligned to your best current understanding of bounded contexts, and split a service only once you have concrete evidence of a real seam: - a part of it that needs to scale independently - a part that's owned by a newly formed separate team - a part whose change cadence has diverged sharply from the rest This is sometimes phrased as 'monolith-first' — not because monoliths are the end goal, but because premature fine-grained splitting locks in boundary guesses before you have the production evidence to make them well, and merging services back together later is usually far more painful than splitting a well-understood, already-cohesive piece out of a slightly-too-coarse one. A concrete real-world echo of this is large tech companies' documented pattern of starting new product lines as a single deployable and splitting out dedicated services (search, recommendations, payments) only once each had clearly separate scaling and ownership needs backed by real traffic and org growth.

  • What's a concrete, observable signal that a macroservice has grown too coarse and needs splitting?
    Look for a deploy that's frequently delayed or rolled back because of a change to a part of the service that an unrelated team owns, or an incident where a bug in one capability causes an outage in an unrelated one because they share a process or resource pool. Divergent scaling needs showing up as one capability's traffic forcing over-provisioning of the whole service is another concrete trigger.
  • Why does 'monolith-first' advice make sense even though the end goal is often microservices?
    Because the correct service boundaries usually aren't obvious until you've operated the system in production and can see where the real seams actually fall, and guessing wrong up front locks in boundaries that are expensive to undo. Starting coarser and splitting out a piece once it has clear, evidenced justification is cheaper than starting too fine and merging several tangled services back together later.
  • Does a mature service mesh and CI/CD platform mean a team should always prefer finer granularity?
    It shifts the break-even point toward finer granularity by lowering the fixed per-service cost, but it doesn't eliminate the coupling and consistency costs of over-splitting a genuinely cohesive capability - good tooling makes small services cheaper to run, not free, and a capability that needs a local transaction still shouldn't be split just because the platform makes hosting more services easy.

It's like renting office space: one giant shared floor for three unrelated companies (macroservice) means noise, scheduling conflicts and shared risk (a fire alarm evacuates everyone); a private office per employee (nanoservice) means nobody bumps into each other but you're paying rent and utilities for fifty tiny rooms - the sane answer is one suite per team that actually works together.

saying these in an interview costs you the question

  • Treats 'macro' and 'micro' problems as unrelated instead of opposite ends of one granularity spectrum
  • Recommends microservices-by-default for a small team with no discussion of operational maturity
  • Gives no concrete, observable signal for when to split (or when to merge)
  • Ignores team topology / ownership as a factor in sizing decisions
  • Assumes tooling maturity is irrelevant to where the right granularity line sits

context