Tom Egan

Writing Business Rules With Gherkin

My industry has a dirty secret; programming is the easy part of software engineering. The hard part is coding the right thing. If a programmer added code for a flight simulator to Microsoft Excel, we could call it bloat or an easter egg. If a programmer working in 1751 England (Julian calendar) added code to a project to calculate the difference in dates but their client was in France (Gregorian calendar) the programmer's personal experience with dates might lead them to write the wrong code. My industry has a second dirty secret; these issues are not always the programmer's fault. All too often a programmer is asked to go code something with little direction and amazingly those programmers often arrive at reasonable code.

As developers sometimes we don't stop to ask clients when their are gaps in a design. Either the client has made it clear that they just want something yesterday or the blithely wave off our concerns trusting our judgement. We do our best but sometimes we make the wrong assumptions; we design user interfaces we would be comfortable using, we get caught up in the latest trend (cloud computing, dark mode, containers) or we simply use the algorithm we are familiar with, though the client's needs dictate a different algorithm.

Over the years many systems have been proposed for specifying what to code. Design documents, rapid iteration, user stories, and business rules all have strengths and weaknesses. What they have in common is that they are tools, tools which take skill to wield. Experience has shown that we can lower the learning curve for these tools by introducing formalities. At my day job, my team has embarked on using Gherkin for writing business rules.

At first, a lack of relevant examples held us back. Later, we found ourselves working against the syntax. But over time we have learned a number of lessons both about what works and what doesn't. Allow me to share with you what I have learned.

Behavior Driven Development

User stories and business rules form the basis of Behavior Driven Development (BDD). Thus it helps to have an understanding of behavior driven development to get the most from business rules and a formal system for business rules like Gherkin.

The core thesis of behavior driven development is that the experience of the end user is of paramount importance and thus that experience is what an organizing contracting for the development will want to specify. How the user experience is specified is by writing business rules. However, business rules should not be written in a vacuum as they must account for the desires of the end user. User stories are employed as a formalism for the thought experiment where we place our selves is our user's shoes and think through what they want.

Sadly, user stories, in my experience, are almost always a chance for organizations to lie to themselves. Thus I'm going to skip user stories for today and assume you have engaged with your users in an honest and open way and therefore have an idea what your users want. Perhaps:

As an administrator I want to restrict the use of equipment in my machine shop to users who have completed safety training so that unsafe usage of equipment is prohibited As a user I want to be able to use equipment so that I may craft things

From the behavior driven development perspective, business rules codify user stories as a set of tests we may run to determine if a system meets the needs of the contracting organization and the desires of end users. From the perspective of a developer, business rules specify an interface that a product must satisfy. In the user stories above there is much left unsaid such as how a user proves their identity to the system and whether the administrator grants permission to use equipment, revokes permission to use equipment, or both. Perhaps a smart card is given to a user and the administrator endorses those smart cards with a token that grants usage to equipment. Or perhaps the equipment is to be connected to the internet and user permissions are to be tracked in a database. These questions must be covered by business rules. Should the user permissions be tracked in a database there is no indication if it is an SQL or NoSQL database. If the type of database does not matter to the contracting organization, it can be omitted from the business rules.

A Quick Review of Gherkin Syntax

While there is a complete reference to the Gherkin, in my experience I have found that both programmers and non programmers alike often jump in to writing business rules by copy and pasting an existing example and winging it. If, like my day job, you are not using tooling like Cucumber Studio or Behat to drive testing you may be able to get away with winging it. Something we learned however was that in winging it we made mistakes that made our business rules something of a hodgepodge mess that look formal but are simply hard to read and understand. Consider this our first lesson learned: "write valid Gherkin". Therefore before we dive into lessons learns let's first look at how to write business rules with a subset of Gherkin.

First, Gherkin attempts to read like prose. Most lines begin with a keyword, the tag mark, or the comment mark. The Feature:, Rule: and Scenario: keywords all introduce a grouping of lines. Lines within a group are indented one level past the line which introduced the group. Organizationally, Gherkin assumes you have decomposed systems into features which are build from business rules which are in turn specified by illustrative example.

The Feature: keyword must begin a line and is followed by a short description of the feature. Additionally, each feature may include freeform text before the first business rule.

Feature: Managing user permissions Administrators may use the web portal to manage the permissions assigned to users. Rule:

