The Agile Architect

The Art of Writing Agile Stories Redux

Our Agile Architect delves deeper into agile story writing by illustrating his own thought processes when evolving stories from concept to final form.

Something has really been bothering me. In my last column, "Defining Your Product with Agile Stories," I discussed the importance of stories for an agile project and how they describe small vertical slices of functionality through the product that is deliverable functionality. I described the mechanics of writing stories and how to put them in a canonical form that allows you to focus on the content of the story rather than the structure. I then went on to write about the art of story writing.

But I didn't. I completely botched it. Instead of writing about the art, I just went deeper into the mechanics of it. So bear with me as I try to fix that.

The reason I botched it is because it's difficult to write about something that is so completely an act of synthesis of different factors that go into deciding what my stories should be; factors like my intimate knowledge of the product, both functional and technical; my vision for where the product is heading long-term; my knowledge of the end users and why they want this particular feature; my understanding of the other features we are building; the scope for the release the stories are targeted for, the importance of the story and the feature it is a part of, and so many more that I can't easily articulate.

And if it sounds like I take this personally, I do. I'm passionate about what I build, regardless of my role, be it developer, customer or agile coach. Writing stories is a process that takes time and a lot of thought, refining, reshaping and sometimes jettisoning the stories until they form a living, breathing description of the functionality for your product.

And although I've been talking about stories, I don't generally deal with them as single units. A story is usually part of a bigger feature made up of many stories. It's useful to talk about minimal marketable features (MMF). An MMF is a set of stories that can be delivered together that provides the minimum functionality you can reasonably deliver to a user. If you are writing small stories, an MMF may be three stories; it may be 20 stories, but hopefully not more. Additional functionality for a feature is built up over a series of MMFs. In a given release, you may build one or more MMFs for that feature.

So the real question is how to break up an MMF into stories and how to size the MMF appropriately.

A Tale of Two Stories
In order to discuss this concretely, let's use an example. Imagine that you are building your own social network. Of course, you want to have a chat capability. You want to differentiate yourself in the market, so you decide that your chat app will facilitate world peace and good will by creating a global chat for everyone in the world. No separate chat rooms. No private chats. Just one long chat session inclusive of every member of human society. Moreover, you want people to be able to post not just text, but pictures, photos, Web links and more. You also want them to be able to mark certain chat entries as favorites so they can find them later.

Since we are using our imaginations, let's also suppose that you've already built all of this and deployed it. Of course, it's a huge success and you are now a multi-billionaire. But despite your newfound wealth, that's not enough for you. You know that something is missing from your app, something important. Something so critical that you toss and turn every night and wake up in a cold sweat, panicked that your success will be short lived. But you can't quite figure out what's missing. And then one day, as you walk the deck of your new yacht, unable to enjoy the gentle lapping of the waves against the hull or the warm wind blowing through your hair, it hits you. You reel backwards, staggered by the simplicity of it all.

Your chat app has been so successful that it is filled with too much information. It is so chock full of goodness that the users can't find anything. And the solution is so simple: You need to add the ability to filter the chat messages.

So you sit down in the captain's cabin (we're still on the yacht, right?), pull out your laptop and prepare to write some stories. Of course, your first thought is to check The Agile Architect columns for useful information on story writing. You discover my previous column, read it, curse me for a fool, throw the laptop out the window in disgust, grab a pencil and some paper and get down to business.

And the first thing you do is create the vision for this new feature. You don't worry about stories, MMFs, canonical forms or any other formalities. This is a creative act that requires you to think about what the users really want, how they will interact with the system and what benefits they'll get from the feature. If you had the time (and this column had the space), you'd be spending time on things like usability testing, paper prototyping and contextual inquiry, but with your competition beating down your door (and this author rapidly running out his editors patience), you decide to forgo these activities and do it all yourself. (OK. Now who's the fool?)

Struggling to start somewhere, you decide to write a first story just to get moving. You want to make it small so you think about what could be built in a short amount of time. Your story looks like this:

Narrative: As a chat user, I want to bring up a filter dialog so I can set filters.

Acceptance Criteria:
Given a chat window
When the filter button is clicked
Then a Log Filters window appears
And it contains a button for 'Default'
And it contains a button for 'Show Everything'
And it contains a button for 'Show Favorites'
And it contains a checkbox for 'Show text'
And it contains a checkbox for 'Show images'
And it contains a checkbox for 'Show links'
And it contains a button for 'Custom Settings'

