Patterns
“Design Patterns” is a terrible term. Mostly because of the baggage and connotations attached to it.
So lets drop it, reduce and cut down to the crux of the matter; patterns. Just patterns. But only the part that relates to software. Because that is the part that I am interested in.
I have struggled for some time to come up with the right analogy, the right explanation, for how I see patterns. And I think a big part of the puzzle finally fell into place today:
In what language does a good composer think, when he composes? In what language does a good programmer think, when he programs?
Not notes, and not codes. Those are too low-level. Those are interned. They bend naturally, sometimes even effortlessly, to his higher-level thinking.
He thinks in a pattern language. Perhaps not consciously, perhaps he calls it something else. But it is the level of abstraction at which his mind works.
The mind hates to work slowly or inefficiently. Especially if it is a kind of work that it has to do often. Working with bigger pieces – patterns – instead of smaller bits, facilitates efficient thinking.
If his mind does not work with patterns, then I see two possible causes: He has not yet attained a sufficient level of skill to recognize the patterns, or how they fit together; or he has transcended the patterns, and probably gone from good to great in the process.
Given this, you can say that programming is like composing music that express logic instead of feelings.
Only Test The Public API
When programming in Java, I have found that …
Unit tests should only be made agianst the public API. Reliance on package or private scopes for testability is detrimental to the design and leads to fragile tests.
Such is the conclusion that I have recently made. In this context, protected scope is also considered public API, however much one might try to discourage implementation inheritance.
My reasoning goes like this: anything not specified by the public API is an implementation detail. Implementations should be allowed to change, as long as they are correct. Our tests should ensure the correctness of the implementation but not the details of how that correctness is achieved.
If a test relies on implementation details, then that test will likely break when those details change.
What I am beginning to notice is, that when ever I think I need to lift some method or class from private to package-private, I actually have a bit of public API wanting to get out.
It often turns out, that the class that would otherwise have grown something package-private, instead gives birth to an interface and another class that implements that interface.
What this means is that not only do my tests get access to the APIs they want, but so do everybody else who might want to integrate my code (especially important if I’m writing library code).
So, the public API is like a specification and the unit tests ensure that the implementation adheres to that specification. If it cannot be tested through the public API, then it doesn’t matter and can be deleted.
This is another way to achieve high test coverage: just delete any code not covered by a test - according to your tests, it will still work afterwards.
That is, it can generally be deleted. This is only a general rule of thumb and as such there are exceptions. Sometimes checked exceptions force you to write a catch clause that will never execute, and other times you just have write guards against a race condition that is impossible to reproduce on your hardware.
I have run into both of these exceptions. And that “impossible catch clause” you might be wondering about; what are the odds of the UTF-8 character encoding not existing on a system that has Java installed anyway?
That is all.
TDD: A Pattern Of Process
I was pondering, the other day, whether TDD stood for Test Driven Development or Test Driven Design. I don’t think the distinction is terribly important, and it might also be that it is a personal choice of philosophy or opinion. Regardless, as I was thinking about this, I ended up grabbing a note book and a pen, and produced the brain dump laid out bellow.
TDD is not a tool of software design, but a pattern of process. Designing is when you precisely describe something before you bring it into existence. Writing a unit test before the production code, can certainly be seen and used as a tool for designing software, but this is not all that TDD is.
Design tools are things like rulers, pencils and unit tests. The process of using a design tool is not itself a tool of designing, but the tools are a constituent part of the process; or rather, their use is.
TDD is a pattern of process, that prescribes the use of unit tests before production code, and continuous refactoring, as design tools. This way, TDD naturally encourages good software designs, but it is not itself a tool or method of designing software.
TDD is a pattern of process. It must be instantiated for every project, for every programmer. The concrete implementation by a person, on a project, is influenced by the context of the project; the tools available, the unit testing frameworks and drivers, the people on the team and their experiences, programming languages, environments, build tools and so on. Even so, the mantra of TDD stay the same; “Red, Green, Refactor.” This mantra is the repetition, the pattern, of the process. This pattern is Test Driven Development.
So there you have it. I call it Test Driven Development, instead of Test Driven Design. I think of TDD not as a process, and not as a design tool, but as a pattern of process.
I think of TDD as something that is composed of smaller parts: writing unit tests, writing production code and refactoring.
I think of TDD as something that defines a strict relationship between its constituent parts: production code must only be written in response to a failing test or as part of a refactoring; refactoring is only allowed when all tests pass; you are not allowed to add new tests when others are failing.
I think of TDD as something that must be composed with other things in order to form a whole; something more complete, practical, useable.
This is my definition of TDD.