Testable Increments

As part of my Think Big, Act Small philosophy of agile software development, I prefer to implement things in small units that can be easily tested. I call this unit a testable increment.

Small

A testable increment is small. An increment can be a new method, a single change to an existing method, the shell of a new class, anything that is a small change and can be tested. A single increment should be implemented, integrated, and tested within a single day. Several, dare I say dozens, of testable increments should be completed in a single day.

By being small, testable increments can be completed quickly. By working with testable increments we can see progress towards getting the bigger things done. It feels good to get things done and with testable increments we can get many things done in a day. Instead saying, “I worked on story A yesterday and I will work on story A tomorrow”, you can say, “Yesterday I completed the get/set methods and the main processing flow of the class. Today I will complete the three exception flows and add the special case creator methods.”

Testable

A testable increment is testable. If it cannot be tested, the quality of the change cannot be validated. By testing it, I have confidence that it works and I can build more things using it. Unit tests, especially automated unit tests, are invaluable, almost indispensable, for coding in testable increments. After I am done with the current testable increment, the automated tests become part of the regression tests that I run frequently to ensure that the current testable increment I am developing does not break all the previous testable increments.

In order to test a testable increment, good unit tests need to be created; good test data needs to be accumulated; and good test harnesses need to be built. While all of these things take time when you are just starting to work in testable increments, in the long run you will save time because what you build is reusable, extendable, and can significantly reduce the amount of time spent investigating and resolving anomalous behavior. Sometimes, if not frequently, the test harnesses can become good demonstration tools, especially for backend or API driven systems.

Benefits

Faster Feedback

Creating and testing small things is faster than creating and testing big things. Because of the faster times, we get much faster feedback loops, which in turn allow us to debug and improve at a faster pace.

Faster Throughput

Smaller batch sizes move through the delivery flow faster than large batch sizes.

Easier Validation

Validating and repairing a few lines of code is easier than validating and repairing hundreds of lines of code. When something is wrong, you have a smaller space in which to find the error.

Better Design

Creating things as testable increments leads to better design. In order to test these small things, they have to be built-in such a way so that they are testable. This leads to components that have well-defined interfaces, are encapsulated, and are not as cohesive with other components.

Higher Possibility of Reuse

By making things smaller, they also have a higher possibility of reuse. A function that is contained in a single testable unit can be incorporated into other functions much easier than one that is in a module with several other functions or spread across several modules.

Complexity Isolation

By creating smaller things, you can isolate the complex aspects of a function into a couple of small complex things so that you have dozens of simple things and on a couple of complex things. In most cases, something that looks complex is only complex in a very limited space within the bigger function. Breaking it down into testable increments allows you to 1) get the simple stuff coded and tested independent of the complex stuff and, 2) isolate the complexity so that it does not affect the rest of the code. You can “stub out” the complex part while one part of the team is working to solve the hard problem. The rest of the team can continue creating the rest of the solution. When the complex part is ready, It can replace the “stub” with little or no impact on the rest of the solution. This approach also allows the team to try multiple solutions without a lot of code rework on the easy stuff.

Evolutionary Development

Testable increments allow the feature to “grow” over time. Starting with the most basic needs to get a feature working and then adding small enhancements to make it better, the software evolves rather than bursts into existence. As it evolves, we can evaluate what things are more valuable than others so that we can direct our attention towards the things that provide the most value.

 


Categories : Undercover