You stare at it knowing that it's bad. So you ask yourself a basic question: Does this story provide value to the end user? The answer, of course, is no. The story makes a dialog appear, but that doesn't actually provide the user with any value. They can't turn filters on or off from this story or in any way change how they view the chat messages. All they can do is bring up a dialog with a bunch of widgets on it that do nothing. (If you are thinking that the story is about implementing functionality behind all those buttons and checkboxes, you're wrong. That would be the entire feature.)

But you did learn something from this first attempt. Staring at it, you realize that this is more of a functional specification than a story. That's not a bad thing, just different and not what's needed in the end. But it's a step forward. You realize that you've implicitly done several things.

  • You've decided on a workflow.
  • You've got an idea of what your user interface will look like.
  • You've defined your filters.
  • You've decided that, by default, there are going to be some things that won't be shown unless the default filter is turned off.

So you start thinking about the functionality you just described and asking yourself some questions: What's a small chunk of real end-user value you can break off as a first story? How can you minimize the work behind it so the development team can start chewing on the harder technical problems like actually filtering without also saddling them with a bunch of other work? You know you've been fixated on building the dialog: Does that really have to be built first or can things be built in a different order? And suddenly you know what the first story really has to be.

Narrative: As a chat user, I want my chats to filter out images by default so I can more quickly see text messages I'm interested in.

Acceptance Criteria:
Given the social networking application is open
And text messages, links, and images have been previously sent
When I open a chat window
Then I see text message and links in the chat history
And I do not see images in the chat history

You smile as you read it again. For the moment at least, this seems like a good first story. There is no user interface change -- it's only a behavior change for the existing application. It gives the developers a chance to start building the filtering infrastructure without having to worry about the user interface

You are a little bothered that, after implementing this story, you have essentially taken away the ability to see images in your chat app. You wonder if it's a step backwards but realize that this is the first story of a larger MMF. You wouldn't deliver this story to your end users without also having a story to turn off the default filter.  And now you know what your next story has to be!

Narrative: As a chat user, I want to be able to turn off the default filter so I can see images that are in the chat history.

Acceptance Criteria:
Given a just-opened chat window
And text messages, links, and images have been previously sent
When I gesture to turn off the default filter
Then I see images in the chat history

Clever, clever you! You didn't specify the user interface in the story. You've left the door open for several things. First, you can specify the user interface in a more appropriate medium. Stories just aren't good for this. A wireframe or mockup works much better. More importantly, you realize that you still might not start implementing your final user interface with this story. After all, you don't need a fancy dialog just to turn the default filter off. So you may decide when it comes time to implement the story that you'll have a toggle button on the chat window to turn it off. It lets you keep the story small and get functionality to your end users faster. You wonder to yourself if this is going to be wasted work since you know (are you sure?) that you'll be building a dialog later. But that's a concern for another day. There's no reason to decide on the specific UI for this story now.

With the first two stories under your belt, you're confident in the third one. After all, you've just done no filter and one filter. So that means the next story can be multiple filters. You scratch out the story on the paper:

Narrative: As a chat user, I want to be able to turn on and off multiple filters to show and hide different types of messages so I can more quickly see other messages I'm interested in.

Acceptance Criteria:
Given an opened chat window and
And text messages, links, and images have been previously sent
When I gesture to hide links
Then the links are hidden in the chat history

Given an opened chat window and
And text messages, links, and images have been previously sent
And links are currently hidden
When I gesture to show links
Then the links are shown in the chat history

Given an opened chat window and
And text messages, links, and images have been previously sent
When I gesture to hide text messages
Then the text messages are hidden in the chat history

Given an opened chat window and
And text messages, links, and images have been previously sent
And text messages are currently hidden
When I gesture to show text messages
Then the text messages are shown in the chat history

You quickly realize that the acceptance criteria are getting out of hand. And you haven't even tackled messages with attached music or video or any of the other message types that you want to be able to filter out. So you decide to break up the story into multiple stories because it's just too big. There's no reason you can't implement each filter as a separate story, then add some stories for multiple types of filters turned on at the same time.

The stories are coming faster to you now because they are all basically the same, turning specific filters on and off, showing only favorites, maybe some others. You can think about that later. The first broken-out story looks like this:

Narrative: As a chat user, I want to be able to turn on a filter to hide links so I can more quickly see other messages I'm interested in.

Acceptance Criteria:
Given an opened chat window and
And text messages, links, and images have been previously sent
When I gesture to hide links
Then the links are hidden in the chat history

