Feature Facades: Keeping Page Components Thin In short: Move state, loading, errors, and actions into one injectable per feature. The page component becomes a template plus one injected dependency, and your business logic becomes testable without rendering anything. Adapters solved mapping. But a real screen also loads data, shows a spinner, handles failures, and sends actions back to the server. Put all of that in the page component and you get a file nobody wants to open. The god component Nothing here is wrong in isolation. The problem is that a component whose job is rendering is now also the state store, the network layer, and the error policy. Three consequences: Testing needs the DOM. To test whether approving reloads the list, you must create a component, compile a template, and mock the HTTP layer. Nothing is reusable. A tablet-optimised version of this screen re-implements all of it. The signals are , so they are reachable only from this template — meaning a sibling component that needs the same data cannot have it. The facade Move everything that is not rendering into one injectable. Two things carried forward from earlier chapters: One discriminated union instead of three booleans — Chapter 3's rule. The facade cannot be loading and errored at once. outward, writes only through named methods — Chapter 2's rule. When a value is wrong, there are two places it could have been set. The page component One line of logic. That is the whole component. and are the pieces the previous lesson added deliberately — an opaque id on the presentation model and an output on the card. Without them this binding would not exist, which is why they were designed in. Testing without a DOM The point of the whole exercise: No component, no template compilation, no fixture. Just a class and a fake API. Scope it to the feature with no , provided on the component or the route: This is Chapter 1's question applied: when this thing goes away, should its data go away too? A dashboard's in-flight deliveries and error message should not survive navigating to billing and back — you want a fresh load, not a stale list. Route-level providers also let sibling components share one facade instance, which is how a header showing an active count and a grid showing the rows stay in step. Use (root scope) only for state that is genuinely app-wide — the signed-in supervisor, the price table. When you do not need one A facade is worth it when a screen has state, loading, errors, and actions. It is overhead when it has one of those. A component that renders a route parameter and nothing else does not need a facade. Chapter 2's Rule of Three applies: add the layer when the complexity has actually arrived. "But I thought a facade was just an extra file for the same code" The line count barely changes, so this is a reasonable read. Moving code from a component into a service next to it can look like relocation rather than improvement. The difference is what the code becomes reachable by . Logic inside a component is reachable only through that component. To exercise it you must instantiate the component, which means compiling a template, which means providing every child component, which means mocking whatever they inject. Your test of "does approving reload the list?" — a question with nothing to do with rendering — now depends on the DOM. Three things change once it moves out: Tests stop needing the DOM. The examples above run in milliseconds and do not break when the template changes. That last part matters more than the speed: a test that breaks when you restyle a card was never testing the logic. A second view becomes possible. A tablet-optimised dispatch screen injects the same facade and writes different markup. Business logic shared, presentation not. Without the split, the tablet version reimplements loading and error policy — and the two drift. The state has a single owner with a name. "Where does the delivery list live?" has one answer. Scattered across components, it has several, and they disagree. Logic in the component Logic in a facade --- --- --- Test needs + template Yes No Test breaks when the markup changes Yes No Second view of the same data Reimplement Inject the same facade Where the state lives Wherever it accumulated One named class Page component length 80–150 lines 8 Files 1 2 One file, in exchange for the top four rows. The caveat from the previous section still stands: this is a real trade, and for a genuinely simple screen the extra file is not worth it. The signal to add one is a page component that has grown a that fetches, more than one boolean about loading, or a second screen that wants the same data. Cheat sheet Do Don't --- --- provided on the component or route for feature state One discriminated union for load state + + outward, named methods for writes Public writable signals Facade returns presentation models, not DTOs Leak DTOs into the template Page component = template + one A constructor that fetches…