An Epic Story About Retro-Gaming

In my previous post on product management, I focused on the overall product context in which a story workflow could occur. I mentioned a follow-on post that would get a little more granular regarding that workflow and this is that post. Here we’ll discuss epics, stories, and tasks and I’ll discuss these concepts in relation to a personal project I’m working on. So let’s dive in!

Quendor: Example Scenario

For the purposes of this post, in order to keep some of the discussion from being entirely theoretical, I’m going to provide details on a personal project I’m working on.

That project is called Quendor. The goal of the Quendor project is to provide a working emulator of something called the Z-Machine and an interpreter for z-code programs that will run on that machine. This means Quendor will be acting as an Interactive Fiction interpreter. Depending on your age and/or nostalgia factor, you might better know “interactive fiction” by the name “text adventure.”

The Z-Machine was originally created by a company called Infocom back in the late 1970s to play their game Zork on microcomputers. Eventually this Z-Machine was used to play a lot of games created by the same company throughout the 1980s. Starting in the 1990s, after Infocom was acquired by Activision and effectively dissolved, hobbyists reverse-engineered the Z-Machine and games have been created for it ever since. So while this is very much a retro-gaming project, it does have a certain amount of modern day relevance.

The development goal of the Quendor project is to take those old games and somehow get them to play on modern hardware via the emulation of the virtual machine that made them work. The base architecture of this thing looks something like this:

That visual, if presented to you as part of a project, should be quite interesting. I say that because, taken at face value, it would seem there isn’t much to Quendor at all since it seems various aspects — like the call stack and the main memory — are outside of Quendor.

And that’s true! The Z-Machine is sort of like a computer but without the operating system. Each z-code program is like an operating system. This means the z-code program must be setup such that it provides the above structures that sit outside of Quendor. Each z-code program is like a serialization of some memory state. Z-code programs are divided into routines and a Z-Machine interpreter is always executing a particular routine. Which particular routine it’s executing is the one which the program counter currently points to.

Some instructions in a routine can cause the Z-Machine to call a new routine and then to return where the first routine left off. That means the Z-Machine needs to remember details of where to go back to. Those details are stored in a stack but this is really just a data structure that is provided as part of the operation of the Z-Machine; it’s not strictly a part of it.

This is important because a lot of our projects involve interactions with third-party elements or with other systems that we don’t develop and can’t control as part of our work.

So, with all of the above, what have I described to you? Have I described an epic? A story? A set of stories? A whole bunch of tasks?

Well, let’s live in a world without any strict distinctions yet and see where that leads us.

Project Work: Starting Broad

Regardless of what project artifacts you have, I think it’s really important to make sure that you don’t distribute your project work across too many of them. This is how we get competing sources of truth, information drift and information cruft. Instead it’s usually best to think about how your project work can be “composed” to showcase how multiple features can act together to provide some sort of business value.

How this brings us into line with some common distinctions is that a feature will generally be just one user story whereas an epic would be used to group user stories together around a common theme. But, again, let’s not get too strict yet with our definitions. Let’s play this out a bit in the context of the example project.

With regard to Quendor, I have a series of things going on. I’ll require some sort of ingest mechanism to load up those z-code programs. Perhaps these can be loaded from a local file system but they can also perhaps be loaded up from remote locations via URLs.

Once I actually get a z-code program loaded up, to emulate the Z-Machine I have to provide an implementation for the instruction set of a given version of the Z-Machine. Wait, what? “Given version”? Yeah, see, that’s something the visual above doesn’t make clear. This is a concern on many of our projects, right? We get visuals that “explain” something but the visual is an abstraction and, as such, details can get lost.

In the case of the Z-Machine there were originally six “generations” or versions of the thing. If I want to emulate multiple Z-Machine versions in Quendor, I have to make sure to implement the changes to the instruction set that each version introduced. And when I say “instruction set,” that refers to the range of possible actions that the z-code program can take. Even more low level, the instruction set refers to how those actions are encoded as numbers in memory.

Whoa! Notice how we went right in the weeds there! This can easily happen as we drift from “user does this” to “how the implementation allows the user to do that.”

The practical upshot is that the interpreter portion of a Z-Machine implementation will be decoding all those instructions from memory. This is being done as the player engages with the game. So there is intersection here between the user need and the implementation of it. As there is with any project, of course. But this notion of crossing from intent to implementation will come up again later.

