Sunday, February 11, 2007

Damn Skippy

From a conversation whilst pairing with a client developer as we attempted to test infect some legacy code last week.

Me: Phew! Well, that little bit is under test now. We can start to fix it up now.

Client Dev: That seemed too hard....you know, if the guys who wrote that had had to put in tests as they went, the API would NEVER have looked like this. It would just have been too painful to work with.


It really is nice to witness the penny drop. True job satisfaction.

Monday, February 05, 2007

Test Code and Production Code – two distinct beasties

There are some common qualities that production and test code must possess in order to enhance their status as ‘good code’. Typical dimensions which one could apply may be conciseness, clarity of code, performance, elegance and extensibility (the list goes on). These are all good methods of assessing ‘good code’. However what differentiates good test code from good production code is not so clear when only these traditional qualities are taken into account. It may be more useful to consider what the drivers for the two type of code are.

For production code, these traditional values are useful, but cannot be assessed meaningfully if the code does not fulfil a business requirement. Ultimately this is the only driver of production code – it has to get the job done for the business. If your widget selling app for Widgets R Us cannot help to sell widgets, then no one will really care how speedy, elegant and extensible your Ultra Widget Framework is. The business code also needs to be robust enough for the business demands to allow the application to stay up and running cheaply enough for them to get a return on the build. It is a harsh world we live in and production code has to cut it in an unjust world.

So what about the test code? Test code has a different set of drives which compliment the production code. The primary driver is to assist in delivering high quality production code which robustly meets the requirements of our client. To this end the code also needs to drive the design and document the expected behaviour of our production code.

Driving the design of the code pushes the code towards delivery of production requirements, but this is only part of the story. Test code can used to accurately model the expected behaviour of the system and ensure that all key behaviour aspects of the system really do behave as per the requirements. By driving the design of the code with tests the system can meet the key delivery and quality drives of the code, but allows the developers the opportunity to make other improvements which improve the traditional values of the code. For example, a developer is more likely to refactor towards an elegant pattern which is emerging when a safety net in place than without one. If our tests measure performance then we are more likely to improve our performance qualities.

The test code is also a driver to document the behaviour accurately and clearly in order to provide a suitable level of traceability to the team and the stakeholders to demonstrate that the business need really have been met. When the test code is clear and comprehensive then the application benefits from not only the traditional test safety net, but also executable documentation that can highlight where and how the application has veered from the course of the business requirements.

So do traditional values not matter any more? Not at all - these values are crucial to quality code – in test and in production. However, you may assess the values differently in test and production code based when you consider what the code is driving to achieve. What may be reasonable in production code may be unsuitable for test code, as the application of a particular approach may obstruct the drives of test code to drive the design of the production code or clouds the documentation qualities of the test code by making a test less clear.

Put another way, just like in acting, it is important to consider your code’s motives first and then apply the traditional values in the context of what the code is trying to achieve.