Resulting context

The primary benefit of this solution is that it heeds Conway's Law that "organizations are constrained to produce application designs which are copies of their communication structures". We are giving teams full control over their feature across the full-stack. The user experiences are decoupled and each is owned by a single team, which owns the synchronous interface that supports the frontend, owns the materialized views that both shield the component from and integrate it with upstream components, and owns the asynchronous outbound interface that produces events to delegate to downstream processing. The only upstream and downstream coupling is limited to event content. This empowers teams to press forward, independent of other teams, with confidence that their feature is functioning properly so long as the changes are backwards compatible.

The client-directed query approach can be very useful in reducing redundancy by supporting multiple variants of the same user experience across multiple device form factors within the single backend component. It is preferable that this is leveraged when the same team owns the development across the form factors, but it can reduce the complexity of shared components as well. When redundancy is necessary to support differences across device experiences, it is useful to recognize that this redundancy is a form of replication, which improves scalability. For example, Android users and iPhone users would interact with different components and materialized views and thus spread the capacity requirements. There is potential for this to lead to the need for bidirectional synchronization between components. 

Decomposing the user experience into many independently deployable frontend applications and frontend features is crucial for all the same reasons that we decompose the backend components into bounded isolated components. First and foremost is that it provides the proper bulkheads needed to empower self-sufficient teams to innovate and continuously deploy the frontend with confidence as well. Next, not all user experiences warrant support for multiple channels and device types. Many can be implemented as a bounded isolated app that performs a specific function in an overall value stream. This user experience decomposition also leads to a naturally responsive, resilient, elastic, and globally scalable component topology when combined with the BFF pattern. In the examples, we will discuss four different categories of your experiences: Authors, Workers, Customers, and Managers, which apply the same patterns in different variations and combinations to implement very different BFF components.

It is inevitable that certain key components are used across multiple channels and device types. These features are often the main value proposition and have a significant code base, which would be unreasonable to duplicate. Likewise, wrapping these components in an additional BFF proxy layer adds little value but significant complexity. Instead, evolving micro-frontend approaches integrate these components in the presentation layer by composing multiple micro-frontend fragments into a single experience. The feature team of a shared component would own the frontend fragment, which is composed with the whole experience.

Finally, achieving an optimal balance of BFF components to support the permutations of channels and device types is an iterative process. Leverage disposable architecture to facilitate experiments, which allow teams to easily pivot and change their approach midstream. Disposable architecture also enables a polyglot approach across components.