TDD Part 1

First lets define TDD. After a quick google around I found a pretty good summary of the methodology here:

“Test Driven Development is a software development process that relies on the repetition of a very short development cycle: first the developer writes an (initially failing) automated test case that defines a desired improvement or new function, then produces the minimum amount of code to pass that test, and finally refactors the new code to acceptable standards.”

If you ask around and speak with other engineers you will come across a lot of opinions on this methodology.

I think the most important consideration is that there are trade offs to every technical decision and methodology. There is no such thing as one size fits all, best approach, best technology, best language, best framework, etc. Even though people use this type of language very often. Best is a quickly moving target and is highly contextual. It is better to approach technical decisions by clearly defining the trade offs between different options and then optimizing based on the context of your project.

Next I’m going to discuss some of the trade offs with this methodology with the caveat that I’m definitely biased because I am somewhat addicted to TDD methodology now. Once you get used to it, it feels somewhat psychologically rewarding to see all those green passing tests.


Downsides of TDD

Some argue that you can’t move as quickly with test driven development.

My personal experience with this is that most of the time I can actually write software the same speed or faster using TDD because it helps clarify my thinking, catches bugs, and saves time preventing regressions. However, here are some of the cases where I am slowed down using TDD:

  • When I need to mock data just to make tests pass correctly. Sometimes it gets tricky when your using libraries that expect a browser environment for example, instead of running in Nodejs env.
  • This is a big one, working with legacy code can be pretty difficult to write unit tests if it is tightly coupled OOP with side effects for example. However, if you push through it your code base usually has huge benefits for the efforts in my opinion.
  • A small thing that might also slow you down is simply not knowing the apis available to you in your testing library.

Conclusion: If you are looking to put up a fast prototype for proof of concept, and if your team doesn’t all use TDD, then TDD might not be the best approach.

Benefits of TDD

Confidence in your codebase

  • I find that I can move faster when there are automated tests in a project because I can know that the changes I made didn’t break any of the past functionality. The alternative to this is to either manually test as much as you can that you might have effected with your code, or to just push changes to staging and hope it passes QA. In my opinion, it is much better to be able to instantly run a ton of tests proving that the code is working as it should still.

Catch almost all your bugs before releasing your software

  • Having almost completely bug free code is much easier to do with TDD since you are running all past unit tests with every new line of code you write.
  • Also, when you do find a bug in your code, it is usually very easy to test for and fix. Especially if you are using functional programming with pure functions and minimal to no side effects (a blog topic for a future date).
  • If your whole team does TDD the right way, you can dramatically reduce the cost of QA for your business.

You save a lot of time debugging, finding errors, and when refactoring

  • Related with the last section. Unless you practice and get into a TDD flow, its hard to express how much time you can save debugging and finding errors. In development, this time lost adds up.

Your code becomes self documenting

  • Some TDD enthusiasts argue that virtually all code commenting should be unit tests instead. The main reason is that code comments often lie. Down the road engineers change the code and almost never take the time to correct the comments. With TDD, the engineer is somewhat forced to change the unit tests if they want to change the functionality, therefore keeping the documentation consistent.

TDD forces code simplicity

  • Proper TDD only writes production code in response to a test requirement.
  • By virtue of this, engineers find themselves writing 30% less production code on average.
  • TDD enforces SOLID code principals.

Code bases using TDD are much easier to maintain

  • I’ve seen software engineers looking through code they wrote a few months ago with a sense of fear. They don’t remember what they wrote, or why they did certain things and each time they touch the code base they are afraid it will break everything (In these cases, things often do break very often because tests are hard to track consistently while making changes).

Code bases using TDD are easier to extend and integrate into existing architecture

  • In other software projects, engineers will sometimes add functionality external to the program architecture out of fear that they will break existing functionality. This can often turn into problems down the road for example with race conditions.

Using TDD actually is somewhat more enjoyable as you are passing tests

  • This one is more on the subjective side of things, but you will see what I mean as you begin and practice TDD.

Conclusion

While TDD may not be best for fast MVP prototyping with a team, you will see there are tremendous benefits to the methodology outlined above. If you haven’t tried it, I highly recommend giving it a shot for a solid three days or so at least. There is a reason that many of the top companies in Silicon Valley use TDD, so give it a shot and learn what it is all about.

Check out TDD Part 2, Clarifying Software Requirements. It mostly covers a high level way of thinking through software requirements in a way that easily translates to unit tests for TDD. I hope you enjoy it.

Next, as time permits, I will hope to cover TDD using Nodejs and Express with mocha and chai all the way from the api to the database (either SQL or Mongo, I haven’t decided yet). Eventually I’m also hoping to cover TDD with React, Redux, and React Router DOM, with jest and enzyme. Stay tuned.