Have you ever wondered why sometimes fixing a bug seems to take longer than it should? When you finally find the problem, it turns out that all you need is a small change. However, it took a lot of time to find out what was going on. This happens more often than I thought.

On the other hand, when you write code and test it and it doesn’t work, fixing bugs is very fast. You jump back into the editor, pull up a line of code, and the problem is solved.

Why is it that even if the problem is simple, sometimes fixing the bug takes a lot of work, and sometimes, fixing the problem is fast – and can be hard to fix? Can we learn from bugs that are easy to fix so that we can spend less time fixing bugs?

Let’s talk about the problem and see what we can do to fix it and stop pulling hair because it’s hard to find the fault.

Typical bug repair process

To determine how long it took to fix the bug, let’s take a look at the steps involved in fixing the bug.

  1. First, we need to understand the problem. That means we need to know what went wrong, where, and what should happen.
  2. Next, we need to reproduce the bug. A typical case might be that we need to go into the application we’re working on and click on something to see what happens.
  3. Then, we need to figure out which part of the code is causing the problem. We can usually start it by using a debugging tool – for example, using Chrome’s debugger to step through the code on the page where we reproduce the problem.
  4. Once we find the code snippet that caused the problem, we need to determine the root cause. This difficulty can vary greatly depending on the complexity of the problem.
  5. After determining the root cause, we were finally able to fix the error.
  6. Finally, we need to make sure that the bug is actually fixed. This is usually done by trying to recreate it again.

Well, I think we’re starting to see a problem here. Fixing the bug itself is only one in six!

But before we jump to conclusions, let’s look at these steps in more detail. Then, we can see how much time each step takes and find ways to make them faster.

Step 1: Understand the problem

The first step in the bug repair process is to understand the problem. We need to gather enough information so that we know what happened and what should have happened.

The biggest contributor to this step taking a long time is horrible, bad bug reporting.

Users never provide good error reporting. It’s an undeniable fact of life.

I might exaggerate a bit, but I’m sure you’ve heard the words “it doesn’t work” more often than you’d like.

“X didn’t work, it needed to be fixed yesterday!”

Then you go on to ask questions in the hope that you can glean something more useful from the reporter than “It didn’t work.”

Of course, sometimes you get a good error report when the planets and stars are aligned correctly. You can see exactly what went wrong, reproduce the exact steps of it, and even get information about the browser and operating system the user is using! At that point you can go straight to Step 2 and start fixing the bug.

But in the worst case, you’ll only have a vague idea of what’s going on, which means more effort in Step 2.

Step 2: Repeat the error

This section can be easy if you get good error reporting in Step 1. You can follow the steps in the error report and repeat the error immediately. That’s great! Now, you can continue to find the corrupted code.

Sadly, this step is often not so smooth.

This step often involves a lot of guesswork due to vague error reports.

Maybe the user is using Firefox, or maybe they’re using Chrome. They are not sure what they have done until they click this button. I wonder if I should press the button at random and hope for the best?

Sometimes, after trying to reproduce the problem, you have to repeat steps 1 and 2 without producing any results. Hopefully, you can get more information from the user and try again.

It is clear at this point that in order to speed up steps 1 and 2, we need to gather as much information as possible. The more information we have, the easier it is to understand and reproduce problems.

Step 3: Find the problematic snippet

Once we reproduce the bug, we need to find the specific part of the code that caused the problem.

The difficulty of this step varies depending on two factors:

  • The amount of code you have
  • You are familiar with the code base
  • (To a lesser extent, what you know about debugging tools)

The amount of code affects this because each line of code increases the number of possible errors. Fortunately, familiarity with the code base Narrows the field considerably.

Finding a problem usually begins by taking an educated guess.

“Ok, that’s the problem, that’s how I can reproduce it, so I think the problem is in the Y part of the code.”

The more familiar you are with the code base, the better your guess will be. This allows you to narrow down the amount of code you need to see, which may require a lot of tweaking.

“Well, I’ve been working on function Z, which has code for this. I’d better check it out first. “

Depending on the type of problem, you can also use debugging tools to help you find problematic code more easily.

“Yes, I get an error when I click on it. I’ll set a breakpoint in the event handler and start from there. “

