Rogish Reading Writing

Software, management, people.

How to Interview Programmers Part 2

In a previous post, I outlined a general strategy to interview programmers. Today, I’ll be more specific, including examples and rationales, on how to hire Ruby/Rails developers.

To keep things simple, I’ll assume you have some sort of inbound funnel that delivers developers into your pipeline. I’ll discuss in a later post how to fill that funnel.

Pre-Screen

Talk to each candidate for 30-40 minutes, outline the current state of your company, product, team, etc. – over communicate – and check for immediate deal-breakers. For example, if you require pair programming and the candidate hates it, there’s no sense in wasting your and their time interviewing if they will not be a culture fit.

If you are operating at next-level Jedi stuff, you can record a video of you explaining all of this and having candidates watch it as a form of self-screening.

In either case, over communicate! It makes no sense to hide what you do, your culture, or your process. The last thing you want is to spend time and money hiring someone only for them to find out after they start that they are not a cultural fit and they quit.

After this, send the candidate a list of questions that you want them to answer. They should be designed to get a sense of the depth and breadth of the candidate – to help discover their “T-Shape”. Clarify with candidates the goal is to not “cheat” and discover the answers and that dishonesty will only hurt them, as it’ll become evident later.

Alternately, you can schedule an additional phone screen to answer them in real-time, but I’ve often found that most candidates are trustworthy enough to save you the time.

First Phone Screen

Provided the candidate exhibits none of the deal-breakers you have (you do have your deal-breakers defined, right?) then schedule a 45-60 minute phone conversation.

I start with some small self-contained Ruby problems adapted from RubyQuiz. I provide them with a github repo that has a bunch of the problems, have them pull the repo, get rspec running (e.g. just run bundle, then rspec), then make the tests pass for as many of the ones as they can do in 45 minutes (leave 10-15 for Q&A). I do this in a screenshare. The idea is to get them to do something more complicated than FizzBuzz but not something that should take more than 15-20 minutes, so they can do a few of them.

They are somewhat complicated but you also have access to a lot of solutions, so you can study ahead of time and help guide them if necessary. Since there are so many of them, you can slowly continue to add them to your repository — and if you are so lucky to be a famous place people want to work, it’s no worry if someone happens to get a copy of your repo because there are way too many to cram ahead of time and “cheat”.

I suppose if someone could study all 100 or so RubyQuizzes and recite them all from memory, I might want to hire them just for that.

You should pick ones that are close to your problem domain or create a few of your own, featuring APIs you use, or particular problems you’ve had to solve. This should not be very difficult and you should be able to have a large library of standardized, work-related problems.

The tests should be comprehensive but incomplete, so they are forced to do TDD. A good thing to look for is if they identify the cases you haven’t covered with tests and add them. This suite will allow you to conduct post-mortems and identify which tests are most diagnostic, removing the rest, leaving you with a repeatable, scalable, representative test suite.

Most of the time you don’t need to review their code, since you were watching it, but you could have them commit and push to your repo (set them up with a fork ahead of time). You can review, and if they pass, move them forward.

Second Phone Screen

I start with an OO theory problem; design a moderate but understandable domain in plain old Ruby. They should be able to do this in 30-40 min, with some time to answer questions at the end. Review and talk through the OO problem.

The example I used to use is model a deck of cards in Ruby (using however many classes, helpers, whatever you want). Talk through it. How would you shuffle the deck? What if you didn’t have Array.shuffle? (This is a personal favorite of mine – how to randomize an array in Ruby if you don’t have shuffle). There is a giveaway answer if the candidate knows it, so have a few other hard questions up your sleeve if they did their homework.

I have never found someone who had never seen a deck of cards, so there’s no risk in a candidate going “I have no idea what a deck of cards are” and giving you a false negative.

You also could do a parking lot with cars. How do you represent the lot? How do you represent cars? Owners? Is it important to have owners?

Bonus points if you can come up with an example that is used in your line of business. You always run the risk of the candidate getting it wrong because of a lack of understanding instead of incompetence, and leading to a false-negative.

Have them commit and push the code to a repo you give them access to, so others can review. If they pass, you’ll use it in the in-person.

Again, conduct post-mortems and reviews to ensure the problems you give are diagnostic.

In-Person

In the morning, do the “Welcome to YourCompany, have some coffee”, warm them up by introducing to people, talk to the CEO, etc. Then after about 30-45 minutes, so they’re warmed up and not too jittery, have them build a Rails app from scratch (or maybe from a skeleton repo you provide with rspec, etc.) that allows the user to take that deck of cards and play War) with another player (or, whatever it is that extends your basic object lesson from the second phone screen – if it’s the parking lot, have them build the interface that the attendant would use for a multi-level parking garage).

Things to look for:

War: How do you persist the game state if you wanted to load it later? Just freeze the array? Represent a row in a table somewhere? Should you persist it at all? Is there a better way?

Parking lot: how to represent a parking garage? Different levels? How would you make it multi-tenant? Should # of levels be configurable? etc.

Continue to dig into the problem, extending it, evolving it toward some goal. Look for things that are both cultural fit designators (do they write tests first? Tests at all?), code quality, and refactoring.

Try this on your own to get a sense of how long it takes, but with both of those examples there’s clearly many hours of work there, if you want to let it go that far. You should stop around lunchtime.

