The Architecture Decisions That Prevent Future Rework In short: A boundary that lives in a wiki page is a suggestion. A boundary that fails the build is a boundary. Three decisions turn everything in this chapter into something the machine enforces. Over the last four lessons we set the rules: pick the right tool, respect the three tiers, group by feature, split smart from presentational. Rules written down are not enough. Someone in a rush will inject a store into a presentational component. Someone will import a billing model into tanker intake, because the IDE offered it and the deadline was yesterday. Nobody is being careless — the path of least resistance simply points the wrong way. Architects change what the path of least resistance is. Here are the three decisions that do it. 1. Make boundaries fail the build If billing is not allowed to import from tanker intake, the compiler should say so. Whether you use an Nx workspace or plain Angular projects, this is dependency boundary linting . You tag each project with what it is, then declare what each tag may depend on. Tags carry two dimensions — the domain that owns it, and where it sits in the tiers: Then the rule, in flat config: Read the first constraint again: may only depend on and . That single line is the "zero business context" rule from lesson two, made real. The moment somebody imports into , the lint fails and the pull request goes red. Why this prevents rework: it makes circular dependencies and cross-domain coupling impossible rather than discouraged. When the billing team genuinely needs tanker data, the linter forces them to stop and move the shared piece into deliberately — which is the conversation you wanted to have anyway. If you are not on Nx, does the same job for a plain workspace using path patterns instead of tags. 2. Wrap third-party dependencies at the edge Enterprise applications outlive their dependencies. The icon library you pick this year will be unmaintained, renamed, or rewritten before the app is retired. If you import icons directly in 200 components, replacing that library is a 200-file change across every repository that uses your platform. If you import it in one, it is a one-file change. Consumers write . Two things follow. First, if you swap Lucide for raw SVG files next year, you change this file and nothing else. Second — and this is the part people miss — is a closed union . Nobody can pass an icon that does not exist, a designer can see the full inventory by reading one type, and the compiler catches typos. The wrapper bought you a real contract, not just insulation. The same pattern applies to date libraries, charting, analytics, and feature flags. Anything you did not write and cannot control. 3. Design for the change you know is coming The first two decisions are about containment. This one is about direction. You cannot predict every requirement. You can predict the categories of change that hit every long-lived UI platform, and leave a seam where each one will land: Change you can be sure of The seam that absorbs it --- --- Branding changes; a new tenant needs different colours Design tokens as CSS variables (Chapter 6) A second application needs the same components Presentation models and adapters (Chapter 7) The backend reshapes its API An adapter layer, not DTOs in components (Chapter 7) A component's internals need rewriting A small public API and private internals (Chapter 4) A shared input must be renamed Deprecation window plus a schematic (Chapter 9) Someone breaks a layout without noticing Visual regression in CI (Chapter 8) Notice that every row is a later chapter. That is deliberate: the rest of this course is the seams. The decision you are making now is simply to leave room for them. Concretely, that means resisting three tempting shortcuts: Do not hardcode colours in components. You will be asked to theme them. Do not put backend types in shared components. You will be asked to serve a second backend. Do not export everything from your library. You will be asked to change something you did not mean to promise. "But I thought code review would catch this" Code review is the most reasonable place to expect these problems to be caught. A senior developer reads the diff, spots the bad import, and asks for a change. It works — sometimes. Three things make it unreliable, and none of them are about reviewer skill. Boundary violations do not look like bugs. A wrong import is one line near the top of a file, in the block reviewers scroll past to reach the logic. inside a UI library is catastrophic architecturally and completely unremarkable visually. Compare that to an off-by-one error, which reviewers are actively hunting for. Review does not scale to the diff. In a 40-file pull request, attention goes to the files with the most change. The three-line file that quietly reaches across a domain boundary gets a glance. Review is inconsistent by design. Different reviewers, different days, different am…