Great excerpt from Jason Hong's article in this month's Communications of the
The most impressive story I have ever heard about owning your research is
from Ron Azuma's retrospective "So Long, and Thanks for the Ph.D." Azuma
tells the story of how one graduate student needed a piece of equipment for
his research, but the shipment was delayed due to a strike. The graduate
student flew out to where the hardware was, rented a truck, and drove it
back, just to get his work done.
Stories like that pluck at my heart strings. Best part of Back to Work,
Episode 1 was this, when around 19 minutes in Merlin Mann said:
I was drinking, which I don't usually do, but I was with a guy who likes to
drink, who is a friend of mine, and actually happens to be a client. And, we
were talking about what we're both really interested in and fascinated by,
which is culture. What is it that makes some environments such a petri dish
for great stuff, and what is it about that makes people wanna run away
from the petri dish stealing office supplies and peeing in someone's desk?
What is it, what makes that difference, and can you change it?
In time, I found myself moving more towards this position — as we
had more drinks — that it kind of doesn't really matter what people do,
given that ultimately you're the one who's gotta be the animus. You're the
one who's actually going to have to go ship, right?
And, my sense was — great guy — he kept moving further toward, "Yeah,
but...". "This person does this", and "that person does that", and "I need
this to do that". And I found myself saying, "Well, okay, but what?" What
are you gonna do as a result of that? Do you just give up? Do you spend all
of your time trying to fix these things that these other people are doing
And, to get to the nut of the nut; apparently — I'm told by the security
guards who removed me from the room — that it ended with me basically yelling
over and over, "What couldn't you ship?!" "What couldn't you ship?!" "What
couldn't you ship?!"
... If we really, really are honest with ourselves, there's really not that
much stuff we can't ship because of other people...
... When are you ever gonna get enough change in other people to satisfy
you? When are you ever gonna get enough of exactly how you need it to be to
make one thing?
Well, you know, that is always gonna be there. You're
always gonna find some reason to not run today. You're always gonna find
some reason to eat crap from a machine today. You're always gonna find a
reason for everything.
To quote that wonderful Renoir film, Rules of the
Game, something along the lines of, "The trouble in life is that every man
has his reasons." Everybody's got their reasons. And the thing that
separates the people who make cool stuff from the people who don't make
cool stuff is not whether they live in San Francisco. And it's not whether
they have a cool system. It's whether they made it. That's it, end of
story. Did you make it or didn't you make it?
The way I see it, you should never stop asking yourself:
What's really going to be different about tomorrow that you couldn't go make
happen today? Why isn't past inaction indicative of what's going to happen
today, or tomorrow?
What reason do you have to believe that appropriate steps to deliver on your
vision are in flight, and what would it take for you to go drive them harder.
What losses might you have to cut in order to get some thing done,
rather than a theoretically more perfect no thing. For some outcomes, it
really does take a village. I wouldn't expect anybody to single-handedly ship
the Great Pyramid.
Of course, sunk costs are powerful siren, so you have to be very careful to
evaluate whether compromises still allow you to hit the marks you care about as
true goals. But, at the end of the day, all those trade-offs roll up into one
subtly simple question:
Bryan also asked me this at NodeConf last year, where I was chatting with him about the then-in-development IonMonkey:
I remembered my talk with Bryan when I went to recruit there last year and asked the same interview question that he references — except with the pointer uninitialized so candidates would have to enumerate the possibilities — to see what evidence I could collect. My thoughts on the issue haven't really changed since that chat, so I'll just repeat them here.
Many of the people I'm really proud that my teams have hired out of undergrad are just "in love" with systems programming, just as a skilled artisan "cares" about their craft. They work on personal projects and steer their trajectory towards it somewhat independent of the curriculum.
Passion seems to be pretty key, along with follow-through, and ability to work well with others, in the people I've thumbs-up'd over the years. Of course I always want people who do well in their more systems-oriented curriculum and live in a solid part the current-ability curve, but I always have an eye out for the passionately interested ones.
So, I tend to wonder: if an org has a "can systems program" distribution among the candidates, can you predict the existence of the outliers at the career fair from the position of the fat part of that curve?
Regardless, it's obviously in systems companies' best interest to try to get the most bang per buck on recruiting trips, so you can see how Bryan's point of order is relevant.
My biased take-away from my time there
I graduated less than a decade ago, so I have my own point of reference. From my time there several years ago, I got the feeling that the mentality was:
C/C++ are horrible teaching languages, so they shouldn't really be taught in general curricula in circumstances where they can be avoided.
Java and applications-level programming is where most of the well-paying industry jobs are. (Not sure how true this is or was, but it seemed to be the conventional wisdom at the time.)
It's a Windows world. And, if it's not a Windows world, you've probably got a VM under you.
This didn't come from any kind of authority, it's just putting into words the "this is how things are done around here" understanding I had at the time. All of them seemed reasonable in context, though I didn't think I wanted to head down the path alluded by those rules of thumb. Of course these were, in the end, just rules of thumb: we still had things like a Linux farm used by some courses.
I feel that the "horrible for teaching" problem extends to other important real-world systems considerations as well: I learned MIPS and Alpha [*], presumably due to their clean RISC heritage, but golly do I ever wish I was taught more about specifics of x86 systems. And POSIX systems. [†]
Of course that kind of thing — picking a "real-world" ISA or compute platform — can be a tricky play for a curriculum: what do you do about the to-be SUN folks? Perhaps you've taught them all this x86-specific nonsense when they only care about SPARC. How many of the "there-be-dragons" lessons from x86 would cross-apply?
There's a balance between trade and fundamentals, and I feel I was often reminded that I was there to cultivate excellent fundamentals which could later be applied appropriately to the trends of industry and academia.
But seriously, it's just writing C...
For my graduating class, CS undergrad didn't really require writing C. The closest you were forced to get was translating C constructs (like loops and function calls) to MIPS and filling in blanks in existing programs. You note the bijection-looking relationship between C and assembly and can pretty much move on.
I tried to steer to hit as much interesting systems-level programming as possible. To summarize a path to learning a workable amount of systems programming in my school of yore, in hopes it will translate to something helpful existing today:
You may have read K&R, but as a newbie it makes sense to beef up on fundamentals, so CS 116: Introduction to C Programming doesn't hurt (and you meet other passionate systems programming people in the process).
CS 415: Operating Systems Practicum made you write C. Sadly, we were given a library for context switching userspace threads on top of the Win32 API in MSVC that we didn't really have to dig into. We had to write things like concurrency primitives, a scheduler, and a rudimentary filesystem that operated in terms of a soft (i.e. fake) disk model. I think there may have been some networking in there as well. The course was being revamped at the time, so I hope it's more bare-metal now with something practical like qemu.
ECE 476: Designing with Microcontrollers was an amazing class for integrating whatever you were most passionate about from CS and ECE curricula. Though at the time we were using 8-bit Atmels on a proprietary compiler that had no dynamic allocation support, you had to write both assembly and C code and talk to your system board via I/O ports. Plus, I got to be a little sneaky and use avr-gcc.
ECE 473: Optimizing Compilers targeted Alpha at the time, but was a great big systems project that taught a lot about machine specifics and code generation (interfacing to syscalls, executable and linkable formats).
ECE 575: High-Performance Microprocessor Architecture made you write real and well-performing C applications for things like cache modeling with static binary translation. This was a very formative course for me.
I did a bunch of independent projects to mess around and better understand areas where I was lacking knowledge.
I did work with systems researchers at the university. Some were unwilling to take any undergrads as a policy, but some groups are more amenable.
I'm not a good alum in failing to keep up with the goings-ons but, if I had a recommendation based on personal experience, it'd be to do stuff like that. Unfortunately, I've also been at companies where the most basic interview question is "how does a vtable actually work" or on nuances of C++ exceptions, so for some jobs you may want to take an advanced C++ class as well.
Understanding a NULL pointer deref isn't writing C
Eh, it kind of is. On my recruiting trip, if people didn't get my uninitialized pointer dereference question, I would ask them questions about MMUs if they had taken the computer organization class. Some knew how an MMU worked (of course, some more roughly than others), but didn't realize that OSes had a policy of keeping the null page mapping invalid.
So if you understand an MMU, why don't you know what's going to happen in the NULL pointer deref? Because you've never actually written a C program and screwed it up. Or your haven't written enough assembly with pointer manipulation. If you've actually written a Java program and screwed it up you might say NullPointerException, but then you remember there are no exceptions in C, so you have to quickly come up with an answer that fits and say zero.
I think another example might help to illustrate the disconnect: the difference between protected mode and user mode is well understood among people who complete an operating systems course, but the conventions associated with them (something like "tell me about init"), or what a "traditional" physical memory space actually looks like, seem to be out of scope without outside interest.
This kind of interview scenario is usually time to fluency sensitive — wrapping your head around modern C and sane manual memory management isn't trivial, so it does require some time and experience. Plus when you're working regularly with footguns, team members want a basic level of trust in coding capability. It's not that you think the person can't do the job, it's just not the right timing if you need to find somebody who can hit the ground running. Bryan also mentions this in his email.
Thankfully for those of us concerned with the placement of the fat part of the distribution, it sounds like Professor Sirer is saying it's been moving even more in the right direction in the time since I've departed. And, for the big reveal, I did find good systems candidates on my trip, and at the same time avoided freezing to death despite going soft in California all these years.
I'll round this entry off with a little brain teaser for you systems-minded folks: I contend that the following might not segfault.
I noticed that Effective Java's foreword is written by Guy Steele, so I
actually bothered to read it. Here's the bit I found particularly intriguing:
If you have ever studied a second language yourself and then tried to use
it outside the classroom, you know that there are three things you must
master: how the language is structured (grammar), how to name things you
want to talk about (vocabulary), and the customary and effective ways to
say everyday things (usage).
When programmers enter the job market, the idea that, "We have the capability
to learn any programming language," gets thrown around a lot. I now realize
that this sentiment is irrelevant in many cases, because the deciding factor in
the hiring process is more often time to fluency.
Time to fluency as a hiring factor
Let's say that there are two candidates, Fry and Laurie, interviewing for a
programming position using Haskell. [*] Fry comes off as very intelligent
during the interview process, but has only used OCaml and sounds like he
mutabled all of the stuff that would make your head explode using
monads. Laurie, on the other hand, couldn't figure out how many ping pong
balls fit into Air Force One or why manhole covers are round, [†] but is
clearly fluent in Haskell. Which one gets hired?
The answer to this question is another question: When are they required to be
pumping out production-quality code?
Even working all hours of the day, the time to fluency for a language is on the
order of weeks, independent of other scary new-workplace factors. Although
books like Effective * can get you on the right track, fluency is ultimately
attained through experience. Insofar as programming is a perpetual decision of
what to make flexible and what to hard-code, you must spend time in the hot
seat to gain necessary intuition — each language's unique characteristics
change the nature of the game.
Everybody wants to hire Fry; however, Laurie will end up with the job due to
time constraints on the part of the hiring manager. I'm pretty sure that
Joel's interview notions are over-idealized in the general case:
Anyway, software teams want to hire people with aptitude, not a particular
skill set. Any skill set that people can bring to the job will be
technologically obsolete in a couple of years, anyway, so it’s better to
hire people that are going to be able to learn any new technology rather
than people who happen to know how to make JDBC talk to a MySQL database
right this minute.
Reqs have to be filled so that the trains run on time — it's hard to let real,
here-and-now schedules slip to avoid hypothetical, three-years-later slip.
Extreme Programming as catalyst
You remember that scene from The Matrix where Neo gets all the Kung Fu
downloaded into his brain in a matter of seconds? That whole process is
nearly as awesome as code reviews.
Pair programming and code reviews:
Trick your brain into learning everything faster through mild stress and the
threat of looking noobish in your colleagues' eyes.
Give you the shoulders of language-fluent programmers to stand on as they
push you in the right direction.
Back off in accordance with your fluency acquisition.
This is totally speculative, but from my experience I'd be willing to believe
you can reduce the minimum-time-to-fluency by an order of magnitude with the
right (read: friendly and supportive) Extreme Programming environment.
What I learned: When you create interfaces for everything (instead of base
classes) it's almost less work to make a factory.
The point is that Fry has the high ground in terms of perceived aptitude. I
actually think most of the Mount Fuji questions are nearly useless in
determining aptitude, though I do enjoy them. The referenced sentence is a
poor attempt at a joke. ;-)