There is also, of course, the need to output the state of the game to some device. After all, the player has to be able to see what’s actually happening in the game as the result of interacting with it. The Z-Machine, being a virtual machine, was designed to be portable across many types of computing architectures. Yet while the Z-Machine itself is portable, screen displays generally are not. Entire graphic libraries are dedicated to this kind of thing; some are cross-platform, some are not.

Project Work: Narrowing Down

Where are we at with what I’ve said so far? Are we talking stories or tasks? Seems like kind of both, right? Well, let’s start with this:

  • User stories provide outcomes.
  • Tasks provide outputs.

That’s pretty simple. And, yes, it really is that simple. Yet let’s consider this: what’s my outcome for Quendor? Well, the overall outcome is that someone should be able to load up a z-code program and play it via my interpreter. That outcome can be realized on a variety of computing platforms.


Windows Mobile
Apple II Commodore 64

Which is great and all … but all of that sounds more like an “epic”, doesn’t it? That outcome is really what everything in this project is all about. That outcome is basically the business value here. The epic is sort of saying: “If I do a whole bunch of work, the outcome will be this!” That “whole bunch of work” is what the stories will describe. Individual stories will thus have their own outcomes; each story will be some iteration on how that ultimate outcome is achieved. Tasks, on the other hand, will be about the details of how the outcome of a story is provided. Tasks are thus about the outputs.

With that, let’s start getting into the project artifact distinctions in some more detail.

Epics

In traditional terms, an epic groups stories that are thematically related. This usually just means stories that have a common goal. Once you have an epic, you determine what user stories you can break out for work during a sprint (or whatever your chosen duration of work is). In one sense you can, I suppose, consider an epic to be a type of story. If an epic is a story then, importantly, an epic is always a story that’s too big to be completed in any single sprint. Thus an epic must be decomposed into user stories.

The above, I find, is necessary to call out because way too many project and product managers treat (and write) an epic as if it was just another user story.

The way an epic is expressed can guide the decompose-into-stories process, helping delivery teams understand what user stories are consistent with what the epic is describing. This is one way that scope is managed while also making sure that the epic, and the work done for it, aligns with the product map that it’s part of.

Everything I say from this point forward regarding how to structure an epic is obviously going to be very opinionated based on how I conceptualize and promote all of this. I don’t think I’m swimming entirely against any broad industry currents here but take what I say below as prescriptive for me, descriptive for everyone else.

Business Injection

Crafting an effective and efficient epic means utilizing business injection. Business injection refers to the following components:

  • Motivation (mandatory)
  • User Narrative (mandatory)
  • Scope (mandatory)
  • Visuals (if applicable)
  • Definitions (optional)
  • References (optional)

When these elements are injected into an epic, this provides what’s sometimes called an “epic hypothesis.”

Let’s break down the injection elements. Clearly the mandatory elements should come first. They are mandatory for a reason in that they, collectively, set up what might be considered the entire context of the epic.

Motivation (mandatory)

This section should describe the motivation behind the overall outcome being described in the epic. Why is this epic important? That can often be answered by talking about what pain points are being addressed or what needs are being fulfilled. This has the benefit of tying back into the product map. The “why” portion of this is what helps the team understand why some epics will be valued higher than others.

So in the case of Quendor, the motivation is that I want to provide an interpreter for the Z-Machine.

Well, hold on. That not really correct, is it?

Actually, my motivation is that I want to provide a way for retro-gamers to play old-style text adventures that were written by Infocom. The interpreter is how I will provide that. The Z-Machine is a particular constraint since that happens to be what all Infocom games were written to run on.

User Narrative (mandatory)

While the motivation above describes the “why”, this section describes the “who” and the “what.” When someone is using this feature (or these features), what experience should they have? These narratives are ideally framed around user personae and can represent a “day in the life” type situation that shows how you’re anticipating someone will make use of the feature(s) in order to receive the desired outcome.

This is important because an epic will usually become a series of user stories. And the underlying structure of a user story is to craft intended experiences of use that are optimized for user engagement. Engagement by a user means a product that people want to use, use often, and recommend to others. Your epic is the starting point of understanding what “engagement” means. Thus when you finally do write stories for your epic, you’re mapping the experience you want someone to have with your product. You are quite literally mapping out an intended experience of use.

