(special thanks to Deepa Joshi for her input!)
I previously explained why you should care about a good work breakdown (WBD), and gave some examples of common ways to do work breakdown that we should try to avoid. None of that is much help unless you know what we’re really trying to achieve. I’ll explain that here.
The whole point of the WBD is manageability. We break work down because a single big 3-month effort is just too difficult to manage without decomposing it and thinking of it in parts. It’s just too much to fit inside any one person’s head at once in its entirety, so it’s easy to fail at managing the parts we overlooked or forgot.
We can organize the WBD in additional ways that improve manageability as well though. We want to make sure things stay as closely to our idea of “on-track” time-wise as possible. When something is off-track, we want to be as obvious about that as possible as well so that we can do something about it as early as possible. Manageability is about easily determining if our approach is working or not, and adjusting.
In short, we want to ensure real progress and immediately see when we’re having difficulty progressing. People need to know about progress in the software development process so that they can determine…
In general, there are 3 primary factors that help us ensure progress: Visibility, Value Delivery, and Motivation. Let’s dig into these factors.
Visibility: Is what we’re trying to do obvious, concrete, well-shared, and well-understood? Can people (including us) see our progress? Does what they see along the way accurately reflect real value being delivered? As pieces are delivered, do we all get more confidence that we’re on the right track? Do we have all the work enumerated so that we’re not adding more work at the last minute? Are we managing the expectations of stakeholders? If we get interrupted partway through, did we do the best we could have done with our time? If we’re doing things that we don’t need to do, will other people be able to see that so that they can tell us?
Value Delivery: Are we derisking early? Are we learning early? Are we delivering the highest value things first? Are we delivering the lower value things later, or successfully saying no to them? Are we getting things to users as frequently and as soon as possible? Are we providing maximum value at all times? Are we learning as much as possible along the way so we can continuously improve the remaining plan?
Motivation: Are we tackling scary unknown parts quickly so they don’t hang over our heads? Do we feel like we’re making progress and getting momentum? Are we delivering regularly and feeling “in the flow”? Are we reducing anxiety by making sure that there’s no point where we have to communicate a big negative surprise to stakeholders? Are we tackling risky integrations early and frequently to avoid a bunch of rework?
If we’re going to maximize these 3 factors, we need to break the work down in a particular way.
Sure, “Working software is the primary measure of progress” is the 7th principle of the Agile Manifesto , but here it’s worth learning and following because it gets us our goals of Visibility, Value Delivery, and Motivation so much better than anything else I’ve seen.
Anyone who’s written a lot of software knows that a bunch of things can go wrong at different stages of the software development process. Let’s talk through three of those stages:
These are all the reasons that no one should really be all that excited when developers say “it’s done but I just have to…”
There’s just so much that can still go wrong that saying you’re done is incredibly misleading to yourself and to others. Many of these things that can go wrong could even require you to have to start again entirely.
This is why we say “working software is the primary measure of progress”. If the thing is working in production, ideally in ways that are verifiable by non developers, and even more ideally in ways that end-users can verify, then we can prove to ourselves and others that we’ve passed all these stages of risk and something is actually done. Delivering as close as possible to the real production environment also leaves very little opportunity for miscommunication about the progress; anyone should be able to go and see it for themselves.
The brutal truth about software development is that until your code is actually working and in real actual use, you've only really managed to cost your company time and money.
In general, you should embrace the most risk-free and comprehensive definition of done that you possibly can so that when you say “done”, it really lets others know that:
This is what everyone really needs to know. All the previous stages still contain too much risk for you to be saying “done”.
As a result, work should be broken down in ways where each piece:
We want to be as outcome-oriented as possible, so that the progress we’re showing is as real as possible. My shorthand for this is “Outcomes > Outputs > Efforts”, which means that while we appreciate efforts, we appreciate outputs more. And while we appreciate outputs, we appreciate outcomes even more.
We appreciate efforts like “coding” and “testing”, but not as much as we appreciate an actual output of the efforts like a shipped feature that we consider production worthy. Similarly, we appreciate outcomes like “the users love the new features”, or “revenue is way up as a result of the features we built” or “we learned a lot from that latest experiment we shipped” even more than we appreciate the output of shipping the features. So when we break work down, as much as possible, we want to avoid breaking pieces off that describe efforts, and ideally break pieces off that describe outcomes as much as possible. Most times your pieces should at least describe an output.
This is the reason that, for example, we generally don’t want “testing feature whatever” broken out as a separate work item from the rest of the work. If the act of testing is extracted from the rest of the work, then the remaining work can never really meet a very meaningful or useful definition of done. “Testing” is just an effort -- it’s very far from an actual business outcome. It also forces the remaining work items to not include testing as well, relegating them to effort status as well. Additionally, testing can find that the other work is broken in ways that invalidate it. Ideally when you break work up, the pieces are maximally decoupled and can’t invalidate each other like that.
Focusing less on effort and more on results is also the reason we don’t want work broken up along what we call horizontal lines. For example, if you were to split the frontend work and backend work into separate pieces (even if the frontend work is in a different codebase, or even still if it’s worked on by different people entirely) that would mean that the separate efforts are never independently verifiable or usable by people as close to the user as possible in an environment as close to production as possible.
Instead we want to slice the work in vertical pieces. Imagine how you’d share a hamburger with someone else: you’d cut the burger vertically so they get bun, lettuce, tomato, burger, and bun again, all at once in one slice. You would never slice horizontally and give them the top half. Similarly, you want each piece of work to deliver a portion of the user’s experience, and not some horizontal slice like “the frontend” or “the backend”.
Also notice that if our work is always broken-down along vertical lines, it’s easiest if it’s now broken-down into extremely small slices. The thinner your vertical slices are, the easier/faster it is to get any one of them through all the risky merge/validate/release stages we talked about earlier. Even more importantly, if something fails to get through one of those stages in a way that requires a dramatic change of plan, you learn about it as early as possible, instead of after building a bunch of software that doesn’t actually achieve the outcomes we want.
In my next post I'll dive a bit deeper into thin vertical slices, because they're so critical and so hard to get right.