RSS Feed
Download our iPhone app
Browse DevX
Sign up for e-mail newsletters from DevX


Achieve the Best of Two Worlds with Behavior-Driven Development : Page 3

Both Extreme Programming and Scrum are more effective when practiced together—and even more effective when combined to form Behavior-Driven Development.

Example User Story
You'll usually write user stories according to the following template:

   As a <role> I want to <goal> so that <motivation>.
The following example user story reflects requirements for a funds transfer between two bank accounts. After having a discussion with the customer, the following requirement surfaced:

   As an account holder, I want to transfer funds
   between two of my accounts.
To help provide more context to the story, you should discuss with users why they want to do a funds transfer. Although the reasons for doing a funds transfer seem self-evident, suppose that you discussed this with the user a few times to try and surface the motivation. Often, it's these aspects of a story that seem so self evident that are ultimately not so evident at all when you try to express them.

Here's the full story with the motivation expressed by the customer:

   As an account holder, I want to transfer funds
   between two of my accounts so that I can maximize
   the performance of my savings and avoid any fees
   associated with overdrafts and minimum balance rules.
Now that you have the motivation, you have a more enriched understanding of the system's context and the user's concerns. This lets you operate in a knowledge-rich environment. Having a grasp of the user's concerns helps you shape a good user experience and clarify the customer's expectations.

So far you've identified the users as "account holders." This differentiates them from any of a number of other user roles that might be able to transfer funds using this system. For example, a teller or a bank manager can probably execute a funds transfer, but the constraints on the behavior of the software might be different for those user roles.

The differentiation of roles gives you a mental framework for considering a user's particular needs and assess whether his role and his particular motivation might require you to write specific code to address any unique needs.

It's not necessary to write any hooks in the code for possible variations that the story might be hinting at. Test-Driven Development allows you greater reversibility of decisions, so it's not necessary to overindulge in the kind of pre-emptive coding; you can just as easily deal with that later. In agile parlance, this is referred to as YAGNI, which stands for "You Ain't Gonna Need It."

The YAGNI guiding principle keeps you from adding hooks and extension points to the code until you have concrete, present requirements in the code directing you to do so, and pulling the code in that direction. YAGNI is a form of waste. In lean production terms, this form of waste is called over-processing.

User Stories Are Conversations
TDD developers think of user stories as placeholders for conversations that they purposefully keep terse. User stories aren't exhaustive requirements specifications, and they're not supposed to be.

Because user stories aren't exhaustive, we can do requirements specification interactively and incrementally in concert with the customer throughout the project rather than in one big analysis activity as is done in phased waterfall-styled software production. User stories are a form of software requirement that help teams do the software development process in a just-in-time fashion.

User stories may remain somewhat undefined and abstract while they remain in the product backlog. As the project team chooses stories for implementation in the next iteration, they flesh out a story's details. This is how detailed analysis and design get started in agile projects.

A team surfaces a story's acceptance criteria though conversations with the customer and the architect or technical lead. Other members of the team may participate, but it's not always efficient to do this kind of work in a large committee. Regardless, the rest of the team will have an opportunity to have their say during the iteration planning and estimation session.

During iteration planning, the customer and the development team sit down to discuss the stories and the customer's expectations of the implementation. At this point even further design details can-and usually do-surface.

Based on a reasonable understanding of the design details and constraints, the development team estimates the amount of work they need to do to implement a user story. Sometimes the development team will discover that a user story is too big and must be broken up. Sometimes smaller stories are conjoined, and sometimes entirely new stories are surfaced.

All this is done in conversation with the customer. When the iteration planning session is done, the team has generated and communicated a tremendous amount of shared understanding about the stories and their expectations.

Still, there might be grey areas that surface while the team is turning the story into software. Subsequent ad hoc conversations between the customer and the development team ensue. And again, these conversations can include any number of members of the team or the whole team.

It's important to note that because the members of an agile team all work together in a common space, many conversations happen out in the open and even folks not directly involved in a conversation might interject if necessary.

