- Do the right thing
- Do the thing right
- Do it efficiently
- Do it safely
- Do it predictably
- Do it sustainably
- Dev ops
- Process Improvement
Do the right thing
Everything the team does must be traceable back to business value. This means “the right thing” is the thing that has been chosen by the business to be the next most important thing, in terms of business value, that we should work on. TDD has no contribution to make to this. Our assumption is that this decision has been made, and made correctly before we begin our work. How the business makes this decision is out of scope for us, and if they make the wrong one we will certainly build the wrong thing. This is an issue of product portfolio management and business prioritization, and we do not mean to minimize its importance; it is crucial. But it’s not a TDD activity. It is the responsibility of project/product management.
As a restaurant owner, the boss has determined that the next thing that should be added to the menu is strawberry cheesecake. He made this decision based on customer surveys, or the success of his competitors at selling this particular dessert, or some other form of market research that tells him this added item will sell well and increase customer satisfaction ratings. It will have great business value and, in his determination, is the most valuable thing to have the culinary staff work on.
Do the thing right
One major source of mistakes is misunderstanding. Communication is an extremely tricky thing, and there can be extremely subtle differences in meaning with even the simplest of words. “Clip” means to attach (clip one thing to another) and to remove (clipping coupons).
A joke we like: My wife sent me to the store and said “please get a gallon of milk -- if they have eggs get six.” So I came back with 6 gallons of milk. When she asked why I did that, I replied “they had eggs.”
The best way we know to ferret out the hidden assumptions, different uses of terms, different understanding, missing information, and the all-important “why” of a requirement (which is so often simply missing) is by engaging in a richly communicative collaboration involving developers, testers, and businesspeople. The process of writing acceptance tests provides an excellent framework for this collaboration, and is the responsibility of everyone in the organization.
The analogy, continued:
You work as a chef in the restaurant, and the owner has told you to add strawberry cheesecake to the menu. You prepare a graham-cracker crust, and a standard cheesecake base to which you add strawberry syrup as a flavoring. You finish the dish and invite your boss to try it. He says “I did not ask for strawberry flavored cheesecake, I asked for a strawberry cheesecake. Cheesecake with strawberry.”
So you try again, this time making a plain cheesecake base and adding chopped up strawberries, stirring them in. The boss stops by to sample the product and says “no, no, not strawberries in the cake, I meant on the cake.”
So you try another version where the plain cheesecake is topped by sliced strawberries. Again the boss in unhappy with the result. “Not strawberries, strawberry. As in a strawberry topping.”
What he wanted was a cheesecake topped with strawberry preserves, which he has always thought of as “strawberry cheesecake.” All this waste and delay could have been avoided if the requirements had been communicated with more detail and accuracy.
Do it efficiently
For most organizations the primary costs of developing software are the time spent by developers and testers doing their work, and the effect of any delays caused by errors in the development process. Anything that wastes time or delays value must be rooted out and corrected.
TDD has a major role to play here.
- When tests are written as the specification that guides development, they keep the team focused on what is actually needed.
- The tests themselves require precision in our understanding of a requirement and thus lead to code that satisfies the exact need and nothing more. Traditionally developers have worked in an environment of considerable uncertainty, and thus have spent time writing code that ends up being unnecessary, which wastes their time.
- Without TDD, defects in the code will largely be dealt with after development is over, requiring much re-investigation of the system after the fact. TDD drives the issue to one of bug prevention (much more time-efficient) rather than bug detection.
Do it safely
Software must be able to change if it is to remain valuable, because its value comes from its ability to meet a need of an organization or individual. Since these needs change, software must change.
Changing software means doing new work, and this is usually done in the context of existing work that was already completed. One of the concerns that arises when this is done is: will the new work damage the existing system? When adding a new feature, for example, we need to guard against introducing bugs in the code that existed before we started our work.
TDD has a significant role here, because all of our work proceeds from tests and thus we have test coverage protecting of our code from accidental changes. Furthermore, this test coverage is known to be meaningful because of how it was achieved.
Test coverage that is added after a system is created is only guaranteed to execute the production code, but not to guarantee anything about the behavior that results from the execution. In TDD the coverage is created by writing tests that drive the creation of the behavior, so if they continue to pass we can be assured that the behavior remains the same.
Do it predictably
A big part of success in business is planning effectively, and this includes the notion of predictability. Every development initiative is either about creating something new, or changing something that already exists (and, in fact, you could say that creating something new is just a form of change: from nothing to something).
One question we seek to answer when planning and prioritizing work is: how long will it take and how many resources will be required? Although we know we can never perfectly predict these things, we want to reduce the degree of error in our predictions.
TDD has a role to play here:
- TDD increases design and code quality. There are many reasons for this, but the shorthand explanation is that bad designs and poor code are very hard to test. If we start from the testing perspective, we tend to create more quality. Higher quality creates clarity, and the more clarity you have the better your predictions will be.
- TDD points out gaps in analysis earlier than traditional methodologies. These gaps, when discovered late, create unexpected/unplanned for work, and this derails our predictions.
- TDD provides meaningful code coverage. This reduces the creation of unexpected errors, and fewer unexpected anything increases predictability.
- TDD helps us to retain knowledge, and the more you understand a thing the more accurate your predictions will be about changing it.
Do it Sustainably
The team must work in a way that can be sustained over the long haul. Part of this is avoiding overwork and rework, and making sure the pace of work is humane. Part of this is allowing time for the team to get appropriate training, and thus to "sharpen the saw" between major development efforts. Issues like these are the responsibility of management whether the team is practicing TDD or not.
However, this work is called "Sustainable Test-Driven Development" for a reason. TDD itself can create sustainability problems if the maintaining the test suite presents an increasingly-significant burden for the team. Much of our focus overall has been and will continue to be avoiding this problem.
In other words, TDD will not create sustainability unless you learn how to do it right.