Categories
Career Programming

Programmer interview challenge 2, part 5: An elegant “watcher”-based FizzBuzz implementation in JavaScript

Silhouette of a little black dress on a dress form
Ask someone who follows fashion what they think of when the word “elegant” comes up, and they’ll often come up with the Little Black Dress.

In the previous article in this series, I put out a call for alternate implementations of the “watcher”-based FizzBuzz solution. Frank Quednau answered the call with this elegant bit of JavaScript:

const wordWatcher = (interval, word) => {
  let count = 0;
  return () => {
    count++;
    if (count === interval) {
      count = 0;
      return word;
    }
    return "";
  }
}

const fizzWatcher = wordWatcher(3, "Fizz");
const buzzWatcher = wordWatcher(5, "Buzz");

for (number of Array(100).keys()) {
  const potentialFizzBuzz = `${fizzWatcher()}${buzzWatcher()}`;
  console.log(potentialFizzBuzz ? potentialFizzBuzz : number + 1);
};

Let’s take a closer look at the code for the watcher, which is assigned a word and keeps track of when to say it:

const wordWatcher = (interval, word) => {
  let count = 0;
  return () => {
    count++;
    if (count === interval) {
      count = 0;
      return word;
    }
    return "";
  }
}
  • wordWatcher has two parameters:
    • interval: The x in “Every xth number”
    • word: The word to be output
  • It uses those parameters to customize the function that it returns: a function that when called, does two things:
    • It increments its internal counter count, and
    • returns either word (if it’s time to say the word) or an empty string.

If you find yourself writing a lot of similar code with only minor differences — or worse, cutting and pasting code, followed by typing in those minor differences — you may be looking at an opportunity to use a function like this.

If you prefer to have your functions marked with the keyword function, you can change out the arrow notation and the code will still work:

function wordWatcher(interval, word) {
  let count = 0;
  return function() {
    count++;
    if (count === interval) {
      count = 0;
      return word;
    }
    return "";
  }
}

With wordWatcher defined, creating watchers for Fizz and Buzz is easy:

const fizzWatcher = wordWatcher(3, "Fizz");
const buzzWatcher = wordWatcher(5, "Buzz");

And here’s the loop that provides the output:

for (number of Array(100).keys()) {
  const potentialFizzBuzz = `${fizzWatcher()}${buzzWatcher()}`;
  console.log(potentialFizzBuzz ? potentialFizzBuzz : number + 1);
};
  • If it’s time to say FizzBuzz, or FizzBuzz, potentialFizzBuzz will contain that string. The calls to fizzWatcher() and buzzWatcher() will also increment their internal counters.
  • If potentialFizzBuzz contains anything, its contents will be printed to the console; otherwise, the current number — which has 1 added to it because array indexes start at 0 and the FizzBuzz game starts at 1 — is printed instead.

You should check out the rest of Frank’s Gist, Fizzbuzzes in many colours, which looks at FizzBuzz solutions written in several languages.

What does it mean for code to be “elegant”, anyway?

In ordinary everyday use, elegant means “pleasingly graceful and stylish in appearance or manner.” The term has been adapted by people in problem-solving fields — science, mathematics, and yes, programming — to mean “pleasingly ingenious and simple”.

And that’s what elegant code is: pleasingly ingenious and simple. This FizzBuzz implementation is elegant because it solves the problem in just over a dozen lines, is simple and concise, and even provides some new insight into programming (the use of custom-generated functions to avoid repetition).

Here’s a good list of qualities of elegant code, courtesy of Christopher Diggins article, What is the Definition of Elegant Code?:

  • It is succinct
  • It is easy to understand
  • Each function does one well-defined task
  • It conveys the programmer’s intent
  • It reflects the problem domain
  • It is easy to modify and reuse
  • If it fails, it is easy to identify that it is has failed, where it has failed, and why it has failed.
  • Its behavior (in good and bad conditions) is easy to predict

Check out the following articles — sooner or later, you’ll be interviewed by a programmer who’ll want to know if you’ve given some thought to some of programming’s more philosophical questions, and “What does it mean for code to be elegant?” is one of them:

What’s next

FizzBuzzBazz! (or: Making FizzBuzz harder).

Previously, in the “Programmer interview challenge” series

 

Categories
Career Programming

Programmer interview challenge 2, part 4: Using “watchers” to play FizzBuzz “properly”

The Marvel Comics character known as “The Watcher” - “I am known as The WATCHER. My sworn task is to observe and chronicle great events within this sector of the universe. My curse is to always witness and never participate. I must be true to this duty, even to the brink of Armageddon!”
Marvel Comics’ Watcher. His people are sworn to observe, but not interfere in, everything that happens in the universe.

