When DRY Code Should Be DAMP

Cody Tatman
Philosophie is Thinking
2 min readJun 16, 2015

--

DRY solves a specific problem: the duplication of knowledge in a system. This is great in application code, but can cause some headaches when applied in the same degree to automated test code.

As a developer, I’m not thinking about any of the tests that have accreted over the years until they break. When that happens I expect to find a handy roadmap to the failing test, which will hopefully explain what I broke and how to fix it.

Looking at the test code, the last thing I want to see is magic:

it 'foos the bar provided a bazzified widget' do
TestHelper.foo_barrer(bazzified_widget)
expect bazzified_widget.bar_was_foo?
end

On first reading, this test is totally opaque. What is this mystery guest “bazzified_widget” and what is “foo_barrer” doing to it? My problem could be anywhere, but it’s probably not here. Sigh. Time to dig into a testing context made ages ago by some random wacko (probably me).

Meanwhile, in a kinder alternate reality:

it 'foos the bar provided a bazzified widget' do
widget = Widget.new(state: :pre_bazzed)
widget.add_trinkets(Trinket.baz)
widget.state_machine.transition(:bazzed)
foo_enforcer = FooEnforcer.new(widget)
foo_enforcer.validate_bars(Trinket.baz)
foo_enforcer.enforce(logger: :test_logger)
expect widget.bar_was_foo?
end

Oh — there’s my problem. FooEnforcer’s logger option was removed this morning, and some schmuck forgot to update this ancillary test (probably me). Transparency is obviously very helpful in this use case.

I’ve heard this type of code described as DAMP: Descriptive And Meaningful Phrases. As you may have guessed, DAMP code suffers from all the obvious problems that we would ordinarily DRY away. These problems might be solvable with code generation (I haven’t tried), but the heart of the solution is to reevaluate our application of DRY — to favor transparency and clarity in our test code, refactoring away complexity only when it becomes significantly painful.

--

--