The claim has been made that test driven development (TDD) encourages good design. The claim has also been made that TDD adversely affects architecture and design. It helps to get a little more concrete than just discussing abstractions, so we will focus on private methods and their relationships to good design and testability - an instance of this apparent conflict.
Szczepan Faber blogged that private methods are an anti-pattern:
Private method a smell seemed to be ignited with the birth of TDD. Test-infected people wanted to know how to test their private methods. Gee… it’s not easy so the question evolved from ‘how‘ into ‘why‘: Why to test private method? Most of TDDers would answer instantly: don’t do it. Yet again TDD changed the way we craft software and re-evaluated the private methods
Jay Fields blogged on a generic way to test private methods in ruby:
... I rarely test private methods. I prefer to test through the public API. However, there are times when life is easier if you write a few tests for a private method or two.
Michael Feathers suggested last year in The Deep Synergy Between Testability and Good Design that TDD encourages good design and, conversely, code that is not testable should make us think twice:
When I write tests and I have the urge to test a private method, I take it as a hint. The hint tells me that my class is encapsulating so much that it has ceased to be "understandable" by tests through its public interface. I listen to the hint, and factor my design differently. Usually, I end up moving the private method (and possibly some methods around it) to a new class where it can be non-private and accessible to tests.
All of the ideas above tend to discourage the idea of private methods and put more weight on testability. But they are not the only word on the subject. In fact, much of what has been written about object oriented design encourages as much encapsulation as possible and fewer classes. By only exposing the absolute minimum in a public API coupling is minimized. David West, in Object Thinking, sites Lorenz and Kidd in Object Oriented Software Metrics:
- An application should consist of no more than 40 stories and no more than 100 classes.
- The application's entire business domain should not require more than 1000 classes.
- 25-30% of the code should be discarded after each iteration.
- Responsibilities per class: average of 7.
- Methods per class: average of 12.
- Lines of code per method: 15.
- Percentage of lines of code requiring comments: 60.
- Number of case statements: average of 0.
If private methods are a smell and need to be pulled out into their own classes aren't we increasing the number of classes in our application just to make testing easy? It seems that doing so will quickly get us to a very large number of classes.
So, what about private methods? They are annoying to test. Do we change private methods and expose them for testing? Do we decide not to test private methods and keep design independent of testability? Or are private methods a code smell - an indication of a class trying to do too much?