A practical lesson on experience-aligned boundaries, when backends-for-frontends or channel-specific integration layers are useful, and how to avoid turning user-interface structure into weak service decomposition.
Experience-aligned boundaries shape part of the architecture around a major user journey, client type, or interaction channel rather than around a deep domain model alone. The classic example is a backend-for-frontend layer that serves web, mobile, or partner experiences differently. This pattern can be useful because different experiences often need different aggregation logic, response shapes, caching strategies, and release cadence.
The important limit is that experience alignment should usually sit at the integration edge, not replace the domain model underneath. When teams misapply the pattern, they end up with service-per-screen decomposition, duplicated business logic, and unstable ownership that changes every time the product interface changes.
flowchart LR
W["Web app"] --> BFF["Web experience layer"]
M["Mobile app"] --> MFF["Mobile experience layer"]
BFF --> C["Catalog domain service"]
BFF --> P["Pricing domain service"]
BFF --> O["Ordering domain service"]
MFF --> C
MFF --> P
MFF --> O
What to notice:
Experience-aligned boundaries are strongest when:
For example:
In those cases, an experience-aligned layer can reduce churn in core services while giving frontend-facing teams more focused control over the integration surface.
This pattern is not:
That distinction matters. A backend-for-frontend can be healthy. A screen-driven service map usually is not.
The strongest design uses experience-aligned layers to:
It should not use them to:
If the experience layer becomes the place where the real business logic lives, then the domain boundary has weakened.
One way to keep the layer honest is to document what it owns:
1service: mobile-commerce-bff
2owns:
3 - response_aggregation
4 - channel_specific_auth_checks
5 - mobile_payload_shaping
6does_not_own:
7 - pricing_rules
8 - order_state_authority
9 - inventory_policy
10depends_on:
11 - catalog
12 - pricing
13 - ordering
What this demonstrates:
This kind of clarity helps prevent drift from experience shaping into accidental domain ownership.
The pattern becomes risky when:
At that point, the system is no longer using an experience-aligned boundary. It is letting the user interface dictate decomposition.
Ownership should still be explicit. A frontend-aligned team may reasonably own the experience layer, but it should coordinate with domain teams through clear contracts. If the experience team must constantly modify domain logic to ship features, then the layer is probably too thick or the domain services are too thin.
A company wants one service for each major screen in its mobile app so every mobile squad can deploy independently. The proposed services would also contain pricing rules, availability checks, and discount eligibility logic. What is the main architectural problem?
The main problem is that the team is confusing experience alignment with UI-driven domain ownership. An experience layer can be a healthy integration surface, but if each screen becomes the home of core business rules, the architecture will duplicate logic, fragment domain ownership, and become unstable whenever the product design changes.