After reading the previous article on FizzBuzz solutions, Reginald “raganwald” Braithwaite, whom I know from my days as part of the Toronto tech scene, tweeted this:

JenniferPlusPlus agrees:

They both make a good point. If you’re playing the FizzBuzz game as the original children’s game and not as an exercise to prove that you can actually write a program, you’d do it like this:

  • Players sit in a circle, not unlike “the circle” in That ’70s Show.(Players don’t have to be high, unless it helps.)
  • The player designated to go first says the number 1, and each player afterwards counts one number in turn. The next player in the circle says 2, and so on.
  • However, for every third number, instead of calling out the number, the player whose turn it is should say “Fizz”.
  • …and for every fifth number, instead of calling out the number, the player whose turn it is should say “Buzz”.
  • The “Fizz” and “Buzz” rules, as the kids would say, stack. In other words, for every number that is both the third and fifth, the player needs to say “Fizz” followed by “Buzz”, or “FizzBuzz”.

So in the spirit of the original game, I’ve put together a FizzBuzz solution that uses “watchers” to keep track of  “every xth number”, with one watcher to keep track of when it’s time to say “Fizz”, and another for when it’s time to say “Buzz”. When it’s time to say “FizzBuzz”, they’ll work in tandem.

I created a class called WordWatcher, which can be summarized as shown below:

Here’s its code:

class WordWatcher:

  def __init__(self, interval, word):
    self.counter = 0
    self.time_for_word = False
    self.interval = interval
    self.word = word

  def observe_next_turn(self):
    self.counter += 1
    if self.counter == self.interval:
      self.counter = 0
      self.time_for_word = True
    else:
      self.time_for_word = False

  def speak(self):
    if self.time_for_word:
      return self.word
    else:
      return ""

Some notes about this code:

    • For those of you who aren’t familiar with Python’s approach to class methods, the first parameter for every method in a class is self. It’s the one parameter you don’t fill when calling a method, because Python calls it implicitly (seemingly in violation of Python’s general guideline that explicit is better than implicit). There’s a reason behind this, and it’s explained in this article: Understanding self in Python.
    • Also note that instance variables are declared and defined in the initializer method, __init__(), and any reference to them is always preceded by self.
    • The observe_next_turn() method is meant to be called as the fizzBuzz method proceeds to each new number. It updates the watcher’s internal counter and sets the time_for_word flag accordingly.
    • The speak() method outputs the watcher’s word if it’s time to say the word, or an empty string otherwise.

For FizzBuzz, we’ll need to create two watchers:

  1. One to keep watch for every third turn, at which point it should say “Fizz”, and
  2. one to keep watch for every third turn, at which point it should say “Buzz”.

With the WordWatcher class defined, we can create these two watchers like so:

fizz_watcher = WordWatcher(3, "Fizz")
buzz_watcher = WordWatcher(5, "Buzz")

It will become handy to have these two watchers in the same place. Since the “ha ha only serious” joke about Python is that everything is a list, let’s put them into a list:

word_watchers = [fizz_watcher, buzz_watcher]

Let’s define a fizzBuzz() function that makes use of this list of word watchers:

def fizzBuzz(word_watchers = [], first = 1, last = 100):
  final_result = ""

  for number in range(1, 101):
    current_result = ""

    if len(word_watchers) > 0:
      # This part might need some explaining
      _ = [word_watcher.observe_next_turn() for word_watcher in word_watchers]
      words = map(lambda word_watcher : word_watcher.speak(), word_watchers)
      current_result += functools.reduce(lambda total, next_element : total + next_element, list(words))
    
    if current_result == "":
      current_result = str(number)

    final_result += current_result

    if number < last:
      final_result += ", "
    else:
      final_result += "."

  return final_result

If you’ve been following the FizzBuzz series of articles, most of this code will be familiar. The part that might need explaining is the part with the comment “This part might need some explaining”.

Explaining the part that needs explaining

Let’s look at the first of the three lines of code in that part:

_ = [word_watcher.observe_next_turn() for word_watcher in word_watchers]
  • The _ on the left side of the = sign is a throwaway variable. It says “I don’t care about what you do on the other side of the = sign; only that you do something on the other side of the = sign”.
  • On the right side of the= sign is a list comprehension, which is Python’s “show, don’t tell” way of building lists. This list comprehension simply says “call the observe_next_turn() method of every object in the list”.

Let’s look at the next line:

words = map(lambda word_watcher : word_watcher.speak(), word_watchers)
  • This line creates a map that converts the watchers in the list into the words they should say for this turn. If the current turn means that it’s time for any one of them to speak, the watcher will be mapped to the word it’s supposed to say. Otherwise, it will be mapped to an empty string.

