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
  • Feature(s): 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.

    author

    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.

    author

    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:

    author

    Story Maintenance

    Stories should be continually updated with relevant information by all members of the team. I personally do not believe that requirements should be left alone once they’ve been estimated — have you ever tried following a comment thread on a story? — as long as it is clearly indicated what the original expectations were, and what they are now (and why the changes were needed). If you need to re-estimate, then do so. If you are working in an agile fashion, you should be able to adapt to these changes in scope.

    Refactoring Your Stories

    Just like engineers refactor code to make it more efficient, your stories should also be refactored as the project progresses. A good product follows a consistent standard of requests and responses. Open standards like JSON API are a great place to look for inspiration, but make sure your users needs come first. Instead of re-defining the same behavior each time, identify these patterns, define your own spec and refer to it constantly.

    General Conventions

    What non-functional standards should be adhered to, and are consistent across the entire product? Think about:

  • Language Support (e.g., English only)
  • Parameter Specification (e.g., snake case, camel case etc.)
  • Data Formats (e.g., date is always YYYY/MM/DD etc.)
  • Names (e.g., routes always use plural form)
  • Functional Conventions

    What can a user expect from each feature, functionally? Which behaviors are consistent, regardless of the path?

  • CRUD (e.g., do all endpoints support all methods of CRUD? Which ones? Why?)
  • WEESLD (e.g., how are empty or error states handled for all endpoints?)
  • Configuration options (e.g., do all endpoints support filtering? Pagination?)
  • Case Sensitivity (e.g., are all endpoints case insensitive?)
  • Encoding (e.g., do all endpoints expect parameters to be URI encoded?)
  • Summary

    In agile development, user stories are your source of truth. They should contain enough information for your engineers to build the right feature, for QA to confidently and independently verify that the feature was built to specification, and for a business stakeholder to clearly and easily understand what the feature does. Technical projects are often subject to more nuance, and require more careful planning to account for the numerous different paths that can be taken. A combination of use case style thinking and user story based approaches can help you ensure all your bases are covered, while keeping the end-user benefit in mind.

    author

    About the author

    Over the last six years, I’ve worked with SOAP web services at Orion Health, a global provider of software solutions for hospitals and healthcare networks, before shifting to the world of REST at AdParlor, one of Facebook’s original Strategic Preferred Marketing Developers. Today, I’m the TribalScale API Product Lead for a large US media company, who produces and delivers localized audio content to 83 million weekly listeners. Together, we’ve helped them build the APIs and backend systems which power their suite of Web, iOS, Android, Alexa, Sonos, Cortana, Google Home, Chromecast, Roku, and FireTV offerings, as well as a number of partner apps.

    Join our fast growing team and connect with us on Twitter, LinkedIn, Instagram& Facebook! Learn more about us on our website.

    Visit Us on Medium

    You might also be interested in…