Make a good feature description from a user story. Examples

This challenge deals with a common way of structuring feature file headers and scenario headers.

We write feature introductions in the user story format (As a… I want… So that…). Then we add scenarios related to different user personas and different user needs, and the original description no longer fits the contents. As the feature file grows, this becomes more and more wrong. Any ideas on structuring the story at the top to be more generic, but not too vague?

Here is the challenge

Gherkin, the format of Given-When-Then files, allows users to add any text after a scenario or a feature title, and just ignores it from an automation perspective. This is incredibly useful to provide more context for readers. Most online examples show the feature description in the Connextra user story format, such as the one below:

Feature: pending invoices report

  As a client account manager, 
  I want a report showing all pending (issued but unpaid) invoices for a client
  So that I can control control client credit risk

This usually works well when a feature is first introduced, since any new functionality should come with a clearly associated user need. But as more stories extend the feature, the connection between the feature and the stories becomes complicated.

For example, we might initially add a pending invoice report because an accounts manager wants it, in order to control client credit risk. But as the system grows, and we might add features to the pending invoice report that help accounts managers achieve other goals. A regular customer might be eligible for a discount, so client managers might want to know quarterly subtotals and averages to decide on discount amounts. Other types of users might want changes to the same report to achieve their own objectives. For example, call centre operators might need a few tweaks to solve client problems faster, or accountants might use it to prepare end-of-year tax returns. After a few such updates, the original value statement no longer captures the purpose for the feature. Teams sometimes try to make the user story at the top more and more generic, to encapsulate all the needs and personas, but then it becomes too vague.

The challenge for this week is: How to write a good description for a feature or a scenario? Think about a feature that evolved over time, potentially through dozens of stories or tasks. What are your ideas on how to structure those descriptions? Should they look like a user stories, or something else? What should they contain?

Solving: Should the feature description look like a user story?

The challenge was to provide guidelines for good context descriptions. The contextual descriptions in many books and online articles look similar to user stories. However, story-like descriptions get tricky for features that evolve over time. For a detailed explanation of the problem, check out the original post. This article contains an analysis of the community responses, and tips on more general approaches to solving similar problems.

Faith Peterson wrote two great responses to this challenge. The first looks at a more general issue of solving the right problem, identifying how “trying to write something vague is often an indication that something has gone wrong with my analysis.” She warns against describing solutions before understanding the real problem. Although not directly related to the challenge, I strongly recommend reading this article.

What makes a good feature or scenario description?

The context description, and this applies equally to features and scenarios, is there to provide additional information that is too long to keep in the title, but would be impractical to show in individual examples. The text in the context description should ideally help the readers and maintainers understand examples more easily and make good decisions about updating the data in the future.

Because the contextual descriptions do not get automated, they do not have to follow a rigid structure. You do not have to force yourself to fit it into any specific format. So, to answer the question from the title, related to user stories: it may, but it doesn’t, and often it should not.

User stories are a format for planning work, not for documenting features. Instead of abusing a story format for documentation, here are some tips for writing a good description:

  • Explain the purpose of a feature or scenario
  • Document complex business rules
  • Document important decisions about scope
  • Explain the structure of the examples
  • Avoid repeating the data
  • Predict questions about the examples and answer them

Explain the purpose of a feature or scenario

The opening statement of a feature file should talk about the purpose of that feature. Explain why that whole thing is needed, so that readers can know if they’re viewing the right file or not. This also helps immensely to set the stage for the scenarios.

If a user story fits that purpose, by all means use it. Very often, when adding a new feature or scenario, the initial story is a good way to capture the purpose. As the functionality grows, rewrite the context, clarify it, and throw away the parts that don’t make sense. Some people keep adding multiple story descriptions to the feature description, but this becomes too long and too boring very quickly.

Faith suggested restructuring feature files as the functionality evolves. One of the options in her post is to split up a feature file into a folder of files, each with a very specific purpose. This is a good way of dealing with a feature that grows in different ways, and various aspects of the functionality deal provide value to different people. If the same piece of functionality serves several purposes, then it’s better to rephrase or restructure stories into something else.

When restructuring work-item descriptions (such as stories) into feature descriptions, beware that they often need different levels of specificity. The original intent of user stories was to be a promise for a conversation. It’s OK, and even expected, to leave important details out of stories and iron them out during a discussion. Feature files should document the results of that conversation, not leave a bunch of questions open for further clarification.

