Apprenticeship Week 2 – Getting Started with Behaviour Driven Development
After an whirlwind start in Week 1, week 2 gave me a welcome chance to find out more about the ideas that had gone flying past, wrangle with Git, and get more hands on experience working with Endjin's codebase. Alongside this was a dive into the deep end of client virtualisation project, as I sat in on two workshops bringing together development and operations leads. Another enjoyable part of the week was getting to find out more about the work of Paul from our creative team, and play with some drawing tools. Paul is full of energising ideas for bringing together the team's home and work interests, and makes me feel a little bit like I'm working at Google.
In this blog I'll pull out one of the light bulb moments of the week. Last week I blogged about using SpecFlow to create test scenarios. However, I don't think I really 'got' the idea of Behaviour Driven Development until this week, when I'd had a chance to read some materials recommended by Howard, and discuss it with Matthew, relating the idea to how I'd approach a development task.
As a relative newcomer to the world of development, the word 'test' in a software context conjured up two things: manual or automated user interface (UI) testing and 'Unit Testing'. I'd loosely thought of Unit Testing as the standard term to describe writing any programmatic tests in the same language and stored in the same solution as the application under test. It sounds daft when I write it out like that but that was my un-thought-out assumption. It quickly became clear that Unit Testing, and the 'Test Driven Development' approach which I'd thought was the shiny epitomy of development best practice, are different to Behaviour Driven Development in both outlook and implementation.
Light began to dawn after started working on setting up support for the Atom-Pub protocol in one of Endjin's libraries. As the API would correspond to the Atom-Pub protocol, so my initial thought was to:
- Read the protocol documentation
- Write a C# interface, exposing methods based on the protocol… or maybe start with a controller.
- Write a SpecFlow test scenario
I wasn't sure whether to start with an Interface or Controller, so I checked with Matthew, and we had a enlightening conversation which I reproduce here with some minor edits:
Matthew: Do you know what the best thing to do is? To try and translate the standard into SpecFlow specs. Then write the code that you would like to write in the SpecFlow specs to get it to do the job you want - make up the entities and functions you need, create their properties. Then use ReSharper to magic up the classes and properties with Alt + Enter. That gives you the API, and it is tailored exactly to the needs of the scenario, because you wrote the code you wanted to write from the 'client' point of view. You can then refactor a little bit to make it nice. Then fill in the actual implementation of the API.
Me (with light bulb slowly going on): Ah Behaviour Driven Development! So I shouldn't use the protocol as the basis of the structure...
Matthew: Exactly. Might well look similar in the end, though!
Next, to clear up something that had been puzzling me about writing SpecFlow scenarios.
Me: Should the SpecFlow scenarios be from the point of view of a human user in this case, or of a 3rd party application interacting with ours?
Matthew: The latter – the app is the 'user'.
And finally, I think I get it! Bolstered by this concrete example of the full Behaviour Driven Development process, I went on to read about the differences between Unit Testing with a Test Driven Development approach, and Behaviour Driven Development. Here are the definitions that I came up with.
What's a Unit Test?
A unit test tests an individual bit of functionality in a programme. The test is usually mapped closely to an individual method within the application. The focus is very much on testing that the bits of code you wrote, do what you want them to do.
What's Test Driven Development?
Test Driven Development (TDD) is a part of the Agile Development Process. Rather than building features then writing tests, development begins with the construction of automated tests. Writing tests helps to establish the boundaries of the System Under Test (SUT) – in other words its behaviour. The tests form a guide to writing the programme.
TDD follows a mantra of 'Red, Green, Refactor'. The initial stage, 'Red', is to write the test, then the write some code that compiles, and run your test which will of course fail. Next, 'Green'. Write the most brutally simple code that passes the test. Elegance is not a factor at this stage. Finally, Refactor – in other words re-organise the code for maintainability, extensibility etc, without changing its external interfaces.
The significant advantage of this approach is that any re-factoring is done from the position of having a passing test. By focusing on passing tests which define the success of the system, TDD lets developers step away from tasks once they are complete, rather than wasting time on endless re-factoring.
What's Behaviour Driven Development?
Behaviour Driven Development (BDD) is an evolution of Test Driven Development. As with TDD, test writing comes first, and the goal is to get working code quickly, then re-factor it. However, rather than focusing in on particular functional units within the code, the tests are framed by clear definitions of the types of user behaviour that a feature is intended to enable. BDD also involves the use of high level language to make all the alternative scenarios that the system apparent. Tapping into the mind's ability to process human language and grammar can bring out problems that might not become obvious until later with a lower level approach.
This leads on nicely to the concept of Ubiquitous Language. Ubiquitous language had come up a few times in client workshops, and it was good to be able to relate this to something I was doing. It's the concept of choosing the language used to describe the application's functionality so that it is clear how it relates to the application's problem domain. This makes it easy for developers, operational and domain expert teams to communicate clearly about the application, without misunderstandings, or the broken processes that arise when decisions require so much technical knowledge that they cannot be understood outside of the technical teams.
The outcome of this conversation, and research, was that what had started off looking a bit like this:
Now looks more like this:
You may have spotted that in the process of trying to flesh out the behavioural requirements, something important has changed! In trying to find some real life examples of AtomPub client activities, to use as the basis of the test scenarios, we found that XML RPC was far more widely implemented, and a decision was made to support this instead. So BDD is saving me time already.
To sum up the week, it's been a time of fun, intensive learning, but new questions are flooding in as fast as old ones are answered! I'm looking forward to finding out more next week.