With that as a guideline, the user narrative can explain that experience of use across multiple features, thus eventually incorporating multiple user stories. This goes back to that “composition” aspect I mentioned earlier.

In the case of Quendor this might be that I want someone to be able to play an old-school Infocom text adventure on any operating system of their choice and by being able to load those text adventures from some public game repository that we provide. So I might include a user persona for mobile phones. And another one for Windows platforms. And yet another for any POSIX-based platform.

Scope (mandatory)

This section defines work that is in scope and explicitly out of scope. What this means is that any user stories that are determined to be necessary as part of fulfilling this epic, they must maintain the in-scope and out-of-scope distinction. This is a way to gauge what stories should be part of the epic and which should not, which goes to that whole “thematically related” thing. Even more specifically, out-of-scope user stories should not be in the epic. There’s no point tracking something that you aren’t going to do.

When you are going to do the work — i.e., when the work becomes in-scope — that would be the time to add it to the epic. The epic should not become a dumping ground of every possible story we might or could do in the future.

Visuals and Examples (if applicable)

Examples here would consist of anything that helps illustrate details about the narrative or the scope. These examples should be just enough to guide understanding around how features might utilize the examples in order to deliver value.

Visuals can effectively be anything that conveys relevant information via a visual mechanism whether that be a schematic, flowchart, diagram, and so forth. Some of the visuals I showed above might be relevant here.

A key point to visuals at the epic level is the amount of fidelity. Too much fidelity may be locking in solutions before the team has the relevant information; but too little fidelity may not be enough to better understand what is ultimately desired.

Definitions (optional)

If you’re introducing new terms, you should provide operational definitions of those terms. In my context, “Z-Machine” and “z-code” would certainly qualify.

The goal, of course, should be to have some canonical location where a team glossary is located. What that means is these definitions ultimately should not live in the epic since, eventually, the epic will pass out of sight in whatever tool you use for tracking. If new terms are introduced as part of an epic, there will need to be a concerted effort to make sure that definitions introduced are pulled out of the epic and placed in the canonical location.

References (Optional)

This section can provide links to supporting documentation, such as market promises within a product map, UI mockups, any technical feature requests, and so on. Note that these should be links rather than a repeating of the reference information in the ticket. This helps avoid an epic that ends up with information that drifts from some other source.

Epic Criteria

Along with the above injections, I think there are some basic criteria that can be applied to an epic. These criteria take the form of questions.

Is it comprehensible?

This means that the context, as provided by the business injection, enables decision-making and avoids key quality degraders. This means the context should avoid being ambiguous, inconsistent, or contradictory. The context should be explicitly referencing concerns, needs and decision criteria.

Is it actionable?

This really means two things: is the epic capable of being estimated and is the epic capable of being decomposed into user stories? If the latter is not possible, I guarantee the former isn’t either.

Is it tied to the business?

Ultimately your epics are linked to your product map and that has a focus on your delivery team. The work of your delivery team is tied to the needs of your customers. However, it’s equally important that your own business is in consideration when you consider epics. This isn’t just in terms of your ability to provide valuable and desired outcomes to your customers but also to make sure that your business remains viable in order to do so. Thus a mantra asserts itself:

“Revenue is king. Liability is queen.”

The idea there being that we serve both the king and the queen. So for every decision we make, we need to say how it impacts both. This should be a reflection of what has already been indicated in the product map. But the epic is more concrete than the product map in that it’s moving along the spectrum of ideation to elaboration. Any epic should be capable of being framed around one (or multiple) of these focal points:

  • Protect revenue (“Don’t lose money!”)
  • Increase revenue (“Make more money!”)
  • Manage cost (“Keep our profits higher than our expenses!”)
  • Increase brand value (“Make us look better than everyone else!”)

So the epic can help us focus on a key deliverable:

“Help us make more money, help us spend less money, and help us protect the money we already have.”

This has the benefit of being relevant whatever product you are producing. Being able to do this means you can better focus on the needs of your customers. I do realize that the above can be shaded differently when you get into non-profit organizations or if you work in a context where “cost” is less tangible. So you can also frame it as:

“Help us make more good stuff, help us make less bad stuff, and help us enjoy more what we are doing.”

