Embarrassing code I wrote under stress at a job interview

(written by lawrence krubner, however indented passages are often quotes). You can contact lawrence at: lawrence@krubner.com

(Note: this post was, in part, inspired by John Lawrence Aspden’s post about FizzBuzz.)

I write terrible code when I go to a job interview. That’s mostly because, when they ask me to solve a coding question, I get nervous. I thought it might be entertaining if I wrote about one such encounter.

Yesterday I went to a job interview, at a company in New York that had once built their stack (for managing online advertising) in Ruby but who are now transitioning all of their stuff to Clojure (Adaptly).

On this particular day, I was to talk to 3 of their senior developers, and 2 of them would hit me with their favorite questions about how to find something in a given number series.

When I got to the company office, they put me in a conference room and sent in one of their senior engineers. He asked me to fire up a REPL, so I launched Emacs and then “nrepl-jack-in”. I was ready to go, but I was also very nervous, because of these 3 reasons:

1.) I’ve got a guy looking over my shoulder and he’s watching every mistake I’m making

2.) I’m suddenly self-conscious about the prettiness of my code — it doesn’t matter if I can solve the problem, since I’m also competing against candidates who can solve the problem, so the real competition is probably about how elegant and idiomatic our code is

3.) this isn’t about getting the job done, it’s about being quick — the pressure to move fast is strong

I was typing code into a live environment, which would then execute my code when I hit “enter”. For those of you who haven’t seen the REPL in Emacs, my screen looked like this:

And yet, as our conversation proceeded, one problem I eventually faced wasn’t Clojure or math, it was English — we had a misunderstanding in our native language!

He asked me if I knew what the “Happy number sequence” was. I said I had never heard of it. He described it like this:

“Take each digit in a number and square it, then add the sums together. Keep doing this recursively.”

The next sentence of English is where the problem started. I thought he said:

“The sequence will either go to one or to infinity.”

but he actually said:

“The sequence will either go to one or infinitely.”

He then offered an example of how to find the next number in the sequence:

“Suppose you start with the number 31. Well, 3 squared is 9 and 1 squared is 1, and 9 and 1 added together is 10, so the next number in the sequence, after 31, is 10.”

And then, with “10″, the “1″ squared is 1 and the “0″ squared is 0, and when you add 1 and 0, you get “1″, therefore we know that “31″ is part of the Happy sequence, because, after 2 iterations, it ended up being “1″.

That much was obvious, but I could not figure out how to test a sequence that goes to infinity — how would I know when to stop testing for more numbers? I mean, I might get to a septillion, but I’d only be taking a small step toward infinity — and then I would need to keep testing till I get to infinity… which is impossible? But I wanted to appear smart, so I didn’t express any confusion. I was thinking that if I dove into the problem, then it would eventually make sense to me. So I started coding in the REPL. The first thing I needed was a function that would find the next number in the sequence, and this would surely be easy:

user>
(defn [x]
 (loop [snc (str x) snc-sum 0]
 (if (seq (rest snc)
   (recur
      (rest snc)
      (+ (+ (* (first snc) (first snc)) sum)))

but that got me:

RuntimeException EOF while reading, starting at line 4  clojure.lang.Util.runtimeException (Util.java:219)

Oh hell, why am I so clumsy? I tried again:

user>
(defn [x]
 (loop [snc (str x) snc-sum 0]
 (if (seq (rest snc))
   (recur
      (rest snc)
      (+ (+ (* (first snc) (first snc)) sum))))))

and that got me:

IllegalArgumentException First argument to defn must be a symbol  clojure.core/defn (core.clj:277)

Embarrassing! And now I felt even more nervous! So I tried:

user>
(defn happy [x]
 (loop [snc (str x) snc-sum 0]
 (if (seq (rest snc))
   (recur
      (rest snc)
      (+ (+ (* (first snc) (first snc)) sum))))))

and I got:

CompilerException java.lang.RuntimeException: Unable to resolve symbol: sum in this context, compiling:(NO_SOURCE_PATH:7:10) 

Ugh! What a stupid typo! I tried again:

user>
(defn happy [x]
 (loop [snc (str x) snc-sum 0]
 (if (seq (rest snc))
   (recur
      (rest snc)
      (+ (+ (* (first snc) (first snc)) snc-sum))))))
#'user/happy

Finally! At least it compiled! Now maybe I can repair my damaged credibility! Let’s try to use it:

user>
 (happy 31)
ClassCastException java.lang.Character cannot be cast to java.lang.Number  clojure.lang.Numbers.multiply (Numbers.java:146)

Oh, good lord. This was the only way I could think to get each digit in a number:

snc (str x)

but this actually gave me a sequence of Characters, not strings. In the real world, I would have stopped at this point, gone to look at the documentation, and maybe found a more elegant way to do this. However, under pressure of time, I just started piling on bandaids to try to fix things enough to get it to work:

user>
(defn happy [x]
 (loop [snc (str x) snc-sum 0]
 (if (seq (rest snc))
   (recur
      (rest snc)
      (+ (+ (* (int (first snc)) (int (first snc))) snc-sum))))))
#'user/happy
user>
 (happy 31)
nil

Damn. I forgot to return any value from the loop. So I tried again:

user>
(defn happy [x]
 (loop [snc (str x) snc-sum 0]
 (if (seq (rest snc))
   (recur
      (rest snc)
      (+ (+ (* (int (first snc)) (int (first snc))) snc-sum))))   snc-sum))

And I get:

CompilerException java.lang.UnsupportedOperationException: Can only recur from tail position, compiling:(NO_SOURCE_PATH:5:4) 

Now I am angry with myself. This whole process is dragging on too long, and I keep making simple mistakes. And its a job interview!

I try again:

user>
(defn happy [x]
 (loop [snc (str x) snc-sum 0]
 (if (seq (rest snc))
   (recur
      (rest snc)
      (+ (+ (* (int (first snc)) (int (first snc))) snc-sum))) snc-sum)))
#'user/happy

Finally! It compiled! Let’s see it work:

user>
 (happy 31)
2601

Ah, damn! The correct answer is “10″, but I am getting 2601! What the hell went wrong?

At this point, the guy interviewing me is starting to get bored. I can see his eyes drifting elsewhere, he starts checking his phone for messages. I am thinking that in his mind he has already decided that I’m a pathetic loser. In a different industry, he might simply shout “Next” and kick me out and drag the next applicant in, but our industry is slightly more polite than that. So he waits for me to stop screwing up. But he looks very bored.

I notice that I am, for some strange reason, summing twice, so I take out the redundant “+”:

user>
(defn happy [x]
 (loop [snc (str x) snc-sum 0]
 (if (seq (rest snc))
   (recur
      (rest snc)
      (+ (* (int (first snc)) (int (first snc))) snc-sum)) snc-sum)))
#'user/happy
user>
 (happy 31)
2601

Damn! Damn! Damn! What the hell is wrong with my code?

In retrospect, the error is obvious, but under the pressure of time, my mind was racing and I was not seeing the problem, so I added some print statements so I could better understand what was happening:

user>
(defn happy [x]
 (loop [snc (str x) snc-sum 0]  (print (rest snc))  (print (first snc))
 (if (seq (rest snc))
   (recur
      (rest snc)
      (+ (* (int (first snc)) (int (first snc))) snc-sum)) snc-sum)))
#'user/happy
user>
 (happy 31)
(1)3()1
2601

Hmm, so, the sequence of numbers is exactly what I thought it would be, so everything should work perfectly, but it is not because…

Oh, right! I am casting a string to an integer, and getting back the ASCII value of the string. Awful!

So, I try to fix that:

user>
(defn happy [x]
 (loop [snc (str x) snc-sum 0]
 (if (seq (rest snc))
   (recur
      (rest snc)
      (+ (* (.parseInteger (first snc)) (.parseInteger (first snc))) snc-sum)) snc-sum)))
#'user/happy
user>
 (happy 31)
IllegalArgumentException No matching field found: parseInteger for class java.lang.Character  clojure.lang.Reflector.getInstanceField (Reflector.java:271)

Hell! What is the right method call? I’ve done this many times before, I just can’t recall, right now, the way to write this. I turn to the guy and ask him permission to look this up in my old code. He gives me permission. I look at some code that I’ve written and see the correct way, and so I can do this correctly:

user>
(defn happy [x]
 (loop [snc (str x) snc-sum 0]
 (if (seq (rest snc))
   (recur
      (rest snc)
      (+ (* (Integer/parseInt (first snc)) (Integer/parseInt (first snc))) snc-sum)) snc-sum)))
#'user/happy

It compiles! So I try it:

user>
 (happy 31)
ClassCastException java.lang.Character cannot be cast to java.lang.String  user/happy (NO_SOURCE_FILE:7)

FML!!!!!

I know there must be something elegant I can do here, but for now I go for the fastest shortcut I can think of:

user>
(defn happy [x]
 (loop [snc (str x) snc-sum 0]
 (if (seq (rest snc))
   (recur
      (rest snc)
      (+ (* (Integer/parseInt (str (first snc))) (Integer/parseInt (str (first snc)))) snc-sum)) snc-sum)))
#'user/happy

Holy hell, this code is ugly! If someone came into a job interview, and I was the one doing the interview, I would have some doubts about the candidate if I saw them write this code.

But anyway, I try it:

user>
 (happy 31)
9

Hmm, very close! I want “10″ but I get “9″. What did I do wrong? Oh wait, I forgot to add in the “false” clause of the “if” statement! That is, what happens if we don’t recur?

user>
(defn happy [x]
 (loop [snc (str x) snc-sum 0]
 (if (seq (rest snc))
   (recur
      (rest snc)  (do (print (first snc))
      (+ (* (Integer/parseInt (str (first snc))) (Integer/parseInt (str (first snc)))) snc-sum)) snc-sum))))
CompilerException java.lang.IllegalArgumentException: Mismatched argument count to recur, expected: 2 args, got: 3, compiling:(NO_SOURCE_PATH:5:4) 

Uh, so, I have a bracket in the wrong place? I have keybindings set up so that Control-1 takes me to the start of any form, and Control-2 takes me to the end of any form, so I can usually, rather easily, see how the brackets line up. But that doesn’t save me from bad thinking under stress.

Maybe I’ll add in a print statement again:

user>
(defn happy [x]
 (loop [snc (str x) snc-sum 0]
 (if (seq (first snc))
   (recur
      (rest snc)  (do (print (first snc))
      (+ (* (Integer/parseInt (str (first snc))) (Integer/parseInt (str (first snc)))) snc-sum))) snc-sum)))
#'user/happy
user>
 (happy 31)
3
9

So, this never gets to the “1″, it only does the “3″. Why is that? Maybe instead of this:

(seq (rest snc))

I should do this:

(seq (first snc))

So I try:

user>
 (defn happy [x]
 (loop [snc (str x) snc-sum 0]
 (if (seq (first snc))
   (recur
      (rest snc)  (do (print (first snc))
      (+ (* (Integer/parseInt (str (first snc))) (Integer/parseInt (str (first snc)))) snc-sum))) snc-sum)))

#'user/happy
user>
 (happy 31)
IllegalArgumentException Don't know how to create ISeq from: java.lang.Character  clojure.lang.RT.seqFrom (RT.java:505)

Yeah, what a stupid idea. I change it back, since that is obviously not where the problem is:

user>
 (defn happy [x]
 (loop [snc (str x) snc-sum 0]
 (if (seq (rest snc))
   (recur
      (rest snc)  (do (print (first snc))
      (+ (* (Integer/parseInt (str (first snc))) (Integer/parseInt (str (first snc)))) snc-sum))) snc-sum)))

#'user/happy

But where is the real problem? Oh, I see, in the “false” clause of the “if” statement, I need to sum the results:

user>
user>
 (defn happy [x]
 (loop [snc (str x) snc-sum 0]
 (if (seq (rest snc))
   (recur
      (rest snc)  (do (print (first snc))
      (+ (* (Integer/parseInt (str (first snc))) (Integer/parseInt (str (first snc)))) snc-sum))) (+ (first snc) snc-sum))))

#'user/happy
user>
 (happy 31)
ClassCastException java.lang.Character cannot be cast to java.lang.Number  clojure.lang.Numbers.add (Numbers.java:126)
3

FML!!!! FML!!!! FML!!!! FML!!!! FML!!!! FML!!!! FML!!!! FML!!!! FML!!!!

The guy who is interviewing me has mostly stopped watching, because he’s already decided there is no chance in hell that they will be hiring me. He is looking at his phone. I half expect him to start playing Flappy Bird.

I realize now that the verbose and horrible “Integer/parseInt (str” needs to be applied to the sum at the end of the “if” statement:

user> (defn happy [x]
 (loop [snc (str x) snc-sum 0]
 (if (seq (rest snc))
   (recur
      (rest snc)  (do (print (first snc))
      (+ (* (Integer/parseInt (str (first snc))) (Integer/parseInt (str (first snc)))) snc-sum))) (+  (Integer/parseInt (str (first snc))) snc-sum))))

#'user/happy
user>
 (happy 31)
3
10

Awesome! I finally got “10″! I finally got the right number!

And yet, I am only at the start of this problem. Writing a simple function to find the next number in the sequence was suppose to be the easy part, and I just wasted 10-15 minutes on it!

So, how do I find out if a number is in a sequence, when the algorithm might lead to infinity? I had previously postponed the question, but now I came back to it. Again, our problem was English, not Clojure.

Thinking out loud, I said: “If the sequence can go to infinity, then I could create a generator that returns the numbers lazily… but at some point we would need to realize those values, to check them… ”

“That is one way to think about it,” he said.

I kept thinking out loud: “…and if they go to infinity, then they will crash my machine…”

“Are you sure?” he said.

I thought long and hard about that. Was I missing something obvious? Was there a way that my machine could count to infinity?

I was quiet a long moment because I was worried that whatever I said next would make me look stupid.

“Well, I could pass in some bound, like perhaps 10,000. I could pursue a finite number of tries before giving up.”

“Are you sure?” he repeated. “Are you sure the numbers go to infinity?”

“Didn’t you tell me that they go to infinity?”

“No,” he said, “I said they go infinitely.”

Finally, the light dawned in my head.

“Oh,” I said, “So they loop?”

“Yes.”

“Oh!” I finally got it. “So they loop over a finite set of numbers?”

“Yes.”

“Ah! So I only need to store the numbers in a set and then I can see if I start to loop?”

“Yes.”

Okay, so now I got it. I could store the numbers in a set, and if I ever saw the same number twice, then I knew that the number that I started with was not in the Happy sequence.

user>
 (defn happy [x]
  (loop [snc (str x) snc-sum 0 seen-so-far #{}]
    (if (seen-so-far (Integer/parseInt (str (first snc))))
      nil
      (if (seq (rest snc))
        (recur
          (rest snc)
          (+ (* (Integer/parseInt (str (first snc))) (Integer/parseInt (str (first snc)))) snc-sum))
          (conj seen-so-far (Integer/parseInt (str (first snc))))
        (+  (Integer/parseInt (str (first snc))) snc-sum)))))

CompilerException java.lang.RuntimeException: Too many arguments to if, compiling:(NO_SOURCE_PATH:5:7) 

Ah, stupid! I’ve got a bracket in the wrong place for that second “if” statement. I’ll try again:

user>
 (defn happy [x]
  (loop [snc (str x) snc-sum 0 seen-so-far #{}]
    (if (seen-so-far (Integer/parseInt (str (first snc))))
      nil
      (if (seq (rest snc))
        (recur
          (rest snc)
          (+ (* (Integer/parseInt (str (first snc))) (Integer/parseInt (str (first snc)))) snc-sum)
          (conj seen-so-far (Integer/parseInt (str (first snc)))))
        (+  (Integer/parseInt (str (first snc))) snc-sum)))))

#'user/happy

Great! It compiles! So now I can:

user>
 (happy 31)
10

Wait, what am I doing? The “happy” function simply finds me the next number in the sequence. I need a function, higher up the chain, that can loop through the whole series, and call “happy” on each iteration of the loop. I reset the “happy” function to the previous version that was working, and then I start on a new function:

(defn find-happiness [starting-integer]
	(loop [test-integer starting-integer seen-so-far #{}]
	      (let [next-integer (happy next-integer)]
	      	   (if (seen-so-far next-integer)
		       nil
		       (recur
		         next-integer
		         (conj seen-so-far next-integer))))))

which gives me:

CompilerException java.lang.RuntimeException: Unable to resolve symbol: next-integer in this context, compiling:(NO_SOURCE_PATH:3:27) 

Sloppy! I am not impressing myself.

I have to take a deep breath and think, for a moment, about what I want to return. By this point, so much time has dragged by that the guy who is suppose to be interviewing me has largely stopped paying attention to what I’m doing. I figure the interview is a bust anyway, so I can take a moment and think about things clearly. The pressure of time disappears once I realize there is no chance I am getting this job.

I know I want this:

	        (if (= next-integer 1)
		   true

That is, if the next number in the series is ever 1, then we know the starting number does belong to the Happy sequence, so we should return true.

And I know I want:

	      	   (if (seen-so-far next-integer)
		       nil

That is, if I have a set called “seen-so-far”, and I store all the numbers that I discover as I iterate through sequence, then if ever I see a number twice, I can conclude that the series is settling into an infinite loop, and I can return false, because then I will know that the starting number is definitely not part of the Happy sequence.

So this should work:

(defn find-happiness [starting-integer]
	(loop [test-integer starting-integer seen-so-far #{}]
	      (let [next-integer (happy test-integer)]
	        (if (= next-integer 1)
		   true
	      	   (if (seen-so-far next-integer)
		       nil
		       (recur
			 next-integer
		       	 (conj seen-so-far next-integer)))))))
#'user/find-happiness

So I try it:

user>
 (find-happiness 31)
true
user>
 (find-happiness 32)
nil
user>
 (find-happiness 33)
nil
user>
 (find-happiness 34)
nil

Nice!!!! Very cool!!!

How about the first 100 numbers?

(map find-happiness (range 100))
(nil true nil nil nil nil nil nil nil nil true nil nil nil nil nil nil nil nil true nil nil nil nil nil nil true nil nil nil nil true nil nil nil nil nil nil nil nil nil nil nil true nil nil nil nil nil nil nil true nil nil nil nil true nil nil nil nil nil nil nil nil nil nil true nil nil nil nil true nil nil nil nil true nil nil nil nil nil true nil nil nil nil true nil nil nil true nil nil nil nil true nil nil)

Hmm, cool, but that is hard to read. Let me add in some print statements, so I can better understand the output:

user>
 (defn find-happiness [starting-integer]
        (println (str starting-integer))
	(loop [test-integer starting-integer seen-so-far #{}]
	      (let [next-integer (happy test-integer)]
	        (if (= next-integer 1)
		   (do
		     (println " true ")
		     true)
	      	   (if (seen-so-far next-integer)
		       (do
		         (println " false ")
		         nil)
		       (recur
			 next-integer
		       	 (conj seen-so-far next-integer)))))))
#'user/find-happiness

And then:

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

Very cool!

And then I wanted to test one of these by hand just to make sure everything was working the way it should. It says that 97 is in the Happy sequence, so I tested to see if that was true:

user>
 (happiness 97)
CompilerException java.lang.RuntimeException: Unable to resolve symbol: happiness in this context, compiling:(NO_SOURCE_PATH:1:1) 

The level of self-sabotage is impressive, isn’t it?

Let’s try that again with a function I actually wrote:

user>
 (happy 97)
88
user>
 (happy 88)
72
user>
 (happy 72)
51
user>
 (happy 51)
26
user>
 (happy 26)
10
user>
 (happy 10)
1

Cool! It does work! And this is a cool number series!

Needless to say, the job interview was a disaster. I think they want someone who can write something like this in 5 minutes, but between the English-language confusion over the definition of the sequence, and the many mistakes I made, this dragged on for almost 30 minutes.

After I was done, the guy said something polite about “good effort” and then he said he would sent in the next engineer.

A few minutes later the next engineer came in. He asked me if I knew what the Collatz number sequence was. I said no. He drew a definition of it on the white board. He asked me to write some functions that would allow me to find the longest iterations through the Collatz sequence, given a set of starting numbers.

What followed was similar to the above: for more than 30 minutes I stumbled through the process, making dozens of mistakes as I went.

Interviews are weird: the pressure of time, and not being able to look things up, distorts the code. I am aware that the code I wrote was ugly, especially the atrocious casting of the number to a string, then to a sequence of Characters, then back to a string, and then back to an integer. But now that I am back in the real world, and able to do a Google Search, a quick search brings a top result that points me to an example by Saul Hazledine:

(map #(Character/digit % 10) (str number)))

So, in the real world, that is what I would have gone with and my code would have looked a bit better.

I guess there are engineers who stay calm in situations like this, and I assume this must be true of all the programmers who got hired at the place. I guess this is a bit like the situation in basketball, do you panic when a defender is faster and taller than you, or do you stay calm and pass the ball in an intelligent way. These tests perhaps bring out how I write code under pressure, like if its the end of the sprint and I’m working on a task that absolutely has to go out during this sprint, though hopefully such crunch-mode programming makes up less than 5% of our programming, since this is when the worst kinds of “technical debt” gets created. Or, possibly, tests like this allow them to hire those programmers who never create “technical debt” no matter how much pressure they are under — but I would be skeptical of that claim.

[UPDATE] David Tuite writes:

Expressing confusion in an interview doesn’t make you appear dumb. In reality it’s quite the opposite.

I would take that advice with a grain of salt. Some interviewers are good and some are bad. The advice is common, but it is wrong. Multiple studies show that your questions can have a subconscious effect on the person interviewing you. Even if they say “Please feel free to ask questions” if you phrase the question the wrong way, or ask a question outside the bounds of what they were expecting, it becomes a mark against you. The effect can be subconscious, but the bias will cost you a job. When you are in the presence of someone who really wants you to ask questions, that typically becomes apparent after a few minutes of talking to them, and in those cases you can feel free to ask what’s relevant — however, it is unwise to start with the assumption that the person who is interviewing you will automatically give you the benefit of the doubt — it is much wiser to start off cautiously and figure out who you are talking to, before you ask too much.

Source