Why Can't Programmers Program? (2007)
blog.codinghorror.com
blog.codinghorror.com
I've done a fair bit of interviewing (on both sides), and while I've seen some bad people, it seems like if 199 out of 200 candidates couldn't write code, then we'd have a lot of out of work coders, since as everyone also complains about, everyone has to write code when doing interviews.
Just because someone can't do exactly the type of program you're looking for, or in a particular way, doesn't mean they can't program. It only means they couldn't program what you asked in the way you asked. A fail for sure, but that doesn't always mean what you think.
I always like to let a candidate go to their strongest area, if that is a particular technology or problem, or bit of code they've written, because then I know I should be able to ask them deep questions (performance, design tradeoffs) that actually matter on their job, instead of fizz buzz or inverting a binary tree.
There's also just the possibility of nerves, or other factors as well. It's fun to follow people on linkedin and keep up good relations even if they're a no-hire, to see if your hunch was right, or dead wrong.
Fyi... that 199/200 quote came from J Spolsky that he got from D E Shaw.[1] That's a hedge fund and like other computational finance firms, they would look for strong programmers who had very good math skills (statistics, probabilities, etc).[2]
Therefore, the typical web programmer who knows the difference between HTML tags and CSS selectors, or knows text slicing with Python/PERL, will not pass the rigorous interviews. Using that criteria, it's very realistic that less than 0.5% of applicants would be hired.
Another way to put it: those trading firms are looking for math nerds who happen to know how to program more than programmers who happen to know some math. Including them in the general discussion about "what's wrong with hiring" will skew the discussion. Most everybody else is just looking for CRUD/web/iOS/etc programmers.
[1]https://en.wikipedia.org/wiki/D._E._Shaw_%26_Co.
[2]http://www.streetofwalls.com/finance-training-courses/quanti...
They just only want STEM Ph.D.s because it makes it easier to justify the ~2+20 fees they charge even when they have a bad year.
TL;DR: I think you mean 0.5%
Two relevant examples of this come to mind.
The first is that the author mentions recursion as a fundamental skill. While I agree, as a Python developer the vast majority of my experience with recursion is thinking "Oh, wait - I can't do that, I'll reach the stack limit". In fact I would go so far as to argue that for any language without proper tail recursion, recursion is almost certainly the wrong way to solve a problem.
The second is the oDesk Python proficiency exam. I took it on a whim a while back and failed. Many of the questions were about obscure parts of the Python standard library. I can't imagine many jobs requiring me to know how to parse email message archives without opening the docs, but apparently that's what they were looking for.
It's taught in CS courses for instance but I know a lot of software "engineers" who aren't able to come up with a solution for such problems. (Hint: It's rampant in the webdev crowd)
As a side note: Yeah I also think that recursion is really seldom needed, but sometimes it's actually your only option. For instance I wrote a Future/Promise library with support for continuation for Rust (it'd be the same for C++). Simply said: Since the Promise is a generic the actual type (and thus it's machine code) changes from type to type so you have to use virtual function calls to invoke the next promise in the continuation chain. This obviously has the disadvantage compared to dynamic languages that the chain length is limited by the stack size.
Thank you for pointing out the thing that I couldn't remember that always bothered me the times that I had to work in Python. I'm blown away by the vast amount of work being done in that language without it, thought I understand Guido's reasons...and I agree with yours about using recursion in it.
So, we changed our strategy and started using a couple of fizzbuzz like questions. The moment they walked in the door we'd hand them the test, a pencil, sit them down at a desk and say "take as long as you want". Then we'd go back to work. When they finished we'd look. If they couldn't pass the test we'd kindly show them the door. If they could then the real interview started.
I guess I don't see how any one who can truely program couldn't answer fizzbuzz or any similarly simple non-puzzle question. How simple would it have to be before you'd decide they can't do it. If you asked them to make "Hello World" in the language of their choice and they couldn't do it would you give them the benefit of the doubt or show them the door?
Also I wouldn't put inverting a binary tree at the same level of fizzbuzz. Fizzbuzz is literally 1 to 6 lines of code depending on your coding style. It's 1 step past "write a loop that counts from 1 to 100". If they can't write a simple loop and check for 2 conditions (or 3 if you think it's 3) they can't code. Really. They can't
Phone screen - maybe 3 out of 10 pass (ish), most are meh, and 1 or 2 out of 10 is terrible. Onsite - because of weeding out at the phone screen level, I think it's maybe 1 in 10 that can't program (or I question their fundamentals), and 1 in 8 that an offer is made, and most are floundering somewhere in between. Most can program but either can't solve the problem, or don't understand some key concepts in the solution.
Adding more gates to reduce the amount of time you're wasting onsite is definitely the right thing. I personally think the phone screen is pretty valuable, as annoying as they are.
To me it seems like 60% to 95% of the people employed as programmers should not be. In other words, most people cannot program, even if they are working as programmers.
:-(
I have no idea what, if anything, to do about this.
(It absolutely shocked the shit out of me the first time an interviewer asked me to write fizzbuzz. He had to convince me he was serious. Double-you tee eff, folks.)
What I do find a lot of is that people can write code just fine, but they often just do the simplest thing that they can get out the door, regardless of whether or not they're doing things the correct way.
I often find myself refactoring systems that are hard to reason about, where they put something into configuration that still requires a code change to reconfigure, or deploy scripts with internecine external dependencies (bash scripts) when the deploy platform can accomplish the same tasks.
Given enough time and guidance I find (almost) anyone can write code, but it's the architecture stuff that's hard and I think it's something a lot of programmers do not spend enough time working on.
More importantly, I have never met any one of these supposed incapable programmers. A better title might have been 'Why Can't Jeff Atwood clean up his recruiting pipeline ?'
(Or was he just stressing candidates out?)
I've literally coded a linked list once, years ago, when reviewing an algorithms book (never played in anything more advanced). I don't have a CS degree.
Am I a programmer in the eyes of these interviewsers? It feels an awful lot like the answer is "no". And "hope you never get an intense technical interview!"
What do y'all think?
Anyone who has cut their teeth on crud apps and server management should be able to figure out how to make a linked list _given specifications_. If a candidate doesn't know the terminology, it should be explained what it does and then I think it's fair to say that someone can build it. They're probably built something related/similar and never realized it. This is a great place for discussion about code! It's an opportunity more than anything.
Discounting candidates because they don't know a subset of the vast amount of knowledge we can have in this field is an _interviewer fail_. I think it says everything about the company culture and very little about the candidate.
Certainly not knowing it doesn't disqualify you from being "a real programmer" or whatever. If you never use one, then there's no shame in not knowing it. (Though it's good to learn things you haven't used because maybe there are better ways to do what you're doing.) But it's not a flaw of the interviewer to ask questions related to the work the candidate will be expected to do, either.
I'm sure I could implement one, but it'd require googling. If that ever kept me from a position, they could gladly keep it.
It's literally:
struct list_node {
struct list_node *next;
...
};
There, you know how linked lists work :)Sure, he can figure it out, but he's gonna look stupid for the first few minutes.
There are pretty simple things that will blow up in your face performance-wise even at rather modest scale if you don't know what's going on under the hood.
Do you know why you're not supposed to concate strings, especially at scale/in loops? Do you know what the N+1 performance problem is? I've seen simple webapps take out beefy servers at modest load because a dev didn't.
So yeah, we're here to serve business needs, and for that we need devs who can reason at the most basic level of abstraction about what's going on under the hood.
Modern programming generally has you approaching any obscure issues like this the same way: You profile your code, figure out where something is going horribly wrong, then try to look up answers for why. If I noticed that my string concatenation was taking an inordinate amount of time, it'd probably take me under 5 minutes to figure out why via Google alone.
Hell, I'd significantly wonder what someone was doing if they were concatenating strings enough to cause performance issues. I can't imagine any business need, for anyone, that could be brought together by that.
That said I think gp's point is that if you ask for a doubly-linked list then you basically filter by having learned programming in school or not, or iow, if you told them how it was supposed to work instead of just saying the magic name then more of them would pass.
[GCC 4.2.1 Compatible Apple LLVM 7.0.0 (clang-700.0.59.5)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> class LinkedList(object):
... def __init__(self, value):
... self.value = value
... self.next = None
... def insert(self, value):
... el = LinkedList(value)
... el.next = self
... return el
...
>>> list = LinkedList("baz")
>>> list = list.insert("bar")
>>> list = list.insert("foo")
>>> list.value
'foo'
>>> list.value.next.value
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: 'str' object has no attribute 'next'
>>> list.next.value
'bar'
>>> list.next.next.value
'baz'
>>>
I do not have a CS background (I've never taken a CS class in my life). I also think this is shitty code! Some immediate things I would talk about with the interviewer include:1) list.insert is awkward, fixing it would require the notion of a head pointer, but I didn't want to waste the memory for what is meant to be a simple example and keeping the API convenient would require the introduction of another type I think.
2) Despite having semantics that look mildly immutable on their face, it's not immutable, and probably not thread safe (I don't know Python's memory model).
3) I haven't written any tests. I don't know how to write a Python unit test, but if I did it would take about 60s to write one.
I could probably have a good conversation with them about this code a similar implementation in Golang (another language I don't know, with strict types but no generics, so the implementation would either be less general or <handwave about Go interfaces>).
Do you really think you couldn't produce this code when asked? The point I'm trying to make here is not that you're dumb, or that I'm some sort of super genius (hopefully that's obviously not true!) but that writing a linked list is truly trivial!
def cons(x, y):
return (x, y)
def car(x): return x if x == () else x[0]
def cdr(x): return x if x == () else x[1]
def append(x, y): return y if x == () else cons(car(x), append(cdr(x), y))
def rev(x, y): return y if x == () else rev(cdr(x), cons(car(x), y))
def reverse(x): return rev(x, ())
def null(x): return x == ()
def list(*tuple): if len(tuple) < 1:
return ()
else:
x = ()
for i in reversed(range(len(tuple))):
x = cons(tuple[i], x)
return x
def mapcar(fn, x): return () if x == () else cons(apply(fn, (car(x),)), mapcar(fn, cdr(x)))
---------------------->>> import sexpr
>>> print sexpr.cons(1, 2)
(1, 2)
>>> x = sexpr.list(1, 2, 3, 4)
>>> print x
(1, (2, (3, (4, ()))))
>>> print sexpr.reverse(x)
(4, (3, (2, (1, ()))))
>>> print x
(1, (2, (3, (4, ()))))
>>> print sexpr.append(x, sexpr.cdr(sexpr.reverse(x)))
(1, (2, (3, (4, (3, (2, (1, ())))))))
>>> print sexpr.mapcar(lambda y : y ∗ y, x)
(1, (4, (9, (16, ()))))
def cdr(x): return x if x == () else x[1:]
x = sexpr.list(1, 2, 3, 4)
>>> print x
(1, (2, (3, (4, ()))))
>>> print sexpr.cdr(x)
(2, (3, (4, ())))
# which is what you want.
>>> def cdr2(x): return x if x == () else x[1:]
...
>>> print cdr2(x)
((2, (3, (4, ()))),)
# which is wrong.
(car x) is the first sexp in x and (cdr x) is x without the first sexp.
(1 . (2 . (3 . NIL))) = (1 2 3)
I chose to implement lists in Python in the same way, out of () and 2-element tuples. So
(1 2 3) = (1 . (2 . (3 . NIL))) in Lisp which becomes (1, (2, (3, ())) in Python.
(cdr '(1 2 3)) = (2 3) = (2 . (3 . NIL)) which should therefore be (2, (3, ())) in Python, i.e. the second element of the 2-element tuple (1, (2, (3, ())), NOT the 1-element tuple ((2, (3, ())),) obtained by removing the first element.
I should point out that there is one difference, in case anyone else spots it: tuples in Python are immutable, whereas dotted pairs in Lisp are not, so my implementation won't allow rplaca and rplacd.
The only time I can remember implementing lists is when writing a Lisp interpreter or virtual machine. And that uses a fixed length array of cons cells, so no dynamic heap allocation is necessary.
I've been asked list-related questions at interviews several times, e.g. how to destructively reverse one, and how to tell if a list is circular. If it's just to check that I really have implemented Lisp, then they're reasonable questions, but I suspect all the candidates for the same job were asked those questions.
How much low-level knowledge does a programmer need today? There's an old-school approach to computing that starts with explaining binary, then goes on to gates, progresses to a full adder, and goes on to an entire arithmetic unit. Few people need that today.
But they probably need to know too much about CSS selectors. Statistics is becoming more necessary to programmers than binary logic. Programming today is following an endlessly churning mess of APIs.
(Today's grumble: the author of the serial port library, "pyserial", decided to change the API so that baud rate is set by "ser.baud = N" instead of "ser.setBaud(N)", breaking existing code. This isn't progress, it's faddism.)
Neither have I, but I didn't write that bloody circular queue in SPARC-V9 assembly language for nothing!
But, seriously, so many interviews are full of these sorts of questions. It's almost like they're trying to hire a reference book... or they don't know how to interview and just use the same sort of methods they were exposed to.
In over a decade of software development including web systems, games development, command line tools and distributed systems, I've never had to implement a linked list. If you haven't used the modulo operator, FizzBuzz isn't necessarily obvious.
Outside of challenges where it's almost required (FizzBuzz), the only thing that I can think of that I've ever used modulo for is to set an upper limit on random numbers. I can probably count the number of times I've needed to do that on one hand and for every one of those I've used several hundred other math functions like abs, floor & trig functions.
I don't really do a lot of math in my code anyway.
It's one of those things I see how to do in the language when I'm first learning the syntax and then move on.
I suppose you also don't often use division in your non-mathy web work. Despite that, would you think it unfair for an employer to think it reflected poorly on you if you couldn't write code to divide two numbers?
But hey, even then, those gotchas overlap with why you shouldn't store prices in floats and devs you don't want to hire do that all the time too.
Some examples...
Outputting a text report with columns. If there were 5 columns, use the "col=i%5" to put it in the correct column as "i" is incremented.
date/time calcs such as...
x%7 is often used for day-of-the-week algorithms
x%3600 and x%60 is often used for converting raw seconds (e.g. convert 86400 seconds per day into hh:mm:ss)
(If programmer doesn't know modulus "x%7", he might hardcode a big switch statement with 7 cases -- which will work, but it's not as elegant.)
round-robin in discrete integer values --> use % modulus
round-robin in continuous values --> use trig sin(), cos()
Say Hello to Leap Seconds for me.
I've used % for various unrelated tasks for more than 20 years. Another example... in languages that didn't have bit shifting like C/C++, I used % to convert bytes to a hex string (e.g. x%16).
x = Time ( now )
...
total_elapsed_time = Time ( now ) - x
print strftime ( total_elapsed_time )
I've actually used your hex example once before!For example with modulo, I feel like I use it quite often, relatively speaking. Somewhat contrived example of usage on the web side of things:
Let's say you're building a grid system that will have an unknown number of items. The grid is 12 columns wide. In the last row, any items that otherwise would be empty should instead have a placeholder item displayed.
Given an arbitrary array of items, how many additional placeholder items should be included in what gets rendered?
const colWidth = 12
const remainder = items.length % colWidth
const numPlaceholders = (remainder === 0) ? 0 : colWidth - remainderMake every nth thing shaded a different color?
Make sure a list of things has a useful amount of elements for a given task?
When I was teaching myself how to program I'm pretty sure I made some terrible pseudo implementation of modulo before I found out it was a thing because that's a naturally occurring need.
What about asking somebody to write (and compile/execute) a hello world program in a terminal window?
I've run across numerous who can't do that without an IDE. Isn't that [1] the most basic part of programming?
[1] being able to compile
You'd probably be better off giving someone the binaries for a broken hello-world and asking them to debug it.
First, I create the universe.
Boy was I surprised when I started interviewing for my second job and got asked to write code to sort a list. My first thought was "Why would you ever do that yourself! Of course I've never thought about that!" Many years later, I've filled in most of the gaps in my CS fundamentals, and I can't help but wonder if a lot of the programmers we're talking about came into it like I did.
That said, I have sympathy with those who struggle with whiteboard questions. Even for an easy problem, you have to context switch to the language and problem type then simultaneously communicate and code, without the environment and tools to which you're accustomed.
It's easy to forget some basic concept or misunderstand the question just because you're not in your element.
Edit: That being said, there's plenty of developers that can't code. But there's plenty of false negatives in interviews too.