Chapter 7: Design Systems and the Frontend at Scale — One Product from Forty Teams
Consistency is not something a product has. It is work that somebody keeps doing.
A fan who buys a ticket from Encore passes through screens built by perhaps a dozen teams. The event page belongs to Fan Discovery, the seat map to the Seat Map team, checkout to the Checkout team and the ticket in the app to Mobile App, while the hold timer on the screen counts down a hold that the Inventory team keeps. The fan sees none of those seams, or should not. To the fan there is one product, with one way of showing a price, one way of saying that something went wrong and one button that means “continue”. Behind the screen, that single product is the joint work of 40 teams who plan separately, ship separately and are measured separately. The question of this chapter is how such an organization keeps its product whole, and how it keeps doing so as fast as each team wants to move, in every language its customers read.
Our touchstone is a binder. In 1970 the New York City Transit Authority issued the Graphics Standards Manual that Massimo Vignelli and Bob Noorda of Unimark International had designed for the subway. It specified how every sign in the system should be built and lettered, so that a passenger changing trains under three formerly separate companies’ stations would read one system. What makes it useful to us is the less celebrated part of its history. A first proposal was built badly by people who had never been told how to build it, the manual itself was applied piecemeal for two decades, and the subway became coherent only when someone was finally paid to maintain the standard and migrate the stations to it. Every lesson of a modern design system is in that story, including the uncomfortable one: publishing the standard was the easy part.
Encore, at about 400 engineers, runs one design system, which it calls Setlist: tokens, tenant themes and accessible components, owned by the Design System team. The fan storefront is still the modular monolith the Architecture book
chose, and the organizer console, which that book left as one separate application, has since become a shell with six remotes that load at runtime. Verified Resale now arrives with needs of its own. It needs new shared patterns, among them a “Verified” badge, a price breakdown that shows face value, fee and total, and a status for a ticket being reissued. It needs a resale page that sees a crowd the moment an on-sale sells out. And it needs prices, fees and dates that are correct, and lawful, in every language and market an organizer sells into, beginning with France at launch.
7.1 Design Systems
The binder at Bergen Street
By the 1960s New York’s subway was three systems wearing one name. The Interborough Rapid Transit (IRT), the Brooklyn–Manhattan Transit (BMT) and the city-owned Independent (IND) had been unified under city ownership in 1940, but each still signed its stations in its own manner, and the oldest signs were the ceramic mosaic tablets of 1904, made with no common typeface, no arrows and no borders. When the Chrystie Street Connection opened in November 1967 and joined IND and BMT services, the confusion became a public complaint. The Transit Authority had already engaged Unimark in 1966. Bob Noorda, who had designed the signage for Milan’s first Metropolitana line, studied how passengers actually moved through the stations, and Unimark delivered a proposal.
What happened next is the part of the story a design-system team should read twice. According to Paul Shaw’s history of the episode, the Authority thanked the designers and then, as far as anyone can tell, put the proposal away. Its own sign shop at Bergen Street began making signs from the proposal without instruction from the designers and without their inspection, and the result was a muddle that Vignelli himself described, by Shaw’s account, as “the biggest mess in the world”. The Authority rehired Unimark in 1968, and in 1970 it issued the Graphics Standards Manual: a binder of precise rules for modular sign panels built from one-foot units, for letter spacing, word spacing and line counts, for arrows and route symbols, and for a black band across the top of each sign. The band began as a way of hiding the black metal channels from which the signs hung, because the stations could not be rebuilt to suit the designers; the manual turned that constraint into a rule of the graphic language. The typeface was Standard Medium, the American name for Akzidenz-Grotesk. Legend gives the subway Helvetica from the start, but Shaw’s research suggests that Helvetica, which Vignelli preferred, was simply not available to the sign shop, although he is candid that he cannot prove the reason.
Then came the drift. Around 1973 the signs were switched from black-on-white to white-on-black to resist graffiti. New signs went up beside decades-old ones from the three former companies, hand-lettered cardboard signs filled the gaps, and through the city’s fiscal crisis the standard was applied wherever someone happened to have money and attention, which was not often. Writing in the New York Times in 1979, the architecture critic Paul Goldberger judged the signs so confusing that “one is tempted to wish they were not there at all”. In December 1989 the Metropolitan Transportation Authority (MTA) made Helvetica its official typeface and hired Michael Hertz Associates to update the manual across its agencies, and the capital programs of the 1990s finally put a coherent system into the stations. The manual had an afterlife. A copy turned up in 2012 in the basement of Pentagram’s New York office, two of its designers, Jesse Reed and Hamish Smyth, licensed a full reissue from the MTA, and their 2014 Kickstarter raised $802,812 from about 6,700 backers. Figure 7.1 lays the episode out as a route with a station for each event, from the mosaic tablets to the reissue.
Figure 7.1 — The subway’s signs from 1904 to 2014. The standard was written in 1970; the stations became coherent only after 1989 brought an owner paid to maintain it and migrate them, and the route between those two stations is dashed.
Figure 7.2 reads the manual as a design system, and it is worth reading in that direction, because almost everything we will say in this chapter about Setlist has a counterpart in the binder.
| In the 1970 manual | In a design system | At Encore |
|---|---|---|
| Typeface, black band, colored route discs | Tokens: named values for type, color and space | Setlist’s token files and tenant themes |
| Modular panels in one-foot units | Components built from a shared grid | Button, PriceBreakdown, SeatLegend |
| Rules for spacing, arrows and placement | Usage guidance and patterns | The living pattern library |
| Bergen Street building from an uninstructed proposal | Teams building from a standard without guidance or review | The contribution path (Section 7.2) |
| Twenty years of piecemeal application | Version skew and abandoned migrations | The version dashboard and codemods |
| Standard Medium because the shop could make it | Tokens limited to what the platform can render | Tokens checked against what browsers and apps support |
Figure 7.2 — The Graphics Standards Manual read as a design system. The binder had every part a modern system has; what it lacked for two decades was an owner with the mandate and budget to keep the stations on it.
The story bears on this chapter in more than one way. A standard of this kind is a design system in every sense that matters, because it consists of named decisions, reusable parts and rules for combining them. Yet a standard is adopted only when the people who build from it are instructed and their work reviewed. The Bergen Street signs failed for want of both, and that is the problem of contribution and governance that Section 7.2 takes up. And a system that nobody maintains drifts one sign at a time, each departure defensible on the day it is made, until the whole has lost the coherence that was its reason for existing. The analogy with signage breaks in one place, and it breaks in our favor. A station sign is metal bolted to a wall and costs a crew a night to replace. A component in a design system can be replaced in every product that uses it by a release and an automated migration, so the two decades the subway needed can be shortened, for us, to the time it takes to run a well-planned migration.
From pages to systems
A design system is the set of named decisions, reusable components and usage rules from which a product’s interfaces are built, maintained by an owner as a product in its own right. The Architecture book’s Section 8.2 introduced it as the frontend’s shared kernel and warned that it must stay thin. This chapter takes that as settled and asks how such a thing is built and kept.
The most widely used way of thinking about the parts is Brad Frost’s atomic design, first sketched on his blog in 2013 and set out in his book of 2016. Frost borrowed from chemistry. Atoms are the smallest useful pieces, such as a button; molecules are small groups of atoms that do one thing together, such as a search field with its button; organisms are larger sections, such as a list of resale offers. Templates arrange organisms into a layout, and pages fill templates with real content, which is where we find out whether the system works. Frost is careful to present this as a mental model, and it is best used that way. Teams that file every component into exactly one drawer end up arguing about whether a date picker is a molecule or an organism. Teams that use the hierarchy as a habit of mind gain something more valuable, which is the instinct to design “systems, not pages”, as Frost puts it: to ask of every new screen what it is made of, and which of those parts already exist.
This is the oldest tool we have for mastering complexity, applied to pixels. Decomposition breaks the interface into parts small enough to reason about, abstraction lets a team use a PriceBreakdown without knowing how its alignment is computed, and hierarchy lets us see the whole at whichever level of detail the question needs. The GOV.UK Design System, the British government’s public system, is a good public example of the hierarchy in practice: it publishes styles, components and patterns as separate layers, so that a team building a new service can see at a glance whether it needs a color, a button or a whole way of asking a citizen for their address. Encore’s Setlist follows the same layering.
The interface inventory
Before a design system is built, someone usually has to prove it is needed, and the best proof is embarrassingly simple. Frost called it the interface inventory: a systematic collection of screenshots of every instance of each kind of interface element in a product, sorted by kind, so that its inconsistency becomes visible at a glance. He described it on his blog in 2013. The method is to capture every button, form field, error message and modal, group them by type in one document, and show the result to the people who pay for the product.
Encore did this at 70 engineers, in its fourth year, when the storefront and the organizer portal had been built by nine teams in a hurry. The inventory found 23 distinct button styles. Some differed in color, some in corner radius, some in the wording of the same action (“Continue”, “Next”, “Proceed to payment”), and two were nearly identical except that one had been copied from an older screen before a contrast fix was applied to the original. No one had chosen 23 buttons. Each had been a reasonable local decision, made by someone who could not see the other 22, which is the subway’s drift in miniature. The inventory did what no argument about efficiency had managed: it turned an abstract cost into a page that a product director could look at for 30 seconds and understand. That page is why Setlist exists, and it is still shown to every engineer who joins the Design System team.
Tokens as named decisions
The smallest parts of a design system are values: a color, a spacing step, a type size, a shadow, a corner radius. Adam Wathan and Steve Schoger, in Refactoring UI (2018), make the case that these should come from a deliberately constrained scale, a handful of spacing steps and a handful of type sizes chosen in advance, so that each new screen picks from the scale. Constraint here is a gift. A designer choosing between 16 and 24 pixels makes a better decision faster than one choosing among every integer, and a product built from eight spacing steps has a visible rhythm that a product built from 40 does not.
A design token is such a value given a name that records a decision, shared by design tools and code so that both draw from the same source. The term came from Salesforce, where Jon Levine and Jina Anne used it around 2014; the repository for Salesforce’s token tool, Theo, dates from February of that year. The idea’s strength is the name. color.action.primary says what the color is for, which is a decision, while #D9482B says only what it is. When the brand changes, or a tenant wants its own color, or the contrast rules tighten, the decision can be changed in one place and every component that used the name follows. It is a small irony that Salesforce has since moved its own system from token files to custom properties in Cascading Style Sheets (CSS): the concept outlived its first implementation, which is a fair sign that the concept was the valuable part.
For most of the decade each tool had its own token format, and moving tokens between a design tool and a build pipeline meant writing translators. That changed on 28 October 2025, when the Design Tokens Community Group published the first stable version of its format, 2025.10, in three modules: Format, Color and Resolver. The status is worth stating precisely. It is a Final Community Group Report of a group hosted by the World Wide Web Consortium (W3C), and it is not a W3C standard nor on the W3C standards track, but its editors declare it stable, and the group lists design tools such as Figma, Penpot and Sketch and token pipelines such as Style Dictionary among its adopters. Setlist’s tokens are written in that format. A fragment shows the shape: a base color, a decision that refers to it, and a tenant theme that overrides the decision.
{
"color": {
"vermilion": { "$type": "color",
"$value": { "colorSpace": "srgb", "components": [0.851, 0.282, 0.169], "hex": "#d9482b" } },
"action": {
"primary": { "$type": "color", "$value": "{color.vermilion}",
"$description": "Primary call to action. Must reach 4.5:1 on surface.default." }
}
}
}
The Resolver module matters more to Encore than the format itself, because it formalizes a base set of tokens plus modifiers that apply in a given context. That is exactly what a tenant theme is: the venue-chain-a storefront at tickets.venuechain.com resolves color.action.primary to the chain’s own color, and everything else follows. Dark mode and a high-contrast mode are modifiers of the same kind, which is why Setlist builds them on the same mechanism and checks every resolved combination against the contrast rules of Section 6.4. Where the theme is stored, and how a tenant’s configuration is rolled out, belongs to the Software book’s Section 7.3
; here the point is that a theme is data on top of named decisions, so a tenant can never choose a value the system has not anticipated.
Function, feel and names
Alla Kholmatova’s Design Systems (2017) offers a distinction that helps a team decide what to document and how. Functional patterns are the tangible parts of the interface, defined by what they let people do: a seat picker, a price breakdown, a countdown. Perceptual patterns are the qualities that make a product feel like itself across all of those parts: its tone of voice, its use of motion, its color and its density. The two need different kinds of documentation. A functional pattern can be specified as a component with properties and states. A perceptual pattern lives in principles and examples, and it is learned more than looked up. Kholmatova’s framework is one author’s lens, untested in any formal sense, but it explains a common failure well. Teams that document only functional patterns end up with a consistent set of components that still produce screens which feel unrelated, because nobody wrote down how Encore speaks to a fan who has just lost a seat.
Kholmatova’s other argument concerns names. She holds that a shared language does more to prevent duplication than any tool, because two teams that call the same thing by two names will build it twice, and her remedy is to name patterns by their purpose, with designers and engineers settling the names together. That is her argument, and nobody has measured it, but anyone who has searched a component library for the thing they need and failed to find it under the name they expected will recognize the problem. Encore applied the practice to Verified Resale. The resale trio and the Design System team held one naming session for the new patterns and agreed three names. VerifiedBadge marks a listing whose ticket will be reissued by Encore. ReissueStatus shows the fan where a reissue stands, from “sold” through “new ticket issued” to “in your wallet”. PriceBreakdown already existed for primary checkout and gained an optional line for the resale cap.
The third name hides an architectural decision that is easy to get wrong. The early sketches proposed a new component called “price with cap”, and the first prototype computed the cap from the face value it was given. That is business logic in the kernel, the failure the Architecture book’s Section 8.2
warns against: the moment an organizer sets a lower cap, or Irish law bounds the buyer’s total, the component would have to change with the business, and every team using it would wait for the Design System team’s release. So the teams extended PriceBreakdown instead. It displays a face value, a fee and a total that it is given, and the Resale service computes them. The component knows how to show a capped price legibly and accessibly; it does not know what a cap is.
Recap. The 1970 Graphics Standards Manual had every part of a modern design system, and its history shows that a standard without instruction, review and maintenance drifts one sign at a time. A design system decomposes the interface into a hierarchy of parts, proves its necessity with an inventory, encodes its decisions as named tokens in a now-stable shared format, and names its patterns by purpose. It displays what the business computes and keeps the computing out.
Exercise 7.1. Choose one kind of element in your product, such as buttons or error messages, and inventory every instance across the product. Count the variants, and for each variant beyond the first, find out whether anyone chose it on purpose.
7.2 Running a Design System as a Product
Its users are teams
A design system is an internal product, and it fails in the ways internal products fail. Its users are designers and frontend engineers in other teams. They have deadlines and an alternative, which is to build the thing themselves. Everything Part I of this book said about deciding what to build applies, pointed inward: the Design System team needs a roadmap tied to the problems of the teams it serves, regular research with those teams, a support channel that answers within a day, and a measure of whether its product is being used. The Software book’s Chapter 6 treats internal platforms as products, and its Section 6.4 on adoption applies here unchanged. What is particular to a design system is the measure of use and the way its users contribute back.
The measure is adoption: the share of a product’s interface that is drawn by the design system’s components and tokens, as opposed to local code. Pinterest published an unusually honest account of how its design systems team measures this for its Gestalt library. A nightly job scans the team’s design files, counting only files edited in the previous two weeks and only pages marked as ready for handoff to engineering, and computes the share of layers that come from the library; in Pinterest’s worked example, seven of 15 layers came from Gestalt, a little under half. Adoption varied from about half on some teams to 2% on others. The team’s conclusion was that adoption begins in the design phase, before any code exists, which is why it measures the design files. On the code side, practitioner guides recommend a different count: for each component, the number of products that use it at all, gathered by scanning imports, because raw instance counts reward a team for drawing one button many times.
Setlist measures both. A nightly scan of the storefront and the console counts the interactive elements rendered by Setlist components as a share of all interactive elements, per surface and per team, and a weekly scan of design files does the same for screens in progress. The figures at the start of the resale work were 86% on the fan storefront and 71% on the organizer console, with the Festivals remote furthest behind at 44%, because it had inherited components from the festival app integration years before Setlist existed. The figure that matters most is the lowest one, because it tells the Design System team where its product is failing its users. When they asked the Festivals team why, the answer was not resistance. Setlist had no component for a multi-day pass selector, and the Festivals team had stopped asking after their first request sat in a queue for a quarter.
Governance
Every design system must answer who decides what goes into it, and the answers fall into a small number of shapes. Nathan Curtis of EightShapes named three team models in 2015. In a solitary model, one product team builds a system for its own needs and makes it available to others, who take it as it is. In a centralized model, a dedicated team owns the system and serves everyone. In a federated model, designers and engineers from several product teams build and maintain the system together, without a dedicated team. Kholmatova adds three dimensions along which any system can be placed: strict or loose in how far teams may depart from it, modular or integrated in how freely its parts combine, and centralized or distributed in who maintains it. Figure 7.3 sets the models side by side.
| Model | Who builds it | Strength | Typical failure |
|---|---|---|---|
| Solitary | One product team, for itself | Fast start, real use from day one | Serves its owner’s needs; others fork it |
| Centralized | A dedicated team | Coherence, quality, accessibility done once | Becomes a queue every team waits in |
| Federated | Contributors from product teams | Patterns come from real work | No one has time to say no; quality drifts |
| Core plus federated contributors | A small dedicated core, with contributions reviewed by it | Coherence with a path for teams to add what they need | Needs a contribution path people actually use |
Figure 7.3 — Design-system team models, after Nathan Curtis (2015). Most large systems settle on the last row; the work is in making its contribution path real.
Few large organizations end up in a pure form. Curtis’s own follow-up in 2016 described Salesforce running a central core team with federated contributors from product teams, and that hybrid is the model Encore uses. The Design System team, six engineers and three designers, owns tokens, the core components, accessibility, documentation and releases. Setlist is strict about tokens and accessibility, where departures harm fans, and looser about layout, where a sovereign tool like the organizer console legitimately needs density that a transient fan flow does not. The model has a known weakness, which the Festivals story illustrates: a central core becomes a queue. The defense is to make contribution the normal way that a missing pattern gets built, so that a team that needs a pass selector builds it and brings it to the core.
The path from local to shared
A contribution path is the defined sequence of steps by which a component built by one team for its own needs becomes part of the shared system. The best public model is the GOV.UK Design System’s contribution criteria. A proposal must first show that the pattern is useful, meaning there is evidence that services need it, and unique, meaning nothing already in the system serves the purpose. Before publication, the implementation must be usable, with research showing that it works for people; consistent with the rest of the system; and versatile enough to serve more than the service that proposed it. The criteria are short, public and applied by a named team, and that combination is what makes them work. A contributor knows in advance what will be asked.
Encore’s path follows the same shape, with one step added before the first. Most new patterns begin as pattern candidates: components that one team builds in its own code, in Setlist’s style, and registers in the library as candidates. A candidate is visible to every team but owned by the team that made it, and it carries no promise of support. If a second team needs it, the two teams and the core review it against Setlist’s criteria: useful, unique, accessible to the component contract of Section 6.4, documented, and free of business logic. Then the core team takes ownership and releases it. The arrangement solves two problems at once. The team that needs something now is never blocked by the core, and the core never absorbs a component that only one team will ever use. It is InnerSource applied to the interface, and the Software book’s Section 8.4
describes the trusted-committer practice that makes such contributions sustainable.
Figure 7.4 draws the path, with the step at which ownership moves from the team that built a component to the core.
Figure 7.4 — Setlist’s contribution path. A component changes owner only after a second team needs it and a joint review has applied the criteria; the lower strip follows VerifiedBadge and ReissueStatus through it.
Verified Resale went through this path twice. VerifiedBadge and ReissueStatus began as candidates in the Resale team’s code during the prototype stage, and both were promoted after Mobile App needed them for the app’s resale module and Fan Messaging needed ReissueStatus for the “your ticket sold” email. The accessibility review caught one thing that the Resale team had missed: the badge conveyed “verified” by color and an icon alone, with no text for a screen reader, and the reviewed version carries a visible label.
Versions, codemods and the dashboard
A design system that cannot change becomes the subway in 1975, so the question is how it changes without breaking 40 teams. The answer has three parts, and each is established practice. The first is semantic versioning, as Tom Preston-Werner specified it: a major version for changes that break consumers, a minor version for compatible additions and a patch for compatible fixes, so that a team can read from the number alone whether an upgrade needs work. The second is a deprecation window: a component or property to be removed is first marked deprecated, with a warning in the console and in the documentation, and stays working for a stated period. Setlist’s window is two minor releases and never less than six months.
The third part is the one that changes the economics. A codemod is a program that rewrites source code automatically to carry out a migration, usually by parsing the code into a syntax tree and transforming it. Addy Osmani and Hassan Djirdeh’s Building Large Scale Web Apps (2024) gives the technique a chapter, and Shopify’s design system, Polaris, offers the clearest public example of its use. Polaris’s guide for migrating from version 11 to version 12 states that the bulk of the migration is automated through its migrator command-line tool, with a named transform for each breaking change and a dry-run mode to preview the result. Encore adopted the same rule: Setlist ships a breaking change only with the codemod that migrates consumers in the same release, and the core team runs it first against every consumer in the monorepo before tagging the release. A breaking change whose migration cannot be automated needs a stronger case, and it usually waits for the next major version. The mechanics of large-scale change belong to the Software book’s Section 2.5
.
I spent a decade maintaining a widely used open-source library, and the lesson I took from it is that a maintainer who cannot see who is running which version is guessing every time they decide what to break. Setlist answers that with a version dashboard, which shows for each storefront context and each console remote the Setlist version it runs, how far behind the current release it is, and which deprecated components it still uses. The dashboard makes migration a visible, finite piece of work. It also protects the core team from its own optimism, because it shows how long the last migration actually took.
One further practice guards the releases themselves. Every Setlist component is rendered in each of its states, in every theme, by a component workshop in continuous integration (CI), and the screenshots are compared against the previous release. This visual regression testing catches the change that passes every unit test and still moves a button two pixels into the hold timer. It is standard practice in mature design systems, because no other automated test looks at the rendered screen.
Documentation that stays true
The Chicago Manual of Style has gone through many editions since its first in 1906, and its authority comes from that revision as much as from its rules: an editor trusts it because it is current. A design system’s documentation earns trust the same way, and the established way to keep it current is to generate it from the code. Setlist’s pattern library is built by the same component workshop that runs the visual tests, so every example on the documentation site is the real component at its current version. Each entry adds what the code cannot say: when to use the component and when not to, examples of correct and incorrect use, the accessibility contract, and a list of the places in the product where it is used, taken from the nightly scan.
Keeping design files in step with code is harder, and the honest description is that the practice is maturing. Design tools gained variables, programmatic interfaces and token import between 2023 and 2025, and the stable token format makes the exchange cleaner. What works reliably today is a one-way flow. Setlist’s token files in the repository are the source; the build pipeline generates the platform outputs for web, iOS and Android, and a scheduled job updates the design tool’s variables from the same files. Designers do not edit tokens in the design tool; they propose changes to the token files through the same review as any other change. Two-way synchronization is offered by several tools, and Encore does not use it, because two sources of truth for one decision eventually disagree. The same tokens and the same governance serve the native apps, whose shared design system is the subject of Section 8.5.
Recap. A design system’s users are other teams, so it needs research, support and an adoption measure, and the lowest adoption figure is the most informative one. Most large systems settle on a central core with federated contributors, which works only if contribution is a real path with public criteria. Breaking changes ship with their codemods, a version dashboard shows the debt that remains, and documentation stays true when it is generated from the code it describes.
Exercise 7.2. Measure what share of your product’s interface is drawn by design-system components, per team. Take the team furthest behind and ask them, without defending the system, what it lacks.
7.3 The Frontend Codebase in Practice
What was settled, and what changed
The Architecture book’s Chapter 8 settled the frontend’s structural decisions, and nothing in Encore’s growth since has unsettled them. Rendering is chosen per page class. State is sorted into local interface state, server cache and genuine global client state. Code is divided by bounded context, with boundaries checked in the build. Micro-frontends must clear a bar measured in waiting. And whoever runs a shell runs a product. This section is about living with those decisions at 40 teams.
One decision did change, in the way that book said it should. In its eighth year Encore had seven teams shipping into the organizer console, which was still the single separate application the Architecture book had described. The Organizer Console team did what Section 8.3 of that book asked and counted release collisions over a quarter. About two releases in five had been held back by another team’s unfinished change, and two teams had begun batching their work to avoid the release train. That was the evidence of waiting. The console moved to runtime module federation: a shell owned by the Organizer Console team, with the organizer backend for frontend (BFF), and six remotes owned by Organizer Onboarding, Event Setup, Pricing & Presales, Festivals, Organizer Insights and Forecasting. Each remote now ships on its owner’s schedule. The fan storefront did not follow. Its teams share one deploy without the same contention, and duplicated payload would cost its on-sale crowds dearly, so it remains a modular monolith with context boundaries, its shell and server rendering owned by the Web Storefront team. Verified Resale’s rules console will become the console’s seventh remote, built by the Organizer Console team, and the fan resale page will be a new resale/ context in the storefront, owned by the Resale team.
The shell as a product
Runtime federation became practical when webpack 5, released in October 2020, shipped Module Federation, created by Zack Jackson with Marais Rossouw and Tobias Koppers. It lets a running application load code that another team built and deployed separately. The shell is the host application that loads those remotes and owns everything they share: routing between them, the organizer’s session, the current tenant and its theme, error boundaries so that a failing remote shows a contained error while the rest of the console keeps working, and the frame of navigation that makes seven remotes feel like one tool. Luca Mezzalira’s Building Micro-Frontends (second edition, 2025) is the best practical account of operating one.
The shell needs to know which version of each remote to load, and here there is a choice. The remotes’ locations can be compiled into the shell, which couples every remote release to a shell deploy and gives back the waiting that federation was meant to remove. They can be listed in an import map, a browser-native mechanism. Or they can be served by a frontend discovery service, a pattern Mezzalira and colleagues at Amazon Web Services have published with an open schema, in which the shell fetches at startup a manifest naming the current version of each remote. Encore uses a discovery manifest. It is one good answer among several, since no industry standard has emerged, and its value lies in what it decouples: a remote’s owner can release, and roll back, by changing one entry, without touching the shell. Progressive delivery of remotes, the canary that sends a new version to a fraction of organizers first, works through the same manifest and is described in the Resilience book’s Chapter 4
.
The Organizer Console team runs the shell as a product, with a changelog, a weekly office hour for the remote teams and a service level objective (SLO): 99.9% of console page loads render the shell and the requested remote without an error boundary firing, over a rolling 28 days. A remote that throws is the remote’s problem; a shell that fails to load any remote is the shell’s. Figure 7.5 draws the console as it now stands.
Figure 7.5 — The organizer console: a shell run as a product, remotes that each ship on their owner’s schedule, a discovery manifest that names their versions, and the short list of shared singletons that the next subsection explains.
Shared dependencies and version skew
Federation gives each remote its own build, and with it the freedom to bring its own copy of everything. That freedom has two costs. The first is payload: a remote that bundles its own framework makes the organizer’s browser download the framework again. The second is subtler and worse. Some libraries hold state that must be single for the page to work, such as the framework’s renderer, the router, and Setlist’s theme context, and two copies of them produce errors that appear only in the browser, only in certain combinations of remote versions, and never in any one team’s tests. Mezzalira names the antipatterns that lead here, among them what he calls micro-frontend anarchy, in which each team picks its own framework and versions. The cure is an explicit and short list of shared dependencies, each declared as a singleton, a library loaded once for the whole page, with a version range that every remote must accept. Encore’s console remotes declare the same block, generated from one file the shell team owns:
// Generated from shell/shared-deps.json — do not edit by hand.
new ModuleFederationPlugin({
name: "eventSetup",
filename: "remoteEntry.js",
exposes: { "./App": "./src/App" },
shared: {
react: { singleton: true, requiredVersion: "^19.0.0" },
"react-dom": { singleton: true, requiredVersion: "^19.0.0" },
"@encore/setlist": { singleton: true, requiredVersion: "^14.2.0" },
"@encore/session": { singleton: true, requiredVersion: "^3.0.0" },
},
});
Four entries is a deliberate number. Everything else, from date libraries to charting, each remote may bundle for itself, accepting the payload in return for independence. The short list makes the hard question visible, which is who decides when a shared dependency moves. At Encore, the shell team proposes and the remote teams agree, and the move is run as a campaign with a deadline. The framework’s last major-version upgrade ran across the storefront and all six remotes as a tracked campaign over two quarters, with a dashboard of who had moved, a codemod for the mechanical part of the change, and a date after which the shell stopped accepting the old version. Remotes that missed the date did not break; the shell kept loading their last compatible release until they caught up.
The tooling around the code needs an owner too, as the Architecture book observed of the monorepo build. At Encore the Web & API Paths team in the platform group owns the frontend build paths, the workspace tooling and the generation of typed API clients from the OpenAPI contracts, so that a change to a backend contract shows up as a type error in the frontend that calls it. Large refactors across the frontend run as codemods, never by hand. The general arguments for the monorepo and for automated change at scale are made in the Software book’s Sections 4.2
and 2.5, and the frontend adds nothing to them except the scale of its imports.
Fitness functions for forty teams
The Architecture book introduced fitness functions for the frontend: performance budgets and cycle checks between contexts. At Encore’s present scale the same idea carries four kinds of check in CI. Boundary checks fail a build when one storefront context imports another’s internals, or when a console remote imports another remote’s code directly, bypassing the shell’s published interface. Bundle budgets, one per remote and one per storefront route, fail a build that exceeds them. Automated accessibility checks fail a build on the errors a tool can detect, knowing that tools catch only a minority of problems and that Section 6.4’s manual testing remains on the release checklist. And design-system usage checks, lint rules that reject raw color values and hand-built copies of Setlist components, warn on new code.
The last kind deserves a caveat. Lint rules that enforce design-system use are common practice, and the reasoning behind them is sound, but there is no published evidence of how much they improve consistency, and a rule that blocks a build for a hard-coded color can tempt a team to disable the rule and leave the cause in place. Encore runs them as warnings on new code and reports them on the adoption dashboard, and it blocks only the two cases where a departure harms fans: raw colors that bypass the contrast-checked tokens, and custom focus styles. Keeping 40 teams’ code coherent through checks and dashboards, with no review board for screens, is Encore’s choice, made in the spirit of the platform’s golden paths, and it depends on the checks being few, fast and explained.
Recap. Encore moved its organizer console to federated remotes when release collisions showed the waiting, and left the fan storefront as a modular monolith because the evidence there did not. The shell is a product with an owner, a changelog and an objective, and a discovery manifest lets remotes release without it. A short list of singleton dependencies keeps version skew manageable, upgrades run as campaigns, and a few explained checks in CI keep the codebase coherent.
Exercise 7.3. List the shared dependencies of your frontend and mark which ones must be a single version on the page. For each, write down who decides when it moves, and how long the last move took.
7.4 Performance as a Feature
Reading the evidence that speed sells
The idea that speed is a property of the product as much as of its servers has a clear lineage. Steve Souders’s High Performance Web Sites (2007) argued from measurements at Yahoo that most of the time a user waits is spent in the browser and on the network after the server has answered, and that a short list of rules about requests, caching and script placement recovered most of it. Ilya Grigorik’s High Performance Browser Networking (2013) opened its first chapter with a section titled “Speed Is a Feature”. Google’s Core Web Vitals, which the Architecture book’s Section 8.1
defined along with their thresholds, turned the argument into three numbers that anyone can measure. This section takes those numbers and thresholds as given and asks a different question: how do we know that being faster is worth the work, and how do we make it a habit at 40 teams?
The evidence most often cited comes in two kinds, and they should not be read the same way. The first kind is an experiment. In 2021 Vodafone published, with Google, the results of an A/B test on a landing page: traffic from paid media was split evenly between the existing page and an optimized version, and the optimized version had a field largest contentful paint (LCP) 31% better, 5.7 s against 8.3 s. It produced 8% more sales. Because the traffic was randomized, the difference can be attributed to the change, and the result is as close to proof as a single published case gets, for that page, those visitors and that size of improvement. The second kind is a correlation. Milliseconds Make Millions, a 2020 study by Deloitte Digital with Fifty-Five, commissioned by Google, examined the mobile sites of 37 brands and reported that a 0.1 s improvement in mobile speed went with an 8.4% rise in conversions for retail and 10.1% for travel. It should be quoted with its nature attached: it is observational, so faster sites may also be better in other ways, and it was commissioned by a company with an interest in a faster web. That does not make it false. It makes it a reason to test, and the Vodafone result shows what a test can establish.
The reasoning that carries over to Encore is modest and firm. Speed has been shown, in at least one controlled experiment, to move sales, and the size of the effect varies with the starting point, the page and the audience. So Encore treats speed as a feature to be designed and measured like any other, uses Chapter 4’s experimentation platform where a change is large enough to test, and does not promise anyone a revenue figure from a percentage borrowed from someone else’s site.
Latency, radios and the car park
Grigorik’s central argument is the one most engineers still find counterintuitive: for most page loads, latency matters more than bandwidth. Beyond a few megabits per second, more bandwidth barely shortens a page load, because a page is assembled from many small requests, and each is bounded by the time a round trip takes, which no faster connection reduces. Mobile networks add a second effect. A phone’s radio goes idle to save battery, and a radio that has gone idle must be woken and granted resources before the first byte moves, so the first request after a pause pays a cost the next one does not. The remedies follow from the diagnosis: make fewer round trips, reuse connections, put content closer to the user through the content delivery network (CDN), and cache whatever can be cached. Grigorik’s book predates HTTP/3, which runs over QUIC (standardized in 2021 and 2022) and removes some of the head-of-line blocking that slowed lossy mobile connections, but the principle it serves is the same.
Encore’s design target is the fan the Architecture book’s Chapter 8
began with: on a phone, in a stadium car park, on a congested mobile network. That fan matters most on the resale page, because a resale page is opened in exactly the circumstances where networks are worst, outside a sold-out venue an hour before doors, or in the minute after an on-sale sells out, when every fan who missed out reaches for their phone at once.
The field is the truth
Real-user monitoring (RUM) is the collection of performance measurements from users’ own browsers as they use the product, reported in aggregate. The Architecture book drew the line between lab and field. At 40 teams, the field data is useful only once it is segmented. A single p75 for the whole site hides the fan in Sofia on a three-year-old phone behind the fan in Amsterdam on a new one, so Encore reports its Core Web Vitals at p75, the 75th percentile, on phones by country, by device class and by route. Interaction to next paint (INP), which replaced first input delay as a Core Web Vital on 12 March 2024, turns out to matter most on the organizer console, a sovereign tool in the sense of Section 6.2, where an organizer types and clicks all day and notices every sluggish response. On the fan side, LCP on the event and seat-map routes matters most.
The resale page is measured separately from the rest of the storefront. Its traffic arrives in spikes, after sell-outs, on worse networks than average, and from fans who are more likely to be on the page for the first time. Blended into the storefront’s figures, a bad resale experience would disappear inside a good average.
Budgets that someone owns
A performance budget is a limit on a measurable property of a page, such as its JavaScript weight or its LCP, enforced in the build. The Architecture book introduced Encore’s checkout budget, 150 KB of compressed JavaScript with LCP no worse than 2 s in the lab on a mid-tier phone, and it explained how budgets stop a page from getting slower one dependency at a time. What changes at 40 teams is the question of who owns each budget. A budget that belongs to everyone is a red build that someone eventually learns to ignore. That is an observation from practice, without a study behind it, but few teams who have lived with an unowned budget would dispute it. Encore assigns every budget to one team, as Figure 7.6 shows (JS in the figure is JavaScript).
| Budget | Owner | Lab gate (CI) | Field target, p75 on phones |
|---|---|---|---|
| Storefront shell and shared code | Web Storefront | 90 KB compressed JS | — |
| Checkout route | Checkout | 150 KB JS; LCP ≤ 2 s, mid-tier phone | LCP ≤ 2.5 s; INP ≤ 200 ms |
| Resale route | Resale | 120 KB JS; LCP ≤ 2 s, mid-tier phone | LCP ≤ 2.0 s; INP ≤ 200 ms |
| Console shell | Organizer Console | 110 KB JS | — |
| Each console remote | The remote’s team | 80 KB JS per remote, beyond shared singletons | INP ≤ 200 ms |
| Third-party scripts | Web Storefront (inventory); requesting team (each script) | Each script listed with a cost | — |
Figure 7.6 — Encore’s frontend budgets and their owners. Each row has one team; the resale route’s field target is tighter than Google’s threshold because its users arrive on the worst networks.
When a field metric regresses, the owning team is told the same day by the RUM dashboards, and Encore’s policy is that every regression has a named owner within a working day, even if the fix takes longer. The alerting itself is part of observability, which the Operations book
covers; what this chapter adds is that every alert names an owning team.
The last row of the figure covers the most common cause of regressions that no team’s code review sees. Analytics tags, marketing pixels, chat widgets and payment-provider scripts are added through a tag manager, often by people outside engineering, and each adds weight and main-thread work to every page it touches. Encore keeps an inventory of every third-party script: who asked for it, which pages it runs on, what it costs in kilobytes and in main-thread time, and when it was last reviewed. A script with no owner is removed. Checkout and the resale route admit no third-party script except the payment provider’s, which is the strictest form of the rule and the one where it matters most.
Peak pages
Some pages see their year’s traffic in an hour. For Encore these are the event page at an on-sale, and now the resale page for an event in the minutes after it sells out. A peak page is a page whose demand arrives as a sudden spike, so that its performance on the worst minute matters more than its average. Before launch, the Web Storefront team and the owning team review each peak page with three questions. Can the page be static, or mostly static? The resale page’s frame, event details and seat-map geometry are rendered ahead of time and served from the CDN, and only the listings themselves are fetched live. Can its next step be fetched before the fan asks? When a fan’s pointer rests on a listing, or a listing scrolls into view, its detail is prefetched; the newer Speculation Rules interface, which can prerender whole pages, works only in Chromium-based browsers, so Encore treats it as an enhancement. And what can be removed? On the resale route the answer was every third-party script, a promotional carousel and a web font that was used for one heading.
The review covers what the fan’s device has to do. The capacity behind the page, the services that must answer when a hundred thousand fans open it in the same minute, is a capacity question, and it belongs to the Resilience book’s Chapter 2
.
Recap. One controlled experiment and one widely cited correlation together justify treating speed as a feature, and they should be read for what each is. Latency, more than bandwidth, bounds most page loads, especially on mobile radios. Field data at p75, segmented by country, device and route, is the truth, and every budget needs one owning team, including the budget for scripts that no team wrote. Peak pages get a review: static where possible, prefetched on intent and stripped of everything they do not need.
Exercise 7.4. Pull your product’s p75 LCP and INP on phones for your slowest country. Find the largest single contributor to each, and name the team that owns it.
7.5 Internationalization
Separate the dimensions
On 18 November 1883 the railroads of the United States and Canada stopped keeping the local solar time of each town and adopted a handful of standard time zones. Before that, a railway timetable had to reconcile dozens of local times, and a traveler changing trains had to know which town’s clock a departure was listed in. The railroads’ solution was to separate two things that had always been fused: where you are and what time it is there. Internationalization requires the same kind of separation, applied to several things at once. Internationalization is the engineering of a product so that it can be adapted to many languages, regions and conventions without changes to its code; localization is the adaptation itself, for one particular market.
The dimensions are easy to fuse by accident, because in the developer’s own country they usually coincide. Language and region are identified together by a BCP 47 language tag, the Internet’s standard for naming languages (RFC 5646, 2009): fr-FR is French as written in France, fr-BE French in Belgium, nl-BE Dutch in Belgium. The tag carries language, script and region. Currency and time zone are not part of the basic tag. The Unicode standards define extensions that can carry them, but most products, Encore among them, store them as separate settings, and number and date formats follow from the locale unless the user overrides them. Figure 7.7 takes one Verified Resale purchase apart along these lines.
| Dimension | Whose setting | Source of truth | One resale purchase |
|---|---|---|---|
| Language | The fan’s | Fan profile, else browser, with fallback | Finnish (fi) |
| Region and formats | The fan’s | BCP 47 tag fi-FI, via the Common Locale Data Repository (CLDR) |
“66,00 €”; dates as “12. kesäkuuta 2026” |
| Currency | The event’s | Event setup; ISO 4217 code | EUR, two minor units |
| Time zone for the show | The venue’s | Venue record; IANA time zone name | Europe/Lisbon: doors 19:00 |
| Legal display rules | The market of sale | Market configuration, owned with legal | All-in price shown first; resale fee itemized |
Figure 7.7 — One fan in Helsinki buying a resale ticket for a show in Lisbon. Five settings, owned by four different parties, combine on one screen.
Each row has a different owner, which is the point of separating them. A fan in Helsinki chooses Finnish; the organizer’s event is priced in euros; the venue is in Lisbon. The fan’s language and number formats follow the fan, while the show’s time follows the venue. Encore applies one subtle rule here. The time of the show is displayed in the venue’s zone, with the zone named, because the fan will be standing in Lisbon when it matters. The time an on-sale opens is displayed in the fan’s own zone, because the fan will be at a keyboard at home. A fan in Helsinki sees doors at “19:00 Lisbon time” and an on-sale at “11:00” Helsinki time for a sale that opens at 10:00 Central European Time.
Three practical matters complete the foundation. Locale negotiation needs a fallback chain: when a fan asks for a locale Encore does not support, it falls back by stages, from fr-LU to fr and only then to the default, in the manner the matching standard (RFC 4647) describes, so that a French speaker in Luxembourg still reads French. Text is UTF-8 everywhere, from the database to the email, so that a Polish ł or a Greek σ survives every hop; Unicode, first published in 1991, is what made that possible. And fonts must cover every script a product displays, which for Encore means Latin, Greek and Cyrillic for Bulgarian, each subset so that a fan downloads only the characters their language needs. Encore’s storefront today is available in 18 languages.
Messages and plurals
The first rule of internationalized code is that no user-visible text lives in the code. Every string is externalized into a message catalog under a stable key, and translators work on the catalog. The second rule is that strings are never built by concatenation. “You have “ plus a number plus “ tickets” works in English and fails in nearly every other language, because word order, agreement and plural forms differ, and a translator given three fragments cannot reorder them.
The established answer is the ICU MessageFormat, the message syntax of the International Components for Unicode (ICU) libraries, which has run in ICU, Java, Android and most JavaScript internationalization libraries for decades. A message is a complete sentence with placeholders and selectors for plurals, grammatical gender and other choices, and the plural categories come from CLDR, which records for each language which forms its plurals take. English needs two categories, one and other. Polish needs four: one, few, many and other. Arabic needs six: zero, one, two, few, many and other. The source message and its Polish translation show why the selector belongs in the message itself.
# en
resale.listings.count = {count, plural,
one {# resale ticket at face value}
other {# resale tickets at face value}}
# pl
resale.listings.count = {count, plural,
one {# bilet z odsprzedaży w cenie nominalnej}
few {# bilety z odsprzedaży w cenie nominalnej}
many {# biletów z odsprzedaży w cenie nominalnej}
other {# biletu z odsprzedaży w cenie nominalnej}}
The English source has two branches; the Polish translator adds two more without any change to the code that calls it. That is the property to insist on: a language’s grammar is the translator’s to express, and the code supplies only the count. Mozilla’s Fluent, whose version 1.0 was announced in 2019, was designed around the same principle, which its authors called asymmetric localization: each language adds whatever grammatical logic it needs, without the source language or the code having to anticipate it.
The format’s successor deserves a careful sentence. MessageFormat 2.0 became a stable Unicode specification in CLDR 47, in March 2025, as part of the Locale Data Markup Language standard. Its implementations are still maturing: ICU’s Java implementation has a core interface at draft status, its C++ implementation remains a technology preview, a JavaScript library implements the specification, and the proposal to build it into browsers as Intl.MessageFormat is at Stage 1 in TC39, the committee that evolves JavaScript. So the specification is stable, and using it in browsers in production still means shipping a library. Encore uses ICU MessageFormat today and has written its new messages so that they convert mechanically when the time comes.
Formatting from data
Dates, times, numbers and currencies are never formatted by hand. In browsers they go through the ECMAScript Internationalization API (ECMA-402, the Intl objects), and on servers through ICU, both of which draw on CLDR’s data for each locale. The currency’s minor units come from ISO 4217, which is how a formatter knows that euros have two decimal places while Japanese yen have none and Kuwaiti dinars three. Times are computed in the IANA Time Zone Database’s named zones, which record every change to every region’s clocks, including the daylight-saving changes that a fixed offset gets wrong twice a year.
The resale price shows why this matters even in a single currency. A €60 ticket resold at face value costs the buyer €66, the face value plus the 10% buyer fee. The Resale service computes those amounts in the event’s currency, as integer minor units, and the storefront formats them for the fan’s locale. The same 66 euros appears as “66,00 €” in French, German and Finnish, as “€66.00” in Irish English and as “€ 66,00” in Dutch, and the French form puts a no-break space before the symbol, so that the amount and the symbol never fall on separate lines, a detail that a hand-written format reliably forgets. Each form is correct for its readers, and only a formatter driven by locale data produces all of them.
Direction and layout
Arabic and Hebrew are written from right to left, and an interface for them mirrors its layout: navigation moves to the right, progress runs leftward, and icons whose meaning depends on direction, such as a “back” arrow, are flipped, while icons that depict real objects, such as a clock or a ticket, are not. The Unicode Bidirectional Algorithm (UAX #9) governs how text of mixed direction is displayed, and the W3C’s internationalization guidance explains how to mark it up. The modern technique that makes mirroring cheap is the use of CSS logical properties. They describe space by the start and end of a line, which is left and right in French and right and left in Arabic, so that one stylesheet serves both directions.
Encore sells only in the EU, and none of its 18 languages is written from right to left. Setlist uses logical properties throughout anyway, for two reasons. The first is cost: written in from the start they cost nothing, and retrofitted they mean revisiting every component. The second is that mixed-direction text appears even in a product with no right-to-left language. An artist’s name in Arabic script, or a venue’s name in Hebrew, set inside a French sentence can reorder the punctuation and numbers around it in ways that confuse a reader. Setlist’s text components isolate user- and organizer-supplied names with the HTML bdi element and dir="auto", so that a name’s direction cannot disturb the sentence it sits in. Such a decision belongs in the design system, because made there once it protects every screen that displays a name.
The translation pipeline
Continuous localization is the practice of translating a product string by string, as it is built. At Encore, every merged change that adds or edits a message has its new strings extracted by CI and sent to the translation platform, together with a screenshot of the screen where the string appears, because a translator who sees “Hold” without context cannot know whether it is a verb or a noun. The platform keeps a translation memory, so that a sentence translated once is offered again wherever it recurs, and a glossary, so that “face value” and “reissue” are translated the same way on every screen. Product copy is translated by machine and reviewed by a human translator before release, which is now common practice. Legal text, terms of sale and anything that states a price or a fee are translated by people, because a mistranslated fee is a compliance failure.
The cheapest test in internationalization is pseudo-localization: an automatic transformation of the source language into a readable but altered form, with accented characters, text lengthened by a third or more, and brackets marking the start and end of each string. Microsoft ships pseudo-locales in Windows, and the technique is long established. Run in development, it reveals at a glance every string that was hard-coded (it appears without accents), every label that was concatenated (the brackets break in the middle), and every button whose text will be truncated in German or Finnish. Encore’s developers can switch any environment to a pseudo-locale, and the visual regression tests of Section 7.2 run Setlist’s components in it.
Prices the law can read
In the EU, how a price is displayed is a legal matter, and an internationalized price display is therefore a compliance surface. The obligation to show the total price, including taxes and all unavoidable charges, comes from three instruments: the Consumer Rights Directive (2011/83/EU), for contracts at a distance and otherwise; the Unfair Commercial Practices Directive (2005/29/EC), which requires an invitation to purchase to state the total price; and the Price Indication Directive (98/6/EC). The Omnibus Directive (EU) 2019/2161, applicable from 28 May 2022, added rules that matter to Encore in other ways. It blacklisted the resale of event tickets acquired by automated means that get around purchase limits, which is the practice Bot Screening exists to stop, and it required disclosure of personalized pricing, which Encore does not use. Section 5.2 sets out Encore’s fee policy and the reasoning behind all-in pricing; this section is about rendering it.
For Verified Resale this means that the first price a fan sees for a listing is the total, €66 in our example, with the face value and the fee itemized beneath it by PriceBreakdown, formatted for the fan’s locale and translated by people. National law adds conditions. Where Ireland’s Sale of Tickets Act 2021 caps the buyer’s total at face value for designated events, the fee comes out of the seller’s proceeds and the breakdown shows it so. Some rules are temporary. When Bulgaria adopted the euro on 1 January 2026, its law required prices to be shown in both lev and euro until 8 August 2026. Rules of this kind are why Encore keeps each market’s display rules as configuration owned with the legal team, and why the formatter, not the page, applies them.
Recap. Internationalization begins by separating dimensions that coincide at home: language and region in a BCP 47 tag, currency with the event, time zone with the venue, and legal display with the market. Messages are complete sentences with plural selectors driven by CLDR, and MessageFormat 2.0 is a stable specification whose runtimes are still maturing. Formatting comes from data, bidirectional text is isolated in the design system, translation runs continuously with pseudo-localization as the first test, and the all-in price is rendered as the law of each market requires.
Exercise 7.5. Pseudo-localize one screen of your product and count what breaks: truncated labels, concatenated strings and hard-coded formats. For each break, find the line of code responsible and say which of the five dimensions of Figure 7.7 it fused.
Kata: The Departures Board
Your brief: “Wayfare.” Wayfare is a travel-booking marketplace that sells rail, ferry and coach tickets and short-stay rooms from about 3,000 operators across Europe, the Middle East and North Africa. Its web product is built by 25 frontend teams. Five years ago it built a design system, and adoption has been stuck at about 40% for two years; the core team of four answers requests in a queue that is three months deep, and the three largest teams maintain their own component libraries. The product runs in 32 locales, including Arabic and Hebrew, and prices in 14 currencies. Its operator console was split into nine federated remotes last year; its consumer site is a single application. Two pages carry its peaks: search results during the January sale, when traffic rises 20× for three days, and the seat-and-cabin selection page when a popular overnight ferry opens bookings. Field data shows p75 LCP on phones above 4 s on both pages in four markets. Wayfare’s legal team has just reported that two markets display fees only at the last step of checkout.
Deliverables:
- Governance model — Choose a team model from Figure 7.3 and justify it from Wayfare’s numbers. Define the contribution path, including what a pattern candidate is and the criteria for promotion, and say what the core team stops doing to make room for review.
- Migration plan — Plan the move of the three private component libraries onto the design system: the order, the codemods each step needs, the deprecation windows, and the version dashboard that will show progress. State the adoption figure you expect after two quarters, and how you will measure it.
- Peak-page budgets — For the search-results and seat-and-cabin pages, set a lab budget and a p75 field target on phones, name the owning team for each, and list what a pre-peak performance review would remove, prerender or prefetch. Keep capacity out of scope.
- Federation hygiene — Write the operator console’s list of shared singleton dependencies, with version ranges, and the rule for who decides when each one moves.
- Internationalization audit — Apply the five dimensions of Figure 7.7 to one booking: a traveler reading Arabic, booking a ferry priced in euros between two ports in different time zones. Identify where Wayfare’s code fuses dimensions, how its messages handle Arabic’s six plural categories, how bidirectional text is isolated, and how the all-in price will be displayed in the two non-compliant markets.
Rubric:
| Criterion | The question to ask yourself |
|---|---|
| Adoption as evidence | Does the plan start from why the three largest teams left, and would they recognize their reasons in it? |
| Migration realism | Does every breaking change ship with a codemod, and does the dashboard show what remains? |
| Owned budgets | Does every budget have exactly one owning team, including the third-party scripts on both peak pages? |
| Skew control | Is the singleton list short enough that the console’s teams can keep it, and long enough that the page works? |
| Locale separation | Could a new currency, time zone or right-to-left language be added as data, without changing code? |
| Lawful display | Would a fan in every one of the 32 locales see the total price first? |
Where you now stand
You can now treat a design system as what the 1970 manual turned out to be: a set of named decisions that is worth something only while an owner keeps the product on it. You can measure its adoption, govern it with a core and a contribution path, change it with codemods and a dashboard, and keep a federated frontend coherent with a short list of shared dependencies and a few checks. You can make performance a habit with owned budgets and field data, and you can build an interface that reads correctly in any language and displays prices as the law of each market requires. All of this assumed that a fix reaches every user at the next page load. Encore’s most important channel does not work that way. Its fans carry the app in their pockets, updated when they choose to update it, through stores whose review Encore does not control, and some of them will open a build next spring that was compiled three summers ago. Chapter 8 takes up software that cannot be recalled.
References
- Brad Frost — Atomic Design. Self-published, 2016 — free online.
- Alla Kholmatova — Design Systems: A Practical Guide to Creating Design Languages for Digital Products. Smashing Media, 2017.
- Paul Shaw — Helvetica and the New York City Subway System: The True (Maybe) Story. MIT Press, 2011.
- Design Tokens Community Group — Design Tokens Format Module 2025.10, with the Color and Resolver modules. W3C Community Group Final Report, 2025 — free online.
- Nathan Curtis — Team Models for Scaling a Design System. EightShapes, 2015 — free online.
- Luca Mezzalira — Building Micro-Frontends, 2nd ed. O’Reilly, 2025.
- Addy Osmani, Hassan Djirdeh — Building Large Scale Web Apps: A React Field Guide. Self-published, 2024.
- Ilya Grigorik — High Performance Browser Networking. O’Reilly, 2013 — free online.
- Google — Vodafone: A 31% improvement in LCP increased sales by 8%. web.dev, 2021 — free online.
- Deloitte Digital, Fifty-Five, for Google — Milliseconds Make Millions. 2020 — free online.
- Ravi Lingineni — How Pinterest’s design systems team measures adoption. Figma blog, 2023 — free online.
- Unicode Consortium — UTS #35: Unicode Locale Data Markup Language, Part 9: Message Format. Unicode, 2025 — free online.
- Unicode Consortium — UAX #9: Unicode Bidirectional Algorithm and Unicode CLDR. Unicode, continuously updated — free online.
- A. Phillips, M. Davis (eds.) — BCP 47: Tags for Identifying Languages (RFC 5646 and RFC 4647). IETF, 2006–2009 — free online.
- Adam Wathan, Steve Schoger — Refactoring UI. Self-published, 2018.
- European Union — Directive 2011/83/EU on consumer rights and Directive (EU) 2019/2161. Official Journal of the EU, 2011 and 2019 — free online.