Specification by Example

Ealden Escañan
Ealden Escañan
Published in
6 min readApr 19, 2020

--

Shared understanding at the 2020 Odd-e Gathering in Sydney, Australia

Specification by Example is a really powerful practice for teams to collaborate and gain a shared understanding in the products and features they create. This forms the core of our Stories to Specifications and Modern Agile Engineering Practices workshops, and I use this practice heavily with the teams I coach and work with.

This week, I decided to work on a small application so I can practice Specification by Example and further refine my approach. I also used this opportunity to learn more about Spring Boot and Vue.js, as well as find out how to best apply Specification by Example with them.

I did Emerson’s Game, which is a racing game that my colleague Emerson (not in the picture above) made a few years back. It’s a short, fun game, that teaches you proper software engineering and why we should focus on quality. I gave a talk on this last year at Software Crafters Manila (slides).

I’ve published my code at Github. The feature file and step definition are available, and I have an instance up at Heroku (free) as well.

The rules of Emerson’s Game are:

  • Choose either normal speed or super speed, then roll a dice
  • If you choose normal, odd dice moves 1, while even moves 2
  • If you choose super, move on the dice, but take 1 damage each roll

I did set the damage to 2 instead of 1, as my race track was short.

Emojis FTW!

Some of my insights this week were:

Start with the model, not the interface

This wasn’t my first time doing Emerson’s Game in Java. My approach before was to go outside-going-in: I wrote my step definitions to validate through the user interface, and then worked my way through the code. This made it extremely difficult to start — I spent significant amounts of time on making things work, rather than implementing scenarios.

The Cucumber Book actually builds an example from the model first, expanding it to eventually execute the specifications through the user interface. I used this approach this week , even skipping Spring Boot entirely at the start. This made it easier to get started and validate my specifications. Once validated, I was able to focus on the user interface, knowing that my specifications were correct.

This was at commit d1d1cd2 , before Spring Boot was added in:

I mostly used IDEA for Java, but Vim for Vue!

One downside of this approach is since the feature file executes quickly, it’s easy to forget to add unit tests. This is especially true for data-intensive scenarios, as example tables tend to more readable and easier to use than unit tests. In fact, I didn’t have any unit tests until a few days later, and I spent some time making sure to add them in when necessary.

Refine the scenario, then implement

In the first few days I would write one scenario, implement it, and then try to figure out what next scenario to write. This is closer to a test driven development loop, compared to what you would call a specification workshop, such as a Product Backlog Refinement session.

One reason might be because I’m the only one who worked on this, and did not have other people to refine the specification with. Another reason might simply be that the quick feedback loop made it possible.

Earlier today, I realized that it would be good to have messages displayed to show game progress. Because I wanted to show the roll of the previous racer, I had to implement a history of rolls made in the race. I also had to craft the actual messages to display. I made example tables for each of these scenarios to lay out the outcomes I wanted:

“Message” and “Log Roll Entry” scenarios

I took extra care to slow down and think of the different scenarios for “Log Roll Entry” (commit a9171e8c) and “Message” (commit 1b3ee5d8). This is significant especially in situations wherein the team is not yet an expert on the product domain, and would refine with actual users heavily. It allowed me to have an overview on fields that I would use, and designed the example tables accordingly at the start.

A really useful addition was a task to run scenarios tagged with @wip (commit w2c75607b). This allowed me to commit the new scenarios in, and slowly implement the actual feature. I could then run the wip task without --strict, so that it doesn’t flag unimplemented steps as errors.

New workflows because of new frameworks

Automating the user interface is difficult. It takes time to actually map the user interface to the executable specifications, and you usually need to deal with page load speed and timeouts. Async JavaScript web frameworks make this even more difficult, as events may not have completed yet when you assert the user interface.

One interesting benefit of async web frameworks is that you can build out the interface and most interactions without the actual controllers, data access, and business rules in. This allowed me to change my workflow to:

  • Start with the specifications, implementing them against the model
  • Design the user interface with interactions, confirming that it behaves the way that I wanted
  • Slowly change the step definition to drive through the user interface instead of directly through the model, implementing the necessary application code to make things work

This is a completely different approach to what I did before, where I would implement the application first before the user interface, as the latter needed the former to actually work.

The next challenge was to deal with the async nature of the interface. I tried to add waits in the step definition, but that was fragile at best. I then realized that just like designing code to be testable, the user interface must be designed to be testable as well!

I started by adding fields visible only during test, so I could confirm if an action is complete. I then waited on these fields, pausing the executable specification until it is good to proceed. This made things consistent and repeatable, which made the executable specifications reliable.

I extended this to other aspects of the user interface: before, I would check where a racer is on the track. This meant looping through all the track cells to check where the racer is. This also tied up my implementation to how the racer looked on the page. I eventually changed it to just output the position of the racer in a field, which I could retrieve and assert.

I made use of Page Objects as well to represent the actual user interface. This led to simpler step definitions, and reusable code.

This turned out to be a productive week. Not only did I have a working sample of Emerson’s Game, but I was able to spend time on Spring Boot and Vue.js and become more familiar with them.

One scenario I plan to implement is to skip racers that have crashed. Right now, the game still asks a racer to roll, even if that racer can no longer move because of too much damage.

I plan to tackle a different set of technologies next week. It may make sense to integrate them to this Emerson’s Game, through the API or so.

Let’s see what happens! 😀

Update: I implemented Emerson’s Game in Ruby (and Rails) a few days later. The feature file is the same from the Spring Boot version, as well as the Vue.js HTML and JavaScript files. Really cool stuff!

--

--