How To Solve Bugs During Development

How To Solve Bugs During Development

How I Debug Code When Stuck

Solving Errors When Stuck

To many developers (like me), software development involves brainstorming problems, implementing solutions, and of course, debugging errors. Inevitably, there may be a breaking change that needs fixing, and sometimes, systems crash entirely, because the developer is unable to find the errors or debug the issue.

Here are the top 4 things I do when stuck during development:

1. Retracing my steps

I always check the error messages to see what broke. In frontend development, I use the browser's developer tools to monitor the logged errors. In backend development, the terminal generally has the error messages. Most times, the error message tells you exactly what went wrong.

dev console error.JPG

Browser error message, telling me I've made a syntax error.

terminal error.JPG

Terminal error message, telling me a variable is not defined.

Many times, I spelt a variable incorrectly (fooo instead of foo), or missed a semi-colon at the end of the line. These are syntax errors, and can easily be solved when identified; and I can continue development quickly.

2. Researching the issue (documentation, stackoverflow, forums, etc)

Oftentimes, the incorrect use of imported libraries can cause the errors. Sometimes, a simple quick fix is not readily available, as the developer does not know how to use the library's APIs correctly.

error from library.JPG

Error trying to find all records using prisma.

When I'm stuck with errors from an API, I google search the library or package and browse multiple links on the topic. For example, if I forgot the proper syntax for creating a record in prisma, I enter the following search:

create user prisma search.JPG

From there, I check the documentation, Stack Overflow discussions, or GitHub forums for proper references and guidance. Most times I leave with much more knowledge than I was looking for, such as how to create a record and update it too.

I also use google when searching for algorithms or other functions I may need, that are too complex to retype every time. Maybe I already implemented a remainder function but realize that it moves slow. Googling existing remainder functions in the language of my choice can bring a much more optimized code snippet that I can use to speed up my own application.

My first ever implementation of a remainder function:

function remainder(dividend, divisor) {
    if(dividend == divisor) {
        return 0;
    } else if(divisor == 0) {
        return divisor;
    } else if(dividend == 0) {
        return 0;
    } else if(dividend > 0) {
        divisor = Math.abs(divisor);
        while(dividend >= divisor) {
            dividend -= divisor;
        }
    } else if(dividend < 0) {
        divisor = Math.abs(divisor) * -1;
        while(dividend <= divisor) {
            dividend -= divisor;
        }
    }
    return dividend;
}

A similar function found while searching:

function remainder(dividend, divisor) {
    return dividend % divisor;
}

Of course, I "generally" did the research to understand the optimized code before I used it in my own work.

3. Manually debugging code

Sometimes, even without syntax errors, your program would not work as expected. Either your function to perform a calculation returns a NaN or Infinity value, you are redirected to an arbitrary page, or your application generates additional fields unexpectedly because you put <= instead of < in a for loop. These can all be caused by logic errors or runtime errors.

When researching or reading error logs do not work, I add breakpoints to my code to interactively see the different values to understand where it went wrong. Can you determine why my add function returns 20 instead of 9 when I input 4 and 5?

function addTwoNumbers(num1, num2) {
    let sum = num1 * num2;
    return sum;
}

If you realized I put the wrong operator, you guessed correctly. It did not give syntax errors, but the application did not work as intended. Adding breakpoints and then monitoring each line can help find logic errors and get your functions working again, so you are no longer stuck.

Debugging Trivia (Shameful Disclaimer)

While I do use breakpoints, I find it easier (and faster) to log my variables in the function and then monitor the console for the specific values:

function addTwoNumbers(num1, num2) {
    console.log("Num1 is " + num1);
    console.log("Num2 is " + num2);

    let sum = num1 * num2;

    console.log("Sum is " + sum);

    return sum;
}

let nine = addTwoNumbers(4, 5)

// Console prints:
// > Num1 is 4
// > Num2 is 5
// > Sum is 20

From the console, I notice the sum was incorrect, which prompts me to check sum assignment expression and realize I wrote * instead of + in the statement.

4. Exploring communities like Discord

When learning to develop, I joined Discord servers such as Web Dev Simplified and Nodeiflux and spent lots of time asking questions there. Many helpful developers assisted in real time debugging and problem solving.

Disclaimer (Being Spoonfed)

While it is helpful to have instantaneous assistance, try to use this option as a last resort. Making mistakes and learning how to solve them is important to a developer's growth and learning. At the beginning I spammed questions for every small issue, but soon realized that I would only depend on others, and not learn anything myself, so I tried solving problems myself before asking for an answer right away. I have actually been able to solve the issues myself without needing assistance!

As time passed, I have been able to give back to these communities by answering questions myself, helping other developers that may be stuck themselves.


Minimizing Errors and Increasing Development Productivity

During development, causing bugs or getting stuck is inevitable. However, with the right tools, sufficient practice, and patient preparation, you can reduce the amount of bugs that may appear in your code, and get stuck less. That way, you can spend more time working on your applications, and less time debugging or being stuck.

Here are 2 tips for decreasing the chances of getting stuck while you code:

1. Spend time brainstorming your problem before implementing it

An important part of development is design; understanding what you are developing as well as what is needed for it. Generally, I spend more time thinking about how I will implement a feature, than I spend actually implementing that feature.

Discuss it with peers

Usually, I request feedback on proposed solutions by asking classmates, talking to discord helpers, or publishing discussions on forums. Sometimes, they share knowledge that benefits me; whether it is a different perspective, a more efficient function, or an existing tool that already solves my problem.

Write it down on paper

I also like breaking down steps on paper to mockup what needs to be achieved, often with pseudocode to help. For my game engine, I often spent weeks designing or constructing an idea or feature, and then when it was time to implement it, I did so in a few days.

The benefit of planning in advance is that you have enough time to think of many general edge cases, and when you get to coding, you implement the feature faster. Also, since you are may already have pseudocode, you can end up with less errors, as you are not instantly coding from your head and thinking of fixing unexpected cases afterward.

Spending lots of time planning first before implementing is not suitable for all development environments; you still spend time on the application. However, that time is spent productively designing and developing, rather than developing and then trying to debug and fix crashes and errors.

2. Use statically typed languages

With dynamically typed languages (such as JavaScript or Python), type checking occurs at runtime. It is easy to write logically incorrect code, such as attempting to subtract objects from integers. While these assignments may not result in syntax errors all the time, they do result in logical errors that are only discovered at runtime.

With statically typed languages (such as TypeScript or C++), type checking occurs at compile time. The benefit of this is that you are warned in advance of any possible unintended expressions that can result in hard to discover bugs. This increases productivity as well, since less time is spent finding bugs later on.

Bonus Advice

It is okay to fail

Even with all those steps and tips, you can still get stuck:

  • maybe the error message is not helpful at all;
  • maybe google has no searches recorded for the issue;
  • maybe debugging code and creating breakpoints shows no abnormalities;
  • maybe no one on Discord can help you with your issue either;
  • maybe after days preparing your solution, implementation fails, and you have to re-plan everything;

That is okay, and to that I suggest taking a break, and trying again at another time. Maybe you may be able to solve it in the future.

In production environments where deadlines are impending, professional advice would be to reach out to a senior for assistance; it is better to admit your shortcomings and seek assistance earlier, than keeping quiet until deadlines where everything is in a rush.

Conclusion

These are all steps that have continued to work for me as a software developer. Of course, it gets frustrating when you are stuck, and I blame the software occasionally, but eventually, I have always been able to solve my problems and proceed with my software development.

It is always a refreshing thrill when your code finally works again!

Stay tuned throughout the next 3 weeks for more articles like this!

Thanks for reading!