Microservices in the frontend – why?

The microservice architecture pattern has revolutionized[1] the way we build software today. But as we are seeing monolith after monolith being split into microservices in the backend, we are still shipping frontend code in large chunks; bundles, minifiers, domain shards, resource inlining is just a couple of techniques used to improve web performance.

Micro frontends describes an architectural pattern in which the frontend monolith is decomposed into smaller features fully owned by different cross-functional teams. This approach enables loose coupling and an autonomous workflow to ensure development, testing and deployment without interference of external dependencies, enabling teams to individually scale delivery output.

When observing the backend transition towards microservices we've seen a lot of success stories, with increased innovation, resiliency, deliverability and ability for easier scaling. But we've also seen increased amount of complexity and latency. So in an area where speed is key, why would we want to add more complexity and latency to our frontends?

Although I'm heavlily excited about the micro architectures, a bit of pragmatism might be healthy; full micro architecture has its trade-offs and is not a silver bullet, but I do think of a couple of reasons to consider decomposing parts of your frontend monolith.

Isolation and responsibility

A generic system typically contains of a variety of moving parts, and it quickly becomes a complex task in identifying what and whom are responsible for each thing. The microservice mindset is based on a perticular solid principle: A service should be small, focused and doing one thing very well.

This is often a problem with fontend code as, with the DOM as runtime, all components within the interface has the ability to interact and affect each other, often unintendend via side-effects.

One common way to decompose an application is to split the application into verticals, also know as self-contained systems. Each vertical is implemented by exactly one team and is responsible for a single domain with clear boundaries[2]. Hence, "the order vertical" has responsibility for the order process, "the search vertical" has responsibility for the search and so on.

While the most optimal way to describe boundaries of a service is debatable; it's clear that this separation of concerns is necessary to obtain brevity. Not only does this introduce clarity in aspect of responsibility, but also introduces a clear ownership of respective domain.

Separation of concerns is necessary to obtain brevity.

Team autonomy

I am a firm believer that a team should have the mandate to work autonomously and not enforced with strange methodologies, frameworks and other limitations. That said, I also believe in collaboration and working towards a common goal.

By leveraging autonomy and loose coupling, the team can be truly technology agnostic, free to select which ever tooling, language, framework, methodology that is suitable for their needs without imposing on other teams.

Decomposing for autonomy also introduces a clear ownership of each feature, which in turn enables additional autonomy regarding deployment, maintenance, monitoring and deprecation, increasing the ability to continously deliver functionality into production.

Improved performance

By decomposing the monolith into smaller pieces, the ability to add individual scaling and component specific cache policies also increase fundamentally. Imagine the ability to automatically allow offloading backend services in the frontend on traffic peaks.

Although it probably won't solve all performance issues, HTTP/2 is probably mandatory in order to succeed with micro frontends. By including performance optimizations, such as multiplexing, header decompression, binary format instead of text, and stream dependencies; the technology is essentially designed for better performance.

This means no more bundles and no need for domain sharding[3] to serve clients for performance, but ultimately be more performant when sliced into and smaller files[4][5].

Decomposing the frontend monolith can gain improvements in isolation, deliverability and performance. Although while it may add extra complexity into an application, it may also increase clarity.

By investing pragmatically in this technique I do believe there's additional benefits other than described in this post. And although if the monolith keeps on living, the principles circling micro architecture could be of use in a non-micro architecture.

Gain more insights on micro frontends:

  1. While Service Oriented Architecture (SOA) have been around for ages it's not the same as microservice architecture (MSA). Microservices vs SOA – whats the difference ↩︎

  2. Scaling with Microservices and Vertical Decomposition ↩︎

  3. High Performance Browser Networking: HTTP/2, Domain sharding, Concatenation and Spriting ↩︎

  4. HTTP/2 Demo: Akamai http/2 demo ↩︎

  5. HTTP/2 Demo: Gophertiles ↩︎