This year marks 15 years since FizzBuzz was popularised as an interview tool for developers. I’m a big fan and have watched over 100 candidates try their hand at my version of the task. In today’s blog post I’d like to take a moment to celebrate what makes FizzBuzz so helpful, discuss some common patterns I’ve observed in the many attempts I’ve witnessed, and finally explore some tweaks that can be deployed to keep the challenge fresh.
Happy Birthday, FizzBuzz! Well, happy belated birthday, I suppose, as it was really January 2022 that marked 15 years of FizzBuzz being used as a programming challenge.
We can trace the “birth” to a 2007 blog post by Imran Ghory. This was the same year as the iPhone was announced, when Nicolas Sarkozy was elected as president of France, and when sub-prime mortgages triggered the “Great Recession”. 2007 was the year that the last of the main Harry Potter books was published when LCD Soundsystem released Sound of Silver and the year that brought us The Simpsons Movie. In other words, 15 years is a long time!
The motivation for Imran’s post touched a nerve in the programming community at the time. The post went as close to “viral” as existed in 2007. Jeff Atwood (who went on to co-found Stack Overflow) wrote about Imran’s article later in the same year, pulling together lots of commentary in agreement with the central thesis: too many candidates for development jobs struggle to write even simple code. Being able to implement FizzBuzz would at least demonstrate that a candidate could do the basics.
As originally stated, a FizzBuzz program should output a sequence of integers from 1 to 100, except that multiples of 3 should be replaced with “Fizz”, multiples of 5 with “Buzz”, and multiples of both 3 and 5 with “FizzBuzz”. This would result in something like 1, 2, Fizz, 4, Buzz, Fizz, 7, 8, Fizz, Buzz, 11, Fizz, 13, 14, FizzBuzz… The interesting thing about FizzBuzz is that it is easy to express but requires some nuance to implement correctly.
One area where Mr Scott and I may disagree, however, is whether FizzBuzz can still be useful and interesting. He attributes the continued use of FizzBuzz to the fact that “some interviewers can’t think of anything better”. My view, on the other hand, is that FizzBuzz is still well suited to evaluating core competencies in developers and offers an adaptable, domain-neutral foundation for exploring more complex ideas.
My experience of setting FizzBuzz in interviews
FizzBuzz has been a key tool in my interviewing arsenal since 2015. Or, put another way, I’ve been using FizzBuzz for the most recent half of its life. I’ve used it at every company where I’ve recruited developers. Over 100 candidates from the UK, Australia, and India have tried their hand at my special brand of FizzBuzz using C# and .NET. Whilst there were obviously patterns and trends, the thing that fascinates me is that every attempt was unique, with its own quirks.
My version of the FizzBuzz task is set up as a pair programming (“tour guide” flavour) exercise following strict (perhaps artificially strict) TDD. The interviewer delivers small, atomic requirements and the candidate is expected to start addressing each requirement with a unit test, before moving on to the implementation. In proper pair programming style, the candidate is encouraged to discuss their approach with the interviewer. Likewise, they are free to use any online reference materials if they forget a method name or some syntax.
Setup and general observations
The candidate is provided with a .NET Core solution containing three projects: a class library, an XUnit project, and a console application. There are stub implementations so to act as a guiding template for the candidate and demonstrate how the three projects interact. There is an example unit test that calls an example method, which is also called by the console application. I even provide interfaces that contain the signatures of the methods I’m expecting the candidate to implement.
The aim of having all these guide rails is equally to…
- Minimize the chance of “analysis paralysis”
- Avoid the candidate having to waste a load of time writing boilerplate
- Prevent this task becoming a syntax spelling bee
Because ultimately, I’m interested in seeing them write some code, rather than watching them flounder and panic.
Nevertheless, a candidate’s reaction to some of this stuff can tell you a lot about their professional experiences. For instance, it will quickly become obvious whether they’ve ever written a unit test before. Crucially, however, there’s enough of a template in there for even a unit test virgin to have a go at it, which means the rest of the task can still be useful in probing other areas of competency.
Other general-purpose indicators of competence I look for include:
- Do they immediately head to the console app to start making changes? This is a behaviour that I’ve come to associate with more junior developers and particularly those whose past experience tends to be more in the realm of “scripting” than application development.
- Are they just (for want of a better word) messy? Do they have any regard for things like indentation or capitalisation? Do they try to use meaningful names for methods and variables? Since code is usually read more than it’s written, these questions aren’t just about me being fussy. Experienced developers understand the importance of producing code that is easy to grok quickly.
- Do they leave loads of vestigial code hanging around? This ties into the point above, but is worth calling out as a special case. I often see developers leaving in chunks of commented-out code. I find this can indicate a lack of confidence and experience, or sometimes just a wariness regarding source control.
To be clear, I’d never rule a candidate out for displaying any of these behaviours. After all, I’ve seen many talented developers who don’t conform to all my preferences. That said, these sorts of observations can be helpful in contributing to the overall impressions of a candidate.
Delivering the requirements
The functional requirements provided to the candidate start off very minimal but get larger as the exercise progresses. This provides a bit of a warm-up, which can be helpful for less experienced candidates. To cater for the other end of the spectrum, there are two stretch goals, with the interviewer being able to switch to one or the other depending on how the candidate is getting on. By these means, I find I can use one task for all candidates, dynamically adapting it during the interview as the candidate’s capabilities are made apparent.
NB: If you’d like to see the task I give to candidates, I’ve uploaded it to Github: github.com/tdwright/FizzBuzzInterviewTask In fact, if you’d like to have a go at completing the task, stay tuned for details of an upcoming competition!
In the last two companies I’ve worked at, I’ve ended each FizzBuzz challenge by asking the developer to commit their changes to a new branch in git. Not only does this allow me to assess their git comfort levels, but it also means I have developed a reasonably large corpus of candidate attempts. This has allowed me to compare them, and find patterns and themes. In the next section of this post then, let’s take a look at the components of the task and what each part can tell the interviewer.
In my version of FizzBuzz, I always start with the string replacement aspect of the problem. The first four requirements handle the four possible outcomes for a single number in the classic FizzBuzz problem. We start by implementing the IFizzBuzz interface, by adding a simple method to the provided class. For now, the method just needs to return a string containing the digits of the integer it was passed as an argument. For example, when passed 1, return “1”. For most developers, this is a gentle introduction to the task which allows them to get acquainted with the solution structure, XUnit, and the TDD approach. For some developers, however, we find that we have to explain how to use
Int32.ToString(), which is in itself highly instructive. For some other developers, this step reveals their inexperience in working with interfaces.
The next two requirements are about extending the same method to handle the cases of Fizz for 3 and Buzz for 5. This is usually pretty quick and is when confidence builds. Depending on whether a candidate has prior knowledge of FizzBuzz (and depending on how strictly they are following TDD), we tend to see one of two main approaches here – those approaching it naively will chuck in some
return statements inside simple
if statements, whereas those who know (or can guess) what’s coming will typically start appending things to an initially empty string.
The fourth requirement is where candidates typically come unstuck. This is not a feature unique to my implementation of the challenge either – Tom Scott mentions this in his video and it is mentioned on the FizzBuzz page in the venerable C2 Wiki. The fourth requirement is all about handling the case for multiples of both 3 and 5 (e.g., 15) where the output should be FizzBuzz. The simplest implementation will involve an extra
if statement with an extra
return, but may still fail if the order of the various
if statements means that the condition is caught by one of the individual checks – for instance returning Fizz due to being a multiple of 3 before evaluating for the FizzBuzz condition. Even if a candidate implements this correctly, it’s a good place to have a discussion about refactoring – Can we reduce the nesting? Can we reduce the repetition of the logical checks? If a candidate had gone straight to a string appending implementation, we can discuss string immutability, the difference between reference and value types,
As an aside, it’s this fourth requirement where the penny often drops about the usefulness of unit tests. In trying to solve the case of 15, it is common for other things to get broken. Being able to re-run a suite of unit tests can highlight this for the candidate and provide valuable feedback.
Variant 0 – Loop to 100
I’ve called this the zeroth variant since most FizzBuzz challenges include this as a core requirement. Although I specify this behaviour in requirements 5 & 6 of the main task, I will often skip them for very junior and very senior developers. My motivation for this is that I will have been able to gauge a developer’s level by the time we have gone through steps 1-4. Time pressures mean that I’d often like to switch to something more challenging for the more competent candidates. Conversely, for candidates who struggle with the main task, we may already have run out of time by this point.
When I do run this section of the task, there are a few things I’ll keep an eye on. Firstly, I’m obviously watching carefully for “off-by-one” errors. These are usually caused by incorrectly bounded loops and aren’t a big deal, but it’s always interesting to see if the developer can spot the cause. The other thing I look out for (and will ask about) is whether they’ll use something more exotic than a simple loop – perhaps Enumerable.Range feeding a LINQ statement, or maybe using
yield return. A loop will clearly do the job, but it can be a nice opportunity for the candidate to show off.
Variant 1 – FlexiFizzBuzz
For candidates who breeze through the first set of requirements, I love to challenge them with this variant. The requirements here aren’t enumerated in the same granular detail, but instead, we point to a new interface to be implemented, describe the desired behaviour in general terms, and provide some examples. In short, the change we want the candidate to make is to generalise FizzBuzz, so that any arbitrary collection of
string combinations can be supplied as replacement pairs. Perhaps instead of replacing multiples of 3 with Fizz and 5 with Buzz, we want to replace multiples of 2 with the word “Even”, for example.
The provided interface specifies the data structure – a
strings as a property. What isn’t specified is whether this should be populated via the constructor, by setting the property, or by calling some method(s) to manipulate the dictionary. This is great for exploring how the candidate thinks about API design and the way in which a caller might expect the lifecycle of the FizzBuzz class to behave.
The really interesting part of this variant, however, is the way candidates adapt their previous code to handle this more general case. For a start, it can be instructive to observe whether they make any attempt to maintain backwards compatibility with the unit tests (and possibly console app) that they’ve already written. To be specific, about half of candidates don’t initially set out to retain the 3: Fizz; 5: Buzz replacement pairs as a default, which obviously leads to all their prior unit tests failing.
Typically, developers will land on some solution involving iteration over the dictionary to check whether the key is a factor of the input number and append the value to some aggregator string.
One interesting exception to this that I’ve seen recently is to ignore the dictionary altogether and instead allow for
Funcs to be added to the class, with each
Func fully encapsulating the logic about what string (if any) to return. This means that the classic FizzBuzz can either be implemented as one or two
Funcs, depending on the calling developer’s preferences. It also means that the replacement logic can deviate from simply looking at multiples. You could, for instance, supply a
Func that returned a certain word based on whether the number is a prime, or the number of digits, or whether the digits formed a palindrome – the sky is the limit. This type of approach could be somewhat controversial (is it even still FizzBuzz?), but that just provides an intriguing line of discussion with the candidate.
Variant 2 – CloudFizzBuzz
This one I can’t claim credit for, as I experienced it on the receiving end… Back in 2018, as I was moving to Australia and applying for jobs, I was delighted when HeadUp Labs tasked me with a variant of FizzBuzz as a technical challenge. Kudos to the excellent James Devlin for this!
Their twist was to implement FizzBuzz as a pair of Azure Functions (one for generating the sequence, the other for handling the replacements) linked with a queue. I remember having a lot of fun with the fusion of FizzBuzz (which I was already using in my own interviews) and cloud technologies.
Fun things to explore with this challenge could include:
- What cloud services to use?
- How to connect the various services?
- How could we make it scalable?
- Since we’re hosting it, should we cache or generate sequences ahead of time?
- How could we secure the service and/or add billing? (Are they aware of things like Azure API Management?)
In other words, the actual implementation (provided it works) will likely be of less interest than the sorts of discussions it can trigger. What I’d be looking for here is not just the extent of the candidate’s knowledge, but also how collaborative and open they are as we bounce ideas around.
This variant is a lot more involved than the one mentioned above, to the point where I wouldn’t ask a candidate to do this as part of a live coding exercise. Instead, this variant could work as a take-home follow-on task, particularly for more senior or cloud-oriented roles. I personally try not to issue homework as part of my interview process, but I know a lot of places do.
The beauty of FizzBuzz in this context is again related to the fact it’s a task that’s easy to understand without being tied to any domain or depending on any specific cultural knowledge.
If any candidates see this…
If you ever have an interview scheduled with me and have read this post, please don’t be shy about letting me know. The fact that you’ve read this demonstrates that you’re plugged into the developer community and is a strong positive signal even before we start coding.
One of the great things about delivering this task as part of a live programming exercise is that it isn’t spoiled by prior knowledge. It doesn’t rely on the candidate being ignorant of the potential pitfalls – the point isn’t to shout “gotcha!” Even if someone aced the programming because they’d memorised this post, I could still evaluate their competencies with follow-on questions. For example, asking why something was done a certain way, or asking if the candidate has ever used a technique in another context.
Here’s to another FizzBuzz years of FizzBuzz!
As you may have guessed by now, I’m a big fan of FizzBuzz. I think it has the perfect level of complexity for an interview task – rich enough to allow insights into the candidate’s skills, whilst simple enough to get from zero to something meaningful in a reasonable time. Like all good interview tasks, FizzBuzz can be fully explained very easily, even to someone who has never heard of it before. It does not depend on any cultural references or domain knowledge.
I hope I’ve shown that FizzBuzz can easily be extended to cater for a wide range of abilities. In fact, the sort of dynamic adaptation I’ve described above means that you don’t need to select a task based on preconceptions about a candidate’s abilities but can instead tailor the task on the fly depending on how they perform.
I find this sets FizzBuzz apart from other common tasks set in technical interviews. Reversing a string or generating a sequence of Fibonacci numbers are both very straightforward to explain, for instance, but have limited scope for extension. Where, after all, does one go on from a successfully reversed string? At the other end of the spectrum, some companies ask candidates to do some work on a real codebase. This is not something I’m a fan of (although I will concede that it could be informative with regards to code comprehension). Aside from tricky issues about unpaid labour, this sort of task has a high barrier to entry, often without any guarantee that it will reveal anything interesting. The flexibility of FizzBuzz (as described) allows it to cover all bases, which is super valuable.
There’s also something to be said for familiarity. I’ve seen so many attempts now that I know what to expect and what to look out for. This can make the interview process a lot more productive than it otherwise might be. On the other hand, we have to acknowledge that a candidate’s familiarity may contribute to their perceived membership of the “in-group”. To improve diversity in the profession, we must reduce gatekeeping, which in this context means focusing on each candidate’s abilities, regardless of whether they’ve encountered the task before or not.
In summary, I can absolutely see myself continuing to use FizzBuzz in interviews for the foreseeable future. Not, as might be suggested, because I’m too lazy to come up with anything better, but rather because after considering the alternatives, I’ve concluded that FizzBuzz is still at the front of the pack. It’s not the only task I’ll set, but it’s a useful default that works in most cases.
So then, here’s to another FizzBuzz years of FizzBuzz!
If you’ve made it this far, you may be interested to know I’m planning a FizzBuzz competition. Subscribe to my blog to be sure not to miss it…