I rarely parrot blogs here but sometimes I find a post I don’t want to lose track of. Robert Martin (Uncle Bob), one of my favorites, just posted The Domain Discontinuity which asks the question: Which came first, the chicken or the road?
Two quick pull quotes.
The first has to do with the appropriate scope of TDD. Why do I include this? Because I am not a TDD fanatic. By fanatic, I mean those developers who would disagree with Uncle Bob here, even going so far as to make private and protected methods public just so their tests can access them.
“Let me stress this more. I do not create a test for every method or every class. I create tests that define behaviors, and then I create the methods and classes that implement those behaviors.
“At the start, when there are just a few tests, I might have only one simple method. But as more and more tests are added, that one simple method grows into something too large. So I extract functions and classes from it -- without changing the tests. I generally wind up with a few public methods that are called by my tests, and a large number of private methods and private classes that those public methods call; and that the tests are utterly ignorant of.
“By the way, this is an essential part of good test design. We don't want the tests coupled to the code; and so we restrict the tests to operate through a small set of public methods.”
The second pull quote is a small set of architectural principles that I completely agree with:
- Refactoring across architectural boundaries is costly.
- Behaviors extracted across architectural boundaries need newly rewritten tests.
- Architecture is an up-front activity.
“The solution to that problem is to know in advance where you are going to put certain behaviors. You need to know, in advance, that there will be a boundary between the GUI, the business rules, and the database. You have to know, in advance, that the features of your system have to be broken up into those areas. In short, before you write your first test, you have to ‘dream up the [boundaries] that you wish you had’.”
I sometimes come across systems that are woefully inadequate to the task, extremely difficult to refactor, and have few, if any, tests that do not require integration across boundaries that are often, if not almost impossible, to mock or fake. Virtually all of these problems are attributable to the false notion that Agile means you rush to coding and skip up-front architectural analysis and design.
Thanks, Uncle Bob!