Question

I'm learning about various software development methodologies, and reading about Lean hasn't clarified what sounds like two contradictory principles:

  • Decide as late as possible
  • Deliver as fast as possible

The first one:

As software development is always associated with some uncertainty, better results should be achieved with a set-based or options-based approach, delaying decisions as much as possible until they can be made based on facts and not on uncertain assumptions and predictions. The more complex a system is, the more capacity for change should be built into it, thus enabling the delay of important and crucial commitments.

The second one:

In the era of rapid technology evolution, it is not the biggest that survives, but the fastest. The sooner the end product is delivered without major defects, the sooner feedback can be received, and incorporated into the next iteration. The shorter the iterations, the better the learning and communication within the team. With speed, decisions can be delayed. Speed assures the fulfilling of the customer's present needs and not what they required yesterday. This gives them the opportunity to delay making up their minds about what they really require until they gain better knowledge. Customers value rapid delivery of a quality product.

From Wikipedia

How does an industry practising lean methods prioritise both deferring decisions until the full set of facts are established, and simultaneously rapidly delivering software?

Was it helpful?

Solution

How does an industry practising lean methods prioritise both deferring decisions until the full set of facts are established, and simultaneously rapidly delivering software?

It's not a contradiction

Let's get one thing straight here. No matter how much the decisions are deferred, no matter how quickly the project gets delivered, one thing always remains true:

Project requirements, and the design designed that come from them, are always established before the project can be delivered.

Because without those requirements you can't make design decisions, and without those decisions you don't have a product to actually deliver, nor any requirements to deliver it for.

This may seem tautological and quite obvious, but it also points out the flaw in your argument, or rather the absence of an inherent contradiction between deferring design decisions and shortening delivery time.

No customer can have an expectation of product delivery before they've finalized the requirements for that delivery. Before a customer can even formulate a concrete expectation of delivery, they must first provide the requirements for the deliverable product.

The developer's job is to translate those requirement into the intended product. Design decisions specifically happen during that time, as your design is the translation of the requirements into the concrete product.

Deferring decisions

Not making design decisions too early is done to minimize the amount of effort spent on the project (assuming an equal end product for comparison).

When the customer changes their mind on a requirement, only their last choice really matters. So the effort spent on building the previous requirement that has now been changed, is effectively wasted (either partially or fully).

Think of it like this: you are ordering food in a restaurant, you're talking to the waiter, but the chef can overhear you ordering.

I think I'm going to have the salmon lasagna. But then again, the steak tartare sounds very nice as well, that might be a better choice. Oh wait, you serve lobster? I hadn't even seen that. I'll have the lobster please.

If that chef was eager and started making a dish the second you mentioned it, instead of waiting until the order was finished (i.e. the waiter walks away from your table), then the chef will have started a salmon lasagna, then a steak tartare, and then a lobster. The salmon lasagna and the steak tartare would've been wasted, since you no longer want these things.

By deferring the decision, you minimize the effort you wasted on requirements that don't end up in the final specification.

You could argue that the customer should've only ordered what they ended up wanting, but that's not good customer service, customers don't like being told what to do, and even if they thought they knew what they wanted, they may have forgotten things, misspoken, or they ended up making new decisions when they received new information that they did not initially have when making the initial order.

You could argue that starting early still helped you deliver more quickly, because parts of the old requirement can be reused for the new requirement, saving some time compared to having to build the new requirement from scratch. While that is certainly possible, it is a gamble, as you cannot guess what a future requirement might be when you only have the old requirement to go on.

Just because something ended up working out does not mean that it was a wise decision to begin with. Building things on the off chance you might need them is gambling. Doesn't mean you can't luck into guessing the correct outcome, but doesn't make it a wise decision either.

Speeding up delivery

The faster you can deliver something, the better. I don't think I need to elaborate on that.

But I do want to point out here that deferring your design decisions may actually help with shortening the delivery time.

We addressed the food that was wasted when the chef started making the lasagna and the steak tartare. But another thing to consider is that the kitchen staff now also has to clean up these wasted dishes, i.e. wash the lasagna pan, clean the steak knife, ... which negatively impacts their ability to deliver that lobster meal quickly.

In programming terms, having to rollback implementations that are no longer valid also takes effort, and more effort means more time needed to deliver. When a customer changes their mind on a specific feature, that specific feature must be rolled back and its replacement needs to be developed. But this can trigger an entire chain of refactoring in and of itself, if that feature led to a design decision that is now no longer valid now that the feature itself has been scrapped.

Is this refactoring chain a common occurrence? That depends on the size of the changes made to the requirement, and the cleanliness of your codebase. For small changes and/or clean codebases, the impact is usually minimized. For large changes and/or dirty codebases, the impact is usually more significant.

