The document discusses different ways of conceptualizing and designing for value. It explores directly measurable, indirectly measurable, and more vague notions of value. It advocates designing for all types of value, not just direct or easy to measure ones. The document also discusses using impact mapping and feedback to track value throughout development. It emphasizes letting engineers show value and presenting through stories to get stakeholders engaged.
1. donât demo facts.
demo stories!
@girba
I help developers
not read code
@girba
I help developers
not read code
@girba
2. designing value
designing value?
Everyone wants to get value. But, what is value?
designing value?
something someone
is willing to pay
something for
Value denotes something someone is willing to pay something for.
1. Directly measurable: It can be that value comes from being able to do more; to do more reliably; to do faster; to do cheaper.
This is the kind of value that can be captured in an Excel ïŹle.
2. Indirectly measurable: It can be that value comes from less tangible things such as how the thing makes you feel. User
experience is an example. This kind of value is non-linear and diïŹcult to measure and even if some measurement happens, it
is always approximate.
3. Even more vague: It can be that value comes from values. These are not even about the thing itself but about something that
you are not even interacting with. It can be the manufacturing philosophy, it can be environmentalism, it can be equal
employment rights.
Most often we only focus on the 1st set. For example, this is measured as throughput.
3. designing value?
Before going further, letâs look at what design means.
designing value?
choosing beautiful
tradeoffs within
given constraints
What is design? Design is all about choosing trade oïŹs within given constraints. If there are no constraints, there is no design.
There is no single best way to embody value, and choosing the right one is a matter of taste, culture, experience, ethics, values.
designing value?
Do not restrain the design to only directly or easily measurable value. The other kinds of value are often more important. Yet,
designing for this kind of value is usually more diïŹcult.
In the end, we have the task of ïŹnding a balance between what is desired and what is possible. There is no perfect solution.
There is only endless choice.
So, how do we design?
4. Impact Mapping, by Gojko Adzic, comes with an interesting proposal.
http://www.impactmapping.org
In many cases, the backlog is not a roadmap. Itâs a tunnel: we go from one end, and after a long time we come out on the other
one. We just split the work in small chunks to appear more ïŹexible, but the backlog rarely changes.
A diïŹerent proposition is to see a product roadmap as a roadmap that oïŹers alternative routes to navigate a space.
5. In this situations, the road is full of decision points that can aïŹect radically the journey. Each of these decisions can be aïŹected
by customer reaction and empirical experiments.
designing value?
Impact mapping sounds great. Still how do you know it works? How do you know everyone is on board?
track value?
But, how do you test the presence of value throughout the team and company?
You need feedback.
6. usability habitability
https://www.dreamsongs.com/Files/PatternsOfSoftware.pdf
Letâs think of a system as a set of layers, such as the intended use, the actual user interface and the implementation (in reality,
there are many more). If the value that should be shown to the user cannot be found in the implementation, how will we keep
track of this value 2 years later? We likely wonât.
Now, letâs look at it from yet another point of view. When we talk about the experience of a user we use there term of usability.
This is great as it allows us to focus on the user needs. But, the engineer lives in the software system for about half of his active
life. It should follow that this system should be suitable for human inhabitance. It should be habitable (Richard Gabriel - Patterns
of Software - https://www.dreamsongs.com/Files/PatternsOfSoftware.pdf). it should be meaningful. Unhappy, unmotivated
people are unlikely to build value.
Btw, when was the last time you threw a perfectly reasonable implementation away only to redo it again in a diïŹerent, more
appropriate way? This is a hard proposition for Excel-based decision making, and it typically never gets to happen. That is why,
the picture above shows a typical reality that needs to change.
track value?
let developers
show the value
Solution: let the engineers show the value.
Why the engineers and not the marketing people? Or the POs?
Because engineers are those that have to embody this value in the system.
feedback
is key
The essence of agility is feedback. Quality of the feedback regulates the quality of the outcome.
8. For example, in Scrum, the review is supposed to oïŹer the space for obtaining feedback from stakeholders. But, does it happen
in practice?
2 hours
20 people
1 man week
every iteration
First, letâs look at the costs. Suppose you have a team of about 8 people. If the project is important enough, it is likely to attract
an audience of some twenty people. If the review takes 2 hours, you have in your hands 1 man week worth of eïŹort spent on the
actual review.
a review is an investment
One way of looking at this situation is to view it as costs, and conclude that the amount of people that participate in the review
should be reduced.
But, the review is an investment in feedback. You just need to ensure that you get its worth.
9. if there is no feedback,
itâs useless
The goal is to make feedback happen. If there is no feedback, it was for nothing. If at the end of the presentation, there is not
even a single question, it was for nothing. This is a factor that can be observed.
if it does not affect product decisions,
itâs useless
Talk without action is not particularly useful either. EïŹective feedback leads to a change in decisions, in behavior. That is
something that can be measured.
present
10. âą presenting
âą is not
âą bullet
âą pointing
The act of presenting became synonym with shooting bullet points at people. This fails to animate the imagination, because
everyone is busy dodging the bullets.
presenting
is
not even
slide showing
To best way to get people on board is through stories. Presenting is storytelling.
presenting
is
story
telling
To best way to get people on board is through stories. Presenting is storytelling.
11. demoing
is
story
showing
To demo is to show the story live. A good demo materializes your story and puts energies in motion.
as a
I want to
so that
This is a famous user story template.
as a user
I want to be able to search in any
folder
so that I can find files and folders
of interest
All you have to do is ïŹll it in. Itâs easy. But, this is no story. Itâs just a set of facts. And facts do not necessarily make for interesting
stories.
In fact the opposite is typically true: that is why iteration reviews are typically unexciting events that are dominated by technical
details:
http://www.tudorgirba.com/blog/you-click-here-you-get-that-considered-harmful
12. I navigate to a folder
where I think I have some
folders and files of interest.
I just do not know
exactly their names.
Would it not be cool to
search in place and then
continue the navigation?
This is a story about the same user story. Itâs not a master piece, but it is more intriguing.
context I navigate to a folder
where I think I have some
folders and files of interest.
conflict I just do not know
exactly their names.
resolution Would it not be cool to
search in place and then
continue the navigation?
It does not follow a template. It follows a pattern. A story pattern.
The diïŹerence to the original user story is not dramatic, but it can make a diïŹerence in terms of how the audience responds to it.
This is how the search interface looks like in Eclipse:
- Top-left: Searching for a type
- Top-right: Searching for a method inside a ïŹle
- Bottom-left: Searching for annotations is not directly supported
- Bottom-right: Searching for declarations is clunky
Engineering-wise, these all work. But, itâs hard to get excited about them. And, itâs hard to tell a story about them, too.
13. How could it look diïŹerent? Here is an example from the Spotter interface that comes with Pharo (pharo.org /
gt.moosetechnology.org):
- Top-left: Searching for a class
- Top-right: Searching for a method inside a class
- Bottom-left: Searching for annotations
- Bottom-right: Searching for ïŹles is as smooth
This interface is uniform, itâs simple and lends itself to a better story. This is not a coincidence either, as during the development,
several versions were thrown away, precisely because the story was not smooth enough. How many versions do you usually
throw away?
demoing
is
story
showing
(the story behind the user story)
Not the user story. The story behind the user story.
content form
Demoing is adding living form to content. When do you build the demo?
Designing and building the form is typically perceived as an effort that comes after the main effort of designing and building the
content. That is not an optimal process, because we cannot reason about content in the absence of form.
14. content form
Content and form must co-exist, because neither has value without the other.
yesterdayâs
weather
Let me tell you a story about the very ïŹrst scientiïŹc paper I ever wrote. It was about predicting changes in a software system using
a Yesterdayâs Weather metaphor.
http://www.tudorgirba.com/blog/yesterday-s-weather
30% 90%
In Switzerland, using yesterdayâs weather as a predictor for todayâs weather is a poor prediction model.
However, in Sahara, it is a great way to predict weather, given that most days look like the previous one.
This prediction model is contextual to the place, or system, in which it is to be applied. So, before applying this technique on a
software system, we ïŹrst have to see if it proved to be reasonable in the past.
15. yesterdayWeatherProbabilityWithTopPreviousWENM: topPreviousWENM
andTopCurrentENM: topCurrentENM
| currentVersions previousClassHistoriesSortedByWENM
yesterdayWeatherHits last2VersionsTopHistories last2Versions
last2HistoriesSortedByENM x valuesCount previousVersionsTopHistories
previousVersionsTopHistoriesNames over |
currentVersions := OrderedCollection new.
currentVersions addLast: (self allVersionNames at: 1).
yesterdayWeatherHits := 0.
(2 to: self allVersionNames size) do: [: i |
self smelly: 'this algorithm is too big and complex'.
previousClassHistoriesSortedByWENM := (self classHistories
selectFromReferenceVersionCollection: currentVersions)
sortBy: [:a :b | a value getWENM >= b value getWENM].
currentVersions addLast: (self allVersionNames at: i).
previousVersionsTopHistories := OrderedCollection new.
x := previousClassHistoriesSortedByWENM first value getWENM.
valuesCount := 0.
previousClassHistoriesSortedByWENM do: [ :each |
(each value getWENM ~= x) ifTrue: [
valuesCount := valuesCount + 1. x:= each value getWENM].
(valuesCount < topPreviousWENM) ifTrue: [
previousVersionsTopHistories addLast: each]
].
last2VersionsTopHistories := OrderedCollection new.
last2Versions := OrderedCollection new.
last2Versions addLast: (self allVersionNames at: (i-1)).
last2Versions addLast: (self allVersionNames at: i).
last2HistoriesSortedByENM := (self classHistories
selectFromReferenceVersionCollection: last2Versions)
Once I had the basic idea, I just implemented it. And indeed, it turned out that my assumption was right. On some systems it
makes sense, on others it does not.
I was happy, but I had a problem: I could not explain my approach to people.
(valuesCount < topPreviousWENM) ifTrue: [
previousVersionsTopHistories addLast: each]
].
last2VersionsTopHistories := OrderedCollection new.
last2Versions := OrderedCollection new.
last2Versions addLast: (self allVersionNames at: (i-1)).
last2Versions addLast: (self allVersionNames at: i).
last2HistoriesSortedByENM := (self classHistories
selectFromReferenceVersionCollection: last2Versions)
sortBy: [:a :b | a value getWENM >= b value getWENM].
x := last2HistoriesSortedByENM first value getENM.
valuesCount := 0.
last2HistoriesSortedByENM do: [ :each |
(each value getENM ~= x) ifTrue: [
valuesCount := valuesCount + 1. x:= each value getENM].
(valuesCount < topCurrentENM) ifTrue: [
last2VersionsTopHistories addLast: each]
].
previousVersionsTopHistoriesNames := previousVersionsTopHistories
collect: [ :each | each value name].
over := false.
last2VersionsTopHistories do: [:each |
((previousVersionsTopHistoriesNames includes: (each value name))
and: [over not]) ifTrue: [
yesterdayWeatherHits := yesterdayWeatherHits + 1. over := true].
].
].
^yesterdayWeatherHits/(self size - 1) asFloat.
Even if Smalltalk is a beautiful language, my code was plain ugly.
yesterdayWeatherProbabilityWithTopPreviousWENM: topPreviousWENM
andTopCurrentENM: topCurrentENM
| currentVersions previousClassHistoriesSortedByWENM
yesterdayWeatherHits last2VersionsTopHistories last2Versions
last2HistoriesSortedByENM x valuesCount previousVersionsTopHistories
previousVersionsTopHistoriesNames over |
currentVersions := OrderedCollection new.
currentVersions addLast: (self allVersionNames at: 1).
yesterdayWeatherHits := 0.
(2 to: self allVersionNames size) do: [: i |
self smelly: 'this algorithm is too big and complex'.
previousClassHistoriesSortedByWENM := (self classHistories
selectFromReferenceVersionCollection: currentVersions)
sortBy: [:a :b | a value getWENM >= b value getWENM].
currentVersions addLast: (self allVersionNames at: i).
previousVersionsTopHistories := OrderedCollection new.
x := previousClassHistoriesSortedByWENM first value getWENM.
valuesCount := 0.
previousClassHistoriesSortedByWENM do: [ :each |
(each value getWENM ~= x) ifTrue: [
valuesCount := valuesCount + 1. x:= each value getWENM].
(valuesCount < topPreviousWENM) ifTrue: [
previousVersionsTopHistories addLast: each]
].
last2VersionsTopHistories := OrderedCollection new.
last2Versions := OrderedCollection new.
last2Versions addLast: (self allVersionNames at: (i-1)).
last2Versions addLast: (self allVersionNames at: i).
last2HistoriesSortedByENM := (self classHistories
selectFromReferenceVersionCollection: last2Versions)
16. yesterdayWeatherProbabilityWithTopPreviousWENM: topPreviousWENM
andTopCurrentENM: topCurrentENM
| currentVersions previousClassHistoriesSortedByWENM
yesterdayWeatherHits last2VersionsTopHistories last2Versions
last2HistoriesSortedByENM x valuesCount previousVersionsTopHistories
previousVersionsTopHistoriesNames over |
currentVersions := OrderedCollection new.
currentVersions addLast: (self allVersionNames at: 1).
yesterdayWeatherHits := 0.
(2 to: self allVersionNames size) do: [: i |
self smelly: 'this algorithm is too big and complex'.
previousClassHistoriesSortedByWENM := (self classHistories
selectFromReferenceVersionCollection: currentVersions)
sortBy: [:a :b | a value getWENM >= b value getWENM].
currentVersions addLast: (self allVersionNames at: i).
previousVersionsTopHistories := OrderedCollection new.
x := previousClassHistoriesSortedByWENM first value getWENM.
valuesCount := 0.
previousClassHistoriesSortedByWENM do: [ :each |
(each value getWENM ~= x) ifTrue: [
valuesCount := valuesCount + 1. x:= each value getWENM].
(valuesCount < topPreviousWENM) ifTrue: [
previousVersionsTopHistories addLast: each]
].
last2VersionsTopHistories := OrderedCollection new.
last2Versions := OrderedCollection new.
last2Versions addLast: (self allVersionNames at: (i-1)).
last2Versions addLast: (self allVersionNames at: i).
last2HistoriesSortedByENM := (self classHistories
selectFromReferenceVersionCollection: last2Versions)
And I knew it was ugly and that I should do something about it. I just did not know what.
present
past future
YesterdayWeatherHit(present):
past:=all.topChanged(beginning, present)
future:=all.topChanged(present, end)
past.intersect(future).notEmpty()
prediction hit
So, I stepped back and rethought the model behind. What exactly was I doing?
I eventually created a small picture and based on that I rethought the model. It turned out that the algorithm to check the
assumption for each day was three lines long.
And I could explain it to people in 3 minutes. And they got it.
hit hit hit
YW = 3 / 8 = 37%
hit hit hit hit hit hit hit
YW = 7 / 8 = 87%
And obtaining the overall value was just an average.
17. yWFor: yesterdayCheck for: tomorrowCheck
| hits |
hits := (self detailedYWFor: yesterdayCheck for: tomorrowCheck)
sum: [ :each | each isEmpty ifTrue: [0] ifFalse: [1]].
^ hits / (self versions size - 2)
yWFor: yesterdayCheck for: tomorrowCheck
^ ( 3 to: self versions size ) collect: [ :i |
| yesterday tomorrow |
yesterday := self
selectByExpression: yesterdayCheck
appliedFromVersionIndex: 1
toVersionIndexAndPresentInIt: i - 1.
tomorrow := self
selectByExpression: tomorrowCheck
appliedFromVersionIndexAndPresentInIt: i - 1
toVersionIndex: self versions size.
yesterday intersectWith: tomorrow ]
And, in the end, even the actual implementation became similarly simple (and even more generic).
All in all, it was because I could not present the idea, that I had to rethink the approach altogether. Of course, I could have just
accepted that the problem is just too complex and cannot be made simpler, but that is never a good enough point.
http://www.tudorgirba.com/blog/yesterday-s-weather
content form
Content and form must co-exist, because neither has value without the other.
V. S. Ramachandran is a neurologist. Among other things, he invented a simple cure for the phantom pain.
The idea is that people with phantom limbs can still feel pain in the non-existent part of the member. The problem is that this pain
cannot be treated directly because it is actually not real. But, it is a serious problem, with people that constantly feel deep pain for
decades.
18. The treatment turned out to be extremely simple and cheap. A mirror is placed on a table, and typically the phantom limb is placed
in a box behind the mirror, and the healthy limb is placed in front of the mirror. The patient is then asked to look into the mirror and
do exercises with the healthy limb. As the patient looks in the mirror, it appears that the phantom limb is actually moving. Through
these kind of exercises, the pain goes away.
You can ïŹnd more information in his very interesting TED presentation:
http://www.ted.com/talks/vilayanur_ramachandran_on_your_mind.html
content form
Form plays an important role in the way we perceive and think of the world. It is time to stop ignoring it and embrace it during the
design process.
Have you ever wonder why is it that Apple allocates such a prominent place for showcasing the interior of their machines? This
is particularly odd given that you will likely never get to see that interior.
19. Itâs not just on the webpage, but also the keynotes show the interior prominently.
And it touches all devices.
And most hardware features.
20. Even the cooler.
The cooler! This is odd. Why?
And it seems that Google does the same, too.
21. Richard Seymour: How beauty feels
https://www.ted.com/talks/richard_seymour_how_beauty_feels
But, do you notice how none of the advertisements show the internal of software systems? Why? There is immense beauty in
software systems, too.
content form
Form and content are equally important. One has no value without the other.
It is for this reason that you do not want to build the user interface at the end of the project. And it is because of this reason that
you should not want to prepare the demo at the end of the work either. The idea of the demo should be a prominent artifact of
the planning game. The team should work with the PO to identify an interesting demo before the main work starts.
Simply talking about what could an exciting demo be makes the team discover implicit speciïŹcations and forces the PO to distill
the important parts. That is because in a demo you cannot show everything, and this puts pressure to everyone to focus on the
most valuable parts.
22. Demoing a system engages people. Engaged people give feedback. Feedback exposes assumptions.
And the system changes.
And at that moment, when all assumptions are out in the open, we can ïŹnd new shapes and an equilibrium that better ïŹts
technical reality.
23. content form
It is time to stop ignoring form and to embrace it during the design process.
Demoing is not an afterthought. It has to become an integral part of development.
donât demo facts.
demo stories!
@girba