And now, the final line:

current_result += functools.reduce(lambda total, next_element : total + next_element, list(words))
  • For some reason, map() comes built into Python, but you have to import the functools library in order to use map()’s partner in crime, reduce(). Remember reduce() is a functional programming thingy that takes a collection of items, performs some kind of calculation on that collection, and returns a single value (which you might call a reduction of the collection).
  • The first argument that I’ve provided to reduce() is a lambda — a small function that isn’t given a name — that simply takes the current item in the list and adds it to the previous collected items. Applied over the entire list, it builds a “total”, which in this case is all the words output by the watchers’ speak() methods concatenated together.
  • The second argument is the words map converted into a list. This is the list that the reduce() method will operate on.

At the end of those three lines, current_result will contain one of the following:

  • The empty string
  • Fizz
  • Buzz
  • FizzBuzz

If current_result is still empty at this point, it means that it’s not time for any of the watchers’ words. If this is the case, the string version of the current number is concatenated to current_result:

if current_result == "":
      current_result += str(number)

Here’s the code in its entirety:

import functools

class WordWatcher:

  def __init__(self, interval, word):
    self.counter = 0
    self.time_for_word = False
    self.interval = interval
    self.word = word

  def observe_next_turn(self):
    self.counter += 1
    if self.counter == self.interval:
      self.counter = 0
      self.time_for_word = True
    else:
      self.time_for_word = False

  def speak(self):
    if self.time_for_word:
      return self.word
    else:
      return ""


def fizzBuzz(word_watchers = [], first = 1, last = 100):
  final_result = ""

  for number in range(1, 101):
    current_result = ""

    if len(word_watchers) > 0:
      _ = [word_watcher.observe_next_turn() for word_watcher in word_watchers]
      words = map(lambda word_watcher : word_watcher.speak(), word_watchers)
      current_result += functools.reduce(lambda total, next_element : total + next_element, list(words))
    
    if current_result == "":
      current_result += str(number)

    final_result += current_result

    if number < last:
      final_result += ", "
    else:
      final_result += "."

  return final_result

fizz_watcher = WordWatcher(3, "Fizz")
buzz_watcher = WordWatcher(5, "Buzz")
word_watchers = [fizz_watcher, buzz_watcher]
print(fizzBuzz(word_watchers))

And for completeness’ sake, here’s the test file:

import pytest
from fizzbuzz_with_watchers import fizzBuzz, WordWatcher

plain_1_to_100_result = "1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100."
fizzBuzz_1_to_100_result = "1, 2, Fizz, 4, Buzz, Fizz, 7, 8, Fizz, Buzz, 11, Fizz, 13, 14, FizzBuzz, 16, 17, Fizz, 19, Buzz, Fizz, 22, 23, Fizz, Buzz, 26, Fizz, 28, 29, FizzBuzz, 31, 32, Fizz, 34, Buzz, Fizz, 37, 38, Fizz, Buzz, 41, Fizz, 43, 44, FizzBuzz, 46, 47, Fizz, 49, Buzz, Fizz, 52, 53, Fizz, Buzz, 56, Fizz, 58, 59, FizzBuzz, 61, 62, Fizz, 64, Buzz, Fizz, 67, 68, Fizz, Buzz, 71, Fizz, 73, 74, FizzBuzz, 76, 77, Fizz, 79, Buzz, Fizz, 82, 83, Fizz, Buzz, 86, Fizz, 88, 89, FizzBuzz, 91, 92, Fizz, 94, Buzz, Fizz, 97, 98, Fizz, Buzz."

def test_fizzBuzz_null():
  result = fizzBuzz()
  assert result == plain_1_to_100_result, f"The watcher solution returned the wrong result:\nExpected: {plain_1_to_100_result}\nActual: {result}."

def test_fizzBuzz_fizz_and_buzz():
  fizz_watcher = WordWatcher(3, "Fizz")
  buzz_watcher = WordWatcher(5, "Buzz")
  word_watchers = [fizz_watcher, buzz_watcher]
  result = fizzBuzz([fizz_watcher, buzz_watcher])
  assert result == fizzBuzz_1_to_100_result, f"The watcher solution returned the wrong result:\nExpected: {fizzBuzz1To100Result}\nActual: {result}."

You can download fizzbuzz_with_watchers.py and test_fizzbuzz_with_watchers.py here (2KB, zipped folder with 2 Python files).

That’s a lot of fuss for Fizzbuzz. Why did you do all that?

  1. Reginald asked me to, and I’ve known and respected him for ages, and JenniferPlusPlus seconded the request.
  2. Wait until you see what customers ask you to do.

