How A Simple Algorithm Goes Straight To Hell

Several years ago, the Oatmeal did a fabulously hilarious poster that showed how a website redesign starts off on the right foot– only to become completely derailed into a horrible abomination by client feedback and endless revisions.

Web Development is more efficient. We don’t let client feedback mess up our code. Instead, we screw it all up by ourselves.

Ladies and Gentlemen, I present to you the “FizzBuzz Problem.”

Disclosure: I went through a job search in 2014, and no one asked me to solve the FizzBuzz problem in a job interview. The only reason I’ve heard of it is because it was mentioned on Quora. Personally, I think it sounds condescending and alienating, but it makes a great example of “HOW A SIMPLE ALGORITHM GOES STRAIGHT TO HELL!”

Shall we get started?

The objectives in the FizzBuzz Problem are simple:

1) write an algorithm that prints the numbers 1 – 100.

2) whenever you reach a multiple of 3, print “fizz.”

3) whenever you reach a multiple of 5, print “buzz.”

4) if you reach a number that is a multiple of both 3 and 5, you should print both “fizz” and “buzz.”

If you are into the test-driven development/iteration paradigm, your progress might go something like this:


// meets first criteria (print out 1 – 100)
for (x = 1; x <= 100; x++) {
console.log(x);
}
// fails to swap in fizz for multiples of 3
// fails to swap in buzz for multiples of 5

view raw

fizzbuzz01.js

hosted with ❤ by GitHub


for (x = 1; x <= 100; x++) {
if (x % 3 == 0) { console.log("Fizz") }
if (x % 5 == 0) { console.log("Buzz") }
console.log(x);
}

view raw

fizzbuzz01.js

hosted with ❤ by GitHub

That came pretty close, but for a number that is a multiple of both 3 and 5, it prints fizz and buzz on two adjacent lines instead of a single line. Let’s get them on the same line if we can.


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

view raw

fizzbuzz01.js

hosted with ❤ by GitHub

At this point, we’ve met all the criteria and the script should be left alone. Except we both know there’s always a developer out there who has to make a “more elegant solution” . . . right?

Easy is the descent into Hell, for it is paved with good intentions.
– John Milton, Paradise Lost

It usually goes something like this:


for (x = 1; x <= 100; x++) {
var sayThis = "";
if (x % 3 == 0) { sayThis += "Fizz"; }
if (x % 5 == 0) { sayThis += "Buzz"; }
if (sayThis == "") { sayThis = x; }
console.log(sayThis);
}

view raw

fizzbuzz01.js

hosted with ❤ by GitHub

Shiny! By using a variable as a flag, we can get rid of those ugly chained if-else statements. See what an elegant programmer I am? #snark

It doesn’t end there, naturally. Someone else comes along and says “Hey, if we make this into a function with parameters, then we can solve this puzzle game using any starting and finishing numbers!” (And I’ll admit it– I’ve been THAT guy before.)


function fizzbuzz(start, finish) {
for (x = start; x <= finish; x++) {
var sayThis = "";
if (x % 3 == 0) { sayThis += "Fizz"; }
if (x % 5 == 0) { sayThis += "Buzz"; }
if (sayThis == "") { sayThis = x; }
console.log(sayThis);
}
}

view raw

fizzbuzz01.js

hosted with ❤ by GitHub

So now we can do things like this:

fizzbuzz(1, 100000);
fizzbuzz(-1000, 1000);

Isn’t that incredibly useful? #moreSnark

But what if we want to play a version of the game that uses different numbers than 3 and 5, or we want to play the game in a foreign language? I know, we can pass even more parameters through the function call!


function fizzbuzz(start, finish, modFizz, modBuzz, txtFizz, txtBuzz) {
for (x = start; x <= finish; x++) {
var sayThis = "";
if (x % modFizz == 0) { sayThis += txtFizz; }
if (x % modBuzz == 0) { sayThis += txtBuzz; }
if (sayThis == "") { sayThis = x; }
console.log(sayThis);
}
}

view raw

fizzbuzz01.js

hosted with ❤ by GitHub

There! That ought to handle anything we should need.

fizzbuzz(-1000, 1000, 2, 13, “Gallifrey Falls”, “No More”);

Except with all those required parameters, it’s only a matter of time until someone accidentally omits one (which will throw an “undefined” error) or enters them in the wrong sequence (in which case the code will run but likely return unintended results). Yikes!

We can add a verbose documentation header to our function . . .


/*
* fizzbuzz() function
* I play the fizzbuzz game (http://en.wikipedia.org/wiki/Fizz_buzz)
*
* arguments:
* start – required integer (e.g. 1)
* finish – required integer (e.g. 100)
* modFizz – required integer (e.g. 3)
* modBuzz – required integer (e.g. 5)
* txtFixx – required string (e.g. "fizz")
* txtBuzz – required string (e.g. "buzz")
*
* Usage: fizzbuzz(1,100,3,5,"fizz","buzz");
*/
function fizzbuzz(start, finish, modFizz, modBuzz, txtFizz, txtBuzz) {
for (x = start; x <= finish; x++) {
var sayThis = "";
if (x % modFizz == 0) { sayThis += txtFizz; }
if (x % modBuzz == 0) { sayThis += txtBuzz; }
if (sayThis == "") { sayThis = x; }
console.log(sayThis);
}
}

view raw

fizzbuzz01.js

hosted with ❤ by GitHub

but no one reads directions any more, do they? #yesEvenMoreSnark

And this is when the Devil himself walks in and says, “Have you considered making it . . . object oriented?”

YES, OF COURSE! WHY DIDN’T I THINK OF THAT BEFORE? EVERYONE KNOWS THAT OBJECTS FIX EVERYTHING! (And we can even initialize our properties with default values that users can override as needed.)


/*
* fizzbuzz() object
* I play the fizzbuzz game (http://en.wikipedia.org/wiki/Fizz_buzz)
*
* properties:
* start – integer (optional, defaults to 1)
* finish – integer (optional, defaults to 100)
* modFizz – integer (optional, defaults to 3)
* modBuzz – integer (optional, defaults to 5)
* txtFixx – string (optional, defaults to "fizz")
* txtBuzz – string (optional, defaults to "buzz")
*
* methods:
* play();
*
* Usage:
* example 1:
* fizzbuzz.play(); // uses default values
*
* example 2:
* fizzbuzz.start = 5;
* fizzbuzz.finish = 50;
* fizzbuzz.play(); // plays with 5 – 50, uses default values for other properties
*/
var fizzbuzz = {
start: 1,
finish: 100,
modFizz: 3,
modBuzz: 5,
txtFizz: "fizz",
txtBuzz: "buzz",
play: function(){
for (x = this.start; x <= this.finish; x++) {
var sayThis = "";
if (x % this.modFizz == 0) { sayThis += this.txtFizz; }
if (x % this.modBuzz == 0) { sayThis += this.txtBuzz; }
if (sayThis == "") { sayThis = x; }
console.log(sayThis);
}
}
}

view raw

fizzbuzz01.js

hosted with ❤ by GitHub

And that, Ladies and Gentlemen, is how to transform a simple for loop into a JavaScript object with more documentation than actual code.