OTHER TIPS

Why are you seeing conflicts between these two statements? postponing decisions helps to deliver fast and delivering fast make teams feel more confortable in postponing decisions

Let's show it with two examples:

  1. You have to develop a complex search feature. You are concerned that the search will be very inefficient, so you have some ideas: building specialized projections, use caching, doing very fine grain optimiziations. All these things will slow down your development but also help you to achieve the best performances. The point is: do you need performances? In order to know the answer you should have an exact idea on the amount of data your query should elaborate, how much frequently users will use this feature, which are the actual performances under a real workload and what is the user expectations

result: turns out that deciding to use these techniques upfront doesn't worth. If you have an observable platform, you can release something that works well enough, collect metrics and alarms and take the right decision under right constraints

  1. You master that fast paced mindset. You build automation pipelines that help to make 30 production deploys, you have developed a new feature but you still need some time for refactoring. Why don't just release the unrefactored code and later on start improving the code? at least you can leverage feedbacks, knowing that the already deployed and tested code works and is considered valuable from customers, so it worths to invest on tech debt reduction

The other side of the coin here is to apply a "micro lean" approach where developers run away from EVERY decision, even the most evident. Too bad, understanding the balance is a very sophisticated art

I'd like to add on the top of Camine's excelent answer, that:

  • Decide as late as possible, does not mean to procrastinate nor to postpone. When you're ready to make a decision, make it. But when elements are missing, and if you can nevertheless advance, decide later.
  • There's even an economic concept for that (option valuation). Take a computer in a shop: the moment you buy it, it has lost instantly a significant part of its market value; if the very next day you decide to resell it, even if you din't unpack it, you will never recover its full price. Of course, if you were sure about your choice, this is not an issue. But if you were hesitating, and if you didn't really need the computer immediately, this could have been wrong if the next day a more powerfull model is available for the same price.
  • "As late as possible", implies "but not later".
  • Deliver as fast as possible doesn't mean to deliver garbage. You need to deliver a high quality. But it doesn't mean that all the decisions need to be done. You don't need to decide how you will improve the performance of a new feautre if you're not sure if the feature is well appreciated in its current form by the users.
  • Moreover, deliver fast, means reduce the uncertainty more frequently. Which will facilitate decision making. A real vertuous cycle ;-)
  • In practice most of the early uncertainty will quickly decrease, leaving less open uncertain decisions. But of course, it's an act of balance: if your progress is blocked by an uncertain decision to make, you will have to make it, even if all the facts are not there.

Delivering quickly applies to the first, incomplete iteration. It will give you valuable feedback early, thus preventing you from doing things that no one cares about or that won't be good enough. This has been pointed out by others already. Let me focus on the other point and give you some raw examples.

Note that the idea of pushing decisions forward particularly applies to architectural decisions. That is, to those decisions that will prove really expensive if you get them wrong. We're not talking design, applying a particular pattern or choosing a file format. These can all be redone relatively easy, quickly and cheaply. Call it a prototype and start over, you only lost a couple of days and you won some understanding. No, think someone in the company talking to some friend at a party, then buying an Oracle license for 5 years for a hundred users, then come back to the office telling you to work with that. When you haven't even figured out if a relational database could be useful or not. That would be too early and likely a disinvestment. Serious money has been spend that will not come back.

The same could be said for settling on a platform, a programming language with expertise to be hired, or buying particular hardware.

Some good answers here, but let me tell you a real-world story about the first statement, which can be indeed controversial to the second one when interpreted too literal:

The more complex a system is, the more capacity for change should be built into it, thus enabling the delay of important and crucial commitments.

This can be easily misinterpreted as "when you don't know all of the requirements now, make every uncertainty configurable, so someone can decide about them later". This strategy seldom works, since making things configurable does not come for free, it will require a certain development effort, maintenance effort, generalizing effort and can slow the development heavily down.

Some years ago we had to design a system with lots of configuration potential. However, it was not quite clear which configuration options the users would actually need. So we postponed the decision and hardcoded several behaviours based on the knowledge we had at that time. We cared, however, for the DRY principle, so making things configurable later should not require to change the code afterwards in several places.

After the users worked with the initial versions of the system for some weeks, we got a lot of feedback which configuration options they really missed, and then we build exactly those into the system. That worked well, it was no problem to implement this afterwards and we did not waste any effort into things noone needed.

So

  • yes, postponing decisions is not contradictory to fast delivery, quite the opposite

  • no, the suggested way of "options-based" design is not necessarily the most efficient way of postponing decisions. Often, "less is more" - just make some decisions, but if possible, make sure the decisions are not distributed over too many places in the code.

Licensed under: CC-BY-SA with attribution
scroll top