How to create 1 point user stories
One of the most common issues I see with teams I work with is knowing how to write user stories that are only one point in size. Before I dig into how to do this, let me take a moment to explain why you want to do it.
Estimation is hard. So hard, in fact, you shouldn’t even do it. One point stories is a way of eliminating estimation and instead you can simply count stories. Iterations become filled with how many stories you got done, not how many points you got done. More stories being done means more functionality to demonstrate and more value being delivered directly to the user. Would you rather demonstrate 5 stories to the user that made up 30 story points, or 30 completed stories? Which one appears to produce more value to the user?
That’s the argument for one point stories distilled to some high level wins, but is by no means a complete discussion. If you want to investigate further, I suggest using your Google-fu to research the #NoEstimates movement.
So how do we get to one point stories? First we need to understand what a well crafted user story looks like. Rather than rehash this, I’ll refer you to one of my previous articles User Story Writing Simplified for a refresher.
Once you have the correct format of a story, that doesn’t mean it’s small enough yet, and in fact what you may have is really a “feature story”. That is, a story that articulates the larger functionality the business owner wants delivered. There are a couple of ways you can break down the story even further, I outlined some user story splitting techniques here but in this article I’m going to present another way, and that is what I call the “fail fast method”.
The Fail Fast Method
Along with the three methods described in the Splitting Stories — Three Easy Ways article, you can also find seams within a story along the “sad paths” of a story.
Quite often when we read a user story we immediately start to think about the “happy path” of the story. That is, if everything goes perfectly well, what will the outcome be for the user. When you think of a story along only this happy path direction, then the story will appear to be fairly large in scope. You begin to think about all the different layers of architecture that must be written in order to produce the desired outcome. However, at each layer of the architecture, something could go also go wrong. Each of these opportunities for things to go wrong can be written as a user story. Below is an illustration of this technique.
Notice that the sad path stories work progressively down to each layer until all of the architecture is put in place for the eventual happy path story. This means that each new sad path story only has to cover the next layer of architecture, not the whole application. Each story then becomes very small due to all the other sad path stories already having covered the upper layers of architecture. By the time you reach the happy path, the story becomes only a matter of not failing. All the code to pass has been written.
But aren’t these stories just acceptance criteria?
Yes! These are really the acceptance criteria (acceptance tests) of the original user story. But acceptance criteria can be rewritten as a new user story if you try hard enough. Even sad paths are outcomes that often deliver value to the user. It may not be obvious and it may not seem as valuable as the happy path story delivers, but they are valuable and they do offer a way to keep stories small while maintaining verticality.
Let’s do a quick example. Here is an acceptance criteria for a possible sad path of a log in story:
GIVEN I submit bad credentials 3 times, WHEN I click the submit button again, THEN I should be redirected to the /failed page.
Ask yourself these two questions about the acceptance criteria above:
- Which layers of the application architecture will this acceptance criteria require?
- How could this be rewritten as a user story to show value?
The answer to the first question is probably just three: the UI, application, and domain layers. Once we know a user has attempted 3 or more bad logins during a session we can block them without requiring to go down any more layers into the application.
To answer the second question you must identify the three parts of a story that the acceptance criteria suggests, who is it for, what is it, and why do they want it? So we might come up with a story that looks like this:
As Susan, I want my account to be locked down after 3 failed attempts, so that hackers will be less likely to steal my account.
There is no doubt this is a very valuable piece of functionality for the user even if it is inconvenient.
Revealing more sad paths
This focus on the sad paths at each layer also exposes some of the failures that could happen within a system that are often not accounted for. What happens when the application is down but the UI is up? What happens when the database is not responding? What happens when the 3rd party API rejects a token? etc. You might write a story that looks like this:
As Susan, I want to be informed that the service is down for maintenance, so that I know it’s not something I have done incorrectly when trying to access the application and I can try again later.
Covering all the sad paths first (or failing fast) is a good practice for doing software development well. Often in our haste to deliver some piece of functionality we ignore these possible outcomes. This results in many bugs discovered later and perhaps long after the original author has left. So not only does this technique result in 1 point vertical stories, it also produces more comprehensive code with fewer defects.
Conclusion
The fail fast method of finding all the sad path route stories first is a great way for developers to write thin vertically sliced stories. Developers who are often used to thinking in terms of architectural layers will often take to this method very easily. It allows for them to still think of the horizontal layers they wish to create for the feature, but pushes them into a vertical way of articulating the functionality delivered to the user.