Sunday 8 December 2013

The Growing Pains of TDD : Developing the Bare Minimum to Pass a Test

Hello Readers!

The first post in my TDD blog series is about developing the bare minimum to pass a test!

According to the TDD paradigm, you must only develop the absolute bare minimum required to get a single test passing.  The motivation of this being that you never write anything that is left untested.  Edge cases and specifics should be dictated by a test before they are developed on.  In many cases, this can feel trivial and nonsensical.  Say you're writing a boolean function 'isUserAuthorized(UserInfo userInfo)' .  Your first test might be to check that the user is authorized to perform some action because their role is 'top dog'.  However, the absolute bare minimum to do this is basically just to return 'true' without any other logic.

This kind of thing leaves me itching all over.  I can appreciate that maintaining this now passing test during further iterations of TDD is at some point going to result in proving some meaningful functionality.  However, I can't help but implement something reasonable before I can truly say this test has 'passed'.  In the example above, I might actually look into the userInfo object for the role 'top dog', return 'true' if it is present and false otherwise.  It frustrates me to deliberately write code I know is actually useless, just for the sake of passing a test.

Rather than getting a test to pass for the sake of getting a test to pass, I'd rather have the test pass knowing that the actual logic that the test is supposed to prove is working is in fact working.  In more complex scenarios, I have found huge value in developing as per this more pragmatic definition of the 'bare minimum'.  It allows you to understand many of the technical details you will need to know about in order to correctly implement the rest of the requirements of the class/interface you are testing.

To illustrate my point, lets say you're auditing a web service query that includes a SAML assertion.  Your auditing feature needs to record all relevant information about the User performing the query as well as the query itself.  Your first test might be to ensure that a query with a single required parameter, 'dataId' is audited.  In order to implement bare minimum required to pass this test, you need to address the following concerns:
  • How do I get the relevant User information from the incoming query?  Generally, SAML headers are used to create a Session for the current web service transaction, so how do I get access to this Session?
  • How do I go about retrieving the 'dataId' query parameter from the request?
  • How do I appropriately format this dataId query parameter in my audit log?  Perhaps in its present state, it is not very readable to someone viewing the log.
  • How do I even audit any of this information once I've gotten it?  Is there some library or service I can make use of to do this for me?
Complex situations like this are where you see the greatest value in developing the minimum.

A great way to solve a big problem is to narrow it down to the smallest possible sub-problem and then to solve it in a quick and dirty manner before moving on.  In this case of this auditing feature, the smallest sub-problem addresses so many issues that are relevant to the remaining set of requirements.  Attempting to write the whole feature set at once while also trying to address these concerns would be exponentially more difficult.

Thus, I have decided to let pragmatism dictate how I follow the 'develop the bare minimum' step of TDD.  I prefer writing the minimum amount of code that I know will become a part of the solution, rather than a bare minimum that I know is destined to be thrown away.  In difficult scenarios such as the above, there is huge value in developing this way as we focus development on the simplest version of a complex problem.  What are your thoughts, readers?  I'd like to update this post with any interesting discussion points.

Next up is a post on the Refactoring pains of TDD!

Shrek

No comments:

Post a Comment