Be Evil

In the fourth “Is TDD Dead?” debate, DHH, Martin Fowler, and Kent Beck discuss the cost of tests. DHH points out that well written tests don’t have to change when you’re refactoring – but he finds that he spends far more time changing behavior, not refactoring code, which, of course, necessitates changes to the tests. He states:

“I want the system to do something else than what it’s currently doing. Sometimes that’s adding new behavior, but a lot of the time that’s also changing existing behavior. If I have to change four lines of test code for every line of production code, then there’s something not right there.”

DHH makes a great point. We all have to consider the cost of change. Lots of things could change in a system: the behaviors specified by the product owner, the database technologies dicatated by your IT departments, the user interfaces needed by your users, even the frameworks written by folks like DHH.

Let’s take the example DHH tossed out in the discussion: a change to an ActiveRecord data validation (e.g., validates :some_field, presence: true). He says that he sees people write a unit test for that declarative data validation, followed by a functional test, followed by a system test. So, what will it take to change that data validation?

If you’ve really written three different tests, at three different levels of the system, for that data validation, then all three of those tests will have to change – along with the validation declaration itself.

This is rigidity. Several things in your system have to stay in sync. Why? Because they all know the same secret: that :some_field is required.

When you change a behavior in your system, how many tests should have to change? One. Do you really need to test the same behavior again and again? No. In fact, in doing so, you’ve spread knowledge of that behavior around your system.

In the real world, we want to spread knowledge as far and wide as possible. As more people know and understand our world, we increase our power to change the world, and to understand the consequences of that change.

A software system is not like our world. Our ability to change a software system is inversely proportional to the spread of knowledge within that system. Like evil dictators, our power over our software system depends on the ignorance of the objects within that system.

One comment

Jeff Winkler says:

Code to Test Ratio is a blunt tool for knowing if tests are bloated..

Orthogonal point.. to obey Law of Demeter in tests, Sandy Metz’s Magic Tricks of Testing video is gold. Combined with the Bogus gem to support API-aware mocking. This means you only test the outgoing messages from the object under test. This avoids outbound method calls and testing for implementation side effects…each of which is another bungee cord hampering agility.