So I’m currently on a hunt for a new position as a Front-End Developer. I know JavaScript very well and can wax poetically about Closures, Currying, Prototypal Inheritance, Design Patterns, App performance and overall Front-End Architecture. But yet I still end up bombing job interviews. (FYI most of the jobs I’m interviewing for are for building SPA’s with some sort of MVC framework)
Usually the coding tests are small code snippets of things I never come across professionally. Like write a function to solve some sort of math problem. Aside from the inherit awkwardness of trying to code while holding the phone in one hand and having a stranger see your screen and watch every character you type, I just don’t usually see this kinda stuff in the real world.
Is this a serious skill set I’m lacking or are the interviewers asking me irrelevant questions. I guess I should work on my functional programming and algorithm chops but I haven’t found many good resources on the web (or in print) any suggestions?
5
Writing code is only a part of the interview process.
Actually solving the logical problem is only a part of the code writing task.
Interviewers want to be sure that:
-
You can write code. Many candidates with ten years professional experience in a language can’t write any code at all, and this test is intended to reject those candidates.
-
You think about a problem before you write code. Many would jump to their keyboards, write tens of lines of code, then find that they misunderstood the original problem, because they didn’t take time thinking about it.
-
You are able to adapt yourself when writing code. Say you found a solution, but when you started to implement it, it appeared that your first idea wasn’t the best one; can you rapidly switch to a better one, eventually refactoring the code you wrote?
This also means that such interviews should be more interactive. Instead of typing with one hand, buy a hands-free kit or call through Skype and use a headset. Type as you are typing at work, while commenting and explaining what you do: it will suddenly become much less awkward.
Have you done pair programming? If yes, the interview situation is very similar, except that the interviewer may not give you his opinion, and you don’t ask him to switch keyboards with you when you’re finished.
Here are a few examples of a purely mathematical problem and how it shows non-mathematical skills of a developer.
Example 1: simple coding exercise
You need to implement Fibonacci number calculator in JavaScript. You should be able to change the index. The Fibonacci sequence follows those rules:
- The first two numbers of the sequence are 0 and 1,
- Each subsequent number is the sum of the previous two.
Example: F0 = 0, F1 = 1, F2 = 1, F3 = 2, F10 = 55.
You have three minutes.
Here, the interviewer wants you to think as fast as possible, find the solution and quickly implement it. Such exercise is unrelated to what actual developers do and is much closer to what you can find when doing a CS degree, but interviewers like this sort of things, so let’s do it. Also, time constraint makes it impossible to do any automated testing, so the interviewer probably doesn’t expect this from you.
“The description of the algorithm makes me think about recursion. The second rule leads to the following recursive function.”
var fibonacci = function (n) {
return fibonacci(n - 2) + fibonacci(n - 1);
};
console.log(fibonacci(10));
“To end the recursion, we will add the special cases by replacing the body of fibonacci
function.”
switch (n) {
case 0: return 0;
case 1: return 1;
default: return fibonacci(n - 2) + fibonacci(n - 1);
}
“Done.”
Conclusion
As I said, such exercise is completely unrelated to an actual job of a developer. Does it make it meaningless? Not really, because at least, it shows that the person:
-
Is able to think about a problem. Some candidates will be totally lost, and under stress, will take more than the allocated time just to think about a possible way to approach the problem.
-
Knows recursion or is able to circumvent recursion through an ordinary loop. Later, the interviewer may ask if there were ways to use/not use recursion, and what are the benefits/drawbacks of recursion.
-
Knows the basics of the programming language. It doesn’t matter if the person used
switch
, a guard clause, a conditional or a dictionary: depending on the background, different candidates will pick different tools to accomplish the same thing. -
Keeps focused on the problem, without bringing things like unit tests, scalability or performance. The interviewer may then ask why performance-wise, the function above is terrible, expecting the candidate to explain what should be done to bring performance to a reasonable level.
Example 2: tricky questions
You need to implement Fibonacci number calculator in JavaScript. It should be as fast as possible. You should be able to change the index ranging from 0 to 100. The Fibonacci sequence follows those rules:
- The first two numbers of the sequence are 0 and 1,
- Each subsequent number is the sum of the previous two.
Example: F0 = 0, F1 = 1, F2 = 1, F3 = 2, F10 = 55.
You have three minutes.
Now, we have an interesting constraint which shows that the interviewer doesn’t really care about the ability of the candidate to solve problems, but rather about his ability to guess which ways are faster than others.
Those tricky questions usually invite tricky answers. Here, given time constraint, there is no way to make multiple implementations, benchmark them, profile the fastest one and come with an optimal solution.
Instead, what about:
“Let me Google “First Fibonacci numbers”… This looks promising. With a simple (that would be an oxymoron) regular expression, we can build a comma-separated list of values.”
sed -e "s;([0-9]*) ([0-9]*);'2',;g" fbncc10.txt | tr 'n' ' '
“Finally, the program itself.”
var map = ['0', '1', '1', '2', '3', '5', '8', '13', '21', '34', '55', '89', '144', '233', '377', '610', '987', '1597', '2584', '4181', '6765', '10946', '17711', '28657', '46368', '75025', '121393', '196418', '317811', '514229', '832040', '1346269', '2178309', '3524578', '5702887', '9227465', '14930352', '24157817', '39088169', '63245986', '102334155', '165580141', '267914296', '433494437', '701408733', '1134903170', '1836311903', '2971215073', '4807526976', '7778742049', '12586269025', '20365011074', '32951280099', '53316291173', '86267571272', '139583862445', '225851433717', '365435296162', '591286729879', '956722026041', '1548008755920', '2504730781961', '4052739537881', '6557470319842', '10610209857723', '17167680177565', '27777890035288', '44945570212853', '72723460248141', '117669030460994', '190392490709135', '308061521170129', '498454011879264', '806515533049393', '1304969544928657', '2111485077978050', '3416454622906707', '5527939700884757', '8944394323791464', '14472334024676221', '23416728348467685', '37889062373143906', '61305790721611591', '99194853094755497', '160500643816367088', '259695496911122585', '420196140727489673', '679891637638612258', '1100087778366101931', '1779979416004714189', '2880067194370816120', '4660046610375530309', '7540113804746346429', '12200160415121876738', '19740274219868223167', '31940434634990099905', '51680708854858323072', '83621143489848422977', '135301852344706746049', '218922995834555169026', '354224848179261915075'];
var fibonacci = function (n) {
return map[n];
};
console.log(fibonacci(10));
Conclusion
Tricky questions invite tricky answers. Don’t be heroic, and don’t start benchmarking and profiling when you only have three minutes. Think of clever ways to solve the problem while using your experience. My experience gives me a hint that using a map may be faster than computing the number. It may be wrong, but this attempt should be expected given the time constraint.
Knowing your tools also helps, and is an essential part of developer skills: without knowing regular expressions, I would either spend the allocated three minutes Googling for a comma-separated list, or would start writing a parser which will build the array I need.
Remember, a good developer is not one who starts coding right away, but who knows how to avoid coding when a better opportunity is available. Some interviewers won’t hesitate to give you assignments which look like coding ones, but which require nearly no code at all.
Example 3: complete application development
You need to implement Fibonacci sequence in JavaScript. The length of the sequence is determined during the execution of the program. The sequence follows those rules:
- The first two numbers of the sequence are 0 and 1,
- Each subsequent number is the sum of the previous two.
Example: 0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89.
The application should be presented as a web page, allowing the user to specify the length of the sequence through an input field.
You have one hour.
Let’s start.
“The example sequence is very helpful, since it will allow me to have a bunch of unit tests to ensure my implementation doesn’t look completely wrong. In general, I use Mocha for node.js or QUnit for client-side JavaScript, but here, for the sake of simplicity, I’ll just throw a bunch of test functions.”
“I start by creating index.htm
and fib.js
files. Then, I fill index.htm
with really minimalistic and not W3C-compliant code (we can get back to this later if you’re interested in my HTML skills as well).”
<label>Length</label> <input id="length" value="15" />
<input id="compute" type="button" value="Compute" />
<div id="result" style="font-weight:bold;"></div>
<div id="tests"></div>
<script src="fib.js"></script>
“Let’s now write some code which will call the Fibonacci generator function and show the results.”
fibonacci = (function () {
var compute,
init;
compute = function (length) {
// TODO: Implement Fibonacci sequence.
return [1, 2, 3];
};
init = function () {
var button = document.getElementById('compute');
button.addEventListener('onclick', function () {
var length = parseInt(document.getElementById('length').value, 10),
result;
console.log(
'Computing Fibonacci sequence of length ' + length + '.'
);
result = compute(length);
document.getElementById('result').innerText = result.join(', ');
});
};
return {
compute: compute,
init: init
};
}());
“It’s time to run the code for the first time and… it doesn’t work. Nothing happens. Why?”
“OK, I’ve forgotten the fibonacci.init();
at the end. I added it, and still, nothing happens, while it should at least display the message in the console. Wait, right, it’s not onclick
, but click
; I use JQuery so often that I start to forget the names of the events in plain JavaScript.”
“Let’s add some tests.”
ensureAreEqual = function (expected, actual) {
var testResultsContainer = document.getElementById('tests');
testResultsContainer.innerText += (expected.equals(actual) ?
'.' :
('Actual [' + actual.join(', ') + '] is different from ' +
'expected [' + expected.join(', ') + '].'));
};
test = function () {
ensureAreEqual([0], compute(1));
};
“Comparing arrays can be tricky, so I just copy-paste Array.prototype.equals
code from this answer.”
“Now that we run the application, it displays:”
Actual [1, 2, 3] is different from expected [0].
“The test failed, which was highly expected, given our actual implementation (return [1, 2, 3];
) of Fibonacci sequence. It’s time to change this.”
“From the original statement, Fibonacci sequence starts by [0, 1]
, so compute
becomes:”
compute = function (length) {
var fib = [0];
return fib;
};
“This makes it possible to pass the first test, and we can now write our second one.”
ensureAreEqual([0, 1], compute(2));
“It fails, so we get back to compute
and modify it.”
compute = function (length) {
var fib = [0, 1];
return length === 1 ? [0] : fib;
};
“Now, both tests pass, and it’s time to move to non-edge cases.”
compute = function (length) {
var fib = [0, 1],
i,
next,
current = 1,
previous = 0;
for (i = 2; i < length; i += 1) {
next = current + previous;
previous = current;
current = next;
fib.push(next);
}
return length === 1 ? [0] : fib;
};
“All three tests pass now, except that the result doesn’t look right for larger lengths such as 100. In order to get those results right, we should have used an arbitrary precision library. There are also things to improve. For example, naming conventions are sometimes too bad (what’s fib
?). HTML-related JavaScript code should also go to a different object, as well as testing code. Also, I haven’t tested compute(0)
and haven’t checked the inputs.”
Conclusion
By walking through the example, you may see the interaction expected during an interview. Not everything was smooth (I did several mistakes at the beginning which lead me to an embarrassing situation where nothing happens when I run the application), and the original approach was lame if we have to support a large sequence length, but I’ve achieved to show that:
- I can handle different issues,
- I use test driven development, Fibonacci sequence being an excellent opportunity for this,
- I copy-paste code when the source is trustworthy and writing it from scratch seems overwhelmingly complicated and error-prone,
- I don’t over-rely on libraries such as JQuery,
- I chose the right scope: since the interviewer wants to check my JavaScript skills, I won’t waste time writing perfect and clean HTML: not spending time here makes it possible to spend more time writing unit tests,
- I know when to finish and tell that I’m done, while keeping in mind that a bunch of things are not perfect (like
compute(0)
which will fail, but it doesn’t matter for the demo).
This is exactly what an interviewer should expect from you.