Decoupling digital with micro-frontends and micro-services

TL;DR: This is an opinionated technology solution using NextJs Zones and federated GraphQL. For the techies, there's a fair amount of upfront business context. Bear with me, it's an important part of the story. Especially so, if you're trying to convince your business leaders to invest in a modern architecture like micro-frontends and federated GraphQL.

The large organisation problem

Large organisations, be they modern tech giants or established enterprises, face tough challenges when it comes to ownership of digital assets. As organisations grow and shrink, technology trends shift from monoliths to microservices, shared platforms to value streams, the brunt of the pain is felt by the teams maintaining those assets. We are all too aware of the discomfort of endless restructures in order to align to the latest tech or agile trends: change fatigue.

Where have we come from

We once aligned ourselves by department, or discipline. This led to multi hand-offs, long lead times for change, and helped internal political systems [which add no value] to thrive. These problems were exacerbated by the scale of enterprise organisations.

Product A
Marketing Team
Frontend Team
Backend Team
Infra Team
Security Team
Ops Team
General
r.--On
Product B
o

Teams were not aligned around the goal of improving 'Product A' because their goals were aligned to discipline. The 'Frontend' (or web team) were focused on building websites rather then working with marketers to improve the sales a product.

The modern organisation

The latest trend, is to have teams align around value streams. End-to-end, or front-to-back multidisciplinary full-stack teams. Empowered to own the full lifecycle of an entire vertical slice of an organisation. The reason to align this way is simple: you can effect change without any dependencies on discipline aligned teams (e.g. marketing), because you have that discipline in your team (e.g. your own marketer). No hand-offs, no dependencies, no email tennis - just the efficient flow of work with everyone working towards a common goal.

Product A
Marketing Team
Frontend Team
Backend Team
Infra Team
Security Team
Ops Team
General
re--on
Product B
Potential
Duplicity

The nirvana, or so you might think. There is a problem with this approach: it creates duplicity and over time, divergence. Following vertically aligned principals to reduce dependencies can lead to different design standards, multiple domains and each vertical having their own version of common services. There are now vertical product silos instead of layered discipline silos. Whilst the people aspects can be solved through cultural initiatives like guilds, deploying brand consistent, decoupled applications as part of a coherent digital estate is still a challenge.

Decoupling technology

The Backend

Microservices

Microservices were meant to solve some of these problems. The idea is simple: establish your business domains and have teams aligned to those domains build small services. The problem is, that’s just the back end - and have we really solved the problem? Now we have many services with unclear dependencies and our front ends have to make multiple requests to multiple services. You can streamline this with an API gateway but that doesn’t solve interface chattiness issues or tightly coupled UI components to microservices.

GraphQL

GraphQL provides a schematically defined separation between UI and microservices. There's a misconception with GraphQL that it is monolithic. Whilst it is possible to create a GraphQL monolith, just as you can with a SOA style REST API, there are ways to avoid such undesirable architectures. Apollo's Federation is good for this. I would highly recommend reading the official Apollo docs here: https://www.apollographql.com/docs/federation/.

A great example of GraphQL federation in production is at Netflix. They have written a great blog on the subject here: https://netflixtechblog.com/how-netflix-scales-its-api-with-graphql-federation-part-1-ae3557c187e2

The Frontend

You can solve the brand/design standards issue with a design system (e.g. Googles Material UI) or at a minimum, a style guide. But how do you solve the problem of the tightly-coupled front end?

One app = monolith, multiple apps = inconsistency + confusing IA, and is not optimised for SEO. What you really need is small UIs or components that are independently deployable. Here's some examples of how that can be achieved:

Single App container

This approach has been around for some time and was historically implemented with iFrames. SharePoint 2013 did this with 'App Parts'. Spotify has done it with Electron. It works well for rich interactive single page applications. The Webcomponents standard now provides an iFrame-less mechanism to do this, albeit with varying levels of maturity in some browsers. There are two flavours of this approach.

Framework-less

Cam Jackson from Thoughtworks has written a really detailed article on this approach here: https://martinfowler.com/articles/micro-frontends.html. He advocates the use of vanilla JavaScript to load bundle.js files from various other apps.

With framework

Guy Nesher recently announced https://www.infoq.com/news/2020/12/micro-frontends-single-spa/ the single-spa framework, which is a lightweight framework to glue together multiple SPAs into a single application.

The cons of this approach are complexity in deployment and testing. If you opt for a statically built app you have to have a central deployment mechanism. And if you want isomorphic Jamstack you will need to roll your own.

Separate Apps

This approach is as simple as it sounds: you have completely separate apps. Itworks really well if you have lots of individual apps aligned to journeys, like applying for a bank account. The downside is that inconsistency will creap in without strong design standards, or preferebly, a design system. You also have to solve the IA issue with an approach that is SEO friendly. There are two main ways to do this:

Layer 7 routing

If you want total control and isolated testing you could use a traffic manager to split your traffic based on URL. This means separate apps, that could be on different tech stacks, in different regions and even different cloud providers. This approach puts a dependency on infra engineering, which could be a bottle neck if you have an IA that is immature or emerging.

Zone Apps

There is another way to decouple: Zone apps. This is a NextJs framework based approach and which will work with React only. It allows you to stitch together the routing of multiple NextJs apps running in different locations. The only coupling sits with configuration within the main home app. This is necessary so it knows where to find the other zone apps. Beyond that, the applications are fully decoupled.

There are some downsides with the separate app approach. We have only solved the IA/SEO issue. The UI could easily become inconsistent. To solve that we can use a design system which includes components for standard furniture like header/nav/footer. We could even content control the config by consuming a shared configuration file hosted and versioned on a CDN or a headless CMS.

An example

Our example business (FakeFurniture.com) has the following requirements:

  • The architecture must support a
    • Home team looking after core brand
    • Account team looking after customer data
    • A Product team looking after products, inventory and reviews
  • The architecture must support adding Product teams over time
  • The account team needs access to reviews written by a customer
  • There will be other UIs built by 3rd parties using our APIs
  • Performance and experience must be best of breed
  • All applications must be on brand and share components/content where feasible

These would be fairly common requirements for an organisation with multiple teams and applications. From an architectural perspective, our estate looks a this:

www.com
Home Team
Account Team
Product Team
Accounts
service
www.com/account
API
Gateway
Review
Service
Products
service
www.com/products
Inventory
service

As you can see, the API gateway could easily become the bottleneck for change. The account and product teams could have their own gateways, but that just fragments the estate and reduces the ease of re-use. Likewise, clients have to conform to API specifications and could break as the specifications change.

If we were to take an approach that used a GraphQL schema as the mechanism to decouple frontends from backends via a federation gateway, we could solve a lot of the integration coupling problems. This has the added benefit of simpler integration for 3rd parties UIs.

On the frontend, NextJs Zones are a good candidate to join up our IA. Using Next and Apollo our application now looks like this: