Writing Testable Code

No, not this kind of test.

This has become my favorite subject because it turns out that testability, above nearly every other metric, is important to strive for in developing software. And all other code qualities seem to be a reflection of testability.

5 Easy Ways to Write Hard-to-Test Code

When I say testable code, what I mean is code that can be verified programmatically and in a very granular way. When a test fails, we want it to tell us exactly why so that we know what went wrong and can correct the problem immediately. This means that we're verifying very small units of behavior. This not only helps us debug code when there are problems, but it also helps keep us focused on building software that fulfills some desired behavior.

Keep Test Coverage Where it is Needed

I'm not a believer in having standards for test coverage. I know teams that require 60%, 70%, or 80% test coverage for their code. I don't like having standards like this because different code has different requirements for testing.

Straightforward code like getters and setters don't really need to be tested. However, more complex code that encapsulates business rules should be tested. When developers do "test after" software development by writing their tests after they write their code, they typically try to find the easiest code to test in order to meet their code coverage standards, but oftentimes this is not the code that we really need to have covered.

One-Click Builds End-to-End

We want to automate the build so that it is easy to use. We wanted it to be so brain-dead simple to use that we use it all the time and we invoke the build whenever we make even a minor change to the system. This is how we get the most value from our build — when we use it all the time.

To facilitate this we have the idea of the one-click build, which means that you can invoke the entire process with a single click. We can set this up so that when we save a change it re-compiles all of its dependencies on the local machine and then runs tests on the local machine. If these tests pass the changes are pushed up into the build server and a more complete set of tests are run against it. All of this should happen automatically. Ideally, we want the build to run fast and that means anywhere from a few seconds to a few minutes.

Use Version Control for Everything

Version control is an important part of file management on every software development project I've ever worked on in the last two decades, regardless of the methodology. I've used Subversion and Git and several others in the process of building software.

I always find it a bit surprising that other industries don't use version control nearly as much as we do in the software industry. For example, I know several writers who know nothing about version control and they would benefit greatly from it. The same is true for several artists and graphics designers who I know. I find that version control it is extremely easy to work with and gives me some key benefits.

Why Practice 3: Integrate Continuously

Once we define what we want and build the smallest increment, we want to integrate it into our system as soon as possible so that we can see it working and get a true measure of our progress.

Continuous integration is at the very heart of every Agile project and so I wanted to introduce it as early as possible. To me, it's the third central pillar of agile software development. Continuous integration means having a fully automated build that not only compiles and runs a system but also fully tests it without the need for any human intervention.

Measure Time to Detect Defects

When I was young I read a study by TRW done in the '60s that measured the cost of fixing a defect that was detected at different points in the development cycle. If the developer who wrote the defect found it immediately after writing it then we can assign one unit of effort for resolving that defect. If that's true, then it takes something like seven units of effort to resolve the defect during the testing phase, 15 units of effort to resolve the defect just before release, and a whopping 67 units of effort to resolve the defect if it makes it into the hands of the customer. In other words, the cost of fixing defects grows exponentially with the amount of time it took from when the defect was created to when the defect was resolved.

It's always cheaper to fix defects sooner. This is because the longer we wait from when a defect was created, the less we are familiar with it. The vast majority of time and effort in debugging isn't involved in fixing the defect. Some defects do require a significant amount of reengineering but most defects are small problems that can be quickly and easily fixed. What can't be done quickly and easily often is finding the defect in the first place. Much of the time, finding a defect is where we spend most of our effort and once we locate the defect it's usually trivial to fix.

Use Development for Discovery

Before you begin to build a house and break ground on the foundation you better have a blueprint and know exactly what you’re going to build. In physical construction, we really need to plan things out ahead of time to ensure that we have the right materials at hand and that things come together as we want them to.

This is a fundamental constraint of physical construction and it forces us to think about and construct physical things in certain ways. Virtual things do not have the same limitations and so in many cases, we can find more effective and efficient ways of constructing virtual things then if we were to just follow a similar plan that we would for constructing a physical thing.

Be The SME

I’m kicking off a new series of blog posts based on the Seven Strategies sections in my book, Beyond Legacy Code: Nine Practices to Extend the Life (and Value) of Your Software. The next seven blog posts will each be based on a different strategy from the section in my book called on Seven Strategies for Product Owners. You can also see the original blog post .

SME stands for subject matter expert, the people who understand the domain that we’re building software within. These people have specialized knowledge and we want to find ways to incorporate that knowledge into the software we’re building.