Mistakes
Mistakes in software are opportunities to learn, but it's incredibly stupid to commit a mistake twice.
Mistake
an action, decision, or judgment that produces an unwanted or unintentional result:I'm not blaming you - we all make mistakes.
It was a mistake for us to come here tonight.
This letter's full of spelling mistakes.
I've discovered a few mistakes in your calculations.
Why am I under arrest? There must be some mistake.
In the above definition, mistakes happen when someone realizes the consequences of the mistake are not the ones desired.
So mistakes are subjective in a lot of cases, a lot of times you think you found a mistake inside the application because the result is not what you were expecting. But your expectation is not written anywhere, so you need to confirm that your understanding is the general understanding inside the team or in the product.
Then we could think we can avoid mistakes if we document beforehand all the possible situations, and we describe what the system needs to do.
Not so easy, because natural language tend to create confusion even if you care a lot about what is written. Also, devs are lazy and don’t read everything carefully enough, at the end something written can be understood in different ways by different people.
Misinterpretations
The best communication is face to face communication and in software we are always transferring knowledge from some people to other people, we need a way to have a common knowledge of what we want to achieve with the things we need to build.
The why’s and the what’s are really important to be understood by everyone. We have several tools trying to reduce errors related to misinterpretations of what it was decided.
User stories, acceptance criteria and BDD try to minimize the misunderstandings, focusing on the behavior of the customer and creating some kind of automatic test to validate that the system does what we want (for the future).
This is good because transforms the words in working software that is usually written in a more formal language, without ambiguity.
These are the types of errors we can avoid, those related to misunderstandings, but for these tools to work the whole team need to understand and provide insights about the acceptance criteria to write.
In fact what we want is making everyone in the room to have a compatible view of what the customer needs, at that stage it’s not important how to do it.
Software development is a balance between different constraints, one of those constraints it’s time. Because any product to be successful need to validate with customers and change.
It’s rare to find something that didn’t change at all during their life, as fast as you can validate your assumptions against your customers, the faster you will be able to adapt your product to them so you will receive money earlier.
This means that it is a bad idea to anticipate everything from the very beginning without validating users needs. Because instead of failing between what we think we have to develop vs what it was developed, we will fail between what we thought the customer wanted vs what the customer wanted.
The first failure can be minimized applying development practices focus on fast and early feedback:
TDD
TBD
CI/CD
The second failure (we build something costly that don’t pay the bill) is usually much risky, with higher consequences for the company.
Profit not achieved, higher costs because we have to change big decisions.
No one wants to fail, but it’s much more intelligent accepting that we are going to fail so that we can define how much risk we want to take on the thing we are building, to unveil what are the real user needs/desires.
Our first guidance should be what the user needs, how to provide value to customers with our product to have a profit in the company. But if we are trying to validate an idea in front of customers we need to remove noise, bugs in something small that try to get feedback are dramatic. High quality of experiments is critical to make them valid.
A lot of companies try to avoid failing at all in this space because they think that everything can be understood upfront, you can see this in a lot of behaviors.
For example, when hiring, if you just look for experts it’s because you don’t want to fail.
Not allowing people to fail it’s a bad idea, because learning happen from books or from failures.
Experts learned from books or from experience, so when there is in front of them the same situation they just applied what they learned, they are not learning anything, just applying experience. This is valuable, but you cannot think you will find experts for everything, you need to build them.
A better mindset for the company is not pretending to avoid all failures, it has no sense, what we think is going to happen is just a percentage of the possible scenarios.
We want to avoid failures when we know with higher certainty what the user needs, we want to avoid misinterpretations. Furthermore, we don’t want bugs in production that are related to behaviors described or that happened in the past (we need to learn from failures).
We want to have those mistakes earlier, if they are going to happen they need to happen as soon as we can, while developing better than in production.
Learning
In fact, no one mind failing small. TDD is about failing small (when developing), it’s about writing a test that proves that your code doesn’t behave as your application need and then make it pass.
This helps you to learn from failures with small consequence, it helps you to reflect once and again over a behavior if there are cases not contemplated beforehand, and if they need to be discussed.
Failures give you a way to learn, and to learn fast, the problem of failures is the consequences attached to them. So we need to learn how to minimize those consequences.
Learning is the real bottleneck in software, software is not about writing fast a lot of code, it’s about learning fast so that we don’t commit the same mistake twice.
We need to learn from mistakes, there is no value at all on committing mistakes and not reflect on them, learn what was wrong and change our behavior to avoid it in the future.
In a team will be a lot of times questions that will be answered with “I don’t know”, you have two options learning from books or learning from failures.
You can timebox learning from books if you want and if the answer is not clear then it’s time to learn from failures.
If the mistake has no consequences, or they are tiny, but they could be higher in another context that will happen soon, then it’s a signal that we are close to the Last Responsible Moment, spending some hours thinking on it, could be really beneficial.
Things to trigger a change in your software design
Software design is iterative, the only case this is not going to happen is if you don’t need to add more features and there are no bugs. I haven’t seen this situation yet.
Mistakes in production are costly, but they will happen, we need to minimize them as much as we can but if they happen we need to learn how to deal with them and how to learn from them.
Blameless postmortems are a great tool to learn from incidents in production.
About AI and the real bottleneck in software
AI is not going to solve any of the things I described before, AI misinterpret as we do the natural language we use. AI is not realizing that there are problems not covered by that solution and asking about them.
AI commit mistakes and will continue committing them because software is about learning of new problems/solutions not described anywhere.
AI will help to write code faster, to make people to learn faster, but it cannot solve an essential problem in software (learning faster).
As a summary, allow people to make mistakes, don’t point finger them but create processes/ways of working to allow the team to learn from mistakes faster and to take actions to avoid them in the future.