Can it be implausified?

Unlike a user story, a criterion for an epic is not that it can be verified or falsified; but rather if it can be implausified. This very much matches what we do in many sciences and ties in nicely with the idea of an epic being a hypothesis of sorts.

Keep in mind that while an epic will have many user stories attached to it, it would be wrong to think of the epic as nothing more than the sum of its parts. After all, the epic is in place to provide a valuable outcome. But if the outcome is not, in itself, valuable to anyone, then it really doesn’t matter how many user stories are associated with it.

Rather than verifying or falsifying epics, therefore, we “implausify” them; meaning, we see if can determine if they are implausible.

You really can’t verify an epic because, looked at conceptually, that can be subject to a great deal of confirmation bias. “I want to provide a means for people to play old-school text adventures based on the Z-Machine … so I verify that this epic is providing that.”

But what’s the key assumption there? That there are, in fact, enough (or any) people who not only want to play old-school text adventures but even more specifically only those that ran on the Z-Machine. But if there aren’t, then that renders my epic, in terms of value, implausible.

Likewise, it’s rarely possible to falsify an epic since ideas can always be modified or extended to match incoming evidence. After all, I could always find some retro-gaming group somewhere that would probably love something like Quendor. So the fact that there are relatively few people would not falsify the epic. But, again, it may render it implausible.

User Stories

Now we can move down a level.

Let’s approach stories high-level first and then get a little more granular.

Stories: Broad Focus

First, there’s an easy way to conceptualize what we do when we get to writing a story:

Hunting (or identifying) the value has happened before story writing occurs. It’s because value has been identified that we’re writing the story in the first place. The next two, however, do occur as part of story writing.

A user story is one artifact, such as a ticket in a tracking system. That sounds really obvious but the challenge is that sometimes what we end up with is a single user story distributed across multiple artifacts. The other problem is sometimes we end up with multiple user stories in just one artifact.

Keeping in mind some core aspects of a user story can help with this conflation or expansion problem. Specifically:

  • A user story has the feature injection.
  • A user story has the acceptance criteria.
  • A user story provides a distinct outcome.

For example, maybe one story in my Quendor project is about “emulation on Windows” and another is about “emulation on mobile.” And even with that last one, maybe it’s going to make sense to have a story about “emulation on Android” and “emulation on iOS”.

A user story is thus defined as some unit of work regarding an outcome that we want to provide. It’s literally that: a story (a narrative) of a user having successful interactions with a particular feature. Here “successful” doesn’t just mean “it works” — the so-called “happy path.” It means handling pain points as well. For example, if the user tries to do something they shouldn’t, then the application should gracefully handle that. Handling bad stuff, not allowing the user to shoot themselves in the foot — all of that is part of a successful interaction.

So with Quendor, perhaps I have a set of stories for my ingest mechanism. Some successful interactions are:

  • User loads up a z-code program file locally.
  • User loads up a z-code program file remotely.
  • User gets a message indicating when a z-code program couldn’t be found.
  • User gets a message indicating when a z-code program couldn’t be read.

Notice how the second story could perhaps be broken up into two stories about protocols; perhaps loading over HTTP/S and FTP. Or maybe that’s considered part of one story. And notice that those last two stories indicate differences in what can happen when things don’t go well.

But hold on a second. Isn’t that overkill? You could also argue that instead of having four stories, as I do above, you just have two:

  • User loads up a z-code program.
  • User gets a message if something goes wrong with the z-code program.

In that way of doing it, details of those tickets could then expand on what needs to be provided. So, yes, you could do that. You have to decide what makes sense for your team.

A key thing here is the user stories are small. In fact, some reading this may have said: “That’s too small! Just being able to load a program is an outcome of value?” That can be a valid point; loading the zcode program is clearly just a precursor to having it decoded and interpreted so that the player can interact with it. Yet, loading the program first is, you know, kind of important! So, yeah, it is a viable outcome. It’s a bare minimum one, to be sure. But it’s also one that can be iterated on, which is what the other stories show.

The important point, regardless of your breakdown, is that you can make sure the outcome is the one you want to provide. And as a spoiler alert for what’s coming up, you can do this because the acceptance criteria in the story will serve as tests that prove the outcome happens as a result of interacting with the feature.

Story Injections

