- Customer dreams up something they want a system to do
- Business analyst and sales team talk to them to nail down chargeable and isolated items (stories if you like)
- Business analysts document the stories for the technical team(s)
- Architects and developers read these, interpret and develop a solution
- Testers read and interpret the BA's docs and create a test suite
In this scenario the requirements are 'written' 2 times by 2 people, 'read' 3 times by 3 people but reinterpreted at each step, so what the 3 layers of this process (customer; BA and sales; dev and test) understand the system needing to do can be vastly different, especially in the detail. A situation can occur where the BA slightly misunderstands the customers needs, then does not communicate their understanding thoroughly. The dev and test teams pick this up and interpret in 2 further subtly different ways. All three layers of the process think they understand everything fully, the system 'works' in so much as it performs a function, all of the tests are passed so the system is delivered or demoed to the customer, but the system does not do what the customer really wanted it to do. Where did the failure happen? Everyone in the process has performed their own individual part successfully, and something has been built that everyone will be to some extent satisfied with, but its not what the customer wants.
What is missing here is a single item that all players can refer to and agree upon as fully defining the requirements. Conventional wisdom would say that the document produced by the BA is that item, and ideally that would work, one document, all parties agree to its contents, all code is built to its specifications, all tests validate these specifications and all the desires of the customer are met. In practise the 3 ways this document is interpreted mean the one single document conveys three messages. So how can we overcome this?
A document that can be 'read' by a machine, interpreted only in one way so code to make the system work and tests to validate this have the same interpretation, and so long as this can be read easily in a non-technical manner by the customer and agreed upon the loop should be closed. Customer agrees to the specification when written into the document, the tests prove this happens and works, and the code is written to satisfy the tests. No ambiguity remains.
This forms something of the basis for the concept of Behaviour Driven Development (BDD) where the desired behaviour of the system is defined and forms the specifications, the tests and drives the development to meet these, akin to test driven development but where overall behaviour of the system is the driver, not the technical test specifications, which in general do not over the overall system, but isolated units of the system. The core advantage of BDD is that the behaviour specification is written in a language that can both be read by non-technical personnel (customers) and interpreted by the computer without translation.
The syntax of defining specifications is a well established one, and one that has many flavors (GWT, AAA etc). A DSL was developed to encapsulate the given when then formulation of requirements and has been given the name gherkin. For the purposes of using this within a .net project a tool called SpecFlow is the one I currently choose to use, although in the past I have used cucumber and had to write Ruby code to access the actual code of the .Net system, the advantage of Specflow is that all the specifications, code to access the system and the system under test itself can exist in one place, and written in one development language.
I am not writing a post on how to perform BDD here, I am looking to highlight the advantages of a BDD tool like Specflow to the development process, and specifically the communication of detailed technical ideas between different groups and disciplines within the process without ambiguity of interpretation creeping in. That said, a simple test specification taken from the cucumber website provides a good place to start in terms of understanding how this fits into the dev process.
Feature: CalculatorAddition
In order to avoid silly mistakes
As a math idiot
I want to be told the sum of two numbers
Scenario: Add two numbers
Given I have entered 50 into the calculator
And I have entered 70 into the calculator
When I press add
Then the result should be 120 on the screen
This specification is the example one that is provided when you add a new spec to a unit test project in visual studio using the Specflow add in, but provides a good point to explore the way gherkin solves the problem of interpretation of requirements.
This specification is very easy to understand, a non-technical person e.g. the customer, could read this and sign-off that this details what they need the system to be able to do. The question is how does this satisfy the needs of the testers to validate that the system does what is described. Well that is the beauty of the cucumber/specflow system. This series of definitions constitute a test as well as a requirement specification. The specflow framework executes a piece of code for each of these lines, the code in question being hooked into by a regular expression match of the definition itself against an attribute on the code method. And the convention is that the 'Then' definition will validate the outcome of the action against the expectations (do an assert if you prefer). The code that needs to be written to hook this into the production system is very straightforward
[Binding]
public class CalculatorAdditionSteps
{
Calculator calc = new Calculator();
[Given(@"I have entered (.*) into the calculator")]
public void GivenIHaveEnteredIntoTheCalculator(int value)
{
calc.InputValue(value);
}
[When(@"I press add")]
public void WhenIPressAdd()
{
calc.DoAddition();
}
[Then(@"the result should be (.*) on the screen")]
public void ThenTheResultShouldBeOnTheScreen(int expectedResult)
{
Assert.AreEqual(expectedResult, calc.Result);
}
}
and this form the basis of a simple unit test. As you can imagine detailing a fully functional production system will involve significantly more code to be written, but with the advantage that if the specifications drive the process, the tests come for free, and the architecture and code design is driven towards a clear and easily instantiated structure. Minimal coupling and dependencies make the production and maintenance of the 'hook' code here significantly easier.When performing this as a BDD process a simple Calculator class will satisfy the needs of the test as far as being able to build
class Calculator
{
internal void InputValue(int value)
{
throw new NotImplementedException();
}
internal void DoAddition()
{
throw new NotImplementedException();
}
public object Result { get; set; }
}
And when run the test will fail. It is also possible to work with only the specification, before the 'hook' code is written, at which stage running the test will give an inconclusive result, highlighting that the specification has been detailed, but that no work has been performed to hook this into validate the system, potentially meaning the system has not had the new functionality added.There are shortcomings to this approach, but as a way of removing the element of Chinese whispers from the development process it goes a long way to solving the problem.
I will showcase a situation where this approach proved problematic in a future blog, a situation where it did test the system successfully but where the overhead of creating and maintaining the specifications and the hook code outweighed the advantages provided.
No comments:
Post a Comment