DEV Community

Cover image for Fantastic Bugs and Where to Find Them
marvinav
marvinav

Posted on

Fantastic Bugs and Where to Find Them

Introduction

Welcome back to our magical journey through the land of software bugs. If you missed the previous part, where we deciphered the enigmatic signs of bugs, fret not. This chapter will delve deeper into the mystical sources of these bugs and reveal the charms and spells needed to ward them off.

Bugs living in code

In the enchanted world of software development, there exists a hidden realm where bugs lurk like mischievous pixies. Much like the infamous Cornish Pixies released by Gilderoy Lockhart, these bugs wreak havoc in the most unexpected ways, causing chaos in codebases instead of classrooms. Welcome, dear reader, to a magical exploration of the dark arts of debugging, where we'll uncover the curious creatures known as mistype bugs, logical bugs, misusing bugs, and the ever-elusive integration bugs. Grab your wand (or, in this case, your keyboard) and prepare for a journey through the enchanted corridors of coding mishaps, where every spell cast (or line of code written) can lead to unexpected enchantments—or disasters.

Mistype bugs

Mistype bugs are typically not dependent on the developer's experience level. They tend to be more a function of company culture than any one person's skill. Common contributing factors are poor code review, no linters in CI/CD pipelines, few unit tests, and tight deadlines. Mistype bugs can range from simple typographical errors to more subtle mistake types that even avoid static code analysis tools. And to give you a personal example: I mixed in the letter 'c' from Cyrillic (UTF16 0441) with the letter 'c' (UTF16 0063) in the name of the endpoint. The name for the endpoint was createPhase with the Russian 'c' at the start. Deployment of this bug led to three web services failing.

Mistype bugs can result in various problems within an application: infinite loops, out-of-memory problems, security hazards, and program freezes. For example:

const Component = () => {
  const [count, setCounter] = useState();
  useEffect(() => {
    setCounter(count++);
  }); // If you forgot the second parameter, the empty array, as a dependency. It will be trapped in rendering an infinite cycle of increasing the counter

  return <div>{count}</div>
};
Enter fullscreen mode Exit fullscreen mode

Logical bugs

Logical Bugs are the ones that live inside the code logic. They occur when the code does not work as expected, even though it is syntactically correct. For example:

const calculateSum = (a, b) => a + b;
const Component = () => {
  const [result, setResult] = useState(0);
  useEffect(() => {
    setResult(calculateSum(1, '2')); // Logical error: '2' is a string and causes the output to be combined
  }, []);
  return <div>{result}</div>
};
Enter fullscreen mode Exit fullscreen mode

In this case, the cause for logical error is that the function calculated should add two numbers, but one of the arguments is a string. This leads to string concatenation instead of numerical addition hence the result it gives is something that is not expected.

Misusing bugs

Misusing bugs occur when a library or infrastructure or some language feature is wrongly used. Those bugs occur because the developer does not know the right way to use the tool and thus gets something wrong or some mistake in the code. These misconceptions can generally result in significant issues regarding the functionality of the application and its performance. Take, for instance, the following misuse of the useEffect hook in React:

const Component = () => {
  const [data, setData] = estate (null);
  useEffect(() => {
    fetch('https://API.example.com/data')
      .then(response => response.json())
      .then(data => setData(data));
  }, [data]); // Misuse: Including 'data' as a dependency leads to an infinite loop of fetching data

  return <div>{data? JSON.stringify(data) : 'Loading.'}</div>
};
Enter fullscreen mode Exit fullscreen mode

In this case, the dependencies for useEffect are being misused, making it result in an infinite loop. The fetch operation is called again on every update of data, hence leading to an infinite re-fetch operation and can be a performance nightmare.

Misusing debounce from lodash:

import _ from 'lodash';

const handleResize = _.debounce(() => {
  console.log('Window resized');
}, 1000);

window.addEventListener('resize', handleResize); // Forgetting to remove the event listener on component unmount
Enter fullscreen mode Exit fullscreen mode

Integration bugs

System-level integration bugs occur mainly when the interaction of two or more units of code written by different developers fails to interact correctly with one another. Inconsistencies or incompatibilities between the components often lead to these bugs in many situations. They are complex to find and repair because developers need to look at more significant chunks of code, which can be lengthy to replicate. For instance, consider the following scenario of an integration problem between a frontend React app and a backend API:

Example 1: Mismatched API Contract

// Frontend: React component expecting data in a specific format
const fetchUserData = async () => {
  const response = await fetch('/api/user');
  const data = await response.json();
  setUser(data. user); // Expects the API response to having a 'user' field
};
// Backend: Express route sending data in a different format
app. get('/api/user,' (req, res) => {
  res.json({ userData: { name: 'John Doe,' age: 30 } }); // Sends 'userData' instead of 'user'
});
Enter fullscreen mode Exit fullscreen mode

In this example, the frontend expects the API response to having a user field, but the backend sends a userData field. This then causes integration problems, leading to failure of the frontend in the correct processing of data.

Example 2: Version Incompatibility

