For a while I was looking for a way to explain why software has bugs to people not working as software developers themselves. Bugs seem to be some sort of mythical creatures that only live in software. But they don't! So let's get it out of the way right from the start: A marketing funnel has bugs too. So do many management processes or even cooking recipes. They're just not called bugs but problems, roadblocks, surprises or something else. Being a software developer for some time now and half the time also father of two kids I started to notice that raising kids has bugs too. So with this little analogy I would like to shed some light on these fantastic creatures and how to find them.
This is the face of awe of a soon-to-be parent staring at a positive pregnancy test. It also happens to resemble the face of an Engineer being confronted with a big new feature, epic or project coming up. It's excitement, it's what we've set out to do (exceptions may occur), yet it is intimidating and we don't know much about what we are about to embark on.
So what do we do? Of course we want to come up with a great plan for that. A process addressing all of the smaller and bigger things we expect to happen. It is going to be perfect.
Perfection has some history to its name but in a nutshell it can be described like this:
The oldest definition of »perfection« […] goes back to Aristotle. […] he distinguishes three meanings of the term […]
– which contains all the requisite parts;
– which is so good that nothing of the kind could be better;
– which has attained its purpose.
In essence it describes a state. We will pick this up later but let's stick to parenting and software developing. Of course with the new challenge ahead we want to build a perfect environment for our kid. In a modern software company you would probably write something like this:
As a parent I want a parenting system so that my kids can grow up to be healthy, happy and nice to other people.
And the odds seem to be in our favour. There are a plethora of books on the subject and millions of other parents out there and not a few parents love to share their experiences with you whether you asked for it or not.
Finally the big day has come: The journey begins. Excitement, endorphins and for some weeks parents and developers alike are surrounded by a tight bubble of joy called either the maternity leave or the project kickoff. But eventually things start to go a little sideways.
There are some really fun myths about the source of the name including the famous Grace Hopper story that a moth got stuck in a Mark II relay thus coining the term bug for something that broke a computer. Lovely story but unfortunately an urban legend.
A bug is basically a situation in which an expectation does not match the actual situation. When interacting with software everybody knows that moment when you click on a button and something else happens. The app crashes, a red error message appears, or something weird happens. Anything but the thing you would have expected. Let's stick with expectation for a bit: What does that even mean? To cut things short this is not easy to answer as there is huge variety of types of expectations:
- Expecting that a computer solves 1 + 1 to equal 2 every time you ask it (deterministic system)
- Expecting that the sun will rise in the east (scientific fact)
- Expecting that a kid would not spit the food back on the plate (social norm)
- Expecting that this time you'll win the lottery (belief)
Again: A bug is simply an outcome that does not match your expectation or put differently: The most likely thing to happen. Defining expectations however is neither straight forward nor is there always one answer only.
So let's jump into parenting and see how it is curiously similar to developing software. Remember the perfect parenting system we were talking about? So what could possibly go wrong? Please note that I skip the obvious: Human errors. Yes, you shouldn't forget to put on a diaper on your baby in the morning but why bother as it's probably inevitable and likely a symptom of another reason – sleep deprivation anyone?
This strikes any parent on many occasions in different severities over many years. Unless you became parents multiple times you start parenting with no previous experience or maybe even set out to »not become like your parents«. You are required to »learn it on the job«, learn from the surprises, adapt from the experience of others. Nobody told you all the things that can happen so the first version of your parenting system won't factor them in. Or did you know that it's normal that babies lose quite a lot of weight right after birth? That can make your sleepless nights even more sleepless unless anybody explained to you that this is fairly normal.
But it gets worse: A newborn has only a very limited set of expressions to tell you want it wants. Right off the bat it has one: Screaming. Over time it will acquire more skills but until a child is able to take one's standpoint, develops empathy or the cognitive and social skills to have a profound discussion it takes years. And once this is possible we likely find that our expectations might differ. Dramatically.
It is not very different in software development. A main contributor to functionality being perceived as buggy is based on different expectations or communication strategies. The sentence »It's not a bug, it's a feature« has not been famous by accident. Missing and misunderstood specifications aren't that very different either as both are rooted in conflicting expectations. What you perceive as missing in a feature specification can be too obvious to write down for somebody else. What you understood from what someone else said or wrote up is based on your prior knowledge, context, perspective.
First of all I don't like the term »helicopter parent« as it is considered solely a bad thing. Essentially it describes parents that are highly invested in the health and well-being of their kids. That is great! At a certain degree some might consider this over-protective as kids naturally need a degree of freedom to learn from their own experiences. But how much is too much considering that each kid is unique? And how can we assert this as a third person? And why should there be a general recipe alias the »silver bullet«?
You can be a »helicopter« developer as well. You can spend infinite time on testing your code and try to achieve a high coverage of tests, i.e., a number that tells you how much of your code is under test. But you can run into paralysis and become unable to let go of an implemented feature at all. Or you just optimise entirely for the coverage KPI assuming this assures working code. It doesn't.
In practise there is no degree of testing that protects all of our code from bugs in production as we as parents cannot protect our kids from any bad experience. That's just the way it is and probably not something to strive for. Instead we can look into the quality of our tests.
Having said that let's use an example: How do you make sure that your kid brushes its teeth right? At home we tried a lot of different strategies:
- Brush at least two minutes → Your kid can conveniently hold the toothbrush steadily while doing something else
- Brush all teeth at least once → Okay, so touch all of them for 10 milliseconds and done?
- Brush all teeth at least once for 20 seconds → »Dad, I am 4, I don't know how long 20 seconds are?«
- Play »Fight the Plaque monster« → »Wait, so you're saying there is a monster in my mouth?«
- Explain the long term effects of caries and how you cannot see, touch or feel it but after many years some person in a white dress will use a drill to make holes in your teeth because you haven't brushed properly
These are just some examples how you can fail to make sure your kid's teeth stay clean and healthy despite all the crazy sorts of candy it comes across at granny's house.
In software development granny's house is the production environment and the teeth are all the big and small features you've developed over time. Just to design a test strategy that actually tests the right thing is far from trivial and in many companies it's the reason why testing is either outsourced or omitted entirely, i.e., its long term value is discarded for short term goals.
Remember how we said that babies only have one way of communication in the first months? Yes, it's screaming/crying and a baby uses it to express a selection of one or many of the following: wanting to cuddle, hunger, thirst, a dirty diaper, tired, too hot, too cold, bored, overstimulated, digestive problems, loneliness, and more. As one can imagine this can be really stressful and hard to pin down, especially in the middle of the night or in case you have more than one kid crying at the same time. And as each kid is unique the same »patterns« won't work interchangeably. To cut a long story short: Understanding the needs of kids requires our dedication, time, experience, and patience and still we'll be surprised over and over again.
Every software starts as a few lines of code: concise, easy to understand and test, with a single identifiable purpose and few variables. But then we start assembling many of those to more complex system, piling functionality on top of each other, using frameworks with dozens of conventions and configuration parameters, then we put it into containers and ship it to even more complicated systems to run our software there. Feature complexity usually grows very quickly and newly introduced technical components add to that and soon we have a software system that cannot be understood by a single developer anymore. And at some point a user contacts customer support saying after clicking on some button something failed and we have a hard time figuring out why. The more complicated the system the higher the likelihood that a combination of parameters will lead to unexpected behaviour.
Once our »parenting system« has evolved to a degree of sophistication we start to say things like »We're out of the woods now«. And that might even be true but now we're entering an area of more subtle cases where expectations and reality differ and lead to bugs. A great first example is your kid's birthday. Your kid, its siblings and best friends, all super hyped, eating tons of sugar; unforeseeable social dynamics and you're in for some surprises. The more kids, the more surprises. At the end of the day you're probably exhausted and the party laid waste to your home from which you need to recover as well. I really wonder if anyone can prepare parents for that?
That's pretty much how integrating third-party code feels like. Ask any frontend developer how hard it is to adapt the style of a third-party frontend component to look like your main application. Or maybe you find that this great library that is supposed to be the silver bullet for all of problems hits the limitations of your current architecture and you start to take compromises here and there. Or the original authors stopped documenting well enough after the »My first hello world« tutorial. It's much easier to develop code that is within your reach, i.e., you have the resources to develop the code yourself. But this will scale as badly as a birthday without party guests. So we are forced to find a balance even though it's an inevitable risk.
Other situations that are very hard to anticipate are occasions where your kid spends time outside the »comfort zone«, i.e., not at home and without the parents being around. To be fair this usually means our comfort zone as the kids will have the time of their life. That could be the weekend with the grandparents that probably have slightly loose rules on candy and TV or the cool aunt and uncle that love to white water raft during a thunderstorm with your kids. Sometimes, if it's really troubling us, we talk to our relatives beforehand to take the edge off but let's be honest: We cannot and should not expect our relatives to live up to the exact standards we would. How fun would that be anyway?
We also cannot expect our software to behave identically on controlled test environments with controlled data in contrast to production environments with real users and their data. We regularly face situations where something happens that is out of our control and which we cannot really prepare for. Just google for news on »DNS outage« for some worst case scenarios. But there are plenty of cases to decide whether we take the effort to test for certain corner cases or not. You will find long articles on the philosophical question how to position yourself between using several deployment environments and testing in production.
So let's talk about scaling or growth. Kids grow quickly. They undergo massive changes in their physique and intellectual capabilities in short amounts of time. Some of it we address actively like giving your kid more freedom when it wants to do things more independently such as playing outside without constant supervision. But some of it just happens naturally over time like growing and losing teeth, increase in body size and eventually puberty. All of that is challenging for kids and parents alike as our accustomed strategies might not work anymore. Our status quo is challenged constantly. Some of these side effects can be addressed easily: That one pair of shoes that used to fit perfectly and doesn't after winter season can be replaced by new ones. But not all of them. In its worst form they are experienced as growing pains.
In principal software scales actively and passively as well. Actively we do this by acknowledging and anticipating growth with good software design so we are able to scale properly. But regardless whether we do something about it or not most software systems scale, i.e., grow anyway. That's because software does not live in a void. Maybe the most prominent pattern is a growing user base. A feature that used to perform fine for our users today can become slow and unresponsive even though we wrote it with some anticipation, good tests and high quality. Sometimes a feature is bug free up until a certain threshold has been reached (a certain number of objects or parallel requests) and all of a sudden something that used to work becomes buggy and we need to adapt the code. Our software might have been built using a framework so it needs constant updates to be safe against new security threats. The list of examples is long.
Finally let us look into singular events in the life of our kids that are usually both exciting and frightening at the same time. For your kid and for us as parents. A great example is the first day of school. Leaving kindergarten and entering school life comes with so many radical changes: A different place to spend the day, new daily routines, many new kids and adults to meet, new expectations. Safe to say that this is a huge change that puts many things that we used to take for granted into question. And whilst entering school is probably one of the biggest changes there are many more examples in the life of kids and their parents where our norms are put to the test.
If you haven't migrated a software to a different infrastructure, i.e., to different servers or services, you will miss out on many challenges that you can run into: Maybe you need to migrate data, coordinate downtimes, communicate with your users, find strategies to educate others about the impact on their daily work and tooling. Or you have to change your monitoring or alerting, discontinue outdated documentation, thus communicating even more. The amount of moving parts is huge and on top of that migrations aren't performed if not for certain urgency and necessity. Because why migrate if your current system scale, security standards or flexibility to deliver new functionality doesn't require you to do so? Keeping a complex process like this bug free is an engineering skill that is really hard to achieve.
With all that in mind I think it's safe to say that there is no perfection. It is a state; an ideal. It is something we can strive for but in reality never achieve. All things considered we might be able to achieve an optimal or the most favourable configuration. For a time. The reality surrounding us as parents and developers will change and we have to be willing to adapt and to find a good balance between pragmatism, quality and sanity. Writing software from scratch won't help either.
So parents including myself try to focus on the most important challenges at a certain point in time. Yes, we could worry to which secondary school to send my two year old kid but right now it's very, very hungry. If we find that something needs to be adjusted along the way we do. In software terms it means we do not waterfall but we try to go for incremental changes and act on the challenges and feedback in order of priority. That means to not slice an entire bread first, then butter all of the slices, then jam, then put one on the plate and the rest in the fridge for some time in the future just to find that our kid wanted musli in the first place. This happened in tons of software projects and that's why agile development was invented.
Parents and developers look for effective testing strategies that serve both the purpose of protecting against something bad and also addressing the fact that you just cannot test everything. The reality in which our kids – and software – lives is way too complex to anticipate all possible outcomes. And it probably helps to stay sane along the way.
We try to automate. Parents use baby monitors to be alerted when the kid wakes up instead of checking every five minutes. Ideally to react quick enough so the kid doesn't really wake up. So do software developers trying to find problems before their users do and to fix them quickly.
Also we take compromises to get to 80% in time instead of shooting for 100% with the risk of getting nothing. That one little episode of Paw Patrol before bed as a reward for brushing teeth can be a fair trade-off every once in a while instead of trying to educate your exhausted and tired kid about the long term effects of bad teeth brushing technique.
We collaborate to challenge our decisions and learn from each others experiences with our partners, family, friends; or in the case of software development: Our team mates and co-workers. And we try to identify efficient and effective ways to react on problems and to learn from them.
One final thing I would like you to take home: There is no – and never will be – software without bugs, processes without glitches, strategy without exceptions, or being a parent without surprises. Things go wrong for many different reasons and sometimes just because our »system« does not live in a void and needs to be adapted over time. Most bugs aren't simple equations but a mismatch between reality and (subjective) expectations. Therefore acknowledging the unique character of our software and the quality of our strategies to identify, react on and learn from bugs are the key factors for a healthy system in the long run.
Published by Basti Tee
Visit author page