Aaron N. Tubbs bio photo

Aaron N. Tubbs

Dragon chaser.

Twitter Facebook Google+ LinkedIn Github

I struggle a lot with various issues when I’m involved in hiring decisions. I’ve been involved at many different levels of the process, assessing fit, knowledge, design skills, technical capability, experience, aptitude, and all sorts of other things that are pretty difficult to assess in X minutes. Sometimes I think I’m doing pretty well, getting a good read on a candidate, and balancing that correctly against the needs of the organization, all while maintaining my personal vision of what makes a good engineer. Other times I’m completely lost, and afraid I’m making the wrong choices, or that I may be synthetically encouraging/discouraging certain decisions. I have a really difficult time with hiring people that I do not think would thrive in my team (full disclosure: I run a team that could be described as having a difficult “fit”; I’m trying to ignore fit as a component in these statements, even though it’s important for final-destination hiring decisions).

Allow me to ramble for a while, and then there’s a specific topic I want to focus on at the end. I’ve been thinking about this for a few days and want to try to at least collate my thoughts.

I am not sure I would have passed an interview with myself, if I were to interview myself from two and a half years ago. I don’t think this is a bad thing. I still believe that I ask a good mix of easy and difficult questions, but I’d like to think I’m more interested in hearing what thought processes a person goes through, and what happens when they run into their limitations. Correct answers and problem solving skills are great, but knowing when to say “I don’t know” is of much greater value to me than fabrication.

That said, standards should be high. Taking a chance on people is an important thing to do, but recovering from the bad hire is a lot harder than missing the good hire. I still subscribe to the “if there is doubt there is no doubt” school. I like the romantic notion of everybody in the room being able to say “I’d work with this person” or “this person would do great on my team.” This can’t always happen, but it’s a warm fuzzy feeling when it does. I’m scared of “they wouldn’t work with my team, but maybe X could use them?” I’ve heard myths that Apple hiring decisions require everybody in the room to be thinking “I’ll quit if you hire this person” or “I’ll quit if you don’t hire this person.” I have a hard time believing this is true, but it sounds like a hell of a system.

I’m with Joel 100% on the point that anybody interviewing for a software engineering job should know C. They don’t need to have studied K&R in detail (it’s my bathroom reader right now, and I’m convinced it’s one of the best books on programming, ever), but they should know enough C to understand memory allocation and deallocation, stack versus heap, iteration, recursion, string library functions, buffers, pointers, and passing semantics. It’s hard to have a serious programming discussion without being able to talk about these things.

People should be able to write code on the fucking white board. We cover white boards with code and diagrams all the time. I get nervous when people have white boards that don’t get used for anything but lists. It’s a critical skill to be able to go up to the white board and implement some code. Here’s the strstr declaration. Implement it. Now. In C. Here’s another simple function. Implement it now, in some other language. Please tell me you know at least two languages, and you know enough syntax to solve a FizzBuzz problem in these two languages with real syntax. No, I’ve never asked anybody to implement FizzBuzz, but I have seen similar simple problems take people 15-30 minutes. These aren’t people that should be hired into a software engineering position. 90% of the crap we have to write involves solving problems at this level of difficulty. We spend a disproportionate amount of time on very small segments of code; the routine crap that composes most of the code we write shouldn’t take any time at all to write.

Sure, when pressured to write some code on the board, you will probably have some bugs, that’s ok. I write bugs virtually every time I write code in an editor. All the damn time. Then I fix them. People need to be able to write code on the board. It should be a real programming language, not a three-way composite of C#, perl, and some made up pseudocode that won’t compile in any environment, ever. If you can’t write a simple program in a real language on a white board, I really don’t want to hire you, because you don’t know how to program. I don’t want to hire people who don’t know how to program for a programming job. Yes, I know, this is insensitive of me. No, this isn’t a matter of memorizing syntax, and being perfect. It’s a basic requirement of any programming job. There’s going to be a time, some day, where I need you to hack a solution together quickly, like in five minutes, right before some critical snapshot is made, or right before some big demo, or right before we ship and we realize we have some massive bug. Or something. Prove to me right now that you’re going to be able to think on your feet and do this when I need it from you.

On the other hand, I don’t see the point in asking how many strip clubs there are in Vegas, or how to escape a burning titanium-covered concrete island surrounded by an ocean of toxic water that can dissolve people, while facing a 2 mph headwind, in a wheelchair, with flammable wheels. Back when I was making hiring decisions at the bank, I used these all the time, because they were the in thing, and Microsoft had made a big deal out of how great they are. Since then I’ve convinced myself time and time again that these problems tell me nothing about how a person will do as an employee. I think they’re fun on a white board with some coworkers shooting the shit, but in my experience they don’t provide useful feedback for evaluating a candidate, and I’ve stopped using them. I’m not convinced that being able to think outside the box is as important as being able to be more resourceful inside the box. My hunch is the average organization is already full of people that are creative and can make brilliant decisions with little to no resources or information.

