Lessons learned from crafting 1,800+ requirement snippets by André Nitze
‘We’re going to learn a lot.’, my boss and CEO said on the six-hour car ride back home. The second of two of the largest projects in the company’s history had just begun. The first one had already been on its way for half a year. This was also the time when I started working for the technology company specialized in building and operating the infrastructure for huge data-driven applications.
But apart from the infrastructure which ‘only’ required the cutting-edge know-how we are known for, our clients also wanted to use the technology in customer-facing software products. That meant besides building and tuning data pipelines, we now had to (help) build full-fledged software products.
And my boss of course already knew we would need to grow to deliver these projects. We defined a system architecture and product roadmap. Then, our Central European clients brought in their offshore teams from Russia and India to start the development of two rather complex software products.
I was proud to be appointed as one of the Scrum Product Owners (POs) in both projects. I’ve been developing software for several years already and I’ve also had hands-on experience in software quality assurance. But I hadn’t done both on such a large scale, let alone being in the role of specifying the requirements for developers. — So I naturally learned a lot, but above all in the role of what can be best described as a hybrid of Software Architect, Requirements Engineer, and Product Owner.
This article contains the distilled experience from writing over 1,800 user stories in those two large software projects.
Who should read this
Some tips in this article are crafted for an agile project environment that is not ideal and, at the same time, one that might be more common than it should. These are solutions for problems that might not occur in a different setting.
In smaller projects, some of these problems might be easier to resolve. A product vision (and progress towards it) is communicated much quicker if you’re in a team of just a few people in the same office. You can negotiate a story’s scope in the hallway. It’s easy to change the direction of a story as more details become known while implementing it. You don’t need an audit trail for the one-year tech-startup with your two best friends.
So this guide is for you if…
- You are a product owner, scrum master, developer, quality assurance engineer, requirements engineer or tester.
- You are working in a medium or large project (25+ people).
- You are using the Scaled Agile Framework (SAFe) or a similar process.
- Your team is distributed across several locations. (And the teams don’t always have an on-site customer representative.)
- You already know the basic quality criteria for user stories (INVEST).
However, many lessons should be equally applicable to any kind of software development project and other forms of software requirement specifications.
The hard thing about writing great user stories
What constitutes a ‘great’ user story? In short, a great user story can be finished within one sprint, provides some business value, and doesn’t incur a hilarious amount of technical debt.And while the INVEST criteria are commonly known and look simple enough, it is usually pretty hard to balance all aspects in every single story. This leads to ugly sprint reports that show almost no progress within the sprint. It might also leave lots of ‘spill-over’ stories for the next iteration (s. figure 1).
Other symptoms of bad user stories are…
- dependencies (you have to wait for one story to be finished before you can start another),
- wrong decomposition (i. e., front-end and back-end parts of the same feature as separate stories),
- incomplete workflows (i. e., several stories for subsequent steps of a huge workflow), and
- lots of false bug reports (i. e., reports of missing functionality that was never specified at all)
The reasons for poor user stories are manyfold, but most certainly the root cause is lack of acceptance criteria. If there are no clear, testable statements that tell the developer when she’s done, it’s easy to extend the scope indefinitely. — Sure, you’ll make progress. But you’ll never know how much and when you can safely stop.
Accordingly, if you find criteria that you expect with every story, create or update your ‘Definition of Done’. Define in the team what should be delivered with every story to consider it ‘Done’. This includes things like…
- having unit, component and end-to-end (E2E) tests written and passed for each story,
- having the feature deployed to some environment or stage,
- having passed a user acceptance test by a specific group or role (most likely the PO), and
- succeeding static code quality and style checks.
Allowing stories to ‘travel’ through sprints erodes the discipline of the team. This is why this anti-pattern should be avoided at all costs. The following lessons should help you to prevent this in your projects.
Lesson 1: Name stories correctly
The name of a story is the first thing people see, so make sure to always use the basic form:
The should refer to your personas. If you don’t have user roles or personas, this is where you should invest some time before writing any user story.
The part makes a nice name for the story and gives everyone the basic thought backdrop when talking about it. So if you find a story with a suspiciously vague title like ‘Setup infrastructure for the platform migration’, this story needs a redo. The same goes for titles that include implementation details. — So instead of ‘Enable admin role to get emails with auth token to view comments’, rather use ‘Receive reports on inappropriate comments’. Move the required details into the story.
Defining a proper forces everyone to challenge the intent of the story and also the business value of the story. If you struggle to phrase a meaningful benefit, you have a removal candidate. Non-functional requirements often provide substantial business value but are generally harder to phrase. It might help to think of business value as ‘averted risk’ in those cases. — Think of 2-Factor-Authentication for sensitive application areas to prevent data loss or leakage. Nobody craves it, but it improves security.
Lesson 2: A picture is worth a thousand words
You know the power of pictures to convey an idea. An encouraging alternative is that even a bad illustration is better than none. And since writing software requirements is all about communicating effectively, drawing pictures will save you and your team lots of time.
Even a bad illustration is better than none.
Keep illustrations simple (one primary and one highlight color; a few simple shapes). Use the tools you’re comfortable with and that other people can use to extend your illustrations and make them their own. Look for portable file formats and integrations into your existing collaboration tools.
Start with boxes and arrows that are just enough to illustrate the idea in your head. Discard these models (= abstractions of the world) after everyone understood what to build. Later, extend your toolbox with more formal modeling methods (s. below).
Advanced: To improve even further, use established modeling techniques. Their commonly known shapes will ease the understanding of stories. The Unified Modeling Language (UML) is the de-facto standard in the software industry for describing problems formally. The following subset of diagram types is particularly useful for adding detail to user stories:
- Structural diagram types: Class diagram, component diagram, object diagram, deployment diagram
- Behavioral diagram types: Activity diagram, state machine diagram, sequence diagram, communication diagram
If you’re not sure how to use these diagrams correctly, ask your architects and developers and draw together.
Lesson 3: Split big stories
One of the most common problems we encountered were huge stories. This is why this lesson should say: Split all stories! — It never hurts to be finished with a tiny product increment.
As an example, from a product perspective, it makes sense to think of ‘Manage user profile’ as a single user story. It can be described within a few scenarios. Inputs, outputs, validation, possible errors, and edge cases are relatively clear. Table 1 below gives an example of how such a simple-sounding feature can be refined and split into many smaller stories. Note that enablers are technical tasks that usually don’t have an impact on the user interface but are a prerequisite for actual user stories. Spikes are time-boxed exploration journeys to gauge the effort required to implement a story. You should only use them if you’re completely clueless about what to build.
The reason Scrum teams ought to be cross-functional is their ability to deliver complete, end-to-end user stories. Hence, most user stories will cover varying degrees of the full technology stack (databases, middleware, back-end services, front-ends). — Likewise, individual team members will contribute more or less to any given user story. Be careful with saying this out loud, because under-utilizing development capacity is a natural fear of managers. Yet, in Scrum, only the team performance counts. So for estimations, rather err on the side of committing to less work than what would be possible. That leaves the team with some wiggle room. If the team pulls too much work into the iteration, any delay will lower its’ self-esteem. Trust from external stakeholders will decrease.
Further reading: For more splitting black magic (e. g., variance in complexity; deter performance; CRUD operations), I highly recommend this article on splitting patterns for user stories.
Lesson 4: More is more
Especially in agile working environments, the idea of deciding on things in the ‘last responsible moment’ is part of the game. Refining your product backlog for the next iteration is exactly that moment. So the more information you can provide, the easier and smoother the sprint will be.
A good description in proper English distinguishes good user stories from mediocre ones. Even bad grammar and punctuation can obfuscate their intention and meaning. You need to articulate as clearly as possible what needs to be achieved with the story. There’s one stellar reason for this: User stories are a communication tool.
The user story (coming from the eXtreme Programming process) should be the ‘promise’ for a discussion about a product feature. As more companies have adopted agile processes, the user story has become the single source of truth for product requirements. Hence, besides text and images, you can even trace the source code changes of stories in your Version Control System (VCS).
The story as a ‘token for a discussion to be had’ works well in small projects. In larger teams, however, the details you provide in a story can be important for rather distant stakeholders, like some involved business people, security champions and auditors. The larger the project, the more impact the user story description has. The more details you can put in a story, the less time you will spend explaining the ‘what’ and ‘why’ to new and remote team members and stakeholders. You don’t have to rely on having the same conversation over and over again and stories can be moved across teams without losing too much information.
As a bonus, it’s comfortable to refer to a story to explain the feature, the reasoning behind a design decision, or a similar implementation. Referring to external documentation and manuals offloads some weight and gives the reader the option to dive deeper.
Lesson 5: Use specific examples
Specific examples put vivid images in the reader’s mind. Software can be forged into any shape, so it’s important to describe the behavior you expect with a memorable example. A good example also ties together different variations of the same story. These variations are called ‘scenarios’ and are the basis for automated tests.
If the example and the actual use match, there are two benefits: At first, it’s much easier to understand the dependencies between the scenarios. Secondly, team members will be empowered to make decisions about the implementation.
To illustrate this, let’s have a look at an example of an example! Consider having a list in your application that lets users manage their customers. It must support
- adding new customers,
- viewing a customer’s details,
- editing and deleting customers,
- searching entries by name,
- sorting entries by all visible attributes, and
- merging duplicate entries.
This list doesn’t tell you where to start, what the value of each part would be, and how it would best be implemented.
Now let’s try a specific example:
Given there’s a call-center agent called ‘Betty’ and she’s logged in to the system. She has the page with the customers list opened in her web browser. When an angry customer ‘Bob’ complains via phone, it’s clear that Betty (while still on the phone) needs to find Bob’s account using the search field in the customers table. In his account details, she should immediately see that Bob is a long-term customer (3+ years) with an expensive plan ($45). Then, she needs to add a 10% or 20% discount (depending on how loud Bob yells on the other side) to his current mobile plan with two clicks maximum.
This example provides a lot of depth compared to the bland feature list. It has:
- actors (angry Bob, poor Betty),
- a very specific problem to solve,
- a business rule (offer discount for unsatisfied customers),
- business rule variations (more discount for more yelling), and
- implicit time constraints.
It’s easily conceivable how the information needs to be presented to help Betty manage the situation and make Bob a happy customer again. The order and the value of each step are much more clear. And it’s easily testable!
A side-effect is the many additional questions you get out of this: Does everyone get the discount? Where do we draw the line for ‘long-term’ customer relationships? What’s a ‘safe’ response time for searches in our customers list when callers have been on hold for 15 minutes? What if Bob doesn’t want the discount? What happens if Bob’s name was misspelled in the database? — None of these points need to be included in the same story. They just get you to think outside of the box.
Here’s a checklist to help you write complete user stories using examples:
- Happy path: This is usually the first thing people come up with. Everything is in place and the user just presses one single button to start some amazing product feature that makes everyone rich. Still, they are a great starting point, because they expose what we think is valuable to the user.
- Preconditions: Sometimes, things have to be prepared, initialized, or created in the right order to work. When you start with the ‘happy path’, you will stumble upon these preconditions automatically. Don’t underestimate their implementation effort. Preconditions are practically begging for being split out into another story!
- Rainy day scenarios: What happens if you try to generate a sales report without having a customer in the database? What if two users update the same customer record at the same time? What if the external payment service is currently down? What if a user fills out a form with invalid data? Make sure to define fallbacks for such situations. They keep the system in a consistent state and the user informed.
- ‘Empty’ states: Showing an empty list sounds weird, but already requires a styled front-end component and maybe an illustration to show it’s done loading. You can deliver it in no time and validate assumptions next week. Then, what about a subtle prompt to enter the first customer?
- Master/detail views: Start with a master view that shows all your business entities on a generic level (think lists and tables). It already provides value. Then, add the detail view with additional functionality in a different story.
- Performance: Define loading times explicitly if they deviate from the standard (of your product). Show loading indicators for long-running requests. If it takes more than a few seconds, show more progress details, and let the user do something while waiting. Also, always let the user cancel the action.
- Confirmations and errors: Always inform your users about successful or failed operations. Hints can be subtle. In error cases, mention missing preconditions. (Did Betty get a confirmation that Bob’s discount was saved? I bet she would want one…)
Advanced: Read up on Specification by Example and Behavior Driven Development. — If you’re able to write BDD-style scenarios, you can greatly reduce testing effort and misunderstanding, because you have ‘executable examples’ (a.k.a. automated acceptance tests).
Lesson 6: Focus on value
The implementation of user stories must provide valueto the user (= the ‘V’ in INVEST). The value should, of course, be visible from the story’s section. But to decide on the most valuable stories, the individual contribution to the product vision needs to be clear at all times. For this, you need to start breaking down the larger business objectives into product features that fulfill them. A common business objective, for example, is to generate a specific amount of revenue with your product. One way to fulfill that goal with a specific product feature is that customers can pay for products. — Potentially with different payment methods and varying degrees of comfort.
This is a good starting point for discussing the value of individual user stories. Get relevant stakeholders together and discuss the features in a product concept session. This will give you the frame of the high-level features of your product (other names: clusters, topics, epics, themes). Map out this overarching structure visually and show how each story would fit in. (Most tools support that. Arranging post-its works equally well.) This helps everyone draw a line between the story and the product vision and takes the guesswork out of interpreting the story’s intent.
Figure 2 shows the link between business objectives, product features and even software tests in the three layers…
- value-driven development (VDD),
- behavior-driven development (BDD), and
- test-driven development (TDD).
This allows you to see the dependencies between business, development and quality assurance. Still, it forces you to focus on the result of the whole product team (‘Were the business objectives achieved?’).
Advanced: Valuable product functionality usually comes in some form of interface, e. g., a mobile app, web site, or web service. But value can also be the improvement of the internal product quality. This could be the maintainability of the codebase or the modularity of the services used. For features that are not directly associated with a user-facing feature, you can use ‘enabler’ tasks. Enablers contain rather technical details, but should also contain the expected benefit or desired goal in a measurable manner, for example:
- Refactor the image processing service to be 2 seconds faster
- Create a deployment pipeline for the user profile service to minimize human mistakes
- Remove all ‘category 3’ code smells in the billing service
Yes, refactoring code can improve the maintainability, extendability, and performance of the product. But you don’t write that down for every code smell you find. These engineering tasks are hard to see from product island, so ask your architect and listen to your team! And developers: Educate your POs!
Enablers provide the ‘invisible value’ that you need to sustain your product over a meaningful period of time. When talking to management, position these enablers as ‘product risk mitigation’ and point out what will go wrong, if you don’t do it. — Usually, something between ‘potential security risk’ and ‘feature delivery will come to a complete halt next year due to an unmaintainable codebase’.
Lesson 7: Agree on roles and accept their (super)powers
There are several roles with different powers and duties in every project. The PO translates market demands into a prioritized backlog. The developers build software from the backlog items. The scrum master educates and empowers the team to commit only to the work they can achieve in any given development iteration and so on.
All roles have to be unambiguously assigned to and accepted by the team members to fulfill their purpose.
Additionally, every role has powers that must be respected when used. Also, there are superpowers for each role that should be used more often:
- The product owner’s superpower to deflect requirements that don’t match the product vision (‘scope shield’).
- The developers’ superpower to find the weak parts in a user story that don’t fulfill the established quality criteria (‘critical hit’).
- The scrum master’s superpower to protect the team from irrelevant external requests and excessive pressure (‘productivity force field’).
- The QA engineer’s/tester’s superpower to see through the user story and spot missing negative scenarios and edge cases (‘QA-ray vision’).
Lesson 8: The best user stories are created by the whole team
If it takes a village to raise a child, it takes a Scrum team to write a user story. Getting more perspectives helps to refine a story. For product owners, there’s a natural limit of time to spend on collecting and integrating feedback into the story. Hence, always involve the whole team to write great stories.
If it takes a village to raise a child, it takes a Scrum team to write a user story.
Consider having small meetings with the team members you think could provide a valuable view onto the story. Encourage them to ask questions and thereby contribute to the contents of the story. Every question will give you feedback on how to improve the story description. Testers and test automation engineers are trained for defining negative or ‘rainy day’ scenarios. Developers will ask you about particular design decisions you didn’t think of. — This also makes the product backlog refinement a real team effort.
Having such meetings regularly with only the necessary people involved is known as ‘Three Amigos’. In its’ smallest form, it only includes a business representative, a developer and a tester. This also helps a lot in writing BDD-style user stories.
The agile way to develop software is to start the development iteration with whatever is known at the beginning of it and learn more on the way. But every minute spent refining user stories can save you weeks and months of implementation and maintenance effort in your product life cycle.
Try out these lessons one-by-one to improve your teams’ ability to create good user stories. More predictable (and satisfying) sprints will be the result (s. figure 3).
“Sucking at something is the first step towards being sorta good at something.” — Jake the Dog (Ryan North)