** The biggest time sink at this stage of the process is to find the exact location where the problem occurred. ** It could be a misbehaving feature, bad value for the user, or any number of things that you need to get to the root of the problem before proceeding.

Step 4: Determine the root cause

This is probably the most important step in the process, but it’s often skipped entirely!

It may be skipped because of perceived time constraints, or simply because inexperienced developers may not know they are supposed to do so. Either way, skipping this step usually means that your code slowly starts filling up with Hacks and Kludges.

Notice, I said feel the time limit. Often you may feel pressured to fix things quickly.

“Just a quick fix and the customer is waiting. You can do good work in the future. “

Therefore, you can use some code to fix broken code and skip the root cause. Of course, you’ll probably never be able to fix it properly, because there’s always something that needs to be done.

But a quick fix a quick fix has the same results as using duct tape to fix a leaky pipe. Even in Finland, we call tape “Jesus tape” because of its amazing ability to fix anything, and at some point the tape fix starts to leak and you need to use some more tape. Before long, you’ll have a huge mess on your hands and you’ll have to tear it all out.

Finally, you need to spend more time fixing quick fixes than you do doing the right thing.

But I digress.

Identifying the root cause means that you need to find the true source of the error. Let me give you an example.

Assume that some values on your site are displayed incorrectly. You can fix this by changing the display code, but more often than not, the code that displays symptoms is not the root cause.

If you dig deeper into the problem, you may find that the data in the database is also wrong. Digging deeper, you can see that the code that holds the value has been corrupted. This is the root cause of the problem. The raw code you find is just a symptom of the problem elsewhere.

If you just fix the symptoms, the real problem is there. It will continue to cause problems in the future as you continue to fix more symptoms.

Unlike looking for symptoms, this step does not require much guesswork. You have a starting point from which you can trace the root cause, so you don’t have to guess.

However, this step can be time-consuming, as you often need to drill down into the code at several levels. How long it takes depends largely on where the root cause is compared to the symptoms – sometimes they may even be the same, but as the example shows, it can be several grades lower.

Step 5: Fix the bug

Finally we can solve this problem. We have replicated the error, found where the symptoms occurred and found the root cause.

After all the work is done, this step is usually fairly trivial. We have information about what went wrong, what should happen and what symptoms are present. Bugs usually don’t require major changes to fix, so the implementation part is often quick.

Step 6: Make sure the bug is fixed

As the last step in the process, we need to make sure that mistakes are completely covered up.

This can be done by repeating the steps you took earlier to reproduce the problem.

Occasionally this bug still recurs. In this case, you usually need to go back to steps 4 or 5 and continue from there.

If software testing, interface testing, automated testing, performance testing, LR script development, interview experience exchange. If you are interested, you can go to 175317069. There will be free information links in the group from time to time, which are collected and sorted out from various technical websites. If you have good learning materials, you can send them to me privately.

What’s wrong with this process?

Now that we have looked at each step in the bug repair process, we can identify the key difficulties:

  • Lack of information about the problem: Error reports often lack important information, which makes it difficult to understand and reproduce the problem. The less information we have, the more time we spend.
  • Guess: We often have to guess. We didn’t have all the information we needed to fix the problem, and there was no way to pinpoint the problem in the code. So we need to guess, which is inherently fallible
  • Time constraints: We often need to fix bugs quickly because users and customers as well as the business depend on the software to work. This, in turn, can lead to a failure to properly analyze the problem, which can lead to more errors and problems.

All of this helps slow down bug fixing and makes it a tedious process. The part where we write code to fix bugs is rarely the biggest time sink!

But, having said that, sometimes we can fix bugs very quickly. This usually happens when we add new features and deal with brand new code.

Why is that?

If we’re thinking about the typical situation when we’re using brand new code, we’re usually pretty familiar with what we’ve just written. The person who finds the error in this case is usually the same person who wrote the code.

That almost completely eliminates speculation!

  1. We know the code we just wrote
  2. We often test our code in small incremental steps, so there is less code that can cause errors

Fixing errors is therefore a breeze. More often than not, you just need to return the Alt-tab to the editor and find the problem immediately and fix it faster, rather than saying, “It doesn’t work.”

Gather better information

It’s safe to say that the lack of information and the resulting guesswork is the biggest factor that causes bug fixes to be slow.

