This post took days to write. I didn’t expect it to take quite so long, but I think the fact that it took so long hits right at the core of hiring developers: It’s hard.
It’s no secret that finding great developers is hard [0, 1, …, n]. Innumerable methods exists for weeding out the bad candidates from the good, and everyone has an opinion about what works and what doesn’t, including me.
Hiring developers is an attempt to mesh the science of programming with creative problem solving and a whole lot of wisdom. It’s an attempt to combine the technical needs of your project with the candidate’s experience, desires and humanity. Finally, it’s a coordination of all other internal and external factors including resource management, benefits and pay, work environment, team personalities, etc.
What follows is an outline of my process for finding great developers.
I enjoy conducting interviews. It’s challenging, you engage with many different types of people with various degrees of experience and knowledge.
It’s great fun.
But you need a plan. It’s a highly structured activity. I like to open my interviews with a brief discussion of the open position, why we’re looking for a developer, what we’re doing within the organization, and how the organization fits within the larger ecosystem of the company. I like to encourage the candidate to ask questions about our business and technologies, and it’s always a positive sign when they ask pointed questions about one or more aspects of any of the aforementioned statements.
I then ask the candidate to tell me a little about their work history. Some candidates can’t articulate their work history at all, and this is an immediate red flag, while others recall very specific details about positions they’ve held two decades ago (not necessarily a good thing). While they’re speaking, I’m listening for specific personality traits: Their ability to tell a story, how well they worked as a member of a team, what technologies they touched, etc. I’ll ask questions about their experience and give them the opportunity to dig a little deeper into their past development activities.
This bantering is part of a much larger soft-skills assessment. Can they communicate? Are they pleasant? How will their personality mesh with the other developers?
Have I sensed any personality red flags? I once had a candidate become agitated and almost aggressive toward me on the phone, simply because I disagreed with one of his statements. Not a good sign.
At this point, the interview shifts into a brief goals and ambition discussion. Where are they today, where do they want to go in the future, how are they going to get there and how do they adapt to change in technology? You may be surprised to find that many people don’t have any goals at all. If they do, they don’t know how to communicate their ambitions. I appreciate the candidate that has a specific plan for professional growth.
Once we wrap up the introductory aspect of the interview, I shift into a technical assessment. I present between ten to twenty highly technical questions touching on various development activities and practices. I’m trying to ascertain whether or not the candidate possesses both depth and breadth. It’s a form of adaptive skills testing, where I dig deeper depending on the candidate’s answer. It might go something like this:
Me: What’s a delegate?
Them: It’s a type-safe function pointer.
Me: How might you use a delegate?
Them: As a callback method, maybe… Or to abstract specific pieces of an algorithm.
Me: Let’s talk about that, how would you implement such an abstraction?
Them: Well, perhaps I’d use a delegate to pass different sort methods to a function depending on performance characteristics.
… and so on. If, in the above case, the candidate couldn’t give me a deep discussion on delegates, I’d simply move on to the next topic. Generally speaking, everyone has their specialty. A candidate weak in delegates may be strong in another area. I try to find both their strengths and weaknesses.
Once the technical discussion has come to a natural close, I give the candidate the opportunity to ask questions about the open position, the team, the company, the pipeline of potential projects, etc. Often, candidates express concerns about the interview or their ability to succeed in the company. A few ask about growth and long-term potential. These are all excellent points of discussion.
A Point About Breaks
Note that I have many natural breaks and transitions built-in to the structure of my interview process. It’s often easy to notice a struggling candidate, and these natural breaks allow space for the interviewer to cut the interview short without sounding obvious. There’s no point in continuing an interview with a weak candidate. However, there’s also no point in making a candidate feel even worse or more stressed about their performance.
Being nice goes a long way, and it goes for both sides of the interview process. I’ve had several candidates politely cut the interview short, expressing either an inability to perform the discussed tasks or a desire to pursue a different direction in technology. I sincerely respect such candidates.
Working With Legacy Code
Candidates that exceed my expectations on the phone are brought in for one or more in-person interviews. This gives both the candidate and the team the opportunity to meet with potential coworkers and for candidates to tour the workplace, ask additional questions about the position and for the technical team to dive even deeper into the technical aspects of the job.
I would prefer to conduct a completely remote technical interview, however due to requests from my manager, I’m required to bring candidates into the office at least once. For now.
For these candidates, I vary the format quite dramatically. I may interview the candidate first before introducing them to additional members of the team, or vice versa. I may interview them individually. I may not meet with them at all. It all depends on the candidate, the availability of my team members, time allotment, etc.
I prefer that my team get to meet with the candidate, however. Different teams members ask different questions with varying goals: Some probe deep into a specific technologies while others are concerned only with soft skills. It’s always an interesting exercise to see how my coworkers respond to a particular candidate.
For my portion of the interview, I present code. I typically present two functions, one function representing code that is literal garbage – really, really awful code – while the other function is representative of the code we produce as a team.
I want to see how well the candidate works with legacy code.
The Bad Code Example
For the Bad Code example, I ask the candidate to tell me everything that they can find wrong with the code, where “wrong” is intentionally ambiguous. Different people approach the question of “wrong” with varying degrees of kindness: Some people are honest to goodness afraid to point out an issue! And they apologize for doing so! It’s odd. They’ll say something like, “I’m sorry, but I think there’s a bug on line 10.” Conversely, other developers are excited to critique a piece of code, and they’ll tear it apart line-by-line. Ultimately, though, I’m looking for their ability to read and analyze code that they’ve never seen.
Most people become fixated on small syntactic issues: They pick out inconsistent variable names, constants, function names, lack of comments, a missing comparison, etc. Some look bigger, and point out issues with exception handling and method structure. Nobody, however, has yet to notice that the function always and forever returns true, no matter what! Which means it’s effectively a dead function: It might as well be replaced with the constant value
true. To be fair, I doubt I would notice this aspect of the code, either… and I begrudgingly wrote it!
This isn’t a scored examination: I’m not marking off points during this exercise. It’s simply an exchange, and I want candidates to walk me through the reading: You’re right, there’s not a standard naming convention. Yes, the defined constant value isn’t used. Yes, the exception handling is broken, how would you fix it? This typically evolves into a much larger software discussion about good coding practices, code reviews, and other such methodologies.
The Good Code Example
For the Good Code example, I present a method that’s slightly modified from some chunk of code we actually have running in production. It’s not the greatest code ever written and it definitely has that “under the gun” quality about it, but it functions and it functions well. Is it elegant? Absolutely not.
Typically, this example might be a web service call, or some block of code that requires an external dependency. It’s verbose, maybe 35 lines long or so.
Here, I’m not looking for nit-picky details. I’m looking for the candidate to read and understand actual, honest to goodness legacy code. Do they recognize the procedural aspect of the code? Do they recognize discrete aspects of the code that may be broken out and refactored into other methods or classes? How can they add (or should they add) resiliency characteristics to the code, and if so, where would they add it and how? How can they effectively implement unit and integration tests?
I’ll bring up aspects of writing software within a large enterprise: How can this code be isolated from its external dependency? How would they implement loose coupling? I encourage the candidate to walk me through a mental design, and I try to poke holes in their design just to see how they’ll react and adapt to a constant stream of change.
The Human Factor
All of this examination of code and back and forth dialog isn’t an attempt to see how clever the candidate may be. Some candidates are, in fact, much more clever than others, and it becomes obvious almost from the moment we sit down just how clever they are.
But there’s a much more important aspect of the candidate that I’m looking for. That is, how well can my team and I actually work with this person?
Some of the brightest developers I’ve ever worked with are terrible people and I say that as kindly as possible. Concerning their personality, they’re rude or arrogant beyond belief, but they’re absolute geniuses when it comes to code.
I don’t know about you, but I can’t work with people like that all day every day. Maybe you can, but I can’t. Soft-skills trump raw code skill any day, as long as the candidate with the great personality has the ability to adapt and learn!
Your mileage may vary, of course.
The final aspect to consider is business need. What are you looking for and why? You may not always arrive at the correct conclusion. As a recent example, my manager wanted to find an individual that could assist our development team with certain aspects of enterprise integration. I interviewed potential candidates for months, only to discover that not only could we not find such a candidate, but that we really didn’t need such a candidate to begin with.
We really needed another developer, so we went back and started the whole process over.
An honest assessment of business need is critical when finding the right person. At the end of the day, a developer with Square Peg skills isn’t going to be interested in working on your Round Hole project. Really think about your organization and its need and make absolutely sure you’re hiring the right candidate for the job.
It’s not always obvious.
This ended up being a much more verbose post than I anticipated. Interviewing is hard. I submit that conducting interviews is much more difficult. Targeting the right mix of personality, skill and need is tough, and there’s really no perfect formula for hiring the perfect developer. My method isn’t foolproof, but it’s been working so far.
I’m always looking for ways to improve the interview process and I welcome suggestions and ideas.
And now that I’ve published my interview process, I’ll need to change it.
Or maybe I already have.