Like many things in life, mastery requires practice and the coding interview is no exception. Often times though, the focus is on trying to find the best solution from the get go rather than the approach on how to iterate and maybe get there.
The most important part, in my humble opinion is to get it right first. In your normal coding life you would rarely, if ever, be able to produce "perfect" code without first going through a set of iterations.
The approach during the coding interview should not differ and if played well should help you score invaluable points into demonstrating your problem solving skills.
I'm going to walk you through of what could be an actual conversation between you and an interviewer if you were asked to solve for the [in]famous FizzBuzz challenge.
The challenge
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
The context
The FizzBuzz challenge is not specific to JavaScript and has been part of the coding interview process in almost every programing language. It is usually a quick check to assess the candidate basic programing instincts, but can also be turned in an assessment for in depth knowledge if the interviewer decides to do so.
It is usually part of a light weight first technical interview done while screen sharing. It is also a favorite from a non JavaScript programmer to ask and quickly gauge your technical knowledge and approach.
In a Javascript context familiarity with some or all the following concepts are expected to be demonstrated:
- Logical operators
- Looping
- Falsy values
- Ternary operator
- Type coercion
The approach
As with any problems that you might encounter, even those that seem familiar, a good read and break down to small pieces is a must. Be clear to the interviewer that you need 3 to 5 minutes to read it calmly and propose a rewrite of your understanding.
If you are comfortable doing that part out loud, that's even better. For example this is how I might go for the rewrite:
- So log to the console numbers from 1 to 100 - I'm going to need a loop
- For multiple of 3 instead of the number output the string 'Fizz'
- Do the same for multiples of 5 with the output being 'Buzz'
- In the case the number is a multiple of both 3 and 5 then output 'FizzBuzz' - how to check if a is a multiple of b??
- If all the above cases fail then just output the number as is
I would probably ask to the interviewer if I should worry about edge cases or bad inputs. It is usually implied that the input will be correct and edge cases might not be necessary. The fact that you ask though, adds a touch of eloquence to your problem-solving approach.
The solution(s)
One thing that is key and is worthy of practice is walking the person through your steps as you are building the solution during the interview. Start with the obvious, you will probably need a function or class as your primary construct. Start there and always think of the K.I.A.S.S.A.P :) principle - Keep It As Stupid Simple As Possible
First step
// comments are me talking out loud
// let's build the function structure
function fizzBuzz( start = 1, end = 100) { // default parameters to set the default range
// I need a loop - let's go with for
for( let i = start; i <= end; i++) {
// probably a variable for what will be outputted
let output = i;
// rest of the logic here
// outputting the result
console.log(output);
}
}
// call the function
fizzBuzz(); // this prints out 1 to 100 - fancy ;)
The above satisfies my first goal on my rewritten challenge understanding
Second step
Now if I follow the cadence of the challenge I will solve for two things:
- Choosing the proper operator to find if a number is a multiple of another
- Apply it for the multiple of 3 condition and output 'Fizz'
The remainder operator - %, is the perfect tool here. If number a is a multiple of number b then
( b % a) === 0; // will be true;
// 4 is a multiple of 2
( 4 % 2 ) === 0; // is true
Let's apply this in the body of our function
// rest of the logic here
if( (i % 3) === 0 ) {
output = 'Fizz';
}
// Knowing that 3,6 and 9 are multiple of 3 let's
// quickly test a small sequence by calling
fizzBuzz(1,10);
// this should output
// 1, 2, 'Fizz', 4, 5, 'Fizz', 7, 8, 'Fizz', 10
Final step
Since the Fizz condition ran perfect we can now apply the same logic to the rest
// multiple of 5
if( (i % 5) === 0 ) {
output = 'Buzz';
}
// multiple of 3 and 5
if( (i % 3) === 0 && (i % 5 === 0)) {
output = 'FizzBuzz';
}
Wowza!! this satisfies all the conditions and gives us this chef d'oeuvre of a solution once assembled
and stripped out of all comments
function fizzBuzz( start = 1, end = 100) { // default parameters to set the default range
for( let i = start; i <= end; i++) {
let output = i;
if( (i % 3) === 0 ) {
output = 'Fizz';
}
if( (i % 5) === 0 ) {
output = 'Buzz';
}
if( (i % 3) === 0 && (i % 5) === 0) {
output = 'FizzBuzz';
}
console.log(output);
}
}
fizzBuzz();
Now at this point, I have a working solution that satisfies the challenge request. What follows is very delicate in an interview situation. Something is bugging me about my code. The last if block that checks for multiples of 3 and 5 seem redundant.
Now should I voice that out loud and propose to refactor it or should I wait for the interviewer to call it out?
Interviews are about managing time and maximizing your pluses over your minuses. If you feel super confident that you have a good shot at coming up with something more solid in a manageable time then go for it. If in doubt, wait to be asked.
This way, the interviewer has decided that the remainder of your time might be worth digging deeper on this question.
If it is decided that it would be interesting to look at a refactor, this might be a way to approach the refactor steps
The refactor
We could, of course, get to a fancy one-liner here for this particular challenge, but I'm not a particular fan of doing stuff for the sake of fancy or pretty.
So let's flip the switch what I'm going to do this time is I will show you my final solution and I will walk you through how did I get to it.
This can turn into a handy skill if you are to read and understand other people's code or if you are to explain it to someone else. Through the years I have provided many solutions for this challenge, but the one below is by far my favorite.
function fizzBuzz( start = 1, end = 100) {
for( let i = start; i <= end; i++) {
let output = ( (i % 3) ? '' : 'Fizz' ); // if multiple of 3 is falsy
output += ( (i % 5) ? '' : 'Buzz') ; // if multiple of 5 is falsy
console.log(output || i); // output value or i if output is falsy
}
}
fizzBuzz(1,15);
The solution uses the ternary operator syntax to set the conditions and takes advantage of something that might not very obvious at first for the untrained eye - JavaScript falsy values.
Let's start with falsy values JavaScript, what in the heck are we talking about. A great definition is provided by the Mozilla Developer Network (MDN ):
A falsy value is a value that is considered false when encountered in a Boolean context.
JavaScript uses Type Conversion to coerce any value to a Boolean in contexts that require it, such as conditionals and loops.
For our particular context the important keywords are "Boolean context" and "conditionals" since they are relevant to our solution. Before looking at how it applies, here is the list of the most common falsy values in Javascript:
- The boolean false not the same as the string 'false'
- The number 0 - once again this is different from the string '0'
- The null object
- The primitive type undefined assigned to a non-initialized variable
- Any representation of an empty string such as a single quote, double quotes or back-ticks.
The rewrite
Let's focus on one segment of our fizzBuzz function
if( (i % 3) === 0 ) {
output = 'Fizz';
}
// this could be refactored as
if( !(i % 3) ) output = 'Fizz';
Breaking down the refactored line gives us this picture
- if (...) ==> conditional construct outside - boolean context inside
- ! ==> is false
- (i % 3) ==> type coercion - will check if value is falsy or truthy
Replace i by a few numbers to better understand it
if (!( 1 % 3) ...) /*becomes*/ if (!( 3 ) ...) /*3 is not false or falsy so check fails*/
if (!( 2 % 3) ...) /*becomes*/ if (!( 6 ) ...) /*6 is not false or falsy so check fails*/
if (!( 3 % 3) ...) /*becomes*/ if (!( 0 ) ...) /*0 is not false but is falsy so check passes*/
I can rewrite now my entire function using the logic above
function fizzBuzz( start = 1, end = 100) {
for( let i = start; i <= end; i++) {
let output = i;
if( !(i % 3) ) output = 'Fizz';
if( !(i % 5) ) output = 'Buzz';
if( !(i % 3) && !(i % 5) ) output = 'FizzBuzz';
console.log(output);
}
}
I was quite ecstatic when I got to this solution, but it did not too long unfortunately. The last line was still redundant to me and honestly was bugging me. How could I combine the checks of 3 and 5 in one pass.
And then it hit me, what if I could start with an empty string, attach to it the word 'Fizz' if it passes the 3 condition and attach the word 'Buzz' if it passes the 5 condition too. I drew this on a piece of paper
- i = 1 ==> no Fizz '' ==> no Buzz '' ==> output is 1
- i = 3 ==> yes 'Fizz' ==> no Buzz '' ==> output is 'Fizz'
- i = 5 ==> no Fizz '' ==> yes 'Buzz' ==> output is 'Buzz'
- i = 15 => yes 'Fizz' ==> yes 'Buzz' ==> output is 'FizzBuzz'
The ternary operator will allow assigning a value if condition checks and an alternate value if it fails in a very terse manner.
Something else became obvious, we are outputting either a string or a number while we cycling through the values of i and as we saw in a previous section an empty string is a falsy value. So how do we translate all that intelligence into working code?
The essential piece to achieve that was that the value of output was either going to be one of the possible strings 'Fizz', 'Buzz', 'FizzBuzz' or be falsy. In the falsy case i will just be passed as is.
So the final rewrite with more comments
function fizzBuzz( start = 1, end = 100) {
for( let i = start; i <= end; i++) {
let output = ( (i % 3) ? '' : 'Fizz' ); // output is assigned a value or empty
output += ( (i % 5) ? '' : 'Buzz') ; // output concatenates the next value
console.log(output || i); // || or operator if output is falsy will show i value
}
}
fizzBuzz(1,15);
Hopefully, you followed all of that :) This was a very satisfying solution to me since I believe it was easy to read, solved the problem and had a touch of eloquent JavaScript in it.
Final words
The coding exercise covers only one aspect of the many things that happen during the coding interview.
As I mentioned the steps and being able to deliver, regardless of the complexity of the problem, take a solid amount of practice.
Don't hesitate to use mock interviews (we will be offering some in Javascript soon but more on that later) to practice the conversational aspect of it.
I hope this was useful, share and live a comment if you please :)
Top comments (44)
Hi Ady! Can I leave you some comments?
Tests. There are no tests around this code. I'm not saying you need to do test-driven development. But if you're going to perform refactoring on a codebase it's important that you're covered by tests that will tell you whether you've introduced a bug while you're ~showing off~ cleaning up the code.
You could argue that this is unimportant for something as trivial as Fizz Buzz - you can easily perform manual testing of your single function with a few select cases. But I would say that, during a coding interview, it's really important to treat the problem with the same respect that you'd give to any program you'd write professionally. It's a real opportunity to show off how you like to work and how you think.
A few test cases, which can be run quickly, can easily demonstrate the interviewer that you've not introduced any regressions in your code.
Other than that, I like where you took the code in the end (but I think there's an even more ridiculous iteration you could get to in one line).
You bet you can leave comments David and what a great contribution.
Regarding TDD I think it can definitely be something to ask at the top of the exercise, you would be surprised that some of the companies would tell not be too worried about it in the interview context but will definitely like that you are thinking that way.
Most of the times, the TDD aspect will be raised as a follow-up question regarding quality and maintainability. I even had many scenarios of where the setup will be a stub function with failing tests and the exercise was to make the tests pass and add more if needed.
I totally agree that, as an interviewer, I would highly think of a candidate who talks and write tests from the get-go. I will probably add a section in the article of what it could look like.
Now regarding one liners :)
I actually have come up with about three of them while I was deep diving, and I still came back to the final solution of the article for a few reasons but mainly for:
For the one-liners, even I was the one who came up with the solution I still needed a minute to remember how I got there so I can only imagine if someone else was to review my code.
I agree that it is subjective and might be about coding culture and style.
Please add the fix for the iteration. I'll be happy to add it as an option to the article.
Cheers
Hi Ady,
With regards testing and your final code for fizzBuzz...
Since testing was mentioned previously, I would like to hear more about your strategy for testing functions that do not have a useful return value (fizzBuzz returns undefined; output is only via console.log).
Perhaps, a follow up post to cover this would be interesting.
Thanks for the post.
Hey John nice to hear from you. Yes will certainly do a follow up and just today someone was asking testing during a lecture.
Will address it aASAP.
Cheers
Thanks Ady, I will await your future post on the subject, but in the meantime, I can see a way that fizzBuzz could be tested although it would need some modification from it's present form.
Great please do share your solution if you do not mind. As I mentioned the one proposed is a personal preference and there are many other ways to solve for it.
Testing for it should also be pretty straightforward. If console.log is an issue we could build and return an array of outputs in the function and write a test for small subsets.
That sounds more interesting than the approach I was thinking of, I would prefer to follow your lead, so could you expand on your idea of an array of outputs and testing small subsets?
Hello John, below I'm adding what I would consider a more 'unit testable' solution to the FizzBuzz challenge.
It is important to note that this steps out of the context of solving a challenge during a coding interview and jumps into the refining and 'make ready for prod' exercises.
Like John Papa says in his talk 'Readable Code' - "Nothing start readable. Write dirty code, then clean it".
I would argue the same for testable in the context of a coding exercise.
The above provides you functions as very isolated units making them easily testable. Now this does not address writing tests for void functions or methods. Depending on the suite you use, there might be different strategies such as using spy if you write with Jasmine.
That should be for an entire different post altogether :) Let me know what you think.
Cheers
Yep, looks pretty good to me. Now it's returning a value it's testable.
Just for some added value I've included a small function called should to test it with and, of course, it passes...
My only other suggestion is you could do the following to get back to your original fizzBuzz implementation.
Cheers Ady ... It's just gone midnight here, so better get some sleep.
Bye for now.
As always great contributions John. I really like the idea of a small assertion library to quickly test code inline and not having to rely on a full blown testing suite. I have in fact started a project on github called dotLog to do just that. I haven't had the chance to do more on it lately but it would be fun to have you contribute to it and maybe have a few other people do.
Good night for now, let me know what you think about that in whatever your AM is.
Cheers :)
Yes, when you don't want the overhead of a full blown test suite a quick and dirty should function will do. I know it pretty minimal, but, sometimes, less is best!
I had a quick look at your dotLog code, but have'nt got much time this morning to figure it out. To aid my understanding, could you update the Readme with an example of usage, eg.
I don't want to guess at it.
Also, I have'nt played about much with the finer points of console.log, but I think the syntax that you use in dotLog will only work in the browser, but not when used with node. However, node's console.log will do colour changes, but I think the syntax is a little different. This would be worth exploring to make dotLog useable in the browser and node. Correct me if I'm writing crap here.
I will take another look this evening and otherwise wait for the Readme update. Yeh! Could be fun, but, as you know, I do have a tendency towards a functional style of JS? But, whatever, I do love JS
Cheers Ady.
Yes you are absolutely right - you should not have to try to figure it out. I need to do an initial clean up and set it in a way that it's intuitive and easy to contribute.
I don't mind the functional approach 'au contraire', I have been writing a lot like that lately. Point free composition is an absolute gem when done right. I just want to steer away from getting into dogma stands with FP vs OOP. I really think they can be complementary.
I've learned a lot from your style of writing and started implementing some of it. I could not handle professor Frisbee though, my head was spinning with that voice after a while lol.
Anyhow I'll clean up the dotLog project and ping you as soon as it's ready. Probably sometimes next week since this one is going to be crazy on my side.
Cheers :)
Yes, absolutely with you on that; fp, oop => it's all JS to me!
Yes, again Prof. Frisbee (aka Brian Lonsdorf) I've watched a number of his talks on youtube and I think he is a great guy to learn from, but making something funny (as he did with Prof. Frisbee) can always risk a "Marmite" response... you either love it or hate it!
No rush on the dotLog project... it's for fun; no deadlines required!
So long for now Ady
Hey Ady,
I've been investigating dotLog. I just wanted to let you know how much I like it. dotLog is minimal, that's nice; personally, I would keep it that way. Start a new project if you want more features. Here's what I've had time to suss so far...
Keep up the good work Ady. I will be using dotLog.
:)
AND THERE IS MORE! How about dotLog described by dotLog
Of course, I'm just kidding. You really should'nt have something that is'nt tested, testing itself! But it was just a moment of madness.
All the best :-)
You are so simply the best mate!!! And that’s very motivating that you could already find use for it.
You just became the official first adopter lol.
Thanks and let’s keep at it.
Cheers
You keep at it mate!
Remember, take your time, don't rush it. Anything worth doing is worth doing well.
:-)
Catch you later.
PS.
Incidentally, when I first took a quick look at the dotLog code I did'nt have much time, but I noticed within the .describe method you were mapping over the testSet array and also that testSet contained objects with two properties label and rule; but still the "penny had not dropped" (ie. I had not got that aha moment). When I looked again at dotLog, some hours later, I then found your .png file(console-test-call.png) and instantly new what was going on.
Now, I'm just telling you this so that you know how important the example you provided in console-test-call.png was to understanding your code.
I think that, for me atleast, was something worth remembering.
Hey Ady,
Just thought I'd give you a heads up on a new log function I propose for dotLog. It basically addresses the issue of logging to nodejs. ie. after the environment that dotLog is running in has been detected, it selects the correct syntax for console.log in node or browser.
I've put it up on repl.it just for a quick preview.
repl.it/@johnboy5358/dotLog
cheers :-)
Great I think we have similar ideas on that. I looked at a package called colors yesterday for the node side of things. The next step was to find a way to detect the environment and to do the appropriate output.
I’m glad you beat me to it 😀
Yes, I saw the colors package, but thought it might be a case of a "sledgehammer to crack a nut"; so decided not to. However, Ady, dotLog is your project and of course you should always have the final say since only you know which way you want to take it.
:-)
No no it's not mine it's open source lol :) The best approach should prevail. I like the simplicity of what you have put together. When I did my initial research colors was the first option that came up. The idea will be to have something as lean as possible.
Please feel free to suggest alternatives and may the one that makes most sense win. It will be of great benefit if you feel entirely enabled to make or suggest whatever you see fit. Cheers :)
One last visit to fizzBuzz re: making output testable and creating small testable pure functions.
Here, I've created a reuseable predicate function isMultOf, which is then used it to make two further predicate functions isMultOf3 and isMultOf5. These are then combined to make the conjunction predicate isMult3And5. Finally, a range function generates the array of integers required.
:-)
Hello,
Not a javascript user here, (python and lua). Still found this a very insightful read.
I would like to add that simlifying code to such a degree to take up less lines can make it less readable, overall not making the end product much better in my opinion.
(Correct me if i'm wrong 🙂.)
But it's certainly interesting to see!
(Even if my limited understanding of js restricted me from understanding the final final solution fully.)
I quickly opened up trusty repl and did one up in python:
I also wrote one up in lua, because I have um, no uh, life. 😊
Lua rocks
"...because I have um, no uh, life" haha welcome to the club :)
Very readable and does the job for someone who does not code in Python. Life is complicated already, code does not need to be :)
Merci Monsieur!
lol je vous en prie :) (so polite)
Any suggestions as too how I could level up my code would be 👌
. Keep finding a working solution first and foremost,
. revisit and refactor when new concepts and better technique can significantly improve your working solution
. read and write (code) everyday
. (most important) share and teach anytime you have a holy s*** moment. teaching will force you to learn and get better
Thank you for your reply, It was very helpful!
StackOverflow to the rescue!
( and night!)
I have certainly found this to be the case.
Back in highschool I sat next to two people who really struggled and helping them inturn really helped me improve my code and realise a better way to write it or engrain it in my memory!
On top of that I used to have to lead the class in middle school as my teacher would literally ask me and my friend for help as she was out of her depth! 😂
Really cool that you break it down part by part.
I think TDD is good only when you are testing a non-junior engineer with very liberal amount of time to work on it.
Instead of a time crunch of within 1 hour for a coding challenge.
Glad you like it Max. I agree that regarding TDD level and time will play a key role here. A good interviewer would not hesitate to take the driver seat in carrying the session towards anything that can add value and overall help the candidate shine.
Out of curiosity, how would it end up looking if you'd clearly solved the problem before and are simply typing in the solution?
I was given this task as a challenge in the bootcamp I'm enrolled in, my first instinct was to jump straight for a nested ternary. After some thinking I then went for the string concatenation (using Ruby in this particular case).
The concern is that my natural instinct to go with ternary may have appeared to be a "he's done this before" despite that not being the case - but now that I've solved it, it would be difficult for me to not just type in my cleanest solution.
How would one navigate this in an interview? Type it in, commenting that you'd previously done the challenge? Alert the interviewer to the fact at the risk of sounding cocky? Play it stupid and solve through more simplistic steps that really wouldn't occur to you naturally?
Hello and thank you for the great question. I have been itching to do actually a full article on this particular subject and I think it's time to put it together, so coming up soon.
In the meantime, I want to take a second and state that having someone who has been exposed to the problem before is not a bad thing at all. It simply shows someone who is well prepared or who has experience.
Now, if they pretend that they have never seen it and 'fake' their way to the solution, I personally feel like that does not reflect as an honest trait of character and any savvy interviewer will not be fooled by it.
I personally think that an interview shouldn't be a disconnected exercise or a trivia showdown of things that have no connection with something that a candidate has been doing long enough to have proficiency in it.
It should be expected that the canditate has seen or been exposed to a similar exercise before. Now it's up to the interviewer to craft a good exercise with the right follow up questions that can reveal depth, understanding, style and culture. For that to happen though the interviewer has to be solid and knowledgeable on the discipline. Sometimes, unfortunately, that is not the case..
Let me finish off with a somewhat relatable example. Let's say you are a private cab company that wants to hire a professional driver that knows the city well and can find the best routes to optimize travel time.
Let's say Main Street and 1st is the most impossible intersection at certain times of the day, but there are ways around it. I'm pretty sure that a savvy local driver might've encountered it many times before. Why wouldn't I want to hear his take and experience about it? I probably would ask them about how they would navigate from certain points without GPS. Essentially I would ask them about what they know and what they have been actually challenged and solved for.
The above example might be a stretch, but I honestly believe that it does not matter at all. I'm even an advocate of having the candidate review all the possible questions that I would evaluate him/her before coming on site. I think that they will be more relaxed which is a win for everyone. The 'depth' conversation will even be richer from that perspective.
Thanks for the response! With regards to your cab analogy, it seems the best approach would essentially be to write down said cleanest solution and while doing so, discuss why it was chosen over other approaches and the possible pitfalls, and how one would circumvent them if they were included in the scope of the question.
I guess it can be an opportunity to show that you're capable of seeing how your solution may need to adapt to slight changes in requirements - I believe the way I solved this in Ruby would have failed with numbers where the length exceeded that of the "Fizz/Buzz" and I'd imagine addressing this while writing the solution would demonstrate a good ability to criticize one's own code.
Appreciate the response - opened my eyes to a different way to approach already known solutions!
Yes, the whole point is to dig as deep as possible to assess levels of understanding. I, for example like the formulation of "How would you explain the concept of closures to a junior developer and to a non technical person?" versus "What is a Javascript closure? Provide some examples"
I think the first one is more prone to reveal depth in understanding than the second formulation which by the way is the most popular screening question in Javascript.
Thank you for adding to the discussion, I surely appreciate the comments.
I would approach it "top down" with pseudo code:
Then all that's left is to write the 'isMultiple' function ;-)
Pseudo code is synonym to thinking out loud in an interview context and is a golden approach that I personally highly recommend.
Awesome stuff and thank you for sharing :)
A nice and simple explanation of things.
The thing you said about managing pulses in the interview is absolutely true. This happens to me In every interview.
Amazing! Thanks for sharing!
Awesome glad you like it. Cheers
We could do (!(i % 15)) right?
yup you could as well always try to read out your conditionals in plain English to make sense of out them. So if I was to replace i with 10 or 15 using your construct I would be saying
is (10%15) falsy? is (6) falsy? No
is (15%15) falsy? is (0) falsy? Yes