Take them out to lunch. You’d be surprised the number of companies that don’t bother to give the candidate the common courtesy of buying their lunch. Some even schedule interviews through lunch, which is a certain sort of jerkitude and has to lead to false negatives.

If they passed the first half you can move them to the follow-up. If not, take them to lunch and have that be the end of it. This way, you’ve got an out so if someone is completely a no-hire there’s no need to waste the rest of the day. You can easily communicate this ahead of time and say “Let’s block out the whole day, sometimes we go that long, sometimes, not, really depends who is in the office, etc.”, so it’s not super obvious that they bombed and allows them to save face.

After lunch, pair with them on an open source lib you use and release the code back, proving you do open source, and set aside example projects similar to the phone screens. Have each developer know which project they will use and what they are looking for in the pair session.

Have them pair with everyone on the team, maybe 1-2 hrs each (depends on # of people).

This is the least objective part of the interview and you have to be very careful not to pick up false signals (positive or negative).

Send them on their way around 4p, have the team huddle at 4:05 and give them a go/no go, and have the offer (or rejection) to them by 4:30.

Post-Mortems and Retrospectives

I can’t tell you the number of places I’ve seen where they have the same script and examples from 2004, using outdated techniques and libraries. If they even have a script (most likely I see folks winging it).

After every hire (or fire), and periodically (quarterly is about right) throughout the year, conduct a post-mortem or retrospective to see what needs to change in the process. Is the suite still representative of your work environment? Did you recently tackle a hard problem that should be added?

Like any other project, if you let entropy take over it’ll win and you’ll end up with a rusty pile of code that ceases to be useful. It requires care and feeding but will pay off with consistent, repeatable, diagnostic interviews and great hires.

What’s in your interview toolkit?

Automatically Maintaining and Improving Code Quality

New software projects start the same way: clean, well-tested, and fresh in everyone’s minds. Over time, however, the knowledge fades as little-visited parts of the code aren’t touched, folks move to other projects, and new developers come on board. Test coverage drops. Mass hysteria.

Without automated, enforced quality and test coverage metrics, entropy wins and you get stuck in a vicious cycle.

We have some tools in our arsenal to help prevent code rust: we can institute code reviews, we can pair program, or folks can “lunch-n-learn” to demo code. All these are well and good, but require active effort to maintain quality. What if there were automated methods to help ensure code quality that didn’t require manual intervention?

I’m a big believer in automating all the things and code inspection is something you should strive to automate. Static code analysis allows us to enforce code standards (no spaces after parens! Two spaces, not tabs! and other holy wars), catch potential bugs or security problems, and improve code quality.

But if it’s outside of your normal day-to-day development routine you’ll forget to check it. And, like the bad old days of waterfall development, if your code gets thrown over a wall and the analysis runs long after you’ve written the code, it merely introduces more inefficiency and churn. If you integrate static code analysis into your automated testing, actual metrics prove your code is improving as you red/green/refactor.

In a Ruby/Rails project, you have several tools to help maintain code quality:

Setup

You should integrate this into your specs to run when you execute all your tests:

Rakefile
1
task default: :all_specs

and

lib/tasks/spec.rake
1
2
3
4
5
task all_specs: :environment  do
  ['rubocop -R', 'rails_best_practices', 'rspec'].each do |task|
    sh task
  end
end

Rails Best Practices

Rails Best Practices performs typical ruby checks but integrates it into a Rails environment. For example, if you have an unreachable route, it’ll report that, or report if you miss an index on a foreign key. It’s super valuable for onboarding new developers to Rails, too. Yes, they should read a Rails book, but if they inadvertently violate one of the many norms of Rails, this gem will catch it.

Rubocop

RuboCop is similar to RBP except focused on Ruby specifically. Things like spaces instead of tabs, methods and classes that are too long or complex, etc.

SimpleCov

SimpleCov allows you to lock the minimum amount of test coverage and also refuse a test coverage drop. You should define a low water line to ensure coverage does not drop below some number (90%?)

spec/spec_helper.rb
1
2
3
4
5
require 'simplecov'

SimpleCov.start 'rails'
SimpleCov.minimum_coverage 90
SimpleCov.refuse_coverage_drop

CodeClimate

CodeClimate ties these all together and has their own flavor of Ruby/Rails linters, along with JavaScript/Node.JS. CodeClimate can plug into your rspec and along with SimpleCov, report code coverage in the tool. More valuable, though, is security monitoring which reports vulnerabilities in your particular version of Ruby/Rails and when you introduce security problems in your code.

CircleCI

CircleCI is a fantastic SaaS CI provider I’ve used for a few years now. Not only are the founders super responsive, their massive parallelization functionality allows us to focus on writing code and tests and not worrying about how long they take to run.

You can combine CodeClimate and CircleCI to get test coverage reports in CC and notified of test coverage regressions in Circle.

Using all these tools, you too can have a non-trivial app that is well-tested, easy to maintain, and a joy to work with.

What tools do you use to improve the quality of your code?

30 Years of Mac

30 years ago, Steve Jobs and Apple unveiled the Macintosh. Most people have seen that video, but I bet most haven’t seen the one he filmed eight years later, demoing the latest version of his new operating system, NeXTSTEP3.0.

Fascinating to see the Mac heritage in NeXTSTEP carry through the acquisition and transformation into OS X. It’s hard to remember, but in 1992 Microsoft had just released Windows 3.1 – NeXT was light-years ahead of Microsoft.