Service Communication (WIP)
[!NOTE]
Please not that the reasoning in this document contains different views.
These are
- Development team
- Organization
- Architecture
- User / Client
All reasoning here should be understood by the reader and be seen as consulting document. The decision how to build an application and the ownership of that stays in the development team.
The following diagram illustrates an example page and its sub-pages or components. The circled nodes represent the data-owning services.
mindmap
root((page))
Billing
((Stripe))
((Keylight))
Marketing
((Consent))
Auth
((Auth0))
Data
((CRM))
((Salesforce))
Favorites
((Fav Service))
This document outlines how to build such pages or components in a coherent, maintainable way that delivers low latency and aligns with our Self-Contained System principles. The best approach depends on the consistency and latency requirements of the UI.
- If you need strong consistency (e.g., for User Data), synchronous communication is required.
- If you can accept eventual consistency (e.g., for Statistics), an asynchronous approach is preferable.
- If you require low latency, you should also favor an asynchronous approach.
Preferred Solution
There is a middle ground between fully asynchronous and fully synchronous communication that still adheres to the self-contained system model. This approach involves the Data teams providing an interface that allows the UI team to asynchronously fetch and store a local private copy of the required data. With this local copy, the UI can render pages quickly and independently of third-party services. However, the data might not always be up to date. If an update is needed, the UI can make a synchronous call to the data team to update the data and then refresh the local copy. If the call fails, the UI can inform the user and allow them to retry later.
sequenceDiagram
actor User
participant UI
participant Data
UI<<->>Data: async replication
User-->>+UI: open page
UI->>+UI: GET Data for Display
UI-->>+User: render
User-->>+UI: submit form
UI->>+Data: POST Data for update
Data->>UI: success/failure & update local copy
UI-->>+User: display new state
Pros
- Coherent UI, as the UI Team maintains design and UX consistency (UX view)
All decisions regarding UX/UI patterns used and how to build and design the pages stays in one Development team. This ensures a unified UI for our customers without governance or coordination effort. - Simple to build as a single remix application (Development team view)
This includes maintenance of the remix application, library updates, security fixes - Adheres to self-contained system principles (Architecture view)
Cons
- Cross-team dependencies may introduce delays and coordination challenges
(Organization view)
This requires coordination within the OKR process and alignment between different teams. It tend to be slow and time consuming. - Requires clearly defined API/event contracts between the UI and data teams
(Development team view)
To ensure operability, the API contracts between teams have to be stable and changes to the APIs need versioning and coordination. This might be slow.
Other Solutions
Data Owning Teams build the components/pages
In this model, each Data-owning team builds and maintains the UI components or pages related to their data. They have full control over presentation and logic.
Pros
- End-to-end ownership of data and its presentation (Organization view)
Having a real end-to-end ownership is good for fast progress and keeping decisions and dependencies in just one team. This improves time to market - Simple to build as a single remix application (Development team view)
This includes maintenance of the remix application, library updates, security fixes - Self-contained by nature (Architecture view)
Cons
- Follows Conway's Law (Architecture view)
- Visual inconsistencies across components/pages (UX view)
There has to be a strong governance model integrated, otherwise all pages could easily be developed with different UX/UI patterns and slight differences. But since end-to-end ownership is built in by the development model, governance is hard to integrate. It does contract ownership of the teams who built the applications/pages. -
Maintenance burden (Organization view)
With each new app/page introduced into this setup, there is another app which needs to be maintained. This introduces a lot of overhead for the company in regards to dependency update and security fixes. This will slowdown teams.To illustrate the issue, we can consider the use case of settings/preferences. There might be a few teams, which own the data of a flag (e.g. consent to send newsletter). This would lead to an app to just toggle a checkbox, while still need to be maintained for all dependency updates and security fixes.
The question here is "what is the purpose of the UI Team?"
UI Team owns the UI with synchronous calls to Data-Owning-Teams
Here, the UI team builds the UI components and pages but fetches data via synchronous calls to the data-owning services.
sequenceDiagram
actor User
participant UI
participant Data
User-->>+UI: open page
UI->>+Data: GET Data for Display
Data->>+UI: Data to Display
UI-->>+User: render
User-->>+UI: submit form
UI->>+Data: POST Data for update
Data->>+UI: success/failure
UI-->>+User: display new state
Pros
- Coherent UI managed entirely by the UI team
- Simple to build and maintain.
Cons
- not a self-contained system
- cross team dependencies
- Latency issues due to real-time API calls
- we need API Contracts to ensure that the UI Team can rely on the Data Teams to provide the required data in a consistent way
[!WARNING]
this approach requires High Availability APIS with low latency of the Data Owning Teams
UI Team owns the UI with asynchronous calls to Data-Teams
In this model, the UI team owns the UI but handles all data via asynchronous replication. Private local copies of the data are required and must be kept in sync with the source.
sequenceDiagram
actor User
participant UI
participant Data
UI<<->>Data: async replication
User-->>+UI: open page
UI->>+UI: GET Data for Display
UI-->>+User: render
User-->>+UI: submit form
UI->>+UI: POST Data for update & mark record as dirty
UI->>Data: async delivery
UI-->>+User: display optimistic state
Data->>UI: async state update
UI<<->>UI: unmark record as dirty & update copy
UI-->>+User: communicate failure states
Pros
- Coherent UI controlled by the UI team
- Easy to build and maintain, the Synchronization is more effort
- Self-contained system with no runtime dependency on external services.
- zero latency issues
Cons
- Eventual consistency issues, as the UI Team has to ensure that the data is kept in sync with the Data Teams
- Data duplication and synchronization efforts
- cross team dependencies, which can lead to delays and coordination issues
- Event Contracts are required to ensure that the UI Team can rely on the Data Teams to provide the required data in a consistent way
[!WARNING]
this approach requires private local copies of the Data Owning Teams data which need to be kept in sync