This article is part of the Continuous Integration, Delivery and Deployment series.
Behavior-Driven Development (BDD) is a process or it can be a tool. In many cases, BDD is both. However, it should not be a goal in itself. The goal of software development is to deliver quality as fast and as cheap as possible. The only real measure of quality is whether it fulfills user needs in a reliable manner. The best way we can take to accomplish that goal is through continuous integration, deployment and delivery. For the sake of this article I will ignore the differences between those three and refer to all of them as continuous integration or CI.
CI is often misunderstood and BDD can provide a missing piece of the puzzle. It is usually implemented as a series of steps that are initiated with a commit to the repository, followed by software being built, statically checked, unit tested, integration tested and, finally delivered. With those steps we are confirming that the software always does what the team expects it to do.
The only way to accomplish this goal is to have the team work as a single unified body. Even though there is always some type of specialization and different profiles might have some level of autonomy (front-end and back-end developers, testers…) they must all work together from the start until the end. Often overlooked element in this picture is the client and the users. Having the software always working as expected can not be accomplished unless those that set the expectations are involved throughout the whole process. Who sets the expectations? Users do. They are the only ones who can say whether the application we’re building is a success or not. They define what should be built because it is their needs that we are trying to fulfill. This is where BDD comes in and creates a wrapper around our CI process.
With CI and BDD we can have the software that is always integrated in a way that fulfills expectations of our users instead doing what we think it should do. This sentence present small but very important difference. Whether software works as we expect it to work is not a goal we should aim for. It should do what users expect it to do. We do not set the expectations. Users do.
BDD replaces traditional requirements with executable specifications written by or in cooperation with customers and users and provides continuous feedback when executed as part of our CI process. While narrative and scenarios are a substitute for traditional requirements or user stories, automation of those scenarios is required for BDD to be fully integrated into the CI process. Narrative and scenarios are a process that through different tools can provide automation that we require. It is both a process and a tool.
Sprint 0 should be used to set up our tools and high level design (IDE, servers, architecture design…), CI server and the BDD framework. From there on we can start writing our BDD stories. Each of them, once written, should be taken by developers and implemented. If the story is pushed together with the implementation code, feedback obtained from the CI is almost immediate. That feedback is the piece often missing in order to have the successful implementation of the CI process. Having Jenkins (or any other similar framework) is not sufficient by itself. If we’re seeking to build reliable software continuously, final verification in the process must be based on some kind of integration and functional tests that confirm that user expectations are met. Otherwise, we’ll never have the confidence required for the decision to implement continuous deployment or delivery.
The question might arise why the feedback from unit tests is not good enough to provide us with information whether our software is working as expected. Unit tests are a must because they are fast to write and to execute. However, they are telling us whether all our units of code are working properly. They can not assure us that all those units are integrated into the functionality they compose.
How about other types of integration tests? If they are based on pure code, they can neither be written nor understood by the customer or users. Without them, integration tests are our assumption of what they want and might or might not be true. More over, since they must work in conjunction with requirements they represent duplication of work by providing two forms of the same concept. Requirements are tests often written in a different format. If requirements become executable, there is no need for separate artifacts.
If BDD is the replacement for requirements and integration tests, can we get rid of unit tests? Yes we can but we should not. Even though one can write BDD on all levels, using it instead of unit tests would increase drastically the amount of work. More over, it would complicate the communication with the customer and users. Keeping unit tests as a way to verify all combinations software can do on a unit level frees us to write BDD scenarios in a compact way that confirms the integration of those unit tests while providing good communication tool that acts as a final verification of functionalities we are developing.
Requirements themselves should be executable and that is what BDD is trying to accomplish. If integrated into the CI process, it provides the missing piece by converting the process that was continuously providing feedback regarding what we think should be developed to what the customer and users think should be developed. It is present throughout the whole process starting as a way to capture requirements, guide through the development and act as the final verification of the CI. It is the missing piece required to have a reliable delivery to production on a continuous basis.