Prior to version 6 of Gherkin, a Feature: would consist of one or more Scenario: blocks leaving users to group those blocks into rules using tags or comments. The Rule: keyword followed by a short description of the rule provides an additional level of grouping for related Scenario: blocks.

Feature: Managing user permissions … Rule: Only administrators may manage permissions Scenario:Scenario:Rule: Users are assign permission to activate types of equipment Scenario:Scenario:

The complete reference builds business rules using the Example: keyword probably because the academic work introducing behavior driven development conceived of business rules as specification by example. I am however going to be using the synonymous Scenario: for reason I'll discuss later. Each Scenario: specifies one test that a system must pass for acceptance.

A test is specified as a situation (Given), a user action (When), and the expected result (Then). Some situations and results may take multiple sentences to completely detail. Gherkin provides the And or * keyword to introduce these lines.

Feature: Managing user permissions … Rule: Only administrators may manage permissions Scenario: Administrators may manage user permissions Given an authenticated user And the user is an administrator When the user request a permissions change Then the permission change is saved to the database

With these building blocks it is possible to write sound business rules but despite Gherkin trying to be readable prose sometimes we need just a bit more explanation. For that we have tags and comments. Tags start with @ and appear on the line before a Feature:, Rule: and Scenario: line. Common uses of tags are to indicate the version of a system which introduced a feature, or rule; to indicate that a feature, rule, or scenario is planned but not implemented; or to indicate that for now, testing of a feature, rule, or scenario may be skipped. A comment line begins with # and is used to provide context to a feature, rule, or scenario.

Putting it all together:

Feature: Managing user permissions Administrators may use the web portal to manage the permissions assigned to users. Rule: Only administrators may manage permissions Scenario: Administrators may manage user permissions Given an authenticated user And the user is an administrator When the user request a permissions change Then the permission change is saved to the database Scenario: Non administrators may not manage user permissions Given an authenticated user And the user is not an administrator When the user request a permissions change Then the permission change is not saved to the database Rule: Users are assign permission to activate types of equipment Scenario: Administrators may grant a user permission to use a type of equipment Given an authenticated user And the user is an administrator When the user grants other users permission to use a type of equipment Then those users may power on that equipment Scenario: Administrators may revoke a user's permission to use a type of equipment Given an authenticated user And the user is an administrator When the user revokes other users permission to use a type of equipment Then those users may not power on that equipment @no-test # A power down process must be employed with some equipment thus # simply cutting power to the equipment would be more unsafe # than allowing the equipment to remain powered on. Scenario: Permissions are only enforced when a user starts equipment Given a user has powered on equipment of a particular type When an administrator revokes the user's permission for that equipment type Then equipment remains powered on.

Best Practices for Business Rules

Adding formality can lower a learning curve but rarely does it eliminate the learning curve. With a few minutes introduction is is possible to begin writing business rules using Gherkin, they may even be soundly written but in my experience it takes a bit of practice. Therefore, I encourage you try writing some business rules for a fictitious system. I think you'll find you eventually fall into a sort of rhythm. It is when a developer tries to put those rules into practice though that experience will show. From my experience there are some best practices that will help you write business rules useful to developers

Avoid Abbreviations and Acronyms

Because Gherkin does not give us the option to wrap lines there is a temptation ot write shorter lines by abbreviating words or using acronyms. They may be common jargon for the contracting organization or the developer but often these parties will not share the same jargon. You are taking the time to specify business rules after all to avoid misunderstandings. Does EOD stand for end of data or end of day? Acronyms are similarly troublesome. Some trade groups and organizations, insist that their official name is their acronym. Sometimes an organization name is also reduced to an acronym in the name of a standard such as ISO-9660 or ECMA-262. It is an uncommon reader who will know those standards by those names however, and it is more readable to use the colloquial names "compact disc" and "javascript"

Avoid abbreviations in business rules. In the limited case of an acronym having become an official name e.g. ICANN, IEEE; it may be acceptable to use the acronym. However, when providing the name of a standard include a link to the standard in a comment so that all parties know exactly which standard and version of the standard are being referenced.