People should have done stuff in their spare time and/or had past jobs. I’ve never contributed to open source, so I’m hardly a model citizen, but either open source or little projects on the side are great things to talk about. People should have made major contributions to their job/project/hobby at some point, and should be able to talk about their design process. About their bugs. The walls they ran into, and how they got past them. The projects at which they failed. No exceptions. If people don’t have this kind of experience, it boggles my mind. How can a software engineer expect to engineer software if they haven’t been engineering software for a while? Sort of a chicken and the egg thing, but I’m not entire convinced it’s the best career to learn on the job.

So, this segues into what I really wanted to talk about. Right now, I’m struggling with this internal debate: Is it more important to hire programmers or computer scientists? Is it worth hiring somebody who isn’t both? Can a programmer become a computer scientist in your organization? Can a computer scientist become a programmer in your organization?

For the sake of argument, I’ll say “Computer Scientist” means somebody with a bachelor’s or above in a computer science curriculum, who has a solid theoretical grounding, and little to no practical experience. A programmer, on the other hand, is comfortable working with, reading, and writing code. I do not believe they are mutually exclusive, so you could have somebody who is both. On the other hand, I do not believe that either term, in my usage, implies the other.

Let’s talk computer scientists first. They’re cool people. In all cases, they’ve had a lot of math, algorithms, and data structures. In some cases they may have had some things about operating systems, networking, language design, compilers, computer architecture, numerical methods, graphics, distributed systems, parallel processing, user interface (I’m probably unpopular in thinking this is a cognitive science, and not a core part of CS), security (ditto: practical, not a CS topic), and ethics (give me a fucking break). Notice there’s nothing here about programming, computers (in the modern sense, being able to use and/or service one), specific languages, technologies, platforms, or Java.

Computer science people have an eye for asymptotic behavior. They recognize isomorphisms faster than most people. They’re good at reading poorly written articles, and being able to say quickly “more or less, the author didn’t actually say anything of use to our particular problem.” Young ones have seen a lot of crazy shit in college and will try to use that crazy shit on your perfectly mundane problem. They’ve become fond of exotic solutions in a life of exotic solutions to more and more contrived problems. They’re probably over-fond of something that one of their professors was over-fond of. They’ve taken the time to understand some stuff that very few people on earth understand, in some cases not realizing (hopefully) that they’ve become intimately familiar with something they’ll never see again once they finish their exam/thesis/project. They need to be beaten down a bit, and are completely out of touch with reality. They need to learn that sometimes the exotic solution is a royal pain in the ass. Ever actually written a quick sort with fib heaps? My point exactly. Nobody talks about introsort in college, but it’s all you use once you leave, for non-radix problems. I digress. Overall, they’re smart people that know some useful stuff.

Programmers are cool people too. They know how to write code. They probably know at least a half dozen compiled languages, and at least as many interpreted languages. They know when to script a task, and when to write a program. They know when to roll something themselves, and when to steal it from somebody else. They’ve got an eye for the practical. If they’re faced with a one-time problem, they’re not going to engineer some crazy solution for it; they’re going to hack the minimum possible solution together, and ship it.

They know how to find libraries to do their task, and they know how to integrate those libraries into their project. They can use a debugger. They’re fond of text processing. They love UNIX, because it makes them feel sexy. They know how to do binary debugging when a debugger won’t find the problem. They probably understand threads, and know that they are things to be wary of. They don’t just write green fields code, and have seen (and worked on) large legacy systems. Their understanding of algorithmic complexity? Fast enough to get the job done and slow. They have a favorite text editor, and know how to use it.

Speaking of which, I don’t like to hire people that can’t type, or can’t use a good text editor. If somebody is really in love with notepad and can defend that, that’s great. But, honestly, there are some really great editors out there, and if a programmer doesn’t have a favorite, and isn’t competent in it, it tells me a) they don’t know how to find good tools or b) they don’t know how to use good tools. Red flags all around.