What can be done to improve the situation?

Let’s first look at what we can do to get more information from the user and into error reporting. The first step is to ask the user some specific questions. This helps guide the user to give us the information we need to solve the problem more effectively.

Here are some questions you can use. I don’t remember the first time I saw these, but I tend to use this format myself and it works fine.

  1. A brief description of the problem
  2. What happened?
  3. What should happen?
  4. How do you reproduce this problem?

The first is not absolutely necessary, but it can be useful if you use a tool like JIRA because you need a name for the problem. The second is fairly obvious, and the third is useful for understanding what users expect to happen. While you can solve this problem on your own, it’s best to know about it beforehand – especially since sometimes it may not be a technical problem, but just the result of confusion.

The fourth point may be the most important, but users don’t always know how to fill it. If possible, it’s best to give them a small sample if you want it to fill, such as “1. I click the button Y. 3. I enter the value Z “.

Other information that is particularly useful for Web applications is the user’s browser and operating system. Depending on the user, they may not always know this, so being able to collect this information automatically can be valuable. To do this, you might consider integrating services such as Usersnap, which helps collect more data into error reports.

Having a stack trace is also often useful in the case of script errors, and you should be able to get it yourself, although with good reproduction steps. Tools like Loggly can be used to automatically collect information about errors, even in client-side JavaScript code, so you can better understand what’s going on.

These steps are a good starting point for improving the process. But they didn’t really solve all the problems. For example, users can and will continue to send confusing error reports no matter how much you try.

I know. I repeatedly tell users that they need to include steps to reproduce the problem, or that we can’t do anything, and I still keep getting horrible “it doesn’t work” bug reports.

“Jani, X is broken fix it.”

Ah.

So what else can we do that doesn’t depend on picky users?

Record runtime information

Records are often overlooked as a tool. Maybe this lacks a good library, or a good tool for using log output – because let’s face it, who wants to browse a huge log file by manually looking up specific events? But done correctly and with the right tools, logs can provide valuable information.

Most developers use logging only as a temporary measure. It’s easy to dump a bunch of ‘console.log’ into our code just to see what happens – I did a lot of that.

But when I say logging, I’m not just talking about debug logs or error logs. I’m talking about login in general – information about what’s happening in the code, what input is being sent, etc.

Logging in in a more systematic way takes some work. We need to be careful to include our code for logging in, and we need to make sure that we record information that might be useful. So does this help speed up bug fixes?

  • Sometimes, if the user doesn’t tell us, there may be a problem. Automatic processes are basically opaque without logging, and you’ll never know what went wrong.
  • If you have good logs, they can help you find problems faster. Depending on what and how you record, they can point to the general direction of the problem and even provide more specific information, such as showing you which values are wrong.

Especially in the case of automated processes, logging is important. Unless you have logs, you usually cannot track what is happening in such processes. The log should be detailed enough to give us a reasonable idea of what’s going on.

Using such logs helps reduce guesswork by giving us more useful information.

As much as I like to make Java suck, logging is one thing they do really well. It has a number of libraries and established logging practices. If you’ve ever had a problem with a Java application, you might look at the log and even increase the log detail. Many of them put out a lot of logs.

What are the records useful for? It’s not absolutely necessary for every application to have a log or log everything, but here are some examples:

  • Record personal requests. For example, if you’ve used Apache or Nginx, they both have a log file that gets a line for each request the server executes, along with information about it. This information alone is not necessarily useful, but if you log more than one piece of information per request, it’s probably a good one to log first.
  • Document steps in a process or transaction. Let’s assume that your users can upload images, but you can resize them. You can record each step in the process, such as “uploaded image”, “Resize image”, etc.
  • Document interactions with external tools/services. Access a database, API, or in our image resizing example, if you call a tool like ImageMagick to perform some action.

Depending on how useful you are to find logs, it is also a good idea to implement ways to enable/disable certain types of logs or to enable/disable logs on a per-user basis.

Find errors faster

All of these measures that we’ve seen so far do not address our key problem. Error reports and logs, while useful, only provide more information after the fact.

Remember how we found the important difference between bugs that were fixed quickly, and bugs that took a long time to fix were the time we detected the problem.

