“A story should be big enough to fit into a sprint, otherwise chop it up until it does” — this is advice that is more or less given to Scrum teams during planning or backlog grooming. The problem is that this is not easy to do. My friends at Growing Agile describe a few ways to achieve this (see their blog post Breaking Down User Stories). These techniques are not wrong in any particular way, and they will certainly result in smaller stories. However, these are what I call “mechanized” techniques. When I’ve been mechanical about splitting stories, I’ve always ended up with weak fracture points in the problem space. So, I prefer to look in the solution space for boundaries that promote or retain conceptual integrity of the software.
Below are just three techniques that are quite commonly used by Scrum teams. I steer away from them at all costs.
- CRUD.
I find that thinking in terms of these database operations removes a
lot of the richness in the domain. Instead, I think about the life
cycle of things. For example, there is no CRUD for an invoice. Instead
a customer buys something which means that a sales person issues an invoice. The customer pays the invoice. Perhaps, a debtors clerk requests payment for an overdue
invoice. These are all different things that can be done with an
invoice at different times in its life. Note also that “creation” is
a very special case in any life cycle, and to bring something into
existence that maintains integrity is quite an effort.
- Dependent Stories. I try to break all dependencies between stories. I’ve found that looking to create “stand-alone” stories results in some very deep and powerful analysis of the domain. Inadvertently, you will crack open a crucial part of the domain. Often the concept which holds several stories together in sequence turns out to be orthogonal to the original stories. For example, there is a workflow for invoices (issue, authorise, pay, remind, resend, etc) that can result in several dependent stories. Alternatively, we can model the invoice state (and operations allowed for each state) independent of the sequence(s) of states. Now we can build software that deals with specific sequences, independently of the operations for each state. This separation can lead to such powerful discussions with the domain expert.
- Job Functions: I’ve
never found job functions to yield useful modules. Extending the
invoice example above, a job function breakdown could be on sales
(create, authorise), debtors (record payment, payment reminders),
customer service (credit notes), marketing (cross sales campaigns). Now
each of those job functions work with invoices in some way, but the
conceptual integrity and cohesion is stronger around the invoice and its
states. Designing good modules is by far, the hardest part of any software design
effort. Get it wrong and it will hurt. More often than not, it is just too costly to try to create new
cohesive modules from code that is already laid down along job
functions (or any other weak boundary criteria).
There are significant consequences to splitting stories in the solution space.
- The product owner just needs a simple phrase or sentence that describes the problem space, but remains part of the feedback loop for the solution space stories.
- Backlog grooming becomes an exercise in understanding the problem space.
- Sprint planning blitzes (one day or less) is not sufficient.
- To be effective, sprint planning becomes continuous; i.e. design is continuous
- Each story can (potentially) be released on completion
- Sprint boundaries (time boxes) become less important moments in time
- … and you will tend towards continuous flow.
Great post Aslam! Question about steering away from using Job functions. Using your example, from a DDD point of view, how do you reconcile conflicting points of view that different job functions might have about an invoice? The people in Sales might have a different opinion to what a valid invoice is compared to the people in marketing?
Kind RegardsFrank
Hi Frank,
That’s a great observation and question. Two thoughts spring to mind for me.
The first is that differing perspectives on the same concept might well be that there are genuinely two different things. The things that sales want to do with an invoice will be very different to the things that marketing does. For example, sales issues, authorises and sends an Invoice, but marketing just wants to collect invoices to find correlations between products that are sold. In that case, marketing is not really working with an invoice, but with a SoldProduct.
The second thought is that job functions may lead to quite natural bounded contexts. Then you have an invoice in the marketing context and an invoice in the sales context. These two models may be designed differently and there is a transformation mechanism when the invoice moves from the sales context to the marketing context. Bear in mind that the bounded contexts are not modules. They are patterns for design in the large.
Very erudite post, Aslam. Thanks!