Did any of this stuff fly over your head?

  1. Don’t feel bad. I had the same trouble when I first learned functional programming, and that was back in 1991, when the computers that ran functional language interpreters were in labs. I spent a lot of time in Queen’s University’s DEClab, which was full of machines that were cutting edge at the time made by a vendor that no longer exists. Computer time, as well as info on any kind of programming, never mind functional programming, was a lot harder to come by. (In case you were wondering, the language we learned was Miranda.)
  2. If you’ve never worked in Python, some of it can be quite weird. It does eventually make sense.
  3. Let me know, either via email or in the comments, if there’s anything you’d like me to cover in greater detail.

Do you have an alternate solution?

I’ve love to hear about it and present it here! Again, let me know via email or in the comments.

What’s next

An elegant JavaScript implementation.

Previously, in the “Programmer interview challenge” series

Categories
Career Programming

Programmer interview challenge 2, part 3: FizzBuzz, minus the modulo operator, plus grit

The modulo operator

The standard FizzBuzz solution relies on the modulo operator, which it uses to determine if a number is a multiple of 3 or 5.

If you have a math, computer science, or engineering background, the odds are good that you encountered the modulo operator in your studies, as your courses tended to take a mathematical approach to  programming. (Remember relational calculus from your intro to databases course?)

If you came into programming from some other field and really got into it because you have a knack for problem-solving, you might not be aware of modulo math. That doesn’t mean that you can’t come up with a FizzBuzz solution.

FizzBuzz minus the modulo operator

When you present the FizzBuzz challenge to a large enough group of programmers — typically a dozen or more — there will be a very determined person who will insist that you provide them with no hints whatsoever. It happens.

When that happens, there’s invariably someone who’s either never heard of the modulo operator (%, which returns the remainder of a division operation) or has forgotten it exists. I’ve also seen a competition comprising quick programming challenges where contestants were told to implement FizzBuzz, but without using modulo.

The more mathematically-inclined will use a method like this:

def multiple_of_n(factor, number):
  return math.floor(number / factor) == number / factor

multiple_of_n() determines if a number n is a multiple of a factor f if the result of n / f is the same as n / f with the fractional part removed.

Occasionally, you’ll run into programmers who are unaware that there are functions to remove the fractional part of a number, either through rounding or truncation. Some of them make up for their lack of math background with a combination of creativity and grit.

I’ve seen one solution that looked something like this:

def multiple_of_5(number):
  number_as_string = str(number)
  last_digit = number_as_string[-1]
  return last_digit in ['0', '5']

This function turns the given number into a string, isolates the rightmost character of that string, and then returns True if that character is “0” or “5”, which is true for the string form of numbers that are multiples of 5.

My reaction:

That was nothing compared to one method I saw that someone cobbled together to determine if a number was a multiple of 3. They remembered the old grade-school rule that if you add the digits of a number and the total is a multiple of 3, then the number is a multiple of 3.

Based on that, they wrote something like this:

def multiple_of_3(number):
  number_as_string = str(number)
  total_of_digits = 0
  for digit in number_as_string:
    total_of_digits += int(digit)
  return total_of_digits in [3, 6, 9, 12, 15, 18]

Again, this function starts by converting the given number into a string. It then iterates through that string character by character, turning each character into a number and adding it to a running total. It then checks to see if that total is in a list of multiples of 3.

Since the standard FizzBuzz challenge is supposed to be performed on the numbers 1 through 100, the largest multiple of 3 will be 99, and the sum of its digits will be 18. Hence the list of multiples of 3 starts with 3 and ending with 18.

My reaction:

But hey, it works!

FizzBuzz plus grit

I’ve seen a handful of people with bachelors’ and even masters’ degrees in computer science face the FizzBuzz test and completely fail to produce working code. I’ve been more impressed by the self-taught coders who, in spite of not knowing about the modulo operator, charge head-first into the problem and solve it. These non-modulo solutions might cause a mathematician to react like this…

…but I think that they’re a sign of grit, which is an important quality for a programmer. These people took what they knew, applied a little creativity, and solved a problem that they shouldn’t have been able to solve. They remind me of a line from aviation pioneer Igor Sikorsky:

According to the laws of aerodynamics, the bumblebee can’t fly, but the bumblebee doesn’t know the laws of aerodynamics, so it goes ahead and flies.

Sooner or later, if you’re working on applications that actually matter, you’re going to run into seemingly insurmountable problems. There will always be the fear that something is just too hard to do. Impostor syndrome may rear its ugly head. Developing grit — and yes, it can be developed — is important, and it’s a quality I look for when forming a team.

