top of page
  • Writer's pictureTodor Kolev

Slicing work for happy users and high team morale



Intro

In this article, we'll discuss two approaches to breaking down user stories: vertical and horizontal slicing. And even though these are nothing new, I've noticed that if teams don't consciously and actively think about the way they chop user stories into smaller, well-grouped subsets of tasks, then things can get disorganized, which can lead to lower productivity and team morale.

What's "vertical slicing"?

When you slice a problem or a feature vertically, you choose to focus on delivering only a small part of the whole feature, but that small part that you are delivering can actually be deployed and put in front of users sooner. This way, your users can realise the benefits (even if partial) early, and you can integrate your code and get feedback faster. Along with that, the team will get a sense of achievement from seeing their efforts materialise into something tangible and useful to users.


What's a "horizontal slicing"?

If a feature spans multiple layers of your techstack e.g. UI, API1 and API2 then slicing a user story horizontally would mean that you have separate tasks for implementing the required functionality in each layer. Only once each of these tasks is completed does the feature become usable.


An example

Let's see a simple example depicting the two approaches. Say we have an internal website that is used by our company's support assistants to help users when they have a problem and contact us via chat. We want to create a UI component so that when the user contacts our support experts via chat, the user's account information is displayed next to the chat window to aid the support expert.


The user story might look something like this: As a support expert When a user asks for help in our support chat I want to have the user's account information readily available So that users can be helped more quickly and without having to ask for information that we already have. So the account information the operator needs in this case is the account number and balance. Let's say that we have the account number and balance both available in the User API (Figure 1) but the balance is currently only updated once a day, and the support experts need the most up-to-date user balance. In order to obtain the latest user account balance, the User API needs to subscribe to a message broker to receive live account balance updates, which the Transaction API needs to first start publishing. Here's a diagram depicting what we want, and the parts in red show what needs to be implemented.

Figure 1 So having the user story in the first place is already a good start, as it almost forces you to think about how you can deliver features vertically. Unfortunately, I often see tasks that are detached from any sort of user context and fed to developers on a piecemeal basis. So context is lost, and when you're missing context as an engineer, you, in a sense, simply implement what you're told without being able to challenge or question why things are being done in a certain way or in a certain order. It's ultimately a loss to the company as they don't fully leverage the brain power and expertise that engineers have to offer. Back to the example, a first pass at breaking down the story might look something like this:

Figure 2 As you see, you have 3 backend (BE) tasks:

  1. Transactions API needs to publish updates to users' balances to the message broker.

  2. User API needs to subscribe to receive balance updates from the message broker.

  3. User API needs to expose an API endpoint so the UI can retrieve the account information (account number and balance).


We also have one frontend (FE) task:

  1. The UI needs to implement the front-end component to retrieve and display the account information to our support experts.


Depending on the team's capacity, you might or might not be able to complete all four tasks in a single sprint, but the risk is relatively high. What if the User API or Transactions API don't have access to the message brokers, and that would require an infrastructure change? You also need to establish a contract between the User API and Transactions API so they can agree on the structure of the message that will be published and consumed. Teams often will just put these tasks in the backlog and prioritise what goes in the next spring depending on capacity and what else is of high priority, looking at the tasks individually and not as something that can be organised into subgroups that constitute a small (even if partial) but deliverable piece of functionality. With our example above, you can say: "In order to reduce risk, we can only display the account number to start with and add the balance later." So we've essentially created a small subgroup of tasks that, considered together, represent a deliverable feature (a vertical), which is both valuable and has a higher chance of being completed in the next iteration. This way, we can put something in front of our users (the support experts) and see what they think about it. We can even maybe start collecting data on whether this new feature leads to a reduction in the speed at which they resolve support requests, the number of requests they can process in a given period of time, the number of abandoned chat sessions, etc. So we might want to consider having the following two tasks prioritised and worked on together in the next sprint. We might also label them so it's clear that they represent a small deliverable.


Figure 3

Then another subgroup of tasks is created for the remainder of the work required to complete the user story:

Figure 4

