I wish the entire elegant solution was posted in one piece at the end.
I almost have it working here: https://gist.github.com/bsima/d14f996bd4700a17c7d4d8abfe135606
As someone who has conducted quite a few technical interviews - enough to have a pretty strong opinion here - some advice for the junior programmers out there: never give this answer.
When I ask you a Fizzbuzz-like question, I’m watching for a few things. If you get huffy when you’re asked to demonstrate something basic, bzzzt, asshole. If you get a look of fear or take a long time to solve a basic problem, I’m going to get really worried. Fizzbuzz is a warm up for both of us because I’m not a full time interviewer and (hopefully) you’re not a full time interviewee; treat it accordingly.
IMO a good Fizzbuzz solution is done quickly, and optionally has a nice twist to show skill. Like, show a test stub that verifies the answers - do it around the bounds of the problem set and for negative numbers and I’ll be happy. I’ll probably tweak and extend the question once or twice, depending on how you solved the problem. But this is a warm up. Your chance to shine comes later.
I’ve heard feedback from other interviewers that have seen people give longwinded answers to the warm up question and it never goes well. Some complaints I’ve had & some that have stuck with me:
If you take too long answering the easy question, my time to ask you the stuff that matters is far limited.
If you take too long solving an easy question, I’ll start thinking you are struggling (even if you clearly aren’t). If you take too long making an easy answer hard, I’ll assume you always solve problems that way. That’s not a good look.
If you start droning on a long winded explanation of Fizzbuzz, the interview is no longer a two way street and I start tuning out.
if I’m feeling salty that day, and you start jumping to category theory when I ask you Fizzbuzz, I’m going to assume you want to be the smartest person in the room - and I’ll do my best to ratchet the difficulty up to eleven.
[Comment removed by author]
Oh no, sure. But I’m doing the same: fizzbuzz serves as an interesting jumping off point for me to talk about something fresh in my mind: how us programmers over complicate things, and how bad that can be in an interview.
Fizzbuzz seems to be a good jumping off point for many things!
Do you give these requirement to candidates before the interview? Otherwise it seems like just another arbitrary set of conditions for the candidate.
There are a number of aspects here I wanted to comment on, but the one that sticks out the most is that the candidate is being set up with many chances to fail, few chances to pass and no chances to succeed. Having a failure-heavy distribution in the outcome for a warm-up problem seems to defeat the purpose of warming up.
FizzBuzz seems like a pretty straightforward problem with a fairly large and obvious success target. Turning a warmup exercise into a half hour exploration of category theory is self defeating.
I didn’t intend to present the category theory answer as the “right” or “best” way to handle it (In fact, I didn’t even refer to it or explore whether FizzBuzz was an adequate interview question at all).
I was thinking about how interviewing goes more generally. @owen has a pre-set notion of what a correct FizzBuzz is and that it’s explicitly supposed to be a warmup. The warmup part doesn’t match well in my head with “has a failure-heavy outcome distribution” therefore I was wondering if the requirements were communicated to candidates or they were left to figure it out on their own.
What’s the bad thing about having a failure-heavy outcome distribution in the early parts of an interview? As long as you take into account interview nerves and programming-on-a-whiteboard, you end up with a fairly decent litmus test for whether the interview should continue any further.
Personally I’ve had about a 30% dropout rate just at fizzbuzz, which has been invaluable for both my time and the interviewees'.
To the contrary: success in fizzbuzz is trivial. Hell, I personally couldn’t care less if the code wouldn’t compile or if you used incorrect constructs; if you are able to produce a loop, an if and a modulo operator on the board you get a smile and the next question.
The only possible failure cases here, as tedu note, are self inflicted. I’ve seen exactly one candidate failed due to a Fizzbuzz-like problem – the guy literally huffed when the question was posed. Dude did just fine with the answer, but had such a miserable attitude about even being asked that everyone came out of the interview saying “yeah, I don’t want to work with him”.
I’ve had concerns before about mostly junior candidates who do fizzbuzz wrong/struggled, but I just gave an extra warm up or two and worked through it with them and almost always it turned out that they were just nervous as hell, which I get.
Do you give these requirement to candidates before the interview?
My instructions tend to be “we will spend ~45 minutes working through n problems of increasing difficulty, with a focus on these concepts: (…)”
If a candidate believes it best to use a majority of their time on problem number one, I’m not going to stop them.
But I’ll also happily give them a “hey, that’s a great answer” and give them the opportunity to move on when things are good.
Work like how you work. If you make every problem hard stop doing that.
there sure are a lot of Haskell dudes who confuse over-golfing with elegance.
While this post is.. overkill in many respects, the general trick of using foldMap to accumulate a collection of functions into a function which does collection of all the outputs is pretty useful: I just used it in a compiler I’m writing to snarf up all the variables mentioned in part of the control flow graph!
Better still, when I switched to an actual graph representation (as opposed to an edge-set) the code didn’t break because it’s all generic over the container.
I always worry about upvoting posts like this because they add to this “wow, what a lack of perspective on the engineering these FP folks have” impression but small abstractions occasionally scale up.
I think the point you just made is the thing he’s missing in the article. He’s excited about the things to come, but it appears as though he’s excited about what he just wrote, which is very similar to enterprise fizzbuzz, gross. https://github.com/EnterpriseQualityCoding/FizzBuzzEnterpriseEdition
Perhaps this is my unfamiliarity with Haskell, but what if we ask the reverse qurstion. What does the following code do?
fizzBuzz :: (Functor f, Foldable t)
=> t (Integer -> Maybe String)
-> f Integer
-> f String
fizzBuzz rules = fmap (fromMaybe <$> show <*> ruleSet)
ruleSet = fold rules
I would have a harder time saying “oh, that prints fizz and buzz for multiples of 3 and 5”.
I think that snippet is incomplete, because you need to invoke it with the proper ruleset.
That snippet doesn’t contain the numbers 3 or 5, or the strings “fizz” and “buzz” (except in the variable name fizzBuzz).
It’s not terribly legible because most of the work is hidden in all of this type information which is informing GHC of which type class instances to use. I would agree that the use of fold which relies on the monoid instance for functions and that applicative stuff to avoid writing \i -> fromMaybe (show i) (ruleSet i) is potentially overkill. The fold is a grayer area though because by using the monoid instance we may get a nice performance boost depending on what t we instantiate this function with. It may be the case that t makes use of the fact that it’s supposed to be able to reassociate the combining function.
\i -> fromMaybe (show i) (ruleSet i)
Does anyone know what the diamond symbol means in logic? It’s used in the numbered list under the “Monoids” heading.
It’s a placeholder generic binary operation. Some use a circle, dot, or cross instead.