The 3 Biases of Software Development - Number 2: Chronology
Building software isn't the same thing as using software, and we must acknowledge that.
In my last post, I talked about how the habit of splitting software into layers can lead us to tackle one layer at a time, producing the undesired BDUF (Big Design Upfront) effect.
This time, we'll talk about how an imaginary user flow can lead us to blindly follow a predefined development flow.
Understanding the Chronology Bias
I remember the first time I played a Mario Bros game in the NES console my father gave me when I was 4. The absurdly unergonomic rectangular controller, the joy of playing a game with a character with which I shared my name… It was a blast, and it was very linear: 8 worlds with 4 stages each. You start on Stage 1-1 and finish the game after beating stage 8-4. There were warps you could take to advance forward, but you could never go back.
Developing software under a Chronology Bias is like playing that Mario Bros game, except it isn't that much fun. You start developing world 1-1 because that's what the user will play first. Then you develop world 1-2, and so on. If we follow that path, we are clearly not falling into the Stratification Bias, because we are creating every layer for each stage (we are not finishing the design of all levels before implementing the game mechanism, for example), and we would be able to gather feedback from the customer after developing each stage and use that to create better stages further on. But still… we are missing some good opportunities.
You know what's funny? This Mario-style linear progression shows up everywhere in software development. Take the login screen, for example - it's pretty much become our "Stage 1-1". It's almost like there's an unwritten rule that says "Thou shalt implement authentication first" just because it's the first thing users see. And more than often, this is the first thing a software development team will work on. Have you ever done that? I did it, countless times.
But what's the problem with this approach?
Problems, I would say. Plural.
The most obvious one is that we are not entirely benefiting from an agile approach if we are following a predefined path. After reviewing Stage 1-1, we'll have some flexibility on how we develop stage 1-2 but not on what we should develop in our next iteration. Besides, all of our conversations about the product will leave that sour taste of wasted time because the path is already defined. This feeling is quite common among developers in Scrum Teams during the Sprint Planning and Sprint Review when they're falling into this bias.
What if stage 6-2 is the most valuable one to my user? They'll have to wait 26 iterations to finally be able to play it.
Another problem will be risk mitigation. If I'm building a Mario game maybe I'll have some bold ideas I want to validate first, such as a water world, a puzzle castle or a very challenging boss. Even the final boss!
So the solution seems straightforward: just develop features in any order that provides the most value, right? We could build stage 4-3 before stage 1-2, following user priorities rather than sequential order.
Well… turns out we often hit a familiar obstacle: dependencies. But here's where another gaming classic offers us an illuminating alternative...
Breaking the Chronology Bias (and the dependencies)
Going back to my childhood and my NES console, there was a game I loved even more than Mario Bros: MegaMan. In every MegaMan game you could select which stage you wanted to play, and once you had beat the stage boss you would gain access to their weapon and could use it for the rest of the game.
So, you could choose to fight Fireman first and use its fire weapon against Iceman, or the other way around. It's up to you. There was absolutely no predefined sequence. But… what happens if we try to use the same approach on software development? Well, sometimes we'll hear and say things like:
We can't develop a report without creating a CRUD to insert the data first, after all there's no report without data!
Ok, let's challenge that: How could we develop a report without having an interface for data insertion? Well, mocking the data. Imagine we are going to build a Hangman game. One could say that the very first thing we need to do is create a dictionary of words we can use during the game, because having a word to play is a pre-requisite!
So, if we fall into that trap, we'll probably spend some time developing something like:
It doesn't seem like much, but it required some time to research a way to generate a random word, read the API documentation, create an account, get an API key, write the code, test it and refactor it a bit. But the game mechanism is way more important, and if we could save some time here we could use that time to develop it further. And one way to do it is by establishing a simple interface.
When I call the function get_word
I get a word, and I don't really care about where it came from. If we do that, we could create our Dictionary like this:
Yes, the word will always be ELEPHANT
. But I'm not saying we should release the game like that! All I'm saying is that now instead of showing the user a screen that generates a bunch of random words, we'll show a fully functional Hangman game that always use the word ELEPHANT
. And by doing that, our product review will become more interesting because now we have a very powerful question to ask:
What should we do next?
We could decide to implement the Dictionary, or the customer could ask for something else, like a scoring system for the game or a hint mechanism. We'll have options. We are not playing Mario Bros, we are playing MegaMan.
And how do I start to do it?
First of all, take notes of all your dependencies assumptions and start to question them. I like to use the How could we / without construction to do that:
How could we authenticate the user without a login screen?
How could we generate a report without having a way to populate the database?
How could we show this information without using charts?
Second and most important: make sure your team knows how to work with interfaces. This is paramount to avoid rework and breaking stuff.
Remember: in order to adapt to changes successfully, we must learn how to do that without increasing the development costs. Just like in MegaMan, the best path isn't always the most obvious one - sometimes you need to fight Fireman before Iceman, and sometimes you need to build that scoring system before implementing the perfect word selection algorithm.
The Chronology Bias, much like its cousin the Stratification Bias, tricks us into following a predetermined path when we should be asking ourselves that simple yet powerful question: "What should we do next?". After all, software development isn't about completing levels in order - it's about creating value in the most effective way possible.
Stay tuned for the final post in this series, where we'll explore our last bias: Modularity.
Oh! And if you came this far, thanks for reading!
Reflection Moment: Take a minute to think about a current project. What tasks are you doing in sequence simply because "that's how it's always been done"? How might you reorder them for better value delivery?