Whenever we actively work on a piece of code and find bugs during development, they are much faster to fix. We have a fresh memory of the code, we already have all the information, so we don’t need to do any other necessary archaeology.

None of this has helped so far, even though this is one of the biggest contributors to how much time is spent.

How can we find more errors faster, even in our development process?

Obviously, we could hire two dozen QA experts to make changes with a microscope. However, this is not very practical for most teams, and even with a quality assurance process, it may take some time to discover the problem, by which time we have moved on, so it doesn’t help.

inOne area of development that helps us find errors is test automation.

  • We can run automated tests on development machines
  • Unit test suites can run automatically quickly, even after small code changes
  • Well-designed tests can give us accurate information about the problem

Test automation is a more realistic goal. It doesn’t require a large upfront investment: you can start using it gradually, and get more and more benefits with each step.

How can unit testing speed up bug fixing?

Every time we change the code, we risk introducing errors. However, if there are bugs in our newly added code, we usually find them easily and fix them.

Newly added or changed code is easy to fix because we’ve mastered it – we just take the time to study it! This means that any problems can be easily found and fixed, since we don’t have to start digging code to find it. We can still remember where things are going.

Therefore, we can agree that the sooner we find the error, the easier it will be to fix it.

But how does unit testing help us do that?

First, unit tests usually contain the following sections:

  • A descriptive name of what is being tested, such as “It should validate the user’s name”
  • A short code snippet for initializing and running tests
  • Validation. There’s one for each testassertionsTo verify that the code snippet produces the correct result.

Then, if such a test fails, we get the following information:

  • The name of the failed test
  • For specific information about how an assertion fails, we are often given a specific comparison, such as “username does not match expected format”
  • A stack trace, which gives us the specific line of code that caused the failure

Let’s compare this to the error report we want:

  • The name of the
  • A description of what happened
  • A description of what should happen
  • A list of steps to reproduce the problem

Can you see the results we got from the test? We get the information we want from a good error report! Not only that, but testing gives us this information during development. *

Unit tests can give you immediate feedback on the information you need while you’re still working on the code, so your ideas are fresh.

All of this helps ensure that we have enough information to fix the bug quickly. We know what happened, what should have happened, and we can reproduce the error by running the tests again… We can even verify that our bug fix code works by running the test again.

As an added bonus, the tests also catch more errors elsewhere in the code. Often as a result of our changes, we accidentally cause errors elsewhere. These are easy to overlook and ultimately hard to fix, but if you have unit tests, no problem – once you write tests, you can keep it, it keeps catching bugs and being useful.

conclusion

By fixing bugs, the biggest receiver of time is not writing fixes. All the work we need to do before we start writing any code to fix bugs. Much of this is due to a lack of information – bad error reporting, lots of code, and even bad code can lead to errors.

We can improve the situation by trying to get more information in the bug report, but the best way to fix the bug faster is to catch the bug earlier.

Bugs encountered during development are the fastest to fix because we are actively working with the problematic code and we have the information we need in our heads. This means we don’t need to start digging through bug reports or code to figure out what’s going on.

The best way to catch more problems during testing is unit testing. They solved all three problems:

  1. We don’t have enough information. Fixed – Failed tests tell us what went wrong and what should have happened, pointing out our exact functionality. The test itself is a reproduction of the bug.
  2. Unless we are very familiar with the entire code base, we need to do some work to get to the root of the problem. Resolved – Failed tests tell us which feature failed, so no guesswork is involved. Better yet, tests often fail during development, so all the code is still fresh in our memory.
  3. Because of time constraints, root cause lookup is sometimes skipped, resulting in code errors. Resolve – The test will fail the root cause, not the symptoms, giving us the exact location we need to address.

You also don’t have to spend a lot of effort testing. You can start adding tests one by one, for example when fixing errors. With each test you add, you get more and more benefits.

The main problem with testing is that it can be hard to get started. However, once you learn these concepts, they are timeless – unlike popular libraries today, tests have been around for a long time and the exact same principles can be used no matter what library or language you use.

Unit testing has more benefits than just fixing bugs faster.

Further reading

  • Learn the best books on software testing. These 8 books can help you a lot
  • Software testing engineer for 7 years, how to break the bottleneck at the beginning? Little detours