Feature: Authentication Users may authenticate via our authentication microservice or OAUTH (https://oauth.net/2/) with our identity providers. …

Keep it simple

Keeping it simple comes up often enough that someone ought to come up for an acronym for it. With business rules written in Gherkin, it can be tempting to write long complex sentences however, this can make your business rules less readable as Gherkin does not offer a strategy for wrapping lines or breaking up long lines. At first, I thought this was an oversight but as I became more practiced writing business rules in Gherkin I realized that long lines are actually a sign that I need to reconsider what I have written.

Occasionally, especially for Feature:, Rule: and Scenario: lines, the long line is unavoidable. In these cases, I write a comment above the Feature:, Rule: or Scenario: line to explain it.

Feature: Access Tokens … # Plain english: our client can choose whether users under their account # can create the authentication tokens needed for configuring third- # -party access i.e. integrations or if that privilege is reserved for # the administrator. Rule: Only tenant administrators may set the tenant policy determining whether tenant users may create integration tokens. …

When a Given or Then line becomes long, consider breaking the line up. Perhaps it is two or more conditions. By trying to be readable prose, Gherkin sometimes tricks us into writing multiple conditions on one line as a series

Feature: … … Rule:Scenario:Given a user who is an administrator, has a valid email address, and has requested that they receive notifications by email WhenThen

when instead we should break this line up as:

Feature: … … Rule:Scenario:Given a user who is an administrator And the user has a valid email address And the user has requested that they receive notifications by email WhenThen

Be careful, however, because

Feature: … … Rule:Scenario:Given a user who is an administrator And a user who has a valid email address And a user who user has requested that they receive notifications by email WhenThen

is not the same. In the later wording, the user who is an administrator need not be the same user as the user with a valid email address or the user who has requested to be notified by email.

Contrary to the guidance given in the complete reference I prefer to indent with tabs and set my editor to display tabs as being four characters wide. I find this to be more readable than the recommended two character wide indents and by using tabs I leave the choice of how large indentations appear to the reader. That said, I consider any line extending past the 120 character mark to be suspicious. When lines get too long, they become harder to read and are likely to hide complexity which has not been given sufficient thought. Long lines are often a warning sign that the system being described can be further decomposed into shorter simpler business rules. Alternatively, it could be that the business rules are that complex but maybe that indicates that the system you are specifying will be so complex as to be confusing to the end user.

Like long lines, Scenario: statements with a large number of lines especially Given lines can make it difficult to understand a business rule. Gherkin does provide the Background: keyword for when all scenarios in a Feature: or Rule: have a number of the same Given lines allowing us to move those lines out of each Scenario: which can help. However, I have rarely encountered a place where the Background: keyword made a significant difference. Instead, I have found that when a Scenario: includes more than about seven Given lines keeping track of the situation being described requires tools other than the business rule and it is often a sign of a design problem.

An excessive number of Given lines can sometimes be helped by splitting a scenario up into multiple scenarios. Real world systems can be complex. Write as many scenarios as you need to fully describe a Rule:.

Use Rule

Prior to version 6 of the Gherkin language, Scenario: and Example: statements could only be grouped by Feature:. This was okay if a Feature: had only a handful of Scenario: and Example: statements but it also encouraged authors to write overly complex Scenario: and Example: statements. Fortunately, with version 6, the Gherkin specification added a new keyword: Rule: which can be used to group Scenario: and Example: statements. While there is no requirement that you use Rule: I have found that when I write what I find to be a well scoped Feature:, I typically end up with a dozen or more Scenario: statements and if I don't group them using Rule: they all just sort of blend together making it hard te remember if I have already covered a scenario. As a bonus, many text editor will allow you to "fold" Gherkin files at the Rule hiding the Scenario: statements away and allowing you to get an overview of the feature. I use this quite often as a starting point when I am coming up to speed on a feature I have been asked to implement.

Avoid Specifying Literals

The complete reference provides Gherkin examples using the Example: keyword and notably providing literal values in the examples. I believe this is a conscious choice on the part of the authors and fits both with the behavior driven development idea of making it easy for non-developers to write business rules and because of the focus on business rules powering automated testing. If you are using your business rules to power automated testing it makes some sense to provide real world values in the rule as those values are passed into the code. However, something is lost when real world values are used. By giving concrete examples we forget to think abstractly about boundary conditions. What happens as a value approaches zero or the maximum value for a 32 bit integer may sound like something out of a math class, but at a fundamental level, systems engineering is about translating the fuzzy nature of the world as experienced by humans into mathematics as experienced by a computer.

It is not my intent to demand that we lock those without a programming background out of software development. But when it comes to designing reliable systems we need to explore boundary conditions and specify what happens not just at some example value but what happens for all values. By all means start with Example: and concrete values if that is what it takes to get the first draft of you business rule written. But developers should be cautious when asked develop a system specified in that way. For that reason I consider business rules using Example: and concrete values to be a rough draft and attempt to convert them to Scenario: and more generic value names before accepting them into a project.

For example:

Feature: Bank Account … … Rule: Deposits Scenario: User deposits $4.32 into their account Given a user And the user has $10.53 in their account When the user deposits $4.32 into their account Then the user's account has a balance of $14.85

does not cover what happens if a user tries to deposit a negative amount or a very large amount. We might think these to be silly situations but a computer doesn't know that. I find it better to rewrite this rule as:

Feature: Bank Account … … Rule: Deposits Scenario: User deposits an amount less than or equal to $0.00 Given a user And the user has an account When the user deposits an amount less than or equal to $0.00 Then the user's account balance is unchanged Scenario: User deposits an amount under the Bank Secrecy Act limit into their account Given a user And the user has an account And the user has an amount to deposit less than the Bank Secrecy Act limit When the user deposits that amount into their account Then the user's account has a balance equal to the sum of the previous amount plus the amount of the deposit. Scenario: User deposits an amount greater than or equal to the Bank Secrecy Act limit into their account Given a user And the user has an account And the user has an amount to deposit greater than or equal to the Bank Secrecy Act limit When the user deposits that amount into their account Then the user's account balance is unchanged And the user's account has a pending balance equal to the sum of the previous amount plus the amount of the deposit.

Notice I did not eliminate all literal values. However, the literal value that is left, $0.00 sticks out as it is a boundary value and something to pay attention to in testing. I also provided additional rules which start to capture the complexity of dealing with large deposits.

Contrary Scenarios

One mistake I see designers make is that they will describe only the successful code path. They often neglect to specify what happens in other circumstances. Software that only handles success tends to feel brittle to the end user. It is always breaking unexpectedly and without explanation. Such software is a chore to use and users will avoid using it or switch to competing products if they can. Instead of writing:

Feature: Access TokensRule: Creating Access Tokens Scenario: Administrators may create access tokens Given an authenticated user And the user is the tenant administrator When the user requests a new access token Then an access token is provisioned Scenario: Users may create access tokens Given an authenticated user And the user is not the tenant administrator And the tenant policy allows users to create access tokens When the user requests a new access token Then an access token is provisioned

write:

Feature: Access TokensRule: Creating Access Tokens Scenario: Administrators may create access tokens Given an authenticated user And the user is the tenant administrator When the user requests a new access token Then an access token is provisioned Scenario: Users may create access tokens if allowed by policy Given an authenticated user And the user is not the tenant administrator And the tenant policy allows users to create access tokens When the user requests a new access token Then an access token is provisioned Scenario: Users may not create access tokens if disallowed by policy Given an authenticated user And the user is not the tenant administrator And the tenant policy disallows users to create access tokens When the user requests a new access token Then an access token is not provisioned And the user is instructed to contact their tenant administrator to create an access token

Write a good description

There is a tension in software development between making code readable and annotating it well. On the one side there are those who argue that comments are lies waiting to happen and on the other side there are those that profess that code is so low level that it does a fair job of expressing implementation to a computer and a terrible job at expressing what is happening to a human. Business rules are not code but they have some of the same characteristics. In my opinion as a programmer, business rules, when well written, are detail oriented. But business rules that are detail oriented can fail to communicate the bigger picture, the utility of a feature leaving readers who are not programmers confused or even push them out of the process. The description for a feature or rule is the ideal place to bridge this divide.

Descriptions are free form text and I try to always start with a sentence or two summarizing a feature. One practice I have found useful is including definitions in feature descriptions. I even have a scheme where I start with Definition: and then list terms one per line and indented one level past the Definition:. While not part of the Gherkin standard I find the aesthetics appealing.

Feature: Account Balance Low Notification Account Balance Low Notifications are sent to users when their balance falls below the threshold set by the Makerspace administrator. Definitions: Account Balance: the unspent funds which a user has deposited with the makerspace and is debited when the user employs makerspace machinery requiring payment. Amazon SES: the service, a part of Amazon Web Services, used by the Portalbox system when powered by Amazon Web Services (AWS) ta send email to users of the system. Rule: Setting the Account Balance Low Notification threshold …