Once the code conventions exist, something has to keep them true as dozens of people commit every week. That is the job of the next two pillars. Process covers the path from an idea to deployed code: how stories are written, where builds happen, how components are packaged. Testing covers the safety net: unit tests for logic, performance budgets for speed, and visual regression tests for the look of every component.

These are the chapters where the tool names have aged the most. Grunt configs, Travis CI, PhantomJS and CasperJS fill many pages. I read them for the reasoning and the workflow decisions, and mentally swap in current tools as I go. The schema-driven idea in chapter 10 is the one I would point people to first; it is still underused.

Chapters 8 to 14 in the book.

Key ideas

Write stories against the system, not the page

Chapter 8 contrasts the old waterfall hand-off (requirements, wireframes, static comps, then frontend paints over finished backend markup) with a workflow where UX, design, backend and frontend gather requirements together and iterate on an in-browser prototype. Only an accepted prototype moves into development, because prototypes are cheap to change and production code is not. If the prototype and the product share CSS and JS, QA can compare the result against the prototype instead of an old spec.

The part I return to most is the advice on ticket writing. A ticket like "update the pricing page" bundles global and local changes, leaves it unclear whether a shared component should change everywhere, and invites two people to edit the same component for different pages. Godbolt's alternative is a story that names a change to the system: create a variation, opt in, then update the page in a separate story. Even then, he shows that a single small variation can be coded several ways (a new class, a mixin, a modifier class, a data attribute), which is why the code pillar's written conventions must exist before the workflow can be smooth.

Weak:   Update the pricing page (bigger button, new heading colour, tighter cards)
Better: Add a "large" size to Button, opt-in only, default unchanged
        Add a "compact" density to PlanCard, opt-in only
        Use Button size=large and PlanCard density=compact on /pricing

Build artefacts in CI, ship them as versioned packages

The book walks through the onboarding path (provisioning, a one-command local setup documented in the README, feature branches, pull requests with review) and then the question of compiled assets. Committing generated CSS means every merge conflicts on output files, and production ends up with whatever the last developer's machine produced. Letting a CI server compile from source gives identical builds every time. For code that many sites consume, Godbolt recommends publishing through a package manager, because consumers get versioned releases, can choose when to upgrade, and only receive the files they need.

Chapter 9 then makes the bigger point about task runners. Compiling, linting, generating icons, running tests, building the style guide and deploying all become scripted steps, and automation is how the architect enforces the process rather than only describing it. The Grunt versus Gulp comparison ends without a winner: pick whichever lets developers get started quickly and ship safely.

The schema as the component contract

Chapter 10 is the most original idea in this part. Red Hat's frontend team worked sprints ahead of the backend, but prototypes and CMS templates kept drifting apart. Godbolt calls this the "last mile" problem: CSS and JS were shared, yet the HTML was written twice, once in the prototype and once in the CMS. They fixed it by rendering the same Twig templates in the prototype and in Drupal, which turned the design system into what he calls a design system API, or theme as a service: platforms send data and get identical markup back. Each component then shipped as a standard bundle: schema, template, styles, visual tests, test data, documentation and documentation data.

The schema is the file everything else derives from, which is why Godbolt calls the approach schema-driven, by analogy with test-driven development. Writing it first forces the design questions that comps leave open: what is required, what is optional, which values are allowed, what happens when there are two items instead of three. The same schema then validates data, hints at the editor UI, and tells the template author every branch they must handle. Here is my own example for a testimonial component, using the current 2020-12 draft:

{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "$id": "https://design.example.com/schemas/testimonial.json",
  "title": "Testimonial",
  "type": "object",
  "required": ["quote", "layout"],
  "properties": {
    "quote": { "type": "string", "minLength": 20, "maxLength": 280 },
    "author": { "type": "string" },
    "role": { "type": "string" },
    "layout": { "enum": ["stacked", "inline"] },
    "avatar": {
      "type": "object",
      "required": ["src", "alt"],
      "properties": {
        "src": { "type": "string", "format": "uri" },
        "alt": { "type": "string" }
      }
    }
  },
  "additionalProperties": false
}

The trade-off is verbosity and a second source of type information next to your TypeScript props. In a React codebase today, I would generate one from the other (for example, define the schema with a library like Zod or TypeBox and derive the TypeScript type), so there is still one source of truth.

Unit tests: small units and budgeted time

Chapter 11 frames unit tests as the foundation every later change rests on. The advice is the classic one: a function that looks up, measures and prices in one go should be three functions, each reusable and each easy to test. Test-driven development writes the failing tests first and then makes them pass.

What I value more is the practical guidance on coverage. On an existing project, start with tests that are easy and still useful to build momentum, then target the most critical or most bug-prone areas. On a new project, the architect makes sure every story carries time for tests; Red Hat added roughly a quarter on top of the development estimate, and only removed test tasks when everyone agreed. A small current example with Vitest, in a different domain from the book's:

