Uncertainty is about what to build, not about how to build.
When we discover what to build, we try to bring the highest value. Then it turns out that more often our ideas and promises don't meet our expectations. This is Agile. In the complex environment, we would "probe, sense and respond". Almost as if I were to say: We build to learn. In more ordered cases - when we are in a complicated environment but still require an expert's knowledge - we would "sense, analyze and respond".
This can be illustrated below, by categorizing systems into 4 categories (Cynefin):
However, once we know exactly what to build, we can easily estimate the costs. Delivery should be repetitive and predictable. For information systems, it's rare when it is not.
How to estimate the cost of delivery?
Each solution can be described by a set of unique business scenarios. Each scenario can be visualized like a movie with frames. Within a frame/slice the system would:
memorize information (write-slice)
read/present information (read-slice)
This can be illustrated below:
So, the slice is not a User-Story. It is the smallest frame of the business scenario where information (facts) is being processed. To put it differently: facts are written to memory or facts are being interpreted and view displayed.
The whole process in which we describe the scenario is called 'Event Modeling'. You can read more about here or here. (Technically, to implement a write slice, we would implement UI/API + aggregate/command-handler. To implement read-slice, we would implement UI/API + projection + read-model).
The implementation cost of each slice is different. However, the difference is usually insignificant, not by the order of magnitude. Because during a sprint, the development team delivers many slices, for estimates, an average can be used.
Functional and non-functional requirements
We can also recognize that almost all the work of a development team is attributable to a 'slice'. Therefore slices will usually have different costs due to non-functional requirements, such as:
High Performance / Scalability,
Extreme reliability, e2e tests, smoke tests, 100% code coverage tests, etc.
Given we know the nature of the product, a development team would usually come up with appropriate standards (non-functional requirements) and a set of practices. This could boil down to a table below:
|Slice||Non functional requirement||Cost||Time|
|Read standard slice||Basic Unit Tests, BDD Tests,||1000$||2MD|
|Write standard slice||Basic Unit Tests, BDD Tests,||800$||1.5MD|
|Critical read slice||HA, HP, Failure resilence, Performance tests, UT, BDD,||2000$||4MD|
|Critical write slice||HA, HP, Failure resilence, Performance tests, UT, BDD,||1500$||3MD|
The table above is calculated based on history of delivered user-stories of certain Team, and thus is dependent on Technology, design, architecture and more. Your Team needs to come up with its own numbers.
'By the slice estimates' work flawlessly with information systems - apps that process information. There are categories of problems that won't work with this approach:
Algorithms - if something requires raw implementation of an algorithm.
Heavy animations, non-standard UI, 3D,
Some 3rd party integrations - some APIs are terrible,
AI, Machine Learning
What for do we build software?
Simply, to solve problems.
Problems might be solved by various means. Business, user experience, and technology are significant in the final solution. Our role is to make sure that those three pillars of any great digital product are well maintained. Cost estimates allows us to better decide on what to build.