One of the most common product development challenges is how to address the interplay among multiple competing factors. Examples of such competing considerations include articulating what customers want, translating customer needs into product creation, and surfacing any trade-offs.
Numerous techniques can help address product development challenges like these. In this article, we’ll take a closer look at one of those techniques — behavior-driven development.
Table of contents
- What is behavior-driven development?
- What are the 3 principles of behavior-driven development?
- BDD in practice: Understanding Gherkin
- The benefits of BDD
- The cons of BDD
- Things to consider when getting started with BDD
What is behavior-driven development?
Behavior-driven development (BDD) is a product management approach that focuses on defining the behavior of a system from the user’s perspective, using simple, domain-specific scripting language. BDD focuses on how users will use and interact with the product, encouraging everyone involved to work together to make sure it meets users’ needs.
In fact, practitioners of agile and lean software development employ numerous techniques that help them deliver products that align with customer expectations. Many such techniques fall under the general heading of test-first development. There is actually a a convention for identifying test-first development approaches by using acronyms, all of which end with “DD,” — short for “driven-development:”
- ATDD — Acceptance test-driven development
- BDD — Behavior-driven development
- TDD — Test-driven development
To begin with the most obvious question, “Why is it called behavior-driven development?” we need to go back to its origins in the early 2000s. While creating a replacement for the JUnit testing framework, Dan Terhorst-North made a key decision — to base the vocabulary and the thought process behind the new approach (to which he assigned the moniker JBehave) on user behaviors, rather than basing the vocabulary on tests.
Test-driven development, as its name implies, bases its vocabulary on unit test creation and execution.
Other early contributors to what we now know as BDD included Liz Keogh and Chris Matts. One of the distinguishing features of BDD, which helps distinguish it from other test-first development approaches, is its particularly strong emphasis on user behaviors and user goals. To enable us to emphasize user behaviors, the syntax of BDD (which we’ll revisit in greater detail later) is characterized by scenarios and related specifications that we can translate into executable tests.
What are the 3 principles of behavior-driven development?
BDD is a model where collaboration among the designers, builders, and testers is always at the forefront. With respect to BDD principles, let’s boil them down to these three:
1. What the software could do
It likely won’t come as a surprise to anyone who’s been involved with agile product development for a while that the first principle — what the software could do — is all about the discovery of what customers actually want. If and when we get this part right, we reduce the likelihood of making the mistake that plagues so many organizations and teams — building the wrong thing.
It is common among BDD practitioners to use conversations that are structured around what customers want, and a common term for these conversations is discovery workshop. During a discovery workshop, the participants do the following:
- Focus on real-world examples of customer needs and behaviors
- Surface any gaps in understanding customer needs and behaviors
- Get an early start on prioritization so that the team focuses first on building features with the greatest customer value/impact
Impact mapping is a particularly popular technique among practitioners of BDD during discovery. Impact mapping works well in a BDD context because it reinforces with team members, visually, what user outcomes are most important, and can also solidify team understanding of how the work aligns with broader organizational goals.
2. What the software should do
As discovery comes to an end, we shift our focus to collaboratively writing structured documentation that articulates those user needs. The structured documentation takes the form of an executable specification, where:
- It is both human- and computer-readable
- It enables automation
The form that the structured documentation takes is similar to the user story construct, in that everything that is needed to design, build, and test a particular story (a “scenario,” in BDD parlance) is in place.
It is particularly important that the specification includes examples, in given-when-then format, that describe the user behaviors that would be part of the user scenario that we are describing.
In BDD, it is common to split a team into sub-groups. This practice is analogous to what we sometimes see on scrum teams during activities such as backlog refinement. While recognizing that team composition can vary considerably, the idea is for each sub-group to have different skill sets and perspectives.
Thus, we might see a business analyst, a software engineer, and a quality engineer working together in a three amigos sub-group.
In much the same way that impact mapping is a helpful technique to teams practicing BDD, we find that story mapping is an excellent complementary technique as teams work through the specifications needed to deliver a particular feature.
Story mapping is particularly helpful because it is a visual technique that helps us avoid the “Can’t see the forest for the trees problem,” where it is easy to lose sight of the big picture when writing structured documentation.
3. What the software does
Using the executable specification as a guide, we now do the following as we create the software, where, one scenario at a time, we:
- Automate the desired behavior by connecting it to the system as a test
- Write the code based on lower-level examples of the desired behavior of system components
- Iteratively improve code and tests, checking for alignment with user objectives
For anywho who is familiar with test-driven development, it may be helpful to point out that the logical flow of activities we just described is similar to the thought process in TDD, often described using terminology such as:
- Write a failing test
- Write code that enables the test to pass
- Iteratively refactor the tests and the code
BDD in practice: Understanding Gherkin
It’s important to recognize that the specifics will differ when it comes to BDD implementation since there are many tools and programming languages any given team might be using. Given those differences, we can take a look at Gherkin, since the usage of Gherkin serves as a sort of common denominator across teams that practice BDD.
What is Gherkin?
Returning to what we said earlier, about the need for BDD specifications to be readable by both humans and computers, Gherkin gives us the language that we need to bridge that human-computer divide. To put it in the simplest terms possible, with Gherkin, we can:
- Capture a user scenario
- Articulate the tests that need to pass to validate that user scenario
In other words, Gherkin helps us connect the concept of cause and effect (which aligns well with how we think as humans) with the notion of inputs and outputs (which aligns well with how computers process instructions).
Gherkin is a line-oriented language, where each line is a “step,” and each step begins with a keyword. Let’s stick with the basic elements:
- Scenario — a descriptive summary of the user goal
- Given — a precondition associated with the scenario
- When — an event or trigger associated with that user scenario
- Then — the expected outcome from that user scenario
Suppose we’re talking about a user scenario of making a withdrawal from a bank account. The basic syntax for such a scenario might look something like this:
- Scenario — Withdrawal of money from an account with an existing minimum balance
- Given — I have the minimum balance in my account
- When — I request $50
- Then — $50 should be dispensed
The example above is quite simple by design, and one reason it is so simple is it only describes a “happy path.” In software development, the reality tends to be considerably more complicated, where we need to account for multiple scenarios before we can consider a feature to be complete. To account for this reality, we can extend our specification to include multiple scenarios for a particular feature.
Staying in the financial domain, we might therefore see syntax such as the following for various error conditions that we can expect to see for an online credit card transaction. We’ve added a top-level feature and we’re using the same “given” statement across all of the scenarios that are part of the feature, preceded by the background keyword:
- Feature — Provide feedback when there is a mistake in entering credit card details:
- Background — I have chosen some items and put them in my cart and I am using a credit card to buy the items
- Scenario — The customer enters a credit card number that is less than 16 digits
- When — I enter a credit card number that’s less than 16 digits in length
- And all the other details that I enter are correct
- And I click the button to process my payment
- Then — The check-out page refreshes
- And I see a message telling me that I entered a credit number that is less than 16 digits long
Then, we move on to:
- Scenario — The customer enters four digits in the CVV field when using a MasterCard, Visa, or Discover credit card
- When — I enter four digits in the CVV field
- And all of the other credit card details that I enter are correct
- And I click the button to process my payment
- Then — The check-out page refreshes
- And I should see a message telling me that I entered a four-digit code in the CVV field
In the example above, we’ve shown most of the keywords that we can use in Gherkin — “feature,” “background,” “given,” “when,” “then,” and “and.”
There are a few other keywords that are available which we won’t cover here — “but,” “scenario outline,” and “examples” — plus a wildcard (*) option.
Putting it all together
Regardless of which test runner we’re using, as long as the following basic elements are in place, the test runner will consider the Gherkin syntax to be valid for any given feature, provided that:
- The file name follows an accepted convention (in our example above, it might be credit_card_details_mistake feature)
- The file begins with the “feature” keyword
- The “feature” keyword is followed by one of the following keywords:
- “Scenario outline”
- Subsequent keywords appear on separate lines
Note that there are additional considerations we need to consider when writing specifications in Gherkin. What we’ve just described is enough to get started.
The benefits of BDD
As is the case with any approach we might try, we must understand the potential benefits and pitfalls associated with BDD.
Here are some examples of benefits that are often associated with BDD:
- Improved understanding of user goals and behaviors
- Enhanced intra-team collaboration
- High level of test coverage
- Test automation friendliness
- Syntax supports code reuse
- Reduced likelihood for rework
Improved understanding of user goals and behaviors
Because BDD is so user-centric, teams that practice it gain a better appreciation for the user community that they serve.
Enhanced intra-team collaboration
Members of teams using BDD interact with one another early and often as they design, build, and test features.
High level of test coverage
Because an initial set of tests is present from the very beginning, teams have a solid framework on which to build other forms of tests.
Test automation friendliness
Teams that practice BDD can reduce the number of manual tests that they need to run.
Syntax supports code reuse
Once teams have mastered the basic syntax, repurposing existing scenarios and the associated code tends to become considerably easier.
Reduced likelihood for rework
The earlier that we see the need for changes, the less they cost, and with BDD, we’re more likely to make such changes early in the development cycle.
The cons of BDD
We need to also be realistic about the nature of our team context when considering BDD. The following constitute examples of headwinds we may encounter:
- High level of business engagement
- Lack of compatibility with traditional software development
- May slow you down before speeding up
- Early team misalignment
High level of business engagement
As is the case with agile approaches to software development in general, one or more people with deep business domain knowledge need to be available to work with the team(s) on an ongoing basis — a reality that some organizations are not able or willing to support.
Lack of compatibility with traditional software development
In many medium to large organizations, it is common to see more than one approach where some teams might still be following a more traditional software development. Teams practicing BDD will look and feel out of step with those more traditional teams.
May slow you down before speeding up
Unless team(s) have some history with some form of test-first development, it will take time for team members to learn how to work this way.
Early team misalignment
Introducing any type of significant change in a team context requires coaching and paying close attention to team signals on an ongoing basis.
Things to consider when getting started with BDD
There are many things we need to consider before deciding to try BDD. Among the things we’ll need to consider:
The extent to which BDD might be a potential fit depends to a considerable extent on what our organization looks like, including how our teams operate. If agile ways of working are reasonably well-established, and especially if we have one or more teams that already have done some form of test-first development, then we’re reasonably well-positioned to try BDD.
Conversely, if our organization is just embarking on an agile journey, then we’re likely to face a much steeper uphill climb to try BDD.
As far as specific teams are concerned, and how good a fit BDD might be for any particular team, asking these questions can help us set ourselves up for success:
- What challenge(s) do we hope to address by trying BDD?
- How familiar is the business domain that our team(s) is/are working in?
- How familiar is the software tooling that our team(s) plan to use?
- How much schedule pressure is there? As with anything new, it takes time to learn BDD
- How much experience and expertise is there on the team(s) with any form of test-first development?
- Who is available to work with the team(s) as a coach, and for how long a period?
The nature of the approval that we’ll need to have in place depends to a significant extent on how wide the “blast radius” is for our introduction of BDD. If we plan to try BDD on a single team, often to address specific challenges that the team is facing, then the set of stakeholders is likely reasonably small that we’ll need to consult with.
If, however, we plan to introduce BDD across multiple teams at the same time (for example, all teams in a particular business unit), then the nature of the conversations we’ll need to have to get stakeholder buy-in will look considerably different.
No matter what approach we might choose to take, we’ll need to be able to articulate the following things to stakeholders:
- What outcomes do we expect to achieve by trying BDD
- How long do we expect our initial experimentation with BDD to last
- What the expected costs are in association with trying BDD
- How we’ll know whether we’ve achieved our initial objectives
The bottom line is, when it comes to expectation-setting, we need to be realistic and transparent:
- Realistic — As with anything new, there is a learning curve with BDD, and it will take time for the team(s) to get comfortable with working this way
- Transparent — Letting stakeholders know how are things are going with the experiment, including what we’ve learned, will have a huge impact on the extent to which BDD takes hold
As is true with software tools in general, what constitutes the best tool for use in a BDD context depends on several variables, such as:
- Open source via closed source — In some organizations, security (and other) considerations might dictate that closed source tools be used, for example
- Integrations — Among the most important integration considerations include how well the BDD tooling plays with continuous integration (CI) and continuous delivery/continuous deployment (CD) pipelines and with application lifecycle management (ALM) tooling, such as products offered by Atlassian, Microsoft, or IBM
- Programming language(s) — Which programming language(s) that teams are using has a lot to do with BDD tool selection. Here are some programming-language-specific examples of popular BDD tooling:
- Java/JVM: Cucumber-JVM, JBehave
- .Net/C#: Specflow, xBehave.net
- php: Behat, Codeception
- Python: behave, Pytest-BDD
- Ruby: Cucumber
Many organizations have achieved success with one or more forms of test-first development. Organizations with at least some exposure to lean and agile ways of working can expect to be able to realize the benefits of experimenting with BDD, while also recognizing what challenges they might need to overcome.
By recognizing the basic principles associated with BDD, we put ourselves in a better position to actually deliver software that helps our customers achieve the goals that are most important to them. And in the process of doing so, we can realize other benefits, such as a high level of team understanding and alignment.
Featured image source: IconScout
LogRocket generates product insights that lead to meaningful action
LogRocket identifies friction points in the user experience so you can make informed decisions about product and design changes that must happen to hit your goals.
With LogRocket, you can understand the scope of the issues affecting your product and prioritize the changes that need to be made. LogRocket simplifies workflows by allowing Engineering, Product, UX, and Design teams to work from the same data as you, eliminating any confusion about what needs to be done.
Get your teams on the same page — try LogRocket today.