5. To think if something works, it's done right

Take a look at this function that adds up odd numbers. Is everything correct there?

const sumOddValues = (array) => {
  return array.reduce((accumulator, currentNumber) => {
    if (currentNumber % 2 === 1) { 
      return accumulator + currentNumber;
    }
    return accumulator;
  });
};
 
 
console.assert(
  sumOddValues([1, 2, 3, 4, 5]) === 9
);

The test passes and life is beautiful, right? Wrong. The problem with this code is that it's incomplete. It only works correctly for a few cases, and our successful test verifies just one of them.

Problem 1

There is no check for empty input. What happens if a function is called without arguments?

An error will be displayed.

TypeError: Cannot read property 'reduce' of undefined.

This is bad code for two main reasons: users of your function shouldn't be confronted with the details of its implementation, and the error message isn't informative.

To the user, the function simply doesn't work, and they won't understand how to fix the situation. It would be much better if the error was reported like this:

TypeError: Cannot execute function for empty list.

Or maybe you should change the function to ignore blank input and return 0? Either way, you have to do something. You can't leave it as it is.

Problem 2

No validation. What if a string, number, or object is passed to the function instead of an array? This is what would happen:

sumOddValues(42);
TypeError: array.reduce is not a function

The catch here is that array.reduce is just a function. But since you named the argument of the function "array," whatever you pass to it (in this example, it's 42) will be called an array inside the function. In fact, the error says that 42.reduce is not a function. Wouldn't it be better to make the error output like this:

ErrorType: 42 is not an array, dude.

Problems 1 and 2 describe standard exceptions that are easy to anticipate. But there are also less obvious exceptions that you have to be careful with. For example, what happens if the array contains negative numbers?

sumOddValues([1, 2, 3, 4, 5, -13]) // => still 9

Should the program treat -13 as an odd number? Or ignore it? Or throw an error? Should the function be renamed "sum of positive odd numbers"? You can easily pick the one you want. But the interesting thing here is that if you don't write tests to document how your function works, those who will accompany them won't even be able to tell if this is a bug or a deliberate assumption.

"It's not a bug. This is a designed functionality" - a convenient excuse for those who do not write tests.

Problem 3

Not all valid cases work correctly. Forget various tricky exceptions. This function doesn't work correctly with a perfectly normal set of variables, either.

sumOddValues([2, 1, 3, 4, 5]) // => 11

In this example, 2 will be added to the sum, even though it shouldn't. This happens because no initialValue is passed to the reduce function, so the first element of the array is taken as the initial value. That's why it's important to write a test for such a case as well. If there isn't one, it's another sign of beginner's code.

Last updated