You wonder if it's silly to say, "when I gesture to hide the links then the links are hidden." But what the heck! It truly is what you want to have happen. If you come up with better wording later, you can always tighten up the story. You're also wondering if listing text messages and images explicitly in the Given section makes sense since there are more than just those three message types. You want to make sure there are different types of messages in the chat history so that when you hide the links, there will still be messages left. Without a compelling reason to take it out, you leave it alone, knowing that it's pretty easy to change Given statements later since its just a precondition and not the functionality you are trying to build

You quickly write the rest of the stories to turn various filters on or off. You know there are probably some additional acceptance criteria. You think about the zero/one/many rule and how it would apply to a chat history with no images, one image or many images. You think about sad path conditions but, in this case, can't think of any. You're sure they'll come up later but no worries for now, so press on.

But before you do, you realize that the zero/one/many rule could also apply to stories for no filter, one filter or many filters. And then you realize that a sad path condition might be that all filters are turned on so nothing shows up in the chat history. What should the system do? Probably tell the user to turn off some filters. Or maybe you want to somehow prevent them from turning on all filters in the first place. You quickly jot down all of these ideas to flesh out later. This is getting into some pretty advanced stuff. (And yes, the above was exactly your humble author's thought process while writing the above paragraphs.)

You're breathless with excitement. This is some good stuff. Your worries are a distant memory. Suddenly the phone rings. You wonder who could know the phone number for the yacht but you go with it since you realize that your humble author is bound and determined to stick with this yacht thing no matter how silly or annoying it is.

The call is from your sales director. It's not good news. Usage of the chat feature is plummeting. No one wants to use it because they can't find anything. It's the Web links! The links are out of control. Your chat app has suddenly become the center of an extremely popular college drinking game. The entire chat history is filling up with links at an incredible rate. Your worst fears have been realized, but you've got the solution in your stories. Now you are concerned with how fast you can get this functionality into production to stop hemorrhaging users. You look at all the stories and ask yourself what is the minimal number of stories that you could implement in order to help the situation.

And it's only the first two. Filter out the images by default and give the users a way to add them back in. Except...it's not the images, it's the links that need to be filtered out by default. So you make a quick change to the default filter story and you are ready. Sure, it's not the full blown filter-anything solution, but it's a start and can be implemented and pushed to production much faster than if you try to do everything. So that button idea to turn off the default filter rather than a full-blown filter dialog is sounding really good.

Wanting to e-mail the first two stories to your development team, you reach for your laptop. Realizing that you threw it into the ocean, you dive overboard, retrieve the laptop, dry it off and plug it in. Through some miracle, it boots up and off you send your two stories.

Relaxing with the knowledge that you've saved humanity from itself, you get back to work on the second minimal marketable feature for your filter functionality.

At the back of your mind, you're starting to think about questions beyond filtering chat. Are there other features that could benefit from filtering? What might that look like? How can you apply what you learn with chat to these other features? You know that you are going to want to talk with your software developers to understand how to make a generic filtering solution rather than one that only works for chat. You might not implement it now, but it's worth a short conversation to see where you might go. It could influence choices you make now in the current user interface design and/or technical implementation.

There's a lot of work still to do, fleshing out the rest of the MMFs and the stories within. But you know it's a journey. There's no easy way to jump to the end state, but you've made the most important step. The first one.

The Story Behind The Story
The story above is true, sort of. One of my teams is writing stories for filtering functionality almost exactly as described above. In fact, the first story (the bad one) was an almost word-for-word copy of the first story I saw from that team. I explained that it was written like a functional requirement, not a story. It's very typical to see stories like this from people used to writing functional requirements. They state what will be in the final form of the application and what each piece does. They don't use the stories to describe an evolving, always self-consistent application that provides value every step of the way.

While I was trying to explain this concept, I was struggling to put into words what I knew. It was another member of my team that chimed up that it's not about functional requirements. It's about workflow. That made me smile because he said so elegantly what I couldn't. Each story is a small workflow. It can't be a piece of a workflow (unless the rest of the workflow already exists) or there's no value to the end user. It doesn't have to be the entire end-game workflow and it doesn't have to have all the bells and whistles. Those can be added later.

With those two events, it finally jelled in my head why I was so dissatisfied with last month's column and why I was driven to write this one.

And one last story... When working on the next MMF that did include the dialog, my developers pushed back on the first story that made them create a dialog and add functionality to it. They said there was enough complexity in creating the dialog that they wanted a story to just launch an empty dialog. While there is no user value in that, I wrote the story for them. I'm not going to override my developers on technical issues for the sake of story purity.

Last Words...
I feel better now. Next time, we'll talk about something different. I promise.