"Hide/show is the first capability, not the root abstraction." — Tinker's house sign
The Easy Wrong Shape
When a tool has exactly one feature, the cheapest design is to let that feature be the tool. An app whose only job is hiding apps would naturally grow a HiddenApps store, a hideAll() engine and a settings screen full of app lists. It would work on day one. On the day a second action arrives — dimming the display, muting a meeting app, pausing a sync — every one of those names would be wrong, and the second feature would either be bolted on beside the first or force a rewrite of the engine underneath both.
Tinker was built the other way round from its first commit. The engine never mentions apps. It knows an open class called Capability: something with a stable type ID, a display name, a set of permissions it needs, and three verbs — prepare, apply, undo. The journal stores receipts for capability changes, not for hidden apps. Presets are lists of capability steps. Commands point at presets or at capability steps. HideApplications is a subclass that happens to be the only one so far.
Inheritance That Earns Its Keep
Dad reads the world through object orientation — not as a coding style but as the way things are organized. Tinker is a clean, small specimen of why that view pays. The root defines the contract every reversible action shares: you must describe a change before making it, make it one planned piece at a time, and be able to take each piece back. The child supplies the specifics: what its input looks like, which permission it needs, what "applied" means for an app and how to reverse it. The engine is polymorphic over children it has never heard of. That is inheritance used for what it is good at — sharing an obligation — rather than for sharing code.
What the Root Deliberately Does Not Know
Look at what is absent from the root: no notion of processes, windows, visibility, or even of the Mac's UI. The root does not know whether a change is cheap or risky, fast or slow. It only knows that a change has a key (so two changes to the same thing can be recognised as one), a serialisable payload (so it can be written to disk and read back after a crash), and a flag saying whether it actually needs applying. Everything else is the child's business. Abstraction here means refusing to know.
The Test of the Design
A good root is one where adding a child touches nothing else. In Tinker, registering a new capability automatically gives it an editable command in Settings and a slot on the app door — before anyone writes a line of UI for it — because commands and presets are data that refer to capability IDs. The final lesson of this quest designs that second child on paper and checks the claim.