Aug 07 2008

Code Generation and TDD

Published by Christopher Keslin at 4:34 pm under Development

Code Generation and Test Driven Development share the same common goal; decrease development time while increasing quality.  However, each technique achieves their common goal by very different, and at first glance, opposing paradigms.  This post focuses on how development teams can increase their velocity significantly by understanding the strengths of each technique and laying out clear rules of engagement upfront.

Code Generation starts with the recognition that many of the patterns used in enterprise development are repetitious.  Many tools have been created to tackle these repetitive tasks and generally come in two flavors.  The first flavor is code generated from a source that will never be hand modified.  If the source changes, the code is simply regenerated. The svcutil provided in the .NET 3.0 framework would fall into this category.  The second flavor generates code that is intended to save developers from a lot of copy and paste operations but will still require some manual editing by the developer.  In this case the code is generated once, but then is never regenerated if the source changes.  (note:  Partial classes have done a lot to help seperate out what can be regenerated without breaking custom changes, but the gen once paradigm described is intended to jump start the manual coding process)

Test Driven Development (TDD) requires that a test be written and fail before any code can be written.  Once you have a failing test, on you go to fix the code so the test passes.  See Introduction to Test Driven Design for more on the overall process.  Following this process results in a clean, minimalist API with extremely high automated test coverage.

Code Generation and TDD come into conflict when development teams implement strict test coverage requirements in their continuous integration environment.  Code Generation that will never be hand modified can skirt this issue through the use of attributes such as [System.CodeDom.Compiler.GeneratedCodeAttribute] which tell the coverage utility to exclude the following class, property, or method from the coverage metrics, however, we still need to address code that is generated to jump start manual coding.

We can still follow TDD using Code Generation to augment the process to get the best of both worlds.  The key is to create templates that generate the smallest unit of work possible instead of the typical “generate everything” paradigm.  Lets take the simple task of adding a data entry screen in a typical ASP.NET application following an MVP pattern (note:  for a good succinct discussion of the difference between the MVC and MVP pattern see Daron Schall’s post titled MVC vs. MVP).

Story Tasks:

  1. Create the database table
  2. Test the domain model representation of the information
  3. Test the CRUD operations of the repository (for illustration purposes this story does not require the ability to update the entity)
    1. Test Adding a new entity to the repository
    2. Test Finding an entity within the repository
    3. Test Removing an entity from within the repository
  4. Test the Business Processor responsible for manipulating the entity
  5. Test the Service responsible for exposing the functionality to the UI
  6. Test the Service agent responsible for communicating with the service
  7. Test the Client Model
  8. Test the Presenter responsible for executing user initiated actions
  9. Create the page and wire up passing events to the presenter.

Execute task one using your favorite database utility and add the resulting script to source control (hopefully in a dbDeploy.NET script)

To execute task two, write the unit test asserting the expected properties are present and functional, then use your favorite code generation tool (Code Smith is my personal favorite) to generate the class from either the table or preferably the select stored procedure. Run the unit test and validate it passes.

To execute task three, write the unit test for the first sub task, develop the required stored procedure, generate the Add methods code from the stored procedure, verify the test works, rinse and repeat for each task.

For task 4 I break with TDD slightly in that I right all of the tests for each method the business processor exposes (and in the 90% case simply delegates) to the repository.  After all three tests are written I generate the complete processor from the associated compiled repository class.  If you use Code Smith for generation custom property Assembly and Type / Class Selector is invaluable for using .NET types as source objects for generation.  By generating the processor from the repository and not the database you do not end up with an Update method the story doesn’t require.

The rest of the tasks follow a similar pattern of writing the test, and then using a template to generate the stub code to satisfy the test.

Following this process has greatly increased my velocity and still results in the clean, minimalist API obtained through TDD with a high level of test coverage while virtually eliminating the copy, paste, massage routine for tasks that follow the 90% rule thanks to the judicious use of Code Generation.  Leveraging templates through Code Smith’s Active Snippet feature in VS 2008 is the icing on the cake!

Comments Off

Comments are closed at this time.