One of the things that my development teams have struggled with for the better part of a decade is story writing. The commonly accepted format for a “good” story is As a <role>, I need <feature> in order to <benefit>. When you’re new to story writing, this format feels forced and awkward. Additionally, as a developer I think it’s really difficult to not think about features in terms of implementation details, and I think that’s been the primary source of countless poorly-written stories over the years. I think I’m finally starting to get it and feel confident about stories that I produce, and I figure that’s probably a good cue to share my experiences. So, here we go!
Like many things, I think step one is to simply commit to doing it. Accept that it’s going to feel forced and that you will probably fail many times. Very few people get it right on the first whack. You’ll get better over time with practice, so you just need to stick with it. Try to be self-aware and learn from your mistakes. Identify what made a story good or bad once you’ve completed it, and use that information to improve over time.
A good story communicates two things: a feature or business requirement and a benefit. You need to have those two things. If you don’t have a requirement, what are you trying to accomplish? If you don’t have a benefit, why are you doing it? If we look back at the user story template, there’s a third element: role. This is who you’re doing it for. This is important because it lets you know who the target audience is.
As an example of why role is important, consider this story for a client-server application: “When an error occurs, information about the error should be logged.” Seems simple enough, but who’s going to be looking at the log? What information do they need? The implementation details for “As a system administrator…” will be very different from “As an end-user…” Additionally, if you need to verify the correctness or completeness of a solution, the two audiences may have different opinions. Knowing which role a feature is intended for helps you determine which opinion should carry more weight.
The final characteristic of a good story that I’d like to discuss is feature completeness. I’ve worked on may projects where we build all of the business objects, then build all of the data access, and then build all of the translators in order to data in a third-party format. There are a few problems here. It’s generally too big to do all of that in a single iteration. I think of the process as a workflow that moves through the layers from left to right, and the different layers seem like good seams at which to break it into smaller pieces. So, a lot of developers will break this workflow into stories horizontally: a story for creating business objects, a story for building the data access, and a story for translation. The danger with that approach is that upon completing each layer, you have provided no value until the final layer is complete. Issues with layers developed early in the process may not manifest themselves until later in the process.
Instead, it is better to break the workflow up vertically. For example, create simplified business objects with minimal details, a smaller data access component to populate the simplified objects, and a translator that outputs the available data. At this point, you’re able to demonstrate the full end-to-end process despite not being close to finished with development. And that takes us to the next point…
The sooner in the development process a problem is identified, the cheaper it is to fix. Think of the example project above. If I build my entire collection of business objects, all of the required data access, and massive translators before getting feedback from my users, there is a lot of risk. Maybe I’m not providing enough data, or–perhaps worse–maybe I’m providing too much. Maybe there was a misunderstanding about what triggers the workflow and the whole process is flawed. It’s also possible that I got it right, but it’s more likely that I missed the mark by at least a little bit.
Looking at the flip-side, if I were to get a barebones, end-to-end process in place and demo it to the customer, we can immediately verify that the workflow is correct. “Look, user, when I do X, it produces Y. Is that correct? It is? Great. Now let’s talk about what Y should look like.” In the event that I have done it incorrectly, I’ve only lost the time it took me to complete that first feature. I haven’t lost any time building out code that I assumed would be needed assuming my previous assumptions were correct. (Assumptions=risk.)