Frontend Architecture and the Illusion of Boundaries

Introduction

Recently I reviewed a proposal in our Angular codebase introducing domain-based folders and facades between domains.

On the surface, it makes sense:

  • split code into domains

  • avoid cross-domain imports

  • expose public APIs

  • use facades for communication

But it raised a deeper question:

Are we actually reducing complexity, or just adding structure to manage complexity created by our architecture?


Frontend vs Backend: Different Nature of Problems

Backend systems naturally fit Domain-Driven Design because they deal with:

  • business consistency

  • transactional boundaries

  • long-lived domain rules

  • data ownership

Frontend systems are fundamentally different. They are:

  • user-flow driven

  • interaction-driven

  • UI composition driven

  • rapidly changing with UX

A single user journey often spans multiple backend domains:

  • account

  • payments

  • address

  • notifications

But to the user, it is still one flow.

This difference matters more than we usually admit.


A Concrete Example: Cross-Domain Flow in Angular

Take a simple flow:

A user applies for a new card and updates their mailing address during the process.

In a domain-split Angular architecture, this is typically divided into:

  • Card domain

  • Customer domain

Now Card needs to trigger an update in Customer.

Because direct access is discouraged, we introduce:

  • a Customer facade

  • an interface contract

  • an implementation hidden behind store/effects/services

So the flow becomes:

1
2
3
4
Card Domain
-> Customer Facade Interface
-> Customer Facade Implementation
-> State / Effects / API

A simple user intent becomes a multi-layered coordination chain.


Why This Feels Strange in React

To React developers, this often feels unnecessary.

Not because cross-feature dependencies don’t exist — they absolutely do — but because React tends to handle them differently.

Instead of introducing:

  • domain facades

  • interface contracts

  • global orchestration layers

React relies more on:

  • component composition

  • local state ownership

  • direct capability usage through hooks

Dependencies are handled through composition, not architectural indirection.


The Real Question

This leads to a more important question:

If the dependency already exists in the user flow, what do we actually gain by wrapping it in facades and domain boundaries?

We are not removing coupling.

We are:

  • formalizing it

  • layering it

  • redistributing it across abstractions

So the real question becomes:

If coupling is unavoidable in frontend flows, should we organize the system around domains at all — or around user flows instead?


The Microservice Parallel

This feels very similar to microservices.

Many systems moved from monoliths to microservices believing:

the monolith is the problem

But often the real issue was:

  • poor modularization

  • unclear boundaries

  • tight coupling

So complexity was not reduced — it was moved across boundaries.

Frontend architecture can fall into the same pattern:

  • domains

  • facades

  • interfaces

  • orchestration layers

We may end up managing complexity instead of reducing it.


Conclusion: Boundaries Should Follow Workflows

I still believe modularization matters.

But frontend systems are not primarily domain systems — they are workflow systems.

They optimize for:

  • interaction, not consistency

  • composition, not strict boundaries

  • user flows, not domain purity

In many cases, workflow or feature-level boundaries are more natural than backend-style domain boundaries.

Good frontend architecture should reduce coordination cost and improve composability — not introduce layers that only exist to manage existing layers.