Like the epic with its business injection above, there are certain things you inject into a story.

Feature Injection

To inject a feature, you have a feature title and statements of value.

Feature Title

Think of something like a Jira (or Asana or Trello) ticket. This is effectively what holds the user story. It’s also going to be a statement of the feature benefit. This means the title of the Jira ticket should be a summary description of the feature. And when you write that title, imagine what someone would likely search on in the system. For my running example, some of my Jira tickets might have titles like these:

  • Loading Local Z-Code Programs
  • Loading Remote Z-Code Programs

The similarity in wording allows for calling out the specific difference. And it should be capable of being very specific about what the difference is at a glance like this, just looking at the title.

Statements of Value

One possible schematic for a statement of value is known as the “Connextra format” and it’s really synonymous with the term “feature injection.” And it reads quite nicely and is easy to remember: As a who, I want what, So that why.

For Quendor, this might be:

As a user of a retro-game platform targeting the Z-Machine
I want the ability to load any type of z-code program file
So that I can reference programs from the past from Infocom
And so that I can reference programs created currently such as from Inform

But hold on. What “types” am I talking about there? Here’s where some narrative can be added to stories.

In the case of Quendor, it’s important to note that z-code programs can come bundled in a variety of ways. Sometimes they are old style “.dat” files; other times they are files that have extensions to indicate the Z-Machine version (“.z1”, “.z2”, and so on). Other times they are bundled up into a format called a “zblorb.”

And note here that we might need to define what “Infocom” and “Inform” are so people can understand this story.

Stories generally should provide context that improves the understanding of the story. Sometimes that context may require mock-ups. Another bit of context, often not considered, would be any constraints. For example, maybe there are certain types of z-code program that Quendor won’t support. A good example here would be, perhaps, what are known as Zcode Version 6 (z6) programs. This version allowed for the incorporation of graphics into the Infocom text adventures but it requires a very different style of interpretation that I may not want to support right away.

Scenario Injection

A feature is broken down into scenarios. A scenario represents a concrete example of the behavior of the feature. Write up the scenarios — specifically the scenario titles — provides a low-fidelity version of scope. For example, I might come up with this:

  • Scenario: User Can Load a Old-Style format (dat)
  • Scenario: User Can Load a New-Style format (z1 – z5)
  • Scenario: User Can Load a Bundled Program (zblorb)
  • Scenario: User Cannot Load a Glulx file (ulx)
  • Scenario: User Cannot Load a Bundled Glulx file (gblorb)
  • Scenario: Graphical Zcode Programs (z6) Support

Just by reading these titles, we can see the scope of the work we are considering. And note that each title should clearly reflect some aspect of the feature title. But this can lead to questions. For example, here’s one: should the latter two scenarios just be one scenario? Something like this maybe?

  • Scenario: User Cannot Load Unsupported Formats

You could do that, sure. But the original approach I took calls out exactly what we believe “unsupported formats” to be. There is a reduction of ambiguity by calling out each scenario. Notice that last one as well. Maybe what that story is going to call out is that while Quendor can load z6 zcode programs and even show the user the text, none of the images will actually be shown. But then perhaps that title is better stated as:

  • Scenario: Graphical Zcode Programs (z6) Show Only Text

And that’s really important for the business to understand because that means, for example, that Infocom’s game Shogun will not show up like this in Quendor:

Instead, users would just be shown the text without the visuals. That may be fine, it may not. That would be a business decision. But at least there is no ambiguity about what we, as a delivery team, are saying we expect to provide.

A key thing to understand is that scenarios are how you modulate scope. They explicitly state what should and should not be included. They effectively serve as a high-level statement of requirements and thus they are the acceptance criteria.

Test Injection

Scenarios can have tests injected into them. In fact, that’s actually what the scenario is. These tests are written with a test injection format. One of the more common is the following:

  • Given {a context}
  • When {an action}
  • Then {an observable}

Depending on your exposure to things, you might see that as “Gherkin” or “Cucumber.” I would urge you to put tooling out of your mind. The goal here is not about automation. The goal is to have communication with the delivery team about what the successful interaction actually looks like.

It’s worth noting that test injection can be parameterized by persona injection. For example, rather than just saying “Given a user loading a z-code program”, you might say “Given a remote user loading a z-code program”.

