Stuck in the Loop

In my last post I talked about quality, and how that as developers we are responsible for at least two levels of quality, the first being that seen by the user, and the second being the quality of the code that is written and how the second quality can effect the rate of future development.

I hinted that we spend a lot of our time not actually programming, but doing a lot of associated tasks, most of which appeared to be to do with debugging!  realising that the programming loop can involve quite a bit of stepping though code, brings us to the conclusion, that the only way to speed this loop up is increate the quality of the code, better code will involve less debugging!

When we write code, we introduce bugs, event the smallest change can have unforeseen consequence, this is a ‘fact’ of life within software development, by stepping through our code we are trying to mitigate any errors we have made. Wouldn’t it be nice if we could find a way to add code to a system, and know that the changes we have added have not broken some far corner of forgotten code.

This desire to be able to check the code that is written lead to the introduction of TDD “Test Driven Development”, which hit the mainstream about around 2003-4, although there have not been many studies done, it is generally accepted that writing tests for code improves the quality of the code speeding the development process over the lifetime of a project.  TDD changes the development loop from

      1: Write code

      2: Run Code, stepping through code

into a three step process

        1: “Red” write a failing test

        2: “Green” write enough production code to make the test pass

        3: “Refactor” both the production code and the test code.

Many developers had/have great trouble with the whole test first paradigm, not necessary with the idea of writing tests, but writing them before writing production code. Deciding what to to test can be extremely difficult if not impossible at first and this position is totally understandable, and very difficult to answer, because the reason to write the test first has nothing to do with the actual test itself. 

Writing the test first changes the way the production code is written, one part of the magic of test first development in any of its forms is that the resulting production code on the whole tends to have a much better structure.  Its almost as if writing the test first, makes the production code confirm to the “SOLID” principles by default, its not always the case, but well structured code, is also code that is easy to test.  So writing the test first makes by definition the code easy to test and probably well structured!

The first problem I faced when learning test first development was “what test to write?”  Actually getting the whole “Red/Green/Refactor” cycle going, can be like pushing a car so to get the wheels turning I used to write a test called “Hook”

  1. public void Hook()
  2. {
  3.     Assert.IsTrue(false);
  4. }

 

Which when run in the test runner would fail, changing the false to true would make it pass, this confirmed that the test runner etc was working correctly and had picked up my class containing the tests, and it gave me thinking room, getting the first test out of the way seamed to get the car rolling, and made the second test easier to write.  But to be honest this is not ideal.

I had a problem. While using and teaching agile practices like test-driven development (TDD) on projects in different environments, I kept coming across the same confusion and misunderstandings. Programmers wanted to know where to start, what to test and what not to test, how much to test in one go, what to call their tests, and how to understand why a test fails.”

Dan North

So I wasn’t the only one having problems, the solution outlined by Dan North was to change the language, to stop talking about tests, and to start to discuss specifications this became known as BDD “Behaviour Driven Development”, Changing the terminology used, but keeping the idea of writing a failing specification first, freed developers from the idea of tests, specifications define what a function is going to do and the expected result. for developers talking in specifications and behaviours is natural which makes it easier to write in code for the specification

So instead of

  1. [TestMethod]
  2. public void Constructor_NullPram_ThrowsArgumentNullException()
  3. {
  4.     Exception lastException = null;
  5.     try
  6.     {
  7.         var shipment = new Shipment(null);
  8.     }
  9.     catch (Exception ex)
  10.     {
  11.         lastException = ex;
  12.     }
  13.  
  14.     Assert.IsInstanceOfType(lastException, typeof (ArgumentNullException));
  15. }

 

the specification  can be written as a sentence

  1. [TestMethod]
  2. public void A_shipment_cannot_be_created_without_an_address()
  3. {
  4.     Exception lastException = null;
  5.     try
  6.     {
  7.         var shipment = new Shipment(null);
  8.     }
  9.     catch (Exception ex)
  10.     {
  11.         lastException = ex;
  12.     }
  13.  
  14.     Assert.IsInstanceOfType(lastException, typeof (ArgumentNullException));
  15. }

 

The change may not be that obvious at first here, but changing what the test is called changes the way the developer thinks about the test, it also changes the output from the test runner.

image

This idea of specifications lead to new test frameworks being developed that totally removed the word “test” from the vocabulary, and concentrated on building better sentence structure in the output, and defining a better structure within the code.  Having a formal layout where each stage of the specification is split using an Arrange/Act/Assert format, made it easier for developers to write the specification code.

  1. [Subject("Shipment")]
  2. public class Constructing_a_shipment
  3. {
  4.     Establish context =
  5.         () =>
  6.             {
  7.                 _emptyAddress = null;
  8.             };
  9.  
  10.     Because of =
  11.         () =>
  12.             {
  13.                 _result = Catch.Exception(() => new Shipment(_emptyAddress));
  14.             };
  15.  
  16.     It cannot_be_created_without_a_recipient_address =
  17.         () => _result.ShouldBeOfType<ArgumentNullException>();
  18.  
  19.     static Exception _result;
  20.     static Address _emptyAddress;
  21. }

 

Ignoring the funky “=() =>” syntax for the minute which is needed by the c# compiler, the above code does exactly the same test as the original one above except in a more structured fashion.

“Establish context” sets the context for the test (Arrange), in this case an empty address variable,

“Because of” is the action that makes this specification work (Act), in this case we are catching an exception raised by the creation of a shipment without a valid address

“it” checks that the result of the action (Assert) in this case ensuring that the correct type of exception is raised.

The output from running this specification is totally different, building a document like specification.

image

In theory given only the output from a specification run, the production and specification code could be recreated! The output has become the specification for the application.

By moving away from talking about tests, to talking about specifications, writing the “test” first has become easier, new frameworks have helped move the code and output towards a more sentence like structure, which in turn make it easier for developers to specify what the code should do.

This movement to a more sentence like structure has resulted in a change at the other end of the testing spectrum as well.  Taking a 10,000 foot view of the whole application at the acceptance test level new frameworks allow the development of feature specifications that are written in a plan text format using a standard notation.

image

This new notation is called “Gherkin” and was originally developed with the ruby language test runner “Cucumber” in mind, but is now used in other frameworks, including the dot-net framework  “Spec-Flow”

This plain text specification is combined with a step definition code file to produce executable specifications, and because the plain text is separated from the developer step definition code, in theory the specification documents can be created first before being handed onto the developer as the actual feature requirement.

This has lead to a new style of development outlined in the “RSpec Book” called “Outside In Development”.  Where the high level features are defined as plain text, twinned with a code definition file, to produce executable features, which the developer uses to drive the lower level specifications, which in turn drive the production code.  Outside in development suits the agile (SCRUM) development cycle because it is totally feature based, which has made it to be popular among the agile software development houses.

Using Outside in development and Behaviour Driven Design specifications, has made it easier to achieve test first development, the structure of the features and specifications make it easier to find and amend code in the future, along with providing up to date specification documentation, through the test runners output.

Having all these specifications at different levels of the application, allow a high level of confidence that any changes made to the application, will have a minimal impact and allow for other agile techniques such as “Continuous Integration”, and Automatic Deployment.

Advertisements

About Duncan Butler

Trying to be a very agile software developer, working in C# with Specflow, Nunit and Machine Specifications, and in the evening having fun with Ruby and Rails
This entry was posted in Uncategorized. Bookmark the permalink.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s