MV Michael van Leest AI, cloud, and platform engineering
Home Blog About Contact

Blog post

How I decide what deserves a service boundary

A practical guide to deciding when a service boundary helps, when it adds operational drag, and how small teams can avoid splitting systems too early.

Teams often talk about service boundaries as if the goal is to find the cleanest decomposition on paper. I think that is the wrong starting point.

The real question is not whether a boundary looks elegant. It is whether the boundary makes the system easier to change, understand, and operate.

If it does not do that, it is probably too early, too expensive, or solving the wrong problem.

A service boundary should reduce friction somewhere important

I do not create a new service boundary just because a codebase has become large.

I want to see a real reason, such as:

  • a part of the system changes at a meaningfully different rate
  • ownership needs to be clearer
  • runtime or scaling behavior is genuinely different
  • one area is creating repeated delivery drag for another
  • operational isolation would reduce real risk

Without one of those pressures, a new boundary usually creates more cost than benefit.

Service boundaries create operational cost

Every new boundary adds something.

Usually that means some combination of:

  • another deployment path
  • another ownership surface
  • more observability requirements
  • more networking or communication complexity
  • more failure modes between components

That cost is easy to underestimate, especially for small teams.

This is why I do not think “split it into services” is neutral advice. It is an operating model decision, not just a code organization decision.

Look for friction that a service boundary would actually remove

The best reason to create a boundary is not that the architecture feels untidy. It is that the current shape is causing repeated pain.

I usually look for pain like:

  • one area of the codebase slowing changes in another
  • conflicting release cycles
  • unclear ownership creating slow decisions
  • repeated incidents caused by overly coupled runtime behavior
  • scaling one capability forcing unrelated parts of the system to move with it

If those things are not happening, the current boundary may be good enough even if the internal structure is imperfect.

A modular monolith is often the right intermediate step

Small teams sometimes jump too quickly from “the monolith is getting awkward” to “we need services now.”

Often the better step is to make the boundaries clearer inside the existing system first.

That usually gives the team a chance to test:

  • whether the domain boundary is real
  • whether ownership becomes clearer
  • whether the change path improves
  • whether the team can keep the contract stable

If those things do not improve inside the monolith, splitting them into separate services usually does not improve them either. It just makes the same ambiguity more distributed.

Good service boundaries are understandable to the team that owns them

I care less about whether a boundary matches a fashionable architecture pattern and more about whether the team can explain it simply.

I want the team to be able to answer:

  • what does this service own?
  • what does it explicitly not own?
  • why is it separate?
  • what changes faster or differently here?
  • what happens if it fails?

If the answers are vague, the boundary is probably not mature enough yet.

Data and workflow boundaries matter more than code structure alone

A lot of service discussions stay too close to the code.

I usually care more about data ownership and workflow behavior.

If a service boundary does not produce clearer ownership over data, behavior, or runtime responsibilities, it often becomes just a packaging change with extra operational cost.

That is why I usually ask where the data truth lives, where workflow transitions happen, and where the business actually needs isolation.

Those answers tend to be more useful than asking which folders should become services.

Small teams should bias toward fewer service boundaries

For small teams, every service boundary has to earn its keep.

That is because the team is not only paying for the design decision. It is paying for the deployment, observability, support, and coordination cost afterward.

So my bias is simple: start with fewer boundaries, make them clearer, and split only when the system shows repeated evidence that the current shape is holding the team back.

That is a much healthier default than designing for a scale or operating model the team has not reached yet.

My default service boundary decision test

Before I recommend a new service boundary, I usually want yes answers to questions like these:

  1. is there a repeated delivery or operational problem this boundary would remove?
  2. is ownership likely to become clearer, not fuzzier?
  3. does the runtime behavior differ enough to justify separation?
  4. can the team support the additional operational surface area?
  5. would this still look like a good idea after the first six months of operating it?

If the answer to most of those is no, I usually keep the boundary inside the existing system and improve the internal structure first.

My default advice on service boundaries

Create a service boundary when it removes meaningful friction, clarifies ownership, or reduces real runtime risk.

Do not create one just because the codebase feels large or because services sound more scalable.

A service boundary should make the system easier for the team to live with. If it only makes the architecture diagram cleaner, it is probably not earning its cost.

Contact

Working on AI, cloud, or platform modernization?

If you are hiring, shaping a project, or need an experienced technical sounding board, use the contact form and send a little context.