Writing Technical User Stories
By: Tribalscale Inc.
Tags: Development, Agile, User Stories, Product Management

Writing Technical User Stories

Building the right thing, and building the thing right

By Sue-Mun Huang

With technical products, deciding what needs to be done is just the first step. Figuring out how to actually define that “what” is a difficult and ongoing challenge for product managers. Fortunately, like the development cycle, feature specification itself is an iterative process, and it’s owned by the entire team.

If you’re building an API, middleware, or any kind of backend product, you’ll likely face these (additional) challenges when defining requirements:

Features are often tightly coupled and co-dependent

Features touch multiple parts of the system (or systems)

Small changes can have far-reaching impact — lots of nuances to consider

Hard to keep end-user value top of mind or explain value to stakeholders

Unfamiliar jargon: highly technical or vendor-specific terms

As such, building a more technical product requires substantial preparation and a lot of communication. But what does that look like, exactly?

User Stories vs. Use Cases

First, you need to decide how you’re going to define what your product does.

User stories are widely regarded as the best way to capture feature requirements in agile development. They were first introduced by the Extreme Programming (XP) framework in 1998, which stated that project scope is defined “with user stories, which are like use cases”. User stories begin as a simple sentence which can fit on a card, describing an action/goal and its benefit to the user. These stories are designed to invoke conversations between team members, where details are added as the functionality is built.

Use cases, on the other hand, provide a more detailed description of the interaction between a user (role) and the system from the beginning. These are more popular in technical projects as they capture the preconditions, triggers, and responses of the system to all the possible paths (successful and unsuccessful) that could occur when the user performs an action — which can make engineers’ lives a lot easier.

The debate on using user stories vs. use cases continues today: some even argue that the two converge as they move from conversation to confirmation. As long as it works for you and your team, it shouldn’t matter what you use. Personally, I really like to use a hybrid approach: leveraging use case thinking to help discover what stories need to be written.

What makes a Good Story?

Stories can make or break a project, especially a highly technical one. Good stories are:

Independent (can be built separately to other stories)

Negotiable (requirements can be adapted)

Valuable (provides benefit to the end-user)

Estimable (to reasonable accuracy)

Small (can be built within one iteration)

Testable (can be verified by QA)

So how do we get from high-level product feature ideas to these INVEST-worthy stories?

First, Establish a Hierarchy

Projects can quickly become overwhelmingly complex and it can be difficult to find and keep track of tasks — creating a human-readable organization layer helps keep the relevant information easily accessible at all times.

I like to use epics to describe large chunks of system functionality, which are comprised of features that describe some kind of job to be done, which are in turn comprised of the user stories required to achieve that job. For example:

Epic: Ability to access on-demand content

Ability to access on-demand content Feature(s): Ability to find a podcast to listen to, and ability to subscribe to a podcast

Ability to find a podcast to listen to, and ability to subscribe to a podcast Stories: Get list of podcasts, search for podcast, and filter for podcast by market or category

Others may prefer to do this differently. If your team prefers using labels, then do that.

Feature Slicing

Features should be sliced vertically, not horizontally, to break them into stories. That is, you should focus on end-to-end user value, and not by frontend tasks vs. backend tasks. A story should reflect the end-user’s action e.g., “be able to add a podcast to their favorites”, which could then comprise of frontend and backend elements contained within that story, like “add a favorites button to the UI” and “save the podcast id to the user’s account”. This applies to all types of projects, technical or not.

If your product is an API, then your stories will still reflect this vertical slicing — except the “frontend” action might instead be with reference to hitting an endpoint like `POST/favorites/podcasts`, instead of clicking a button that looks like x.

Stories get Smaller Over Time

As you work with your engineers and QA to better understand what should be done, stories can be broken into smaller and smaller chunks as the details and dependencies become apparent.

You should consider breaking down a story if:

There are multiple unrelated acceptance criteria

Some elements are considered ‘nice to haves’

Team is struggling to estimate development effort

Story does not fit within a single iteration

But how Small is too Small?

For example, to provide an end-user with the ability to search for a resource by typing in search terms, the acceptance criteria should cover these scenarios:

Single search term

Multiple search terms

Search + other query parameters

No matches found

The end-user doesn’t differentiate between “searching for one term” vs. “searching with multiple words”. To them, it’s just “searching”, so they can be combined in the same story. Separating these may lead to confusion during implementation, especially if different people are working on the stories.

However, different functions, like sorting vs. searching, should be broken out into separate stories.

Happy and Unhappy Paths

Use case-thinking is really helpful to ensure your stories cover all the possible paths, conditions, triggers, and outcomes, e.g., “the user performs a successful ‘create’ action”. As a big fan of the Checklist Manifesto, I always use this quick list as a reminder to consider the different types of paths which can be taken by the user (obviously, this can vary from product to product):

CRUD actions (a classic):

Create

Read

Update

Delete

WEESLD states (pronounced “weaseled”):

Waiting

Empty

Error ← THIS IS VERY IMPORTANT

Success

Limits

Default Values

Configuration options (FSSPI? Open to suggestions here!):

Filtering (single parameter, multiple parameter)

Sorting (single parameter, multiple parameter)

Searching (single term, multiple term)

Pagination (page size, page number)

Include (what related information can also be returned in the response?)

At the most detailed level, I usually find you need at least one story per action-state-configuration permutation to completely define a feature e.g., “unsuccessful create” or “successful read with filtering applied”.

This approach can lead to needing multiple stories to properly define a feature: in addition to labelling, prefixes and consistent naming conventions can be used to find these more easily. Also, emojis are a fun way to quickly differentiate between happy path and unhappy path stories!

The Story Itself: Bringing It All Together

If an API is the product, then the routes, method, request, and response definitions are the business requirements. I’ve found writing stories in the Gherkin format (given, when, then) to be helpful since this accounts for pre-conditions, and offers an elegant means to describe different outcome paths:

Summary: As a {end user}, I should be able to {action}, so that I can {benefit}

Acceptance Criteria:

GIVEN: A {end user} is {doing the action} in the {app}

WHEN: The app hits the {endpoint route} endpoint with a valid request, containing {required request parameters}

THEN: The app should receive a status {code}

AND: In the response, the following information should be returned: {required response parameters}

Sample Request/Sample Response

Dev Notes/Resources: {any supporting notes here}

Testing Notes: {notes for QA, with examples if applicable}

As tempting as it may be: stories are not implementation instructions. Technical stories are supposed to describe what happens, not how it should be built — let the engineers find the best solution for this, and let them document this. Remember, no one likes to be told how to do their job.

Supporting Materials

To help ensure the right functionality is built and tested, stories should be supported by:

User workflow diagrams

Wireframes, design prototypes, high fidelity mocks

Customer feedback

Architecture diagrams, schema definitions, and technical documentation

Response matrices

Explanation of jargon (I always create and maintain a glossary)

Error Handling

Error handling is especially important for backend-heavy products where there is no UI available to prevent a user from going down an unsuccessful path. Responses should ideally contain at least the following information:

Error id (to help trace the specific instance of the error)

Transaction id (to help trace the workflow a user was performing, especially if there are multiple steps)

Status code (e.g., 400)

User-friendly message (e.g., “Please log in and try again.”)

Error key (more technical information for debugging purposes e.g., FACEBOOK_ACCESS_EXPIRED)

Using a response matrix is a quick and easy way to specify these requirements (for happy and unhappy paths), and should be referenced in the story itself. For example: