Test-Induced Design Damage: Extract Just to Test?
While fixing a SQL injection in a legacy DAO, I parameterized the query and then wondered: should I pull the 4-line person_sn validation into its own method just so a unit test can pin it?
Extracting it forced a throw / catch pair whose only reason to exist was the test. That smell has a name.
The concept
David Heinemeier Hansson (DHH) coined test-induced design damage — “damage done to your code in the name of making it easier to test.” [1]
But it is not settled. A ThoughtWorks piece revisiting the idea concludes there is “no right or wrong answer — the answer depends on the context.” [2] And Robert C. Martin pushed back: decoupling a rule so it can be tested “enhanced changeability and made the business rules much clearer” — good design, not damage. [3]
Our case, both sides
Extract it (parsePersonSn):
- Gives the security rule a name (“
person_snmust be numeric”). - Pins that rule with a fast unit test, including the injection payload.
- Leaves
getLovSeta little cleaner.
Keep it inline:
- The validation is 4 trivial lines.
- It was already verified end-to-end by replaying the pentest payload against the running app (it returns
null). - The extraction existed only to serve the test, and dragged in exceptions-as-control-flow.
Decision
For a trivial, already-verified validation, we reverted to inline. Simpler wins; the security guarantee is covered by the live replay and integration tests, not by a unit test that bends the design to fit it. Were the rule complex or reused, extracting would earn its keep — context decides.
References
[1] Test-induced design damage — DHH. https://dhh.dk/2014/test-induced-design-damage.html
[2] Test-Induced Design Damage: Fallacy or Reality? — ThoughtWorks. https://www.thoughtworks.com/insights/blog/test-induced-design-damage-fallacy-or-reality
[3] Test Induced Design Damage? — Robert C. Martin. https://blog.cleancoder.com/uncle-bob/2014/05/01/Design-Damage.html