Kent Beck is down with TDD.
My first introduction to test-driven development was not exactly a pleasant one. It was my first week at the Flatiron School and knowing little more than how to iterate through one-dimensional arrays and puts “Hello World” to the screen, I found myself attempting to write code to pass seemingly abstract tests written by the Flatiron labs team. Little did I know that test-driven development is a prominent and hotly debated (because what in the programming world isn’t?) software development process used in some capacity by thousands of programmers across the world.
As my time at Flatiron winds down, and I begin my job search, I am reminded of something a guest speaker once told us. He said he would never work at a company that didn’t write tests for their applications. At the time, I didn’t feel strongly one way or another about tests, but now I know what he means. Neglecting to write tests leaves your code vulnerable. It’s risky – like skydiving without life insurance.
So, what exactly is test-driven development? Simply put, it is a programming paradigm that requires developers to specify an application’s features and design before writing any functional code. Any proponent of TDD lives by the “red, green, refactor” mantra, which follows this process:
The TDD Process
- Before writing any feature into your application, write some code to test that feature.
- Run that test, and see that it fails.
- Write the necessary code to make that test pass. It doesn’t have to be beautiful code; in fact, you should write the least amount of code necessary to make the test pass.
- Run the test again, and see that it passes.
- Refactor your code. Go slowly when refactoring, and keep testing along the way to make sure you aren’t breaking any functions of your application.
Sounds pretty simple, right? The idea is that neglecting to practice feature-first development can leave your code open to vulnerabilities you may not have foreseen. Here are a few other reasons why many programmers swear by test-first development:
Benefits of TDD
- It forces a team of developers to thoroughly think through the purpose and requirements of an application before diving into building it
- It ensures each feature of your application is working as expected
- It acts as an effective means of communication between project managers and members of a team. A new developer who comes onto a project at a later stage will be able to understand tests (assuming they’re well-written) much better than she will be able to understand hastily-written, comments explaining what several lines of code should be doing. Ideally, your tests should be a clear and concise way of communicating across your application.
- It allows you to take small steps when writing large applications. When you write several lines of code and find that your tests are failing, it is relatively easy to find your errors and debug them, as opposed to searching through hundreds of lines of untested code.
It sounds great right? Why wouldn’t every developer want to write test-first software? It may surprise you that not all programmers feel this way. Now that I’ve covered the benefits of test-driven development, let’s look at some of the limitations.
Limitations of TDD
- Writing code is time consuming, especially when you’re continuously adding new features and aren’t entirely sure how they will fit within your application or whether they will remain in the code base at all
- Having many tests can make it more difficult to make any changes to the functionality or design of your application. Even simple changes can become too difficult or time consuming.
- If your team members aren’t skilled at writing tests, you can end up with a lot of unclear code that doesn’t effectively communicate the features of your application. Furthermore, your tests might be testing the wrong thing or testing something the wrong way. Either way, poorly written tests are expensive to maintain.
- If other members of your team aren’t committed to writing tests, the application can fall apart.
At this point you’re probably wondering: what are the alternatives to feature-first development?
One alternative supported by DHH, the creator of the Rails framework, is system testing. Whereas unit testing involves testing small pieces of code, like class methods, system testing (as you may have guessed) tests how the entire application works together.
“The current fanatical TDD experience leads to a primary focus on the unit tests, because those are the tests capable of driving the code design (the original justification for test-first). I don’t think that’s healthy. Test-first units leads to an overly complex web of intermediary objects and indirection in order to avoid doing anything that’s ‘slow’. Like hitting the database. Or file IO. Or going through the browser to test the whole system. It’s given birth to some truly horrendous monstrosities of architecture. A dense jungle of service objects, command patterns, and worse.” DHH
So really, the question is not “to test or not to test”; most programmers can agree that testing is a fundamental aspect of software design and development. But how to implement those tests – that is where opinions diverge. While not all programmers worship traditional TDD and test-first development, most will agree that some kind of testing framework is necessary to prevent exposing your application to vulnerabilities. What kind of framework you decide to implement is ultimately up to you and your team. To me, the most valuable aspect of writing tests is ensuring that you and your team members are on the same page every step of the way while building an application. For maximum effectiveness, all members of a team should agree what kind of testing framework to use and how to implement it.