So, which is more important? I’m not sure. I’ve been involved in hiring computer science people, and I’ve been involved in hiring programmer people. I’ve even been involved in hiring computer science programmer people. Unsurprising, perhaps, the pure programmer people tend to hit the ground running faster than pure CS people. I think the programmer people tend to have an easier time picking up CS concepts on the job than CS people do picking up programming. Programming is a craft, and takes a lot of time and practice to get better. You either know a CS topic or you don’t; I don’t think (for most things; proofs of complexity and so forth take some practice`) practice or time on the job makes much of a difference. If the job isn’t all about research, I’m inclined by this reasoning to think the programmer is the best choice if I have to pick one. On the other hand, the naive programmer can run into performance brick walls and tricky situations where they may not have the full CS toolkit to solve the problem. At least I think that’s the theory. I haven’t really seen any good programmers get stuck in algorithmic or data structure issues; they figure it out or find somebody who knows that stuff and solve their problems.

Programmers are resourceful people. They’ve been learning how to steal, adapt, fix, and hack together stuff for years; they know how to go and get help. I often see a lot of foolish pride in CS people, and they don’t seem to want to ask for help. This strikes me as dumb.

This is starting to sound a bit biased against CS, and in favor of programmers. Obviously the best bet is to get somebody skilled in both fields, and the decision is easy. These people are exceptionally hard to find, attract, and retain, and they’re all going to work for Google right now. Figure out a way to convince them you’re the better option. Sorry, not an easy task.

Still, I think the push has to be to get somebody that has at least the core concepts of both fields. I’ll probably have to revise this over time, but here’s what comes to mind:

  • Basic data structures: Arrays, hash tables, lists, trees, maps, composites, etc. CS folks are good at drawing pictures of them, programmers are good at actually using them.
  • Basic algorithms: Sorting, searching, traversal, path finding. A lot of libraries out there for these things (programmers), but people still write their own all the time. One of the more important skills here is knowing what’s available and shaping it to your need, rather than rolling your own all the time. Same goes for data structures.
  • Complexity: Understanding basic algorithmic complexity is important. Constant, logarithmic, linear, quadratic, cubic, and slow (polynomial beyond quadratic (hey, that includes cubic), exponential, and factorial approaches belong here, but “slow” is sufficient) should at least be familiar to most people. Keep an eye out for a problem that’s not in P. CS majors are obviously the masters here, right? Wrong. Recognizing asymptotic algorithmic performance before you hit the “hey, this is taking really long” point is key. Being able to prove your algorithm is O(n**2 log log n) (hello, CS majors) is not. On the other hand, don’t focus too much on complexity, or folks start having insane notions. Ten linear passes may still be “linear” but the program is now slow. Constants matter a lot more than your education will have you believe. Mosts routine programming tasks do not involve n on the order of a million. Most times we’re not even into thousands. Two identical map lookups are a habitual no-no for a programmer, but are meaningless to a CS major.
  • Space/time trade-off: CS says that this is what it’s all about, but programmers feel this one a lot more often.
  • Heuristics: CS majors study them, programmers write them without thinking about them. Don’t get too excited about all those fancy heuristic methods for solving NP problems. Anybody that can read Wikipedia can implement a simulated annealing algorithm. You’re not special, move along. Keeping an eye out for problems, and shaping them into forms that can be solved in this way is admittedly a CS art, though.
  • Compilers, interpreters, linkers: I don’t need one written on the fly, but knowing the differences, and how to use these for various tasks isn’t really optional. Having had an epic battle with each one at some point is a rite of passage not to be missed. Finding a bug in your favorite one gets you bonus points. Being able to implement and/or leverage a mini-language is a plus. Spotting opportunities where one might make sense is also a big win.
  • Text editors: See above. I know it’s a programmer thing, but it should be an everybody thing. People need good tools to be good engineers. The text editor doesn’t make the engineer, but it makes them a hell of a lot more efficient.
  • UNIX. Yeah. Say what you will. Understanding the pure joy of cantrips, text processing, everything-is-a-file, and so forth shouldn’t be missed. We can’t all be lucky UNIX programmers when we grow up, but I think knowing UNIX makes people better Windows programmers, and so forth. That probably sounds insane. I’m not particularly sane.
  • Various other tools: Source control, bug tracking, diff tools, build systems, etc. Programmers know this stuff, CS majors don’t know that it exists.
  • Production code: Programmers learn over time how to make big systems that work, how to deal with the fact that there are always bugs, and how to write code that’s more than a few hundred lines and thrown away in three days time. This is harder skill than it seems, and most fresh CS grads don’t have the first clue about how to do it.

I’ve got to be honest; I don’t think a fresh computer science grad who is lacking in practical experience is a good fit for a software engineering job. The difference between a CS student who has been hacking for years and who just does their class projects is massive. This may be a bit odd in theory; a civil engineer isn’t (necessarily) going to be designing roads and building bridges for practice (though they can), whereas I expect a CS major to enjoy coding and spend time doing it away from their classes.

Don’t get me wrong, I’ve seen a lot of self-taught programmers or products of vocational educations that would make terrible software engineers. A lot of these folks have been writing back office data entry and reporting applications for years (I’ve seen really brilliant back office programmers before that can do some amazing things; they are exceedingly rare and prime targets for removal to a software engineering organization), and they should stay in the corporate back office. Prepare to be outsourced to India. Yeah, I went there. If your job consistently involves mindless coding and implementation of fully (and easily) specified designs, it’s time to start fearing for your job, because it is going to be taken away. Sorry.

So, anyhow, if I’m faced with a choice between a programmer and a CS major, my choice is pretty easy. I never get easy decisions like this, of course, as the decision is really “do we hire this person?” not “pick one of these.” But, generally speaking, I’ve over time come to appreciate programming skills for a software engineering job a lot more than CS education. Maybe that’s crazy.