Fizz? Buzz? FizzBuzz? Let’s discuss.

What's the buzz all about? Well, originally it started out as a small children's game, but now and again I see it being used to detect weak developers in job interviews (I think there are better ways to do this). The assignment has a view nice properties. In this blog I would like to look at some implementations and discuss the pro's and con's of each implementation.

The assignment goes a little like this:

Write a program that prints the numbers from 1 to 100. But for multiples of three print “Fizz” instead of the number and for the multiples of five print “Buzz”. For numbers which are multiples of both three and five print “FizzBuzz”.

Source: http://wiki.c2.com/?FizzBuzzTest

Let's solve it in JavaScript, as almost anyone can read JavaScript.

Straightforward solution

Let's start with the simplest solution first, because: first make it work, then make it pretty. Let's take the rules and convert them into a program.

for (let i = 1; i <= 100; i++) {
  if (i % 3 == 0 && i % 5 == 0)
    console.log('FizzBuzz');
  else if (i % 3 == 0)
    console.log('Fizz');
  else if (i % 5 == 0)
    console.log('Buzz');
  else
    console.log(i);
}

Pro: it is very readable and a direct translation of the original question into code. Con: it will test for mod 3 multiple times in the same path of execution. The max number of mod operations on i will be 3 - when something is mod 5. This also goes against the DRY principle, because we are repeating our selves here.

Eliminate multiple mod 3 tests

Let's make sure no mod is tested excessively:

for (let i = 1; i <= 100; i++) {
  if (i % 3 == 0) {
    if (i % 5 == 0)
      console.log('FizzBuzz');
    else
      console.log('Fizz');
  }
  else if (i % 5 == 0)
    console.log('Buzz');
  else
    console.log(i);
}

Pro: the code is still readable. The number of mod operations on i is 2 - which we would expect (for a single number). Con: we have multiple tests for % 5, but they don't execute on the same path - some might consider it duplicate code (thus going against DRY).

Test for 15?

Some solutions will test for modulo 15 as a number that is a modulo of 3 an 5, must be modulo 15 as well. The code would look like this:

for (let i = 1; i <= 100; i++) {
  if (i % 15 == 0)
    console.log('FizzBuzz');
  else if (i % 3 == 0)
    console.log('Fizz');
  else if (i % 5 == 0)
    console.log('Buzz');
  else
    console.log(i);
}

Pro: code is readable. Con: where does 15 come from? You might need some explanation / comments in the code on how the number came about. The max number of mods on i is now 3 - but 2 was the optimum solution.

Introducing variables?

What if we introduce some constants into the example code. Will readability and re-usability improve?

const fizz = 'Fizz', buzz = 'Buzz', fizzBuzz = fizz + buzz;

for (let i = 1; i <= 100; i++) {

  const isFizz = i % 3 == 0;
  const isBuzz = i % 5 == 0;

  if (isFizz) {
    if (isBuzz)
      console.log(fizzBuzz);
    else
      console.log(fizz);
  }
  else if (isBuzz)
    console.log(buzz);
  else
    console.log(i);
}

Pro: it is now very clear what when something is fizz or buzz. Number of "heavy" mod operations is limit to 2. Con: the code becomes slightly more verbose. We introduced 2 extra variables in the loop - giving us a little more memory overhead.

String manipulation

Some solutions use string manipulation to get the right answer:

for (let i = 1; i <= 100; i++) {
  var str = '';

  if (i % 3 == 0)
    str += 'Fizz';
  if (i % 5 == 0)
    str += 'Buzz';
  if (str.length == 0)
    str = i;

  console.log(str);
}

I'm not sure what to think of this solution. It solves the assignment. A con might be the string manipulation overhead (?).

Conclusion

A simple problem. Many solutions. Some optimize for the computer, other's optimize for the human (readability). What I like about this assignment is that it will give you stuff to talk about.

expand_less