Quality, Specification by Example

How to organize BDD Specifications

I have been using Specification by Example (a.k.a BDD, ATDD) for the last couple of years. This has helped bridge the gap between technical people and business people. It has also helped ramp up new members on our team, since we have a living documentation of the system. This isn’t always easy and we’re continuously looking for ways of improving the structure of our BDD specification files.  There are some questions that help us spot improvement points:

  • How easy is to have an overview of what the product does?
  • What are the main business areas of the product?
  • How easy is to find a specification?
  • How easy is to find related specifications?
  • How does this feature relate to that feature?
  • If you just point a new joiner to the specifications folder, will she have a decent idea of what the system does?

In this blog post I hope to give you a few tips that might help answer some of these questions. These aren’t new ideas, but I find them pretty effective.

User stories and features should be orthogonal

The first piece of advice (and the most important) doesn’t apply only to BDD, but to requirements in general. Treat user stories and features as orthogonal to each other. This is because they have different goals.

A feature describes the behavior of the product. It is helpful for understanding what the system should do and verifying that it does it. A feature is valuable for the entire lifespan of a product.

A user story on the other hand is a planning tool. It can help you plan and track work, but that’s it. After you’ve implemented it, you can throw it away. As a side note, how many times did you go back to user stories in Jira? How many times was the information still up to date? My guess is that doesn’t happen too often. This is because the functionality described in one user story might be changed by the next user story. Trying to understand a feature just from user stories is a daunting task.

Why is this important? Because some beginners start by adding a feature file for each user story. This might seem intuitive at first, as it is easy to track. But as you add more features, this structure becomes too complex to understand and maintain. A feature can be broken down into many user stories, but at the same time, a user story might touch many features. This structure doesn’t allow this flexibility.

Note:  If you’d like to find out more about this, Matt Wynne has a very good blog post on this subject.

Group features by business capability

If someone looks inside the specifications folder, can he figure out what kind of product you are building? What would you rather see: Sprint1, Sprint2? US134, US456? Or Products, Payment, Shipment? Or maybe Patients, Doctors, Appointments, Treatments? Or Players, Games, Rooms? I think you get the point here – always structure the features around business capabilities. (As a side note, Sandro Mancuso gave a great talk on how to structure your code base so that it answers two important questions: What is the application about? and What does the application do? He advocates that you should actually structure your codebase around business capabilities too. I recommend you watch this talk if you haven’t already).

By structuring your specification this way, it’s easy to have an overview of what are the main functional areas of the application. If you want to find out more about a given business capability, you can just browse the correct folder. This can go as many levels as necessary, with nodes being feature files. This gives you the ability to zoom in and out as required. Here is an example:

+---Payment
+---Products
\---Users
    +---Account
    |       ChangePassword.feature
    |       CloseAccount.feature
    |       ManageNotifications.feature
    |       ViewHistory.feature
    |
    +---Profile
    |       EditProfile.feature
    |       UpdatePrivacySettings.feature
    |       ViewProfile.feature
    |
    \---Wishlist
            AddToWishlist.feature
            ShareWishlist.feature

By looking at this you would imagine this is some kind of  eCommerce Store and you would have a good idea of what a user can do.

Of course, this isn’t always black or white. You might have one feature that might touch on more then one functional areas. Usually, the scale tilts in one direction, so put the feature in that folder. But how can you still link the feature to the other functional area? The answer is to…

Use Tags

Most of the BDD frameworks out there provide a way to tag your specifications. I think tags are a great way to add metadata to your feature files and group specifications. You can use tags for many reasons: reporting, traceability, technical or functional. Their main advantage is that you can create and use as many as you’d like. Of course, you can overdo it, but at least it’s easy to clean them up (comparing to changing the folder structure). In my opinion, their main disadvantage is that they may not be as self explanatory as a tree structure. You have to know beforehand what to look for and how to group the specifications using different tags. This is why you should standardize and document your tag classes and the reason why they exists.

Here are some scenarios in which tags are useful:

  • Link to a related business capability
  • Add links between features
  • Specify at what level is the specification test implemented (@Unit, @Integration, @UI)
  • Link a feature to a tracking ID (e.g. a user story ID). This can be useful if you want to know what user stories have touched a certain feature.
  • Specify in what step of your deployment pipeline (or on what environments) the specifications should run (@CI, @Test, @Acceptance, @Staging)
  • Group specifications in different test suites (@Smoke, @Critical, @Fast)

Keep all the specifications in a single location

I favor putting all my specification in a single project. There might be good reasons for splitting the specifications into multiple projects. One such reason could be to align the specifications with the test types. This way you would have all your specifications implemented at unit level in one project, the ones implemented at a service/integration level in another and the broad stack tests in yet another project. This makes sense, since the implementation looks very different, depending on the type of the test. But this structure is harder to read. And if we want the specifications to act as a living documentation, we should optimize for readability.

There are other more compelling reasons for splitting the specifications into multiple projects. But these should be functional, not technical. For example, if you’re following the Service Oriented Architectural style, it might be a good idea to have a specifications project for each service. This is because each service is focused on a specific business capability. Each service is autonomous and contains all the business rules. This makes it easy for a Marketing Expert to find all the features and business rules in Marketing. This does pose the question: what if my specification actually targets multiple services? I see this happening in practice less often then you may think. Most of the times it’s just a feature that wants to be split or a test case disguised as a feature.

Consider splitting command features from query features

When using CQRS, features could be split in two types: commands and queries. The command features contain most of the logic and describe all the business rules within a service.  They describe the behavior of the system and help you learn what the system does. Query features are less interesting since they describe querying/reporting capabilities. One could argue there is no benefit in having specification files for queries. This is a valid point and you could have regular tests for these. But, considering that queries are used as part of business flows, I say there still is some value in having specification files for them. Since commands and queries have different purposes, it might make sense to split the features in two different folders (e.g. Use Cases and Queries). This way you can clearly differentiate the business use cases from the reporting capabilities of the system.

Conclusion

These are some tips that might help you structure your BDD specification files. The main theme here is to think about the purpose of the specifications – to encourage collaboration and communication and their audience – everyone.  This should guide you in making the right decisions. And remember: when in doubt, favor readability.

If you’re just starting out with BDD or would like to find out more, I highly recommend Specification by Example: How Successful Teams Deliver the Right Software by Gojko Adzic.