Micro-frontends & SCS
It’s safe to say that frontend development has gotten pretty complicated over the years, even though I consider myself to be reasonably up to date with modern tech stacks, I’ll be the first one to admit that I’m far from an expert in a lot of it - nor do I strive to be.
If we take a look at some of the things we come across - like Docker, React, Preact, Vue, Svelte, Typescript, Linters, testing libraries, Storybook, Redux, Recoil, Tailwind, CSS in JS libs, Flutter, React Native, Expo, Webpack, Rollup, Express, Koa, GraphQL, Apollo, URQL, ORMs, Next, Gatsby, Sapper & plain vanilla JS you quickly realize that stating something other than what I wrote above is simply impossible. Nobody knows everything (...except full stack devs ofc).
Luckily, adding micro-frontends to the mix doesn’t necessarily require you to learn a new framework or a library, or that you need to stop using any of the libraries above.
But what it does ask of you is that you rethink how you look at frontend development and that you let go of the typical control associated with monolithic frontends.
In return, together with SCS you end up having options you didn’t have before, some being:
- Being able to scale to multiple teams, each being independent and owning their own SCS.
- Having autonomous release cycles per team - no more big bang releases.
- A way to opt out of the current frontend refactoring meta taking place every other year.
What are micro-frontends and why now?
Micro-frontends architecture is the adoption of micro-services extended all the way to the UI layer. Other typical characteristics are that they’re built vertically, owned by dedicated cross-functional teams and that they span from the database to its interface.
Due to the nature of our ever-changing frontend eco system, micro-frontends offers us the option to independently invest in certain key areas of our UI and to optimize throughput by grouping the right people together.
So why now? why are micro-frontends getting popular 2020? I think that one answer is that frontend development right now has gone full circle, from our main line of business being dressing things up and making HTML look good, to the age of preferring CSR (client side rendering) and now back to acknowledging that rendering on the server / serving static content is good.
Assumed disadvantages = advantages
Some of the general skepticism of micro-frontends comes from what I believe are misguided assumptions, where the contrast of wanting to build something like we've always have, to actually working towards the end goal of breaking up a monolith into smaller decoupled UIs, can easily lead us to perceive design advantages as disadvantages along the way - I’m referring to:
How do we deal with global X?**
- Global styling,
- Global state,
- Global common code
- How can we make a unified experience in terms of UI / UX
- And what about DX?
All of these "pain points" are actual benefits in a micro-frontend architecture, so let’s go left to right and address each problem area with its simplest, most naive solution.
But first - context:
A team's journey towards SCS and micro-frontends
Let’s say we have a larger team of people working on a monolithic frontend / backend, the end product is a food app made as a node powered isomorphic React SPA.
Having had issues for quite a while regarding the ability to scale and deploy, and their CTO fresh back from vacation reading Team Topologies, they decide to dive head first and adopt SCS and micro-frontends, resulting in changes made to the current team structure - now divided into two separate teams with clear responsibilities:
Team A
In charge of the start page which contains all products
Team B
In charge of the checkout page, but not only that - they’re now also in charge of the cart shown on the start page.
As an effect to these changes, their isomorphic SPA has now been chopped into two separate projects (repos), both now with independent CI/CD setup and there’s something in front handling routing between the two, laying the ground for everything to still behave like it used to.
Suddenly, with doubled costs and their main React competence jumping ship, they collectively decide to sunset isomorphism and serve views using EJS / Razor or some other view engine on the server (or static).
Some devs in team B panic at first since they're the team owning the more complicated checkout application with behavior. But they keep their cool when they realize they could move logic to the server and progressively enhance client side.
Things are going great, but they do have som some valid concerns...
Nr.1 - Styling
The checkout button used to be the same component as the buy button, how can we achieve the same level of visual consistency across frontends? and what base styles and media queries?
Buttons - copy the markup and CSS, achieving visual consistency is only a challenge if there is something hindering the teams from communicating properly. Base styles and media queries are infrastructure and should reside in some kind of baseline (CDN).
Nr.2 - State / interactions
How do we work with global events and optimistic UI changes now that we don’t have a global state store like Redux?
The same thing can be achieved dispatching custom events.
document.dispatchEvent(new CustomEvent('name', { detail: 'payload' }));
document.dispatchEvent(new CustomEvent('name', { detail: 'payload' }));
document.addEventListener('name', eventHandler);
document.addEventListener('name', eventHandler);
Nr.3 - Global utils / Shared infrastructure?
How do we solve common code / utilities ? I’m helping team A do X and I already have that in team B's repository.
I would say - tell yourself that D.R.Y is dead and start by duplicating X. Adding X to the common baseline is opening a door that you want to have closed. Chances are you'll start adding more and more things to it, and in the end building a frontend library that your teams are dependent of.
(D.R.Y stands for Don't repeat yourself)
General rules regarding the baseline infrastructure:
- CSS base and media queries.
- Typography.
- Polyfills.
Nr.4 - Sharing components
We now need to find a way of delivering a mini cart to team A and possibly other teams, how should we approach this?