What’s next

Using “watchers” to play FizzBuzz “properly”. 

Previously, in the “Programmer interview challenge” series

Categories
Career Programming

Programmer interview challenge 2, part 2: Functional FizzBuzz

(In case you missed it, here’s the previous article in this series.)

FizzBuzz became popular in the late 2000 – 2010 decade, which was around the same time that may programmers were beginning to rediscover functional programming. I say rediscover rather than discover because functional programming goes back all the way to Lisp, whose spec was written in 1958, which is the dawn of time as far as modern computing is concerned. As Wikipedia puts it, Lisp is “the second-oldest high-level programming language in widespread use today. Only Fortran is older, by one year.”

(Both Fortran and Lisp are heavily based in mathematics — in fact, Fortran is short for FORmula TRANslation. This is one of the reasons that there’s a strong math bias in programming to this day.)

One senior developer I know tested prospective developers’ functional programming skills by issuing this test to anyone who passed the original FizzBuzz test:

Write FizzBuzz, but this time, instead of FizzBuzzifying the numbers 1 through 100, FizzBuzzify the contents of an array, which can contain any number of integers, in any order.

(The senior developer didn’t use the word “FizzBuzzify,” but I think you get my point.)

The resulting app, if given this array…

[30, 41, 8, 26, 3, 7, 11, 5]

…should output this array:

[‘FizzBuzz’, 41, 8, 26, ‘Fizz’, 7, 11, ‘Buzz’]

Note that the original array contained all integers, while the result array can contain both strings and integers. The senior developer was interviewing programmers who’d be working in Ruby, where you can easily use arrays of mixed types.

You’d get a passing grade if your solution simply adapted the original FizzBuzz to take an array as its input. Here’s a Python implementation of that solution:

def fizzBuzz_list_imperatively(numbers):
  finalResult = []

  for number in numbers:
    currentResult = None
    isMultipleOf3 = (number % 3 == 0)
    isMultipleOf5 = (number % 5 == 0)

    if isMultipleOf3 and isMultipleOf5:
      currentResult = "FizzBuzz"
    elif isMultipleOf3:
      currentResult = "Fizz"
    elif isMultipleOf5:
      currentResult = "Buzz"
    else:
      currentResult = number

    finalResult.append(currentResult)

  return finalResult

However, the developer was looking for a more functional approach. In functional programming, if you’re being asked to perform some kind of calculation based on the contents of a list, you should probably use a map, filter, or reduce operation.

In case you’re not quite familiar with what these are, here’s a simple explanation that uses emojis:

Map, filter, and reduce explained with emoji.
Much nicer than a dry textbook explanation, isn’t it?

The map operation, given a list and a function, applies that function to every item in the given list, which creates a new list. The senior developer granted bonus points to anyone who came up with a map-based solution.

Here’s a Python implementation of what the senior developer was looking for:

def fizzBuzz_list_functionally(number_list):
  return list(map(fizzBuzzify, number_list))

def fizzBuzzify(number):
  isMultipleOf3 = (number % 3 == 0)
  isMultipleOf5 = (number % 5 == 0)

  if isMultipleOf3 and isMultipleOf5:
    return "FizzBuzz"
  elif isMultipleOf3:
    return "Fizz"
  elif isMultipleOf5:
    return "Buzz"
  else:
    return number

This implementation breaks the problem into two functions:

  • A fizzBuzzify() function, which given a number, returns Fizz, Buzz, FizzBuzz, or the original number, depending on its value, and
  • A map() function, which applies fizzBuzzify() across the entire array.

Remember, the senior developer was looking for Ruby developers, and Ruby doesn’t support nested functions. Python does, however, and I like packaging things neatly to prevent errors. I think that if a function a makes exclusive use of another function b, you should nest b inside a.

With that in mind, let’s update fizzBuzz_list_functionally():

def fizzBuzz_list_functionally(number_list):

  def fizzBuzzify(number):
    isMultipleOf3 = (number % 3 == 0)
    isMultipleOf5 = (number % 5 == 0)

    if isMultipleOf3 and isMultipleOf5:
      return "FizzBuzz"
    elif isMultipleOf3:
      return "Fizz"
    elif isMultipleOf5:
      return "Buzz"
    else:
      return number

  return list(map(fizzBuzzify, number_list))

What’s next

In the next installment in this series, we’ll look at FizzBuzz solutions that don’t use the modulo (%) operator.

Previously, in the “Programmer interview challenge” series

Categories
Career Programming

Programmer interview challenge 2: The dreaded FizzBuzz, in Python

The “job interview” scene from Good Will Hunting.