// Frontend: Using an old version of a shared library
import { format } from 'shared-library@1.0.0';

const formattedDate = format(new Date()); // Uses old formatting function

// Backend: Updated to use a new version of the shared library
const { format } = require('shared-library@2.0.0');

const formatted date = format(new Date(), 'YYYY-MM-DD'); // New formatting function requires an additional parameter
Enter fullscreen mode Exit fullscreen mode

Here, the frontend and backend are two different environments working with the same shared library, but in this case with versions not compatible with each other. Because the frontend relies on an older version of the formatting function, it will break when working with the backend, which has the updated version of the library.

Bugs created by business

The incantations of business requirements often summon unexpected creatures into our codebase. Much like a misfired spell from a novice wizard, these bugs emerge from the foggy misunderstandings between developers and the business side of things. Gather around, dear reader, as we delve into the world of business-induced bugs—those mischievous gremlins that sneak past the boundaries of specifications, twist the logic of business rules, and conjure unnecessary complexities.

Out of Bound

Features and functionalities may go past or deviate from the specified requirements or intended use cases. The error might have occurred because of miscommunication or misconception in the first place between business developers and users. Implementation usually happens in features that are not required that are not accurately defined, or that are outside the project's scope. This may lead to resource waste, increased complexity, and potential issues in another part of the system.

Example 1: Unnecessary Features

A project requirement calls for a simple user registration process. A developer goes ahead to implement a multi-step registration that is meant to integrate with social media and additional verification steps because they misunderstood the requirements. It went out of scope, unnecessarily added complexity, and possibly more points of failure.

Example 2: Misinterpreted Requirement

The requirement is that users should receive email notifications for critical updates. A developer perceives these as notifications for every minor change, and the end users get bombarded with irrelevant emails, hence missing out on crucial updates.

Business Logical Bugs

Business logical bugs arise when the implemented logic does not align with the business rules, requirements, or use cases. These bugs usually arise from an improper or partial understanding of business logic, leading to features whose functionality does not serve the intended purpose, or they misbehave under certain conditions. Such bugs may have terrible effects on a system's functionalities and operability.

Example: Application of Discount in the Wrong Manner

An e-commerce website has a business rule that declares that a 10% discount applies on orders over $100. Developers implemented this logic, but after new feature was deployed product owner seen that discount applies for order with the price after tax applied for it. This case wasn't clarified in requirements, and e-store owner spent more money on the promo campaign than it wanted.

Reducing the Number of Bugs

Bugs, after all, are an inevitable part of software development. Still, their frequency and impact can be significantly reduced through best practices incorporated throughout workflow processes, code development, and business communication. A brief guide is given below.

Workflow Process

  1. Implement Project Management Methodologies: For example agile methodologies have made it easier to do iterative development with continuous feedback and adaptive planning. This way, you can address pitfalls early in the development phase.

  2. Continuous Integration/Continuous Deployment (CI/CD): Automated integration and deployment processes further ensure that any change to code keeps being validated and integrated, with a reduction in the chances of integration bugs and maintaining builds in a stable state.

  3. Code Reviews: This is a means of correcting mistakes that may be overlooked. Multiple pairs of eyes on your code can easily catch potential issues earlier and improve the general quality of the code.

  4. Automated Testing: Unit, integration, and end-to-end tests as part of the CI/CD pipeline detect bugs at various levels of the development process.

Code Development Process

  1. Adopt Coding Standards and Guidelines: Having coding standards and guidelines ensures that code is uniform, readable, and maintainable and that one can quickly identify and fix bugs.

  2. Static Code Analysis Tools: Utilize tools such as ESLint, SonarQube, and Pylint, among others, to check the source code for likely issues: errors, code smells, and security vulnerabilities that a developer has to take into account beforehand.

  3. Unit Test Writing: Ensure that all test cases are written to find bugs on-time—more of the logic and mistyped bugs. Try to attain a high percentage of coverage with meaningful test cases.

Business Communication Process

  1. Clear Requirement Gathering: Thorough and precise requirement gathering from stakeholders is critical. Arrange regular meetings with stakeholders so the development team is well-versed with business needs.

  2. Maintain a Well-Defined Glossary: Involvement in creating and maintaining a glossary will ensure that team members have a common understanding of central concepts and terms. Thus, it will minimize the possibility of miscommunication.

  3. Regular Feedback Loops: Ensure that your development team has set up regular feedback loops with the stakeholders. This ensures that the project work is coherent with the business objective; thereby, any deviation may be checked promptly.

  4. User Acceptance Testing (UAT): Engage users in testing the system to ensure the software meets their needs and expectations. Business logical bugs are not likely to be detected by developers; UAT is an effective way of identifying these errors.

Conclusion

Minimizing the number of bugs is an exercise in several dimensions, calling for perfection in all phases of software development. Best practices in workflow processes, along with the rigorous development of code and intensive communication of business issues, ensure a significant reduction in the number of bugs that crop up; this ultimately results in more reliable and robust software.

Top comments (0)