A practical lesson on the decomposition shortcuts that most often fail, including service-per-CRUD, schema-first splitting, screen-based services, vague utility services, and org-chart-driven boundaries.
Bad boundary heuristics are useful to study because teams rarely arrive at them by accident. They usually look attractive in the moment. They are fast, easy to diagram, and often seem objective. That is why they recur so often. The problem is that they produce boundaries that are thin in business meaning and heavy in coordination cost.
This lesson focuses on the shortcuts that most often create distributed monolith behavior.
flowchart LR
A["Service per CRUD entity"] --> E["Weak boundaries"]
B["Service per schema"] --> E
C["Service per screen"] --> E
D["Vague utility or org-chart split"] --> E
E --> F["Chatty calls, shared logic, ownership confusion"]
This is one of the most common anti-patterns. Teams see important nouns in the schema and create customer, address, invoice, or discount services directly from them. The result is usually a set of thin endpoints that cannot complete meaningful business work alone and therefore coordinate constantly with one another.
The core problem is that entities are not the same thing as responsibilities. A healthy service usually owns a capability, not just a noun.
Schema-first decomposition feels objective because the tables are already there. But tables reflect historical implementation, reporting compromises, and legacy design choices as much as they reflect good boundaries. When teams draw services directly from the schema, they often turn storage artifacts into long-lived architecture.
That usually produces shared concepts split too finely or unrelated concerns grouped together for legacy reasons.
Splitting by UI page or front-end surface often leads to service boundaries that mirror presentation concerns rather than business meaning. A screen can be a useful signal about workflow, but a screen is not automatically a coherent backend capability.
This heuristic often creates services that:
Utility and platform can be valid labels when they describe a narrow, stable supporting capability. They become dangerous when they absorb unrelated helpers simply because no one else wants to own them. The same problem appears when services are drawn from politics rather than from model and workflow. A reorg may change the reporting structure, but it does not automatically define a good domain boundary.
The easiest way to catch bad heuristics is to ask which service smell would appear immediately if the split were accepted.
1proposed_boundary: customer-service
2derived_from: main-schema-entities
3likely_smells:
4 - duplicated-logic
5 - shared-identifiers-without-shared-meaning
6 - high-cross-service-query-volume
7review_decision: reject-until-capability-and-ownership-are-made-explicit
What this demonstrates:
A team proposes one service per front-end page because each screen already has a dedicated UI squad. The resulting design would create checkout-page-service, profile-page-service, and orders-page-service. Why is this likely to be weak?
The stronger answer is that the split mirrors presentation structure, not business responsibility. As the product evolves, the services are likely to become chatty, duplicate domain logic, and require frequent cross-boundary coordination to support one customer workflow.