Mediator
An email input calls submit.disable() whenever the value changes, add a password field and email grows an if; add remember-me and every older handler grows another. Four fields, twelve edges of coupling, and every new one re-edits the rest.
- ▸Four fields each importing three others, twelve edges, and every new field forces edits in every old one.
- ▸Pull the rules out of the peers and into one rules table; each peer shrinks to
notify('changed')and stops growing. - ▸MVC's 'don't import a model from a view' rule isn't style, the controller IS the central object.
Open the dialog. Email field, password field, remember-me checkbox, submit button, four files, all in the same folder.
// EmailField.js import { submit } from './SubmitButton'; import { password } from './PasswordField'; import { rememberMe } from './RememberMe'; email.onInput = (val) => { email.value = val; if (isValid(val) && password.value && rememberMe.touched) { submit.enable(); } else { submit.disable(); } };
The other three peers carry near-copies of the same logic. Each one knows about all the others. Each one re-checks the same enable rule on every change. Add a phone-number field next sprint and the diff touches every existing file: each existing peer needs to import the new one and add a new clause to the if.
Count the edges. Four peers, three references each, twelve. Five peers becomes twenty. The shape is a clique: every box reaches every other box. The dependency graph fills in completely as the dialog grows.
The scaling problem is N(N−1). Each new field doesn't just add itself; it edits every other field. The cost of a new requirement isn't the rule it expresses, it's the cost of distributing that rule across every peer that needs to know.
A second symptom hides inside the first: the rule isn't readable in any one place. To answer "what makes submit enable?" you have to read all four peers' bodies and assemble the AND-clauses in your head.