When working with a feature that evolved to address the needs of multiple personas, sometimes people try to rephrase the user category into a more general one. Faith gives the example of “Report Consumers” or “Report Readers” which could imply all the various types of employees that access an invoice report, and shows how that’s too broad to help with understanding.

I prefer to list all the related roles, but perhaps in a different way. Usually, you can throw away the “I want” part of the user stories because it will be implied by the scenarios in the file. You can group the “So that” parts under personas, then remove duplicates or consolidate similar entries into a more general description. Instead of listing a dozen story blocks, focus on the big picture:

Feature: Account reporting

   The account reports are primarily used by account managers 
   to control client credit risk. They also use these reports
   to decide on eligibility for discounts and special deals.

   Other users include:
     * call centre operators, who use them to quickly look
       at recent transactions to assist clients when on call
     * accountants to audit end-of year tax reports

Scenario: …

Faith suggests writing a “narrative” instead of a story, and provides a great example identifying a persona, a need and the proposed solution in a much longer format.

Feature: Pending Invoice Report

  Sabine, an account manager, is responsible for maintaing Acme
  Financial's credit risk exposure within defined levels. One way
  she does this is to closely monitor whether customers who have a
  history of slow payment have paid their current invoices or if
  those invoices are at risk of becoming past due. When she does
  this, she wants to see a list of all customers with billing
  dates within the next three business days with invoices that are
  pending. (Pending means the invoice has been issued and payment
  has either not been received or not been settled.)

For very complex features, you can also use this kind of scoping introduction for individual scenarios or scenario outlines. For example, if there are some specific features introduced into the reports for call centre operators to assist clients quickly, list that in the introduction of the related scenarios only.

Document complex business rules

For scenario descriptions, documenting the purpose often means explaining the underlying business rule. Sometimes a single scenario is not enough to demonstrate a business rule, so it’s useful to provide a more general description of the rule for a whole group of scenarios. The feature file description is a good place to do that. Faith provides a nice example in her post:

Feature: Pending Invoice Report

  Rule: Account Managers may only see pending invoices 
       for their assigned customers
  Rule: Account management supervisors may see pending invoices 
       for customer assigned to the account managers they supervise

Note that Gherkin (the tool-independent language for Given-When-Then feature files) introduced a special keyword for grouping scenarios, Rule. Not all tools support it though, but Specflow does. The Rule keyword allows you to provide some context that applies to a set of scenarios, but not necessarily the whole feature file.

Document important decisions about scope

You can use the context descriptions to better manage the expectations of stakeholders or colleagues outside the immediate team. A good title should explain the overall business scope, but it cannot document design scope decisions. There’s just not enough space. If you’ve postponed some functionality in order to deliver an initial version faster, or agreed that something is completely out of scope, list it in the introduction of the file so people won’t bother you about it later. Explain questionable aspects of what’s in scope, what’s out and why. For example:

Feature: Account Reporting
  This feature explicitly excludes transactions from the legacy
  database, which will be added in a future iteration (Christian
  approved this by email on 13th January). 

This trick applies equally well to scenarios and scenario outlines. If you decided to exclude a class of examples from a scenario, you could in theory set up examples that show how the system rejects them, but that might be an overkill. Sometimes, it’s enough to just explain why they were excluded. For example:

Scenario Outline: Filtering by currency

  European currencies other than EUR are not listed below, since
  it's currently not possible to set up an EU account with a
  different currency through the user portal.  We may need to
  revisit this once the user portal is updated.

Explain the structure of the examples

If the examples are not self-explanatory, make sure to document the structure.Explain why important pieces of data are listed in scenarios, and why some other equally important fields are not there. Having the structure of the examples explicitly documented helps to focus the attention of the readers, and align everyone on the terminology and the model.

Feature: Account Reporting

  For risk assesment, we only use the Consolidated Net Amount,
  which is the after-tax value converted to the seller primary
  currency. The reports ignore delivery costs and tax.  These are
  not important for assessing risk but may vary by country, so
  including them could lead to complex calculations and misleading

Faith goes even further and suggests explicitly listing definitions of important terms in the description:

