Card 06/ 08
Extension Points Nobody Uses
A plugin system for the one tax rule that has not changed in eight years.
The open/closed principle protects code against the kinds of change that have already happened, not against every change you can imagine. An extension point added where nothing varies is cost without benefit: another interface to read, another class to find, and a guess about the future frozen into the design. This card explains how to decide when one is worth adding.
The expectation is understandable. Once a type conditional has hurt you, every if looks like the next one. So a developer looking at a payroll system's tax rule, a single function that has not changed in eight years, proposes a plugin system: a TaxRule interface, a registry that discovers rules at start-up, and configuration to choose between them. There is one rule. There has only ever been one rule.
Every part of that proposal has a cost that is paid now. Readers must learn the registry to find the one function that matters. The interface fixes the rule's inputs, and if the second rule ever arrives, it may need inputs the first did not, so the interface is changed anyway, along with its one implementation. The flexibility bought in advance often turns out to bend in the wrong direction.
Martin's own advice is to close code against the changes you have seen. The first time a new case arrives, add it the simple way, even with a conditional. The second time a case of the same kind arrives, you know what varies and what stays the same, and you can design the extension point around real evidence. Some people call this the rule of three: tolerate repetition twice, abstract on the third occurrence.
This does not mean waiting until code is painful. Some places are known to vary from the start: payment methods, export formats, discount rules, anything where the business already talks about adding more. Those deserve an extension point early. The tax rule that has not moved in eight years does not, and if it ever does move, a function with one branch is a few minutes' work to turn into an interface.
← → move through sections and cards