If another test or example format better serves describing how the scenario plays out, use that instead of the above. The important point is really just that the scenarios can be broken into examples. Examples are framed as test injection using some structuring format; whatever format works best for you. It might even be that different scenarios benefit from different formats.

Another key point here is that a representative set of examples will be the acceptance criteria for the feature. Further, since these examples are effectively tests, good test writing practices should be applied. Thus examples should demonstrate the intent only and not include incidentals. Further, examples should generally avoid describing interactions in terms of the user interface. The goal is to focus on intent (and business domain), not implementation.

And I can’t emphasize enough that the scenario injection + test injection basically become the acceptance criteria. What this means is that the acceptance criteria is always executable.

So is a user story and a feature the same thing?

I would say, basically, yes. Some people will say that a story does not describe a product feature. Instead, stories describe a need that can be satisfied by introducing a new feature or changing an existing feature. That’s great and fine but a feature is functionality that enables users to do something. Whatever that something is has to be described by the user story. If I take away the “enables a user to do something” part away from my user story, what am I left with?

As I’ve described it, each story has a feature injected into it. Thus the two effectively become synonymous. Each story is an end-to-end user journey along the spectrum of one particular feature. Multiple stories will describe different features and those features can be composed to create a user journey.

This is important because the idea of composability means that a story is very limited in scope and defined in such a way that the story can be estimated and planned independently and the the story can be developed, tested, and released (ideally) in one release cycle.

So, yes, each story does describe a need — but it’s a need that can only be satisfied by introducing a new feature or changing an existing feature. Thus user story and feature are effectively synonymous.

When you don’t adhere to this, you end up with stories that provide outputs but not outcomes. And when you do that, you are incrementing, not iterating. And when you are doing that, you lose the quality focus that I talked about in a product context.

Developer Stories

This is a term that doesn’t get talked about a lot. A developer story is an extension of a user story that has its own injections: dependencies and anticipated tasks. These clearly relate to a user story but are distinct from it.

I feel that the separation of a developer story from a user story is important because the outcomes of the user story are not affected by the inputs or expected sub-divisions of work to implement the feature. Yet those inputs and sub-divisions of work are critically important for the developer to be able to create the outputs that will provide the feature, and thus the story outcome. So think of it like this:

  • User Story == Intent
  • Developer Story == Implementation

As the name clearly implies developer stories are for developers (broadly: engineers) and not so much for product or design. This is part of how we can allow for greater implementation details but keeping them separate from intent-focused user stories. After all, users are not going to care about those implementation details so they make no sense as part of a user story. Because, remember, user stories are all about successful interactions with the feature.

So for Quendor, it’s critical for developers to understand how a z-code program has a memory map. That memory map is a key implementation detail that tells the developer where to look for certain bits of data, which the interpreter is going to have to reliably find.

None of that information, however, should be making its way to a user story.

Likewise, when instructions are being decoded, to respond to player input within the game, this corresponds to breaking down what are called opcodes (operation codes):

The details of that very much matter to the developer. Not at all to the user. So the above is great context for a developer story.

So is a developer story and a task the same thing?

They can be; they don’t have to be. That’s a team decision. Developer stories define the context that developers will need in order to estimate complexity and the context necessary to create outputs from given inputs. Just as multiple tasks can be attached to a user story, so can multiple developer stories. Some tools don’t really distinguish between “user story” and “developer story” so it can be confusing to have what amount to nested stories. In those cases, perhaps using a task makes more sense.

There’s a couple of points to keep in mind here, whether you frame all this as developer story or task. These artifacts may have technical acceptance criteria. These are effectively tests that the developers may implement at some appropriate level of abstraction that confirms their work was done.

These artifacts may also list out technical constraints. And those are very important to surface to the delivery team. I already gave one example with the version 6 zcode programs. As another example, perhaps in trying to support multiple mobile platforms with Quendor, I’ve determined there’s some cutoff point with Android SDKs where certain functionality just isn’t present and it would be very cost-ineffective to develop my own functionality to compensate for that. In that case, this is worth surfacing. “Quendor will only be able to support Android devices that have the following SDK or greater.”

I mentioned a few injections earlier so let’s briefly consider those.

Dependency Injection

