Published October 16, 2021
by Doug Klugh
Always Deliver Value
Write user stories that represent thin, vertical slices of functionality through the layers of your application’s architecture. This will help keep your stories small and ensure they deliver value to end users or other system components. Throughout development, user stories will pass thru all stages of the Software Development Lifecycle (SDLC), but may not necessarily include slices from all architectural layers (see figure 2). For example, APIs will not include components from the UI or presentation layers. Always preserve architectural boundaries by ensuring that no class spans architectural layers.
To facilitate CI/CD, these vertical slices of functionality should be as thin as possible. The user story must be able to be implemented and tested independently of other user stories; and most importantly, provide value to the user.
While every software system will be designed with their own architecture, figure 1 (below) shows one way to layer a software architecture to provide separation of concerns.
Much of the functionality encapsulated within a software system does not directly serve the end user. For well designed, loosely coupled systems, most users of user stories are other system components (not people). While this is often true for polylithic applications, it is always true for firmware and low-level system software (such as cache managers, device drivers, etc).
When writing such user stories, always elevate the abstraction by one level. While all components can be traced up n-levels to the end user, only go up one level. That is the component that realizes direct value from that user story.
When thinking of it from a use case perspective, consider what component initiates the user story and what component realizes value from the story. Often it is the same component, but not always.
User stories must encompass all SDLC stages to ensure they provide complete, high-quality value to the customer. For example, you should never split user stories into separate implementation and testing activities. None of them (by themselves) provides complete, direct value to the user — as they are dependent on the other card(s). However, you can create separate tasks within a user story to create the design, implementation, testing, and deployment artifacts (and others).
While some stages of the SDLC may not always deliver tangible artifacts, the outcome does exist in one form or another. One example I often use is modeling. Your team may not take time to explicitly build a model of the existing system behavior, but it does exist (in many forms) in the minds of every team member. The problem there is everyone has their own understanding (their own model) of how the system works. Build an explicit model and everyone is that much closer to having a common understanding of the current state of the system.
As illustrated below in Figure 2, a user story must encompass activities for all stages of the SDLC. At the same time, a user story may impact only a subset of architectural layers. A change to a screen layout would only impact the UI layer. Migrating to a new database would only require a change to the data layer. A new API may only require changes to the service, use case, and business layers. These examples assume well-designed, polylithic software systems.