Requirements and design constraints are communicated and held through conversation and shared understanding. That doesn't prevent architecture and modeling from taking place as a result of these conversations, nor does it inhibit generation of harder artifacts, but the starting point for these artifacts are user stories and the conversations they engender throughout the project.

Contexts and Specifications
Acceptance criteria are story specifications written in plain language, transformed into lower-level specifications written in code, and executed using a testing or specification framework.

After talking in greater detail with the customer about his expectations for the funds transfer, the following three acceptance criteria surfaced:

   The amount of the transfer is debited from the "from"
   account and credited to the "to" account
   The "from" and "to" accounts are different accounts
   Cannot transfer an amount greater than the balance of the
   "from" account
These acceptance criteria are the starting points for test-first programming. The development team can translate these criteria into specifications that in the team will write as code and implement using Test-Driven Development.

Members of the team will gather sets of related observations (tests) into contexts. Contexts aren't simply arbitrary groupings; they are representations of cohesive and consistent circumstances that software modules can be found in. TDD teams use contexts to describe anything from system states to user experiences.

The examples that follow present context specifications as having concerns, contexts, and observations.

Consider the first acceptance criteria: The amount of the transfer is debited from the "from" account and credited to the "to" account. Here's a first cut at representing the acceptance criteria as a description, based on a concern, a context, and observations:

   Concern: Funds Transfer
   Context: When transfering between two accounts
   Observation: The amount is debited from the "from" account
   Observation: The amount is credited to the "to" account
Here's a context-based description of the second acceptance criteria, "The 'from' and 'to' accounts are different accounts:"

   Concern: Funds Transfer
   Context: When transfering between two accounts where the
   accounts are the same account
   Observation: The transfer is not allowed
This brings up the issue of the sameness or equality of two accounts. It suggests a need for a means to determine whether two accounts are the same.

After discussing this with the customer, it was determined that two accounts are the same account if they have the same account number. So the team added new acceptance criteria to the story.

   Accounts are equal if they have the same account number
Below you can see the derived context-based representation of the criteria:

   Concern: Account Equality
   Context: When determining whether two accounts are the
   Observation: The accounts are equal when they have the
   same account number
   Observation: The accounts are not equal when they have
   different account numbers 
The last criteria is, Cannot transfer an amount greater than the balance of the "from" account. Here is the specification:

   Concern: Funds Transfer
   Context: When the balance of the "from" account is less
   than the amount of the transfer
   Observation: The transfer is not allowed
It's not necessary to go through the motions of reformatting acceptance criteria as contexts and specifications before getting down to the work of writing code.

Usually, the acceptance criteria are taken directly from the form written by the customer in the customer's comfortable language, and translated directly into code by the developer who uses the customer's specified criteria and any notes that he's made in the conversation with the customer to get into any greater details.

It's not even necessary to transcribe the acceptance criteria addressing account equality to the list of criteria that are formally associated with the user story. This level of specification might be deemed to be far too low-level for the story's acceptance criteria.

You aren't trying to achieve seamless traceability of requirements with user stories and acceptance criteria. You're capturing just enough specification to get the work started.

Any new criteria that surface in the process of elaborating on a user story in code are captured directly in code, and can be communicated back to the customer later if necessary.

Executable Specifications
Sooner or later the conversations have to subside and the team has to write some software. As mentioned earlier, the team will do their coding using a client-driven approach like Test-Driven Development.

I didn't write this article to rehash a decade of material on Test-Driven Development, but rather to demonstrate how to use the user stories and Test-Driven Development to forge tighter bonds and smoother transitions between user stories and conversations, and TDD through increased feedback and communication.

Test-Driven Development is a form of executable specification. Teams use TDD and test-first programming in Behavior-Driven Development to turn a story's acceptance criteria into example code that specifies the application code that the story requires.

Close Icon
Thanks for your registration, follow us on our social networks to keep up-to-date