In October 2026 I spoke at CityJS Athens about something I lived for years before I ever put it on a slide: keeping a large frontend architecture coherent when many teams ship to the same product. I had given a version of this talk, "MicroFrontends a gran escala", at Front in Floripa a year earlier — but this time I was speaking with a few more scars, and a few more opinions.
This post is the written version of what I've learned. It comes from almost five years at Globant (October 2021 to July 2026), working for large clients: first on internal tools and design system components for a global media and entertainment company, then on the payments area of its parks and resorts sites, then on the web experience of a major airline, and finally as Tech Lead on the rebuild of that airline's website — a Next.js, TypeScript, Tailwind, Storybook and Docker stack with a team of more than ten engineers on my side, inside a much larger program.
I can't share client internals, so this is about the engineering patterns, the decisions, and what I'd do differently — not about any specific codebase.
What a design system actually is
Before Globant, "design system" meant a Figma file and a components folder to me. After working on two different divisions of that entertainment company, my definition changed. A design system at that scale is a product with its own users — the engineers who consume it:
- Design tokens — color, spacing, typography, radii — versioned as code, not as documentation. Tokens are the cheapest contract you can maintain and the most expensive one to break.
- Primitive and composite components, built once and consumed by every team.
- Documentation people actually read, which for us meant Storybook: every component with its variants, states, and usage notes.
On the parks and resorts project I worked on components built with Stencil, which compiles to framework-agnostic Web Components. That choice looks unusual until you see the constraint it solves: when dozens of teams on different stacks — React here, Angular there, legacy templates somewhere else — all need the same accessible, brand-compliant button, compiling to a web standard is cheaper than rewriting the library per framework. The framework changes; the contract doesn't.
On the media side the problem was different: internal tools being rebuilt on the company's design system while the system itself was still evolving. Building new components for the library and shipping features on top of it at the same time teaches you the golden rule: a design system is a dependency you version, not a folder you edit. Breaking changes go through deprecation cycles. Teams pin versions. Upgrades are someone's planned work, never a surprise.
Microfrontends: why and when they earn their complexity
On the airline program, the frontend wasn't one app — it was a composition of independently deployed microfrontends, each owned by a different team, assembled under a shared shell.
The motivation was never technical fashion. With many teams working in parallel, a single deployable frontend becomes a queue: every release waits for the slowest team, every integration conflict lands on someone's Friday. Microfrontends gave each team a bounded context they could build, test, deploy, and roll back on their own cadence.
The parts that made it work:
- The shell owns the seams. Routing, authentication, layout, and the composition layer lived in one thin host application. Teams never negotiated cross-MFE navigation — the shell mediated it.
- Shared dependencies are a contract. React, the design system, and a few core libraries were aligned at the shell level, so they loaded once instead of shipping N copies. Everything else, teams could own.
- Semantic versioning was a social contract. When the design system published a breaking change, it came with a migration window and deprecation warnings first. Consuming teams upgraded on their schedule — but within a bounded window, or the shell stopped guaranteeing compatibility.
What actually went wrong
I'd be lying if I presented this as a clean success story. The failures are the interesting part:
- Duplication crept back anyway. Two teams needed "a date picker slightly different from ours" and suddenly you're maintaining three date pickers. The fix wasn't technical — it was a contribution model: teams could propose changes back into the design system instead of forking it.
- Version skew is silent. When five microfrontends run five versions of the design system, the product feels inconsistent in ways users notice before engineers do — a hover state here, a spacing rhythm there. We learned to treat visual drift as a bug class, not an aesthetic nitpick.
- Local development got harder before it got easier. Running one microfrontend in isolation is easy; reproducing an integration bug across three of them needs the shell, the right versions, and a staging environment that actually mirrors production. Underinvest in that tooling and every integration bug costs a day.
- Microfrontends are an organizational investment. They trade technical complexity for team autonomy. For a small team on one product, that trade is a loss — I tell everyone who asks: if your bottleneck isn't team coordination, don't pay the MFE tax.
Leading the humans behind the architecture
The architecture decisions were the easy half. The harder half was keeping 10+ engineers — plus adjacent teams owning other slices — moving in compatible directions without turning me into a bottleneck:
- Decisions in writing. Anything that crossed team boundaries became an RFC: short, opinionated, with a decision date. Verbal alignment evaporates; written rationale survives team rotations.
- Reviews as teaching, not gatekeeping. With a mixed-seniority team, code review was where conventions actually propagated. A rejection without an explanation just trains people to fear you.
- Quality gates that don't negotiate. TypeScript strict, tests on the paths that handle money, Storybook coverage on shared components, Docker so "works on my machine" stops being a sentence.
What this taught me about multi-agent software development
Here's the part I couldn't have written a year ago. Since then I've spent a lot of time building software with AI coding agents — and the problems feel strangely familiar.
Coordinating engineering teams on a shared codebase is, at its core, a problem of contracts, ownership, and review. When I watch multiple autonomous agents — or even one agent — modify a codebase, I see the same failure modes in miniature: uncoordinated conventions, silent contract violations, duplication where a shared abstraction already existed, integration failures discovered late.
I don't know yet how far the analogy goes, and I want to be honest that these are observations, not results. But the questions are the ones I've spent years on: How do independent contributors — human or artificial — share a codebase without a slow drift into inconsistency? What does "review" mean when the author is an agent and the reviewer can't check every line? Where should the contracts live so that autonomy doesn't erode the architecture?
That's a big part of why multi-agent collaboration and the evaluation of autonomous coding work have become the problems I most want to study — the same systems thinking, with a new kind of teammate. If you've lived this problem on either side, human or agent, I'd genuinely love to hear what broke for you.