Feature: Pending Invoice Report

  Account Manager: person who manages Acme's relationship with
                 a specific set of customers
  Pending Invoice: invoice that has been issue but has not yet been paid

For simple feature files, where all the scenarios use the same structure, you can do this in the feature header. For more complicated feature files, it might be worth doing this in individual scenario descriptions.

Avoid repeating the data

A common way to mess up the scenario or feature description is to summarise the data from the examples. This is particularly important to remember if you want to document a business rule in a description.

When the scenario or feature context repeats the data from the examples, then it’s not adding information to the executable part of the specification but just complicating it. This is a common symptom of a problem that causes long-term maintenance headaches. Here is an example:

Scenario: risky accounts should be shown separately

Any client accounts with overall risk factor > 0.5 should be shown
on the 'Risky' tab

Given the following user accounts
| account id    | risk factor |
| low-1         | 0.10        |
| low-2         | 0.49        |
| at-limit-3    | 0.50        |
| above-limit-4 | 0.51        |
| high-risk-5   | 0.99        |
When the client account report is generated
Then the following accounts should appear in the 'Risky' category
| account id    | risk factor |
| at-limit-3    | 0.50        |
| above-limit-4 | 0.51        |
| high-risk-5   | 0.99        |

The issue with this scenario context is that it just gives us the same information again, in a different format. It does not provide any further information to understand the purpose or structure. Even worse, because the context description is not tied to an executable step, it is not easy to keep up-to-date with the rest of the system. If someone decides to change the limit in the future, they might update the examples but forget to update the context. This is a common cause of confusion when maintaining feature files.

It would be much better to make the context more generic and explain the purpose, so people can decide better in the future how to edit the examples. In addition, making the context more generic often forces people to think a bit harder about the model. What does this magical value 0.5 actually represent? This is another situation when the technique give it a good domain name helps. Identifying a good name, such as ‘account risk threshold’, makes it clear that this is a property of the model and allows us to design a system so it’s easier to change in the future. Here is one potential way of rewriting this scenario:

Scenario: risky accounts should be shown separately

  Client relationship managers need a quick way of identifying
  accounts that should not be allowed to get discounts, long
  payment terms or large credit. 

  We currently do not have specific risk factors for those three
  categories, but use the overall risk factor on the account (this
  is likely to change in the future). 

  The Risky tab of the account reports should list all accounts
  where the overall risk exceeds the account risk threshold, but
  only those accounts.

Given the risk threshold of 0.5
And the following user accounts
| account id    | risk factor |
| low-1         | 0.10        |
| low-2         | 0.49        |
| at-limit-3    | 0.50        |
| above-limit-4 | 0.51        |
| high-risk-5   | 0.99        |
When the client account report is generated
Then the following accounts should appear in the 'Risky' category
| account id    | risk factor |
| at-limit-3    | 0.50        |
| above-limit-4 | 0.51        |
| high-risk-5   | 0.99        |

If the risk threshold changes in the future, we don’t need to update or change any features or tests. By identifying it as a domain property, we can make the system configurable. Also, if the underlying logic needs to change, it’s easy to identify features that include the risk threshold and discuss how they should be updated. The scenario context will help us decide how to split it and re-write it. A generic “As a … In order to … I want …” statement would not come even close to that.

Predict questions about the examples and answer them

Of course, there are many more things you could add into the feature description. One of the best ways to describe the feature or scenario context is to check what kind of higher-level information is missing from the examples. After all, the free-form text is there to complement the executable examples and make them easy to understand. Show the feature file or a scenario to someone who did not participate in the specification workshop (discovery session, or collaborative analysis session). Find someone who understands the domain, but was not part of the discussions. Just show them the feature file, ask if they understand it, and keep quiet. See what kind of questions they ask, and try to answer them all in the context description. It’s very likely that someone reading the same file in the future might have similar questions, and having the answers ready will mean that they don’t have to chase you about it.

You can test if you’ve done this correctly by showing it so yet another person, and see if anything else is missing.

Use Markdown with Specflow

As an additional tip, some documentation tools can apply rich-text formatting to scenario and feature descriptions. For example, Specflow allows you to use Markdown to add links, embed images and format text better. When viewing the feature file with LivingDoc, the markdown syntax becomes HTML, allowing you to provide a lot more than just text with your living documentation. You could add web links to related features, or diagrams that explain the scope of a feature better.