Dependencies define the inputs needed to create the outputs that will satisfy the outcomes of a feature. For example, my developer story may inject the dependency of a known endpoint, perhaps for reading in z-code programs:

endpoint for retrieving zcode programs: /zcode/:program_id

That description of a dependency (“we need an endpoint”) is also combined with the acceptance criteria of what the endpoint actually is (“/zcode/:program_id”).

Maybe there will be a particular JSON shape returned for data when the details of a z-code program are queried. That can be done in the developer story:

{
  "name": "Outer Periphery",
  "author": "Jeff Nyman"
  "ifid": "40593C4F-F40B-4BCC-881E-D7F842F7069F",
  "license": "Creative Commons",
  "Development System:" "Inform 7",
  "Forgiveness Rating:" "Polite"
}

Once again, we have a description (“there will be JSON response”) and we have the acceptance criteria of what that response will look like.

Anticipated Tasks Injection

Anticipated tasks are the expected steps that a developer might take to implement the feature defined in the user story, based on the acceptance criteria and dependencies. They don’t define the actual tasks that will occur and are useful only in the context of estimating the complexity of implementing a feature.

This might include things like:

  • Need to understand the structure of a z-code program.
  • Need to find a library that provides cross-platform GUI support.

These anticipated tasks just need enough context so that all developers on the team understand what they mean and don’t need to be verbose. These are not for the business to consume yet they certainly could impact the time frame for being able to deliver a feature.

Distinction: Outcomes / Outputs

I can’t stress enough the distinction between outcomes and outputs. A task or developer story is basically something we do in the context of a user story to (eventually) make the outcome possible. This can be writing some front-end code, writing some back-end code, setting up a database, creating gRPC endpoints, and so on. When those kind of details leak into the user story, it becomes a case of the implementation overwhelming the intent.

Distinction: Persistent and Transient

Another key point but one I found it’s easy for people to forget: our artifacts, in whatever system we use, are transient. But stories (in the non-artifact sense) are persistent. So the important point is that we can’t treat the user story like we treat the user story artifact.

Stories don’t stop being relevant after a given sprint whereas the artifact for the story can be out-of-sight, out-of-mind. This means it’s critical to be able to reference the story itself at any time to provide a shared understanding of how the entire platform delivers value. And this means you need to start thinking about how stories continue to live outside of your workflow system.

Product Workflow

My previous two posts in this topic covered the idea of an overall view of most project workflows. My hope is that this post puts into place some of the granular specifics around the artifacts that move through our workflow when we operate as a delivery team.

Conceptually, this is what our world looks like:

To make this world manageable is the idea of that “release slice.” We will have an epic that guides the ultimate outcome of what is being provided. We will have a narrative flow that users can experience. That slow has to be consistent with the epic it is part of. Further, that flow will be made up of various features and those features will be captured in user stories. But for a given release slice maybe we only focus on a few features that can be composed — the ones with the orange dots in the above image — and that will be our first iteration.

In the Quendor project, those orange dot tickets might be:

  1. User can retrieve a z1 file.
  2. User can execute z1 file on Windows platform.
  3. User can save their game state.

And that’s it. That’s three features, composed and delivered together. They provide a very minimal slice of what Quendor will ultimately be. But it’s enough to say I delivered something. And it is something of value, albeit only to certain users (those on Windows) and only on a limited set of zcode programs (z1 version). It’s a minimal set of value that allows the delivery team to learn and course correct if need be.

My next iteration may expand on the versions that can be retrieved. Or maybe my next iteration will stick with only z1, but expand to POSIX systems (MacOS and Linux). Or maybe we’ll decide our iteration can support updates to the amount of z-code program versions we support and the platforms we support.

All of that work will be reflected in our artifacts and that’s why it’s crucial that we have some rigor around what those artifacts are and how we use those artifacts to support and enable our delivery activities rather than get in the way of them.

Share

This article was written by Jeff Nyman

Anything I put here is an approximation of the truth. You're getting a particular view of myself ... and it's the view I'm choosing to present to you. If you've never met me before in person, please realize I'm not the same in person as I am in writing. That's because I can only put part of myself down into words. If you have met me before in person then I'd ask you to consider that the view you've formed that way and the view you come to by reading what I say here may, in fact, both be true. I'd advise that you not automatically discard either viewpoint when they conflict or accept either as truth when they agree.

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.