“Begin with the end in mind.”
You must have heard that phrase, right? It’s a common one that’s led many people to great success, not just in agile, but all throughout history. In fact, it’s habit #2 in Stephen Covey’s best-selling book The 7 Habits of Highly Effective People.
Starting with the end in mind is what Olympic athletes do when they visualize their gold medals. Musicians do it when they envision their perfect performance before stepping on stage. Architects have a full picture of the completed skyscraper in their head before ground is broken. If you know what you are aiming for, in detail, you’ll find it much easier to achieve.
That’s exactly the philosophy behind Test-Driven Development, or TDD. Before you start coding business logic, you write a test. It’s almost like a detailed specification for the module you are creating, except it’s produced as a set of functions and gates that the module will have to pass through to confirm it is working as expected. When you initially run the test, it’ll naturally fail because your code doesn’t yet do anything. However, once the test passes, you know you’ve built what you needed to build.
TDD is there to make sure you don’t overbuild. You control costs, you increase efficiency, and you build quality into the product from the beginning. You only create what’s needed to pass the test – no more, no less. You eliminate all that wasteful junk that ends up never getting used (or at least a lot of it). For most people, TDD is a great way to ensure that your app delivers on the functionality it needs to.
Can TDD Apply To Performance?
Test-Driven Development is a great tool for functional testing, but can you apply the same technique to performance testing?
The purpose of TDD is to build out small unit tests, or scenarios, under which you control your initial coding. Your tests will fail the first time you run them because you haven’t actually developed any code. But once you do start coding, you’ll end up with just enough code to pass the test.
There’s no reason the same philosophy can’t be applied to performance testing. You can develop performance tests that stress algorithms and exercise code at the unit-level, just like functional tests do. Unit performance tests give you a baseline confidence in your core algorithms. They force developers to think about how their code behaves under stress at the time that code is being written.
Just like with functional testing, TDD helps to eliminate big, systemic problems that may appear later on. The process just requires the forethought involved in careful scenario planning.
Performance TDD Is a Good Start, But It’s Not Everything
Let’s face it: even if your app passed all its TDD-based unit tests for functional testing, you still wouldn’t feel confident that it was flawless. No matter what you were doing for TDD, you’d still create larger functional tests, integration tests, end-user tests, and a whole host of other tests. You’d have a suite of different functional test methods you’d bring to bear to make sure your app was ready for users to attack it.
The same thing is true for load & performance testing. Just because you incorporate Performance Test-Driven Development, doesn’t mean all your performance issues are solved. You’ll still need to coordinate your large, integrated load tests to push your algorithms to their breaking points.
But with Performance TDD, you’ll have much more confidence in your product’s ability to pass those tests at the get-go.
Some Tricks for Performance TDD
If you want to incorporate Performance TDD into your development process, here are a few tips that may come in handy:
- Create small-batch load tests that can stress small components. As you start planning your module, think about how that module would be stressed. What algorithms are most likely to limit scalability? Is there an opportunity for resource contention? Do you have queries that could impact performance if they get too large or complicated? Then create your test scenarios specifically to stress the component in these ways. As you and your team work through more and more of the product, you’ll end up building an amazing library of load test scenarios that you can leverage in lots of interesting ways moving forward.
- Don’t apply TDD to optimizations, instead just use it for base-level performance. The job of a performance engineer is often focused on optimizing code that’s already been written by someone. TDD isn’t really going to be much help here. Remember, TDD is best leveraged at the beginning of the code-writing process. So that’s where you should start. As your product matures, it’s completely appropriate to make your load tests incrementally more demanding (a certain function must return in 2 seconds instead of 4 seconds), but that may not always be the ideal place to focus because scaling problems are often driven by more complex interactions that are best suited for different kinds of test methodologies.
- Automate. TDD and automation go hand-in-hand, and you should approach it that way from the beginning. Think about how to automate your TDD from the moment you start doing it, like any modern development method. By doing this, you’ll be able to easily plug your performance testing into other automated processes like continuous integration, but you’ll also end up with a number of micro-load test scenarios that can be strung together into a larger automated test scenario. This gives you a ton of leverage.
As we’ve said before, the more you can plug performance testing into your standard development process, the more effective you’ll be as a team, and the more successful your application will become. If your team operates using Functional TDD, you’ll definitely find value enhancing that practice with Performance TDD.
Photo Credit: Andrew Hurley