import { describe, expect, it } from "vitest";

export function columnsForWidth(widthPx: number): 1 | 2 | 3 | 4 {
  if (widthPx < 480) return 1;
  if (widthPx < 768) return 2;
  if (widthPx < 1200) return 3;
  return 4;
}

describe("columnsForWidth", () => {
  it.each([
    [320, 1],
    [480, 2],
    [767, 2],
    [1199, 3],
    [1440, 4],
  ])("width %i gives %i columns", (width, expected) => {
    expect(columnsForWidth(width)).toBe(expected);
  });
});

Performance budgets with teeth

Chapter 12 treats performance as a test like any other: set targets, check them before every merge or deploy, and when a feature breaks the budget, either fix it or remove something else. Two ways to set the numbers are offered. One is to beat key competitors by around 20 percent, the gap the book says users can notice. The other is to beat industry averages from HTTP Archive. The metrics fall into three groups: raw (page weight, request count), timing (time to first byte, start render, document complete) and hybrid scores (PageSpeed score, Speed Index). The automation shown is Grunt plugins wrapping PageSpeed and WebPageTest.

The budget idea is the keeper. Several specifics are dated, and I cover them below.

Visual regression: a gold image for every state

Chapter 13 explains why visual bugs keep coming back: another developer's unrelated change leaks into your component, designers compare against different versions of a mockup, and change requests arrive disguised as defects. Visual regression testing answers all three by storing approved screenshots and comparing every new build against them. The book sorts tools by approach: whole-page diffing, component-level diffing, CSS assertion tests, headless versus real browsers, scripting for interactions, and approval through a web UI or the command line.

Chapter 14 shows Red Hat's setup and, more usefully, their conventions. Tests targeted components in the style guide rather than the live site, because it shared CSS and stayed stable. Every component folder held its own tests and baseline images, so a pull request that changed a component also carried its new baselines. Suites ran per component, so a failure pointed at one place. And a failure in a component you did not touch is the signal: either your change was too global, or the two components should share a style and the designer needs to confirm it.

Reading it in 2026

  • Task runners. Grunt and Gulp are still around, but a common setup now is package scripts, a bundler such as Vite for compilation and dev server, and a monorepo runner such as Turborepo to order tasks and cache their outputs. The point stands; only the layer moved.
  • CI and distribution. GitHub Actions and similar services fill the Jenkins and Travis role. Compiled assets stay out of git, and design systems ship as versioned npm packages, often from a monorepo with workspaces. Changesets-style release notes help consumers decide when to upgrade.
  • Unit tests. QUnit and NodeUnit gave way to Vitest and Jest for most frontend teams. Vitest 4, released in October 2025, made its Browser Mode stable, so component tests can run in a real browser.
  • Performance. Time to first byte still matters, but the metrics teams report against are now Core Web Vitals. Interaction to Next Paint replaced First Input Delay as a Core Web Vital in March 2024. Lighthouse CI or bundle size checks in CI play the role of the Grunt plugins.
  • Visual regression. PhantomJS development was suspended in 2018 and the repository is archived, so PhantomCSS and CasperJS are not options for new work. Playwright has built-in screenshot assertions with toHaveScreenshot, Vitest 4 added toMatchScreenshot, and hosted services such as Chromatic or Percy add the approval UI the book describes. Running visual tests against Storybook stories is the modern version of testing against the style guide.
  • Schemas. JSON Schema is still the right contract, now at draft 2020-12. Headless CMSs and block editors rely on structured content models, so the idea of deriving editor fields from a component schema is more practical now than in 2016.

Putting it to work

  1. Rewrite your next three page-level tickets as component changes plus one page-composition ticket.
  2. Make the README setup a single command, and treat any extra step a new hire needs as a bug.
  3. Keep build output out of git. Build in CI, and publish the design system as a versioned package with a changelog.
  4. Give every component a schema or typed contract before its template, and list the allowed variants explicitly.
  5. Add estimates for tests to every story by default; remove them only by explicit agreement.
  6. Set a budget per key route (for example, LCP, INP and JavaScript size) and fail CI when it is exceeded.
  7. Store visual baselines next to each component and run visual tests per component on every pull request.

Check yourself

  1. Why should the prototype share CSS and JS with production? So development only wires data into already-approved markup, and QA can compare the product against the prototype instead of a stale document.

  2. What two problems come from committing compiled assets? Constant merge conflicts in generated files, and production output that depends on whichever developer's machine compiled it last.

  3. Why does Godbolt call his approach schema-driven? Because the JSON schema is written first and every other deliverable (template, tests, docs, editor UI) follows from it, as tests do in TDD.

  4. How should a team react when a visual test fails in a component they did not touch? Either the change leaked too far and must be fixed, or the two components really should share the change and a designer must confirm it.

  5. Which tools replace PhantomCSS for new work? Screenshot assertions in Playwright or Vitest Browser Mode, often combined with a hosted review service and Storybook stories as targets.

Further reading