Spotting the programmers who can’t program

Sooner or later, you will encounter — or worse still, end up working with — a programmer who only seems good at programming. This person will have an impressive-looking resume. They’ll know all the proper terminology, be able to speak intelligently about the key concepts in this programming language or that framework or library, and may even have given a pretty good talk at a meetup or conference. But when they’re put to the task of actually writing working software, they just can’t do it.

These aren’t programmers who have difficulty taking on big problems, such as the kind you run into when working on complex problems and writing all-new code from scratch. They’re not even programmers who run into trouble just working on the sort of everyday problems that you encounter maintaining established, working software. These are programmers who can’t solve simple problems, the sort that you should be able to do during a lunch or coffee break. They might be good in other roles in the development process, but not in one where they have to write production code.

As a result, there’s a category of little assignments whose sole purpose isn’t to identify great programmers, or even good ones, but to spot the ones you shouldn’t hire. The best known of these is the dreaded FizzBuzz.

FizzBuzz, explained

Fizzbuzz is an exercise that then-developer Imran Ghory wrote about back in 2007. The programmer is asked to implement a program — often in the language of their choice — that prints the numbers from 1 to 100, but…

  1. If the number is a multiple of 3, print Fizz instead of the number.
  2. If the number is a multiple of 5, print Buzz instead of the number.
  3. If the number is a multiple of both 3 and 5, print FizzBuzz instead of the number.

Simply put, its output should look something like this:

1, 2, Fizz, 4, Buzz, Fizz, 7, 8, Fizz, Buzz, 11, Fizz, 13, 14, FizzBuzz, 16, 17, Fizz, 19, Buzz, Fizz, 22, 23, Fizz, Buzz, 26, Fizz, 28, 29, FizzBuzz, 31, 32, Fizz, 34, Buzz, Fizz, 37, 38, Fizz, Buzz, 41, Fizz, 43, 44, FizzBuzz, 46, 47, Fizz, 49, Buzz, Fizz, 52, 53, Fizz, Buzz, 56, Fizz, 58, 59, FizzBuzz, 61, 62, Fizz, 64, Buzz, Fizz, 67, 68, Fizz, Buzz, 71, Fizz, 73, 74, FizzBuzz, 76, 77, Fizz, 79, Buzz, Fizz, 82, 83, Fizz, Buzz, 86, Fizz, 88, 89, FizzBuzz, 91, 92, Fizz, 94, Buzz, Fizz, 97, 98, Fizz, Buzz.

In his blog entry on FizzBuzz, Imran wrote:

Most good programmers should be able to write out on paper a program which does this in a under a couple of minutes.

Want to know something scary ? – the majority of comp sci graduates can’t. I’ve also seen self-proclaimed senior programmers take more than 10-15 minutes to write a solution.

I’m not saying these people can’t write good code, but to do so they’ll take a lot longer to ship it. And in a business environment that’s exactly what you don’t want.

Let’s look at a couple of Python implementations.

The dumb-as-a-bag-of-hammers solution

If you think your interviewer has a sense of humor, you might try throwing this solution at them. I put this in a file named fizzbuzz.py:

def fizzBuzzDumb():
  return "1, 2, Fizz, 4, Buzz, Fizz, 7, 8, Fizz, Buzz, 11, Fizz, 13, 14, FizzBuzz, 16, 17, Fizz, 19, Buzz, Fizz, 22, 23, Fizz, Buzz, 26, Fizz, 28, 29, FizzBuzz, 31, 32, Fizz, 34, Buzz, Fizz, 37, 38, Fizz, Buzz, 41, Fizz, 43, 44, FizzBuzz, 46, 47, Fizz, 49, Buzz, Fizz, 52, 53, Fizz, Buzz, 56, Fizz, 58, 59, FizzBuzz, 61, 62, Fizz, 64, Buzz, Fizz, 67, 68, Fizz, Buzz, 71, Fizz, 73, 74, FizzBuzz, 76, 77, Fizz, 79, Buzz, Fizz, 82, 83, Fizz, Buzz, 86, Fizz, 88, 89, FizzBuzz, 91, 92, Fizz, 94, Buzz, Fizz, 97, 98, Fizz, Buzz."

Note that I wrote this as a function that returns a string instead of as just a print statement. There’s a reason for this — as a function, it’s testable.

Let’s create a file for FizzBuzz tests. I called mine test_fizzbuzz.py. It’s also pretty dumb — all it does it confirm that fizzBuzzDumb() spits out the right result. It’s pretty much guaranteed to pass, since I copied and pasted the string from fizzBuzzDumb() into the constant that the test uses to confirm that the output is correct:

import pytest
from fizzbuzz import fizzBuzzDumb

fizzBuzz1To100Result = "1, 2, Fizz, 4, Buzz, Fizz, 7, 8, Fizz, Buzz, 11, Fizz, 13, 14, FizzBuzz, 16, 17, Fizz, 19, Buzz, Fizz, 22, 23, Fizz, Buzz, 26, Fizz, 28, 29, FizzBuzz, 31, 32, Fizz, 34, Buzz, Fizz, 37, 38, Fizz, Buzz, 41, Fizz, 43, 44, FizzBuzz, 46, 47, Fizz, 49, Buzz, Fizz, 52, 53, Fizz, Buzz, 56, Fizz, 58, 59, FizzBuzz, 61, 62, Fizz, 64, Buzz, Fizz, 67, 68, Fizz, Buzz, 71, Fizz, 73, 74, FizzBuzz, 76, 77, Fizz, 79, Buzz, Fizz, 82, 83, Fizz, Buzz, 86, Fizz, 88, 89, FizzBuzz, 91, 92, Fizz, 94, Buzz, Fizz, 97, 98, Fizz, Buzz."

def test_dumb_fizzBuzz():
  result = fizzBuzzDumb()
  assert result == fizzBuzz1To100Result, f"The dumb solution returned the wrong result:\nExpected: {fizzBuzz1To100Result}\nActual: {result}."

With fizzbuzz.py and test_fizzbuzz.py in hand, I ran the test, and it unsurprisingly passed:

Working towards a real solution

The multiple problem

The first stumbling block I’ve seen people trying to write FizzBuzz is that they have no idea how to tell if a number x is a multiple of some other number y. This happens particularly often when the programmer doesn’t come from a math background.

(There’s a bit of math snobbery and bias in classical computer science. Some of it is just general academic snobbery, and some of it is from the fact that computer science wasn’t originally its own field of study in universities, but often a branch of the math or engineering department.)

To solve this problem, you want to use the modulo operator — the % symbol. It performs integer division, but instead of giving you the quotient (the result of a division), it gives you the remainder.

For example 3 % 2 gives you a result of 1. That’s because after dividing 3 by 2, you get a remainder of 1. 5 % 2 also gives you a result of 1, because 2 goes into 5 twice, leaving you a remainder of 1. 9 % 5 gives you a result of 4, as 5 goes into 9 once, leaving a remainder of 4.

If a division operation results in no remainder, % returns a result of 0. For instance 2 % 2, 4 % 2, 6 % 2, 8 % 2, and 10 % 2 all return a result of zero, since they’re all even numbers, which are all evenly divisible by 2. Another way of putting it is to say that they’re multiples of 2.

With this in mind, we can easily come up with a couple of statements that test if a number is a multiple of 3 and if a number is a multiple of 5:

isMultipleOf3 = (number % 3 == 0)
isMultipleOf5 = (number % 5 == 0)

Fizz, Buzz, FizzBuzz, or number?

This is the part that really trips up the weak programmers. It doesn’t follow this simple decision structure:

  • If condition A is met:
    • Perform task X.
  • Otherwise, if condition B is met:
    • Perform task Y.
  • Otherwise, if condition C is met:
    • Perform task Z.
  • Otherwise, if none of the above conditions are met:
    • Perform the default task.

FizzBuzz’s decision structure is more like this:

  • If condition A is met:
    • Perform task X.
  • Otherwise, if condition B is met:
    • Perform task Y.
  • But if both condition A and B are met:
    • Don’t perform task X or Y. Perform task Z instead.
  • Otherwise, if none of the above conditions are met:
    • Perform the default task.

This seems like a minor change, but it’s enough to make FizzBuzz a way of filtering out people might have serious trouble writing production software.

I’ve demonstrated live-coding Fizzbuzz in a number of presentations, and the approach I usually take is summarized in this Python code:

if isMultipleOf3 and isMultipleOf5:
  currentResult = "FizzBuzz"
elif isMultipleOf3:
  currentResult = "Fizz"
elif isMultipleOf5:
  currentResult = "Buzz"
else:
  currentResult = str(number)

At the end of this if statement, currentResult contains one of the following: FizzBuzz, Fizz, Buzz, or a number.

When live-coding in front of an audience — which is pretty much what a technical interview is — you want to keep a couple of things in mind:

  • You want to use the code to communicate your intent to the audience as clearly as possible.
  • Complexity is your enemy. You want to make the simplest thing that works.

My approach was to do handle the trickiest case first. My if statement handles the case where the number is both a multiple of 3 and a multiple of 5 first, followed by the individual multiple cases, followed by the default case. It’s simple, it’s easy to follow, and best of all, it works.

