Bugs... those pesky little creeps that tend to infiltrate the most obscure places and destroy the great aspirations of engineers!
The term was first used to describe a computer flaw or glitch in 1947, when a team at Harvard observed that their computer, the Mark III, was delivering a consistent stream of errors. After tearing apart the hardware, they found an actual bug - a moth - on its insides.
This term is more commonly used in computer software but, in reality, reports on what is now called bugs can be found as early as the 1800s in Thomas Edison’s reports of his designs. Any type of system is susceptible to bugs, but for the sake of the article, we will be focusing on the computer kind.
It’s of no surprise to anyone working in or with technology that bugs, or as I prefer to call them surprise features, are a very common concern. Jokes aside, they are a very real and very likely consequence of software development. They can impact everything about a software product including performance, and basic functionality, or in the best case scenario, they just create unexpected situations for the final user.
So now that you have a basic understanding of what bugs are, let's dig into how to handle their existence, the concept of offensively looking for bugs, and tools you can use to find or prevent them. We are also going to address why in the end, bug hunting can be a very positive use of developers’ time.
Offensive Bug Hunting
For the rest of the article, we will call actively looking for bugs Offensive Bug Hunting. Bugs are not magical entities that make code misbehave. They are flaws written into the product, they are unacknowledged behavior. For the most part in software development, conditions are deterministic, and I am not saying that some aspects like network conditions, temperature, and interference can’t create unexpected conditions, but even those for the most part can be accounted for and coping mechanisms can be added.
So, let's say that you have minded every uncontrollable factor, everything that is left is your code and your design and this is where the hunt begins. When offensive bug hunting, you are taking an active part in causing bugs, so you will look for the conditions that can disrupt your system and force them to occur. But how do you start?
There are multiple first approaches but I would say that if your product has a client-facing aspect, start from there. These will be the bugs that your client will see. I am not speaking exclusively of frontend issues but problems you can see on the user side. Latency can be one of them for example.
Define your user behavior. Imagine your product is a mobile app. Do you know how your clients are using it? How long are they in the app? How do they explore your content? Can they exploit issues? Put yourself in their shoes, and use the app. Now you know a user type (yourself) but my advice would be to account for different types of users. They may be children, they may not be used to working with technology, and they can have your app in the background of their phone almost permanently because they can never seem to remember to close their apps.
My point is that an app should be able to handle different types of users. From a developer perspective, this is scary because we strive to make something work but that is a dangerous mental framework. It reduces the resilience of the product. The client won’t be doing you any favor. Users will use the app when, where, and however, they want.
Finally, on the topic of users, you should also account for malicious users. There are users equally in their right to download your app to try the things that you did not prepare for. Not hacking per se, but abusing the mechanisms that are built into the system, that you put there, to perform actions that are not in your business's best interest. If you ever played video games, you know that this is very common. Bugs in games can be harmless, funny, or even creative but in other types of apps, you are opening yourself up to exploits.
So, put yourself in the malicious user’s shoes. Your goal is to break the system so you can build it stronger.
Strategies for the hunt
I have spoken about some generic types of users, but now I’ll go into further detail regarding the user profiles and conditions. The goal is to increase the likelihood of encountering edge cases. These situations are difficult to encounter in the development environment because they do not represent the norm.
You should attempt to account for all types of network conditions while testing. Stress your product with intermittent connection, random latency, mobile connection... These approaches will create conditions that are more difficult to reproduce but equally possible. The problems are already there, you just have to expose them. Acknowledge that conditions will likely not be perfect for many users.
As previously mentioned you should account for different clients using the app differently. To approach the subject I suggest the creation of defined user profiles or personas. For demonstration purposes, I will define three very simple users of a social media app for sports streaming and news but they may not be the most adequate for your product.
The Teenager: Josh
- It’s tech-savvy and interested in sports
- Uses the app mostly for articles and stats. Loads a lot of content fast and leaves the app soon after opening it.
- Does not tolerate buffering so any type of loading will result in leaving the app before the loading ends
- When he leaves the app does not leave it open in the background
- Has a bad internet connection because he only uses mobile networks
Let's analyze Josh. From a backend perspective, Josh will probably be a high-stress user because a lot of content will be served in a short time when compared to other users. This may cause loading issues, UI may not change fast enough, the variety of content may be so great that a lot of it may not be cached anywhere and so it may take a bit longer to load. As we know, if Josh starts encountering loading times in the app, he may leave. When this occurs, what will happen to the requests that he did not complete?
The Grandpa: Jack
- It’s not used to smartphones, it’s his first device and it’s an old model
- Sometimes he does not lock his phone before putting it in his pocket
- His son installed the app so he can view football games while on the bus
- At the end of a session, he leaves the app open in the background or simply open
What can we say about Mr. Jack? His behavior in the app may be random when it's in his pocket. Is the app prepared for completely accidental/random behavior? Most of the content he watches may be live or recorded streams but if he leaves the app open on a stream in his pocket, what happens to those connections? He watches mostly streams on the bus, the connection will probably vary, causing buffering.
The Hacker: Jolyne
- She looks for application exploits
- She is a computer expert
- Her smartphone is rooted
- She has scripts running in the background of the smartphone running the sports app just looking for unexpected behavior
- She is actively looking for access to other user’s information
Of course, Jolyne is an absolute edge case. In her scenario, the issue may be more related to security and penetration testing than edge case bugs. Nevertheless, the truth is that unexpected actions can lead to revealing security flaws. And these can lead to massive data leaks and jeopardize your company.
Remember, these personas are just examples of those you can use to represent your clients. In the end, the most important takeaway is that you should prepare your product for any kind of behavior. If you are having trouble imagining it from the confines of the development environment, try to impersonate the various types of users your app may encounter.
So be creative, and think outside the box.
I am not going to go into much detail about the tools you can use to prevent or find bugs. Truth is that most software developers at some point are placed in contact with these. But I’ll give you a taste.
Before you are looking for bugs in the wild production environment, I suggest that you take a look at your development processes. Consider using a tool for continuous inspection of your code quality and add it to your development processes. Take a look at all those warnings that your IDE has been yelling at you for some time. I know this is no surprise to anyone reading this article, but consider unit testing and when that’s done, or if it can’t be done, attempt integration testing. Don’t forget to also do this in the backend and if you use Kubernetes, consider chaos testing.
Why go on the Bug Hunt?
In my opinion, actively looking for bugs and issues can be very healthy for any project and team. It can improve attention when performing code reviews. Generates a greater knowledge of the project which can help reduce code debt. Being aware of the best practices can also help improve code quality and readability, which will lead to the easier integration of new members into the team.
At the end of the bug hunt, the hunter will probably be more aware of many fragilities of the processes involved in the development and that knowledge can be used to improve them.
From a startup perspective, quality is especially important to be mindful of potential issues. Bugs can spell doom for a company especially when they occur in the hands of a client, so proper attention should be given to them. They are easy to ignore when grinding for new features but the ground in which you build should be the most secure.
To end this article I just want to empathize that bugs are difficult, common, annoying, and appear unexpectedly. So try to prepare for the edge cases because they do exist (even if they only happen to a fraction of the users).
Be offensive in how you approach your app and go catch them all.