Skip to content

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.

  1. If you need strong consistency (e.g., for User Data), synchronous communication is required.
  2. If you can accept eventual consistency (e.g., for Statistics), an asynchronous approach is preferable.
  3. 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