Putting it all together

Here’s the fizzBuzz() function that I wrote. I put it in fizzbuzz.py, just after the definition of fizzBuzzDumb():

def fizzBuzz(first = 1, last = 100):
  finalResult = ""

  for number in range(first, last + 1):
    currentResult = ""
    isMultipleOf3 = (number % 3 == 0)
    isMultipleOf5 = (number % 5 == 0)

    if isMultipleOf3 and isMultipleOf5:
      currentResult = "FizzBuzz"
    elif isMultipleOf3:
      currentResult = "Fizz"
    elif isMultipleOf5:
      currentResult = "Buzz"
    else:
      currentResult = str(number)

    finalResult += currentResult

    if number < last:
      finalResult += ", "
    else:
      finalResult += "."

  return finalResult

Here’s the full text of fizzbuzz.py:

def fizzBuzzDumb():
  return "1, 2, Fizz, 4, Buzz, Fizz, 7, 8, Fizz, Buzz, 11, Fizz, 13, 14, FizzBuzz, 16, 17, Fizz, 19, Buzz, Fizz, 22, 23, Fizz, Buzz, 26, Fizz, 28, 29, FizzBuzz, 31, 32, Fizz, 34, Buzz, Fizz, 37, 38, Fizz, Buzz, 41, Fizz, 43, 44, FizzBuzz, 46, 47, Fizz, 49, Buzz, Fizz, 52, 53, Fizz, Buzz, 56, Fizz, 58, 59, FizzBuzz, 61, 62, Fizz, 64, Buzz, Fizz, 67, 68, Fizz, Buzz, 71, Fizz, 73, 74, FizzBuzz, 76, 77, Fizz, 79, Buzz, Fizz, 82, 83, Fizz, Buzz, 86, Fizz, 88, 89, FizzBuzz, 91, 92, Fizz, 94, Buzz, Fizz, 97, 98, Fizz, Buzz."

def fizzBuzz(first = 1, last = 100):
  finalResult = ""

  for number in range(first, last + 1):
    currentResult = ""
    isMultipleOf3 = (number % 3 == 0)
    isMultipleOf5 = (number % 5 == 0)

    if isMultipleOf3 and isMultipleOf5:
      currentResult = "FizzBuzz"
    elif isMultipleOf3:
      currentResult = "Fizz"
    elif isMultipleOf5:
      currentResult = "Buzz"
    else:
      currentResult = str(number)

    finalResult += currentResult

    if number < last:
      finalResult += ", "
    else:
      finalResult += "."

  return finalResult

This new function calls for a new test. Here’s the updated test_fizzbuzz.py:

import pytest
from fizzbuzz import fizzBuzzDumb, fizzBuzz

fizzBuzz1To100Result = "1, 2, Fizz, 4, Buzz, Fizz, 7, 8, Fizz, Buzz, 11, Fizz, 13, 14, FizzBuzz, 16, 17, Fizz, 19, Buzz, Fizz, 22, 23, Fizz, Buzz, 26, Fizz, 28, 29, FizzBuzz, 31, 32, Fizz, 34, Buzz, Fizz, 37, 38, Fizz, Buzz, 41, Fizz, 43, 44, FizzBuzz, 46, 47, Fizz, 49, Buzz, Fizz, 52, 53, Fizz, Buzz, 56, Fizz, 58, 59, FizzBuzz, 61, 62, Fizz, 64, Buzz, Fizz, 67, 68, Fizz, Buzz, 71, Fizz, 73, 74, FizzBuzz, 76, 77, Fizz, 79, Buzz, Fizz, 82, 83, Fizz, Buzz, 86, Fizz, 88, 89, FizzBuzz, 91, 92, Fizz, 94, Buzz, Fizz, 97, 98, Fizz, Buzz."

def test_dumb_fizzBuzz():
  result = fizzBuzzDumb()
  assert result == fizzBuzz1To100Result, f"The dumb solution returned the wrong result:\nExpected: {fizzBuzz1To100Result}\nActual: {result}."

def test_fizzBuzz():
  result = fizzBuzz()
  assert result == fizzBuzz1To100Result, f"The dumb solution returned the wrong result:\nExpected: {fizzBuzz1To100Result}\nActual: {result}."

With fizzbuzz.py and test_fizzbuzz.py revised, I ran the test, and it passed again:

You can download fizzbuzz.py and test_fizzbuzz.py here (2KB, zipped folder with 2 Python files).

What’s next

In the next installment in this series, we’ll look at a different approach to coding FizzBuzz: functional programming!

Recommended reading

Previously, in the “Programmer interview challenge” series