Notice how both FE Task 1 and BE Task 2 are smaller compared to the previous diagram (Figure 3), as, at this point, we already have the UI component and the User API endpoint implemented as part of the previous vertical story for displaying the account number.


It's a mindset

Vertical vs. horizontal slicing is not only relevant when planning new user stories. It should also be adopted as a mindset when planning what will be worked on in the immediate future (e.g., the next sprint if you work in sprints). It's about grouping tasks together that, when completed, will produce something tangible for the business and/or our users. For example, if the QAs have come across a bug in the API that will only manifest itself after a certain front-end component is completed and that front-end component won't be worked on and completed in the next sprint, then why would my team focus its attention on fixing that backend bug? We might surely fix it if we have some spare capacity, but our focus should be on delivering something that is usable and valuable in and of itself. Equally, the same approach could be taken if we go down a level and consider a tech debt task, a bug fix, or a small feature within a single service or software component. We pick a ticket, and our first goal should be to write a test that describes what we're trying to achieve and get it to pass. After that, we can merge our code into "main" and iteratively work on improving the initial design and implementation to a point where the benefits no longer outweigh the effort that we're putting in.


Pros and Cons

Here are some of the benefits of focusing on breaking stories down and organising them into small, deliverable subgroups:

  1. Reduces stress.

  2. Helps you break down bigger tasks into smaller, more manageable ones.

  3. Delivers something that benefits the users faster.

  4. Keeps the team focused and reduces context switching.

  5. Encourages cross-team collaboration. When tasks span multiple teams but we have a common goal, it's more likely that team members will get behind that goal and collaborate.


The problems with horizontal slicing and prioritising tasks in isolation:

  1. It doesn't necessarily deliver user value. Consider the following task: "Maintain an up-to-date account balance in the User API." So what? Who cares if the balance is up-to-date when that balance is not used anywhere? I might spend a lot of time trying to implement the publishing and consumption of balance update messages, and in the end, that would be invisible to the users.

  2. Can lead to QAs having to do lots of manual testing and duplication of effort. If the tasks in Figure 2 are delivered in no particular order, we might have forced QAs to test each task in isolation and manually, as the functionality is not accessible via any official channel yet and therefore it's hard to come up with an automated test for it. Only after all tasks are delivered can a full E2E test be created. So all the manual effort that went into verifying each task in isolation has been in vain.

  3. Delivering stories this way can also lead to nasty last-minute bugs, as the individual components have never been put together before, and now that you actually get to use them together, you are more likely to discover flaws and imperfections, so the risk is definitely higher!

  4. I've also seen this type of prioritisation lead to silos as people might spend a long time working in a specific area or layer, e.g., User API and become narrowly specialized, and then inevitably someone will brand them the "User API guy." They'll just keep working in that little corner of the business for a long time, thus creating a knowledge silo.


Why does this happen?

There's this myth that if you pull in as many tasks as you think your team's capacity is and parallelize them, you'll accomplish the maximum amount of work possible. But there's work, and there are outcomes. You can get a lot done in a sprint and still not see real outcomes if those tasks are all over the place and the team doesn't focus on delivering something end-to-end. The problem is that sometimes, if the backlog is arranged without the involvement of all team members, things can slip through the cracks. For example, if we're trying to deliver a feature and we've prioritised a few tasks that we think will get the job done but we've left out a bug for that button on the front-end that's not working, then the whole feature might be unusable even though 90% of it has been implemented. It requires technical knowledge of the current state of the system and the ability to identify which are the relevant tickets that can to be grouped together in order to deliver something that is usable and functions end-to-end. That's not always possible, as we often need to fix urgent bugs or issues that might be a real drag on productivity, etc. But the point is that, if you keep asking the question of whether we can break stories down and organise them into small subgroups of deliverable slices, chances are you will start seeing real results at the end of your iteration cycle more often. Your team will also likely reduce context switching, improve the feedback loop, and improve its sense of achievement.

20 views0 comments

Subscribe to this blog. No spam, only quality content!

Thanks for submitting!

bottom of page