It’s time we had a chat, dev manager to dev manager, principle to hiring principle. We know what makes good programmers. Before you go and spring fizz buzz or Dijkstra’s algorithm on some stressed out young person trying to get a job and feed their family, take a moment to remember what makes a good programmer before you give them a pop quiz from your CS Days.

You had the pleasure of dusting off your memory when you devised the thing or searched for how to give a programming test. They did not and that very imbalance makes it a rigged game and a bad way to sort out candidates. Stop doing it.

We see good programmers in action daily. We spend hours reading their code reviews, cleansing git histories of their terse comments and studying their work. We give them time to complete their tasks. That’s the important part. We give them time. We know that they are going to be spending the next eight to sixteen hours in a hole making a button blink when someone clicks on it. We know they will be sorting through 1.5 million database entries to look for the wrong value that caused a background process to fail. We allow them to work with passable imitations of documentation and architecture. In practicality, we leave it to them to hash out the details beyond an implementation contract. We have a need and we give it to them to figure out how to fulfill.

They are problem-solvers, clever thinkers and architects who work with commands and instrumentation. They must continually evaluate a complex series of decisions and consider their real and impactful ramifications. We want them to be calm, level-headed and clear minded. Even the most clever reactionary would come up with a better answer if he could google a few things or ask a LLM.

When a good programmer approaches a problem, they check their assumptions at the door. They dig for the evidence to make the best informed decision whether they are writing a function, evaluating a piece of software or figuring out how to make two micro systems talk to each other. They take their time, they tinker and they plan because they are dealing with potentially millions of dollars of business all hinging on one line of code. They are careful and diligent, neither of those things are fast. Good, fast, cheap, pick one - remember?

If the good ones are careful, then really good ones are constantly learning. Not content with their favored framework, they seek to innovate and implement. They read the open source version notes. They lurk on Ars Technica for the really obscure languages. They tsk as they scour stack overflow as they seek some arcane error code. They are always evolving.

Learning is a patient process. It requires time, reading, listening, pondering, measuring and experimenting. Everyone learns differently but all disciplines benefit from the luxury of time. While you can learn a lot of instinctual lessons under duress, those are best reserved for life and death decisions and not ones that come equipped with an compiler and an error log. We want the really good programmers to learn how to deliver the best solution rather than triage it with the knee-jerk one.

No one writes code on a clock measured in minutes. If someone can sort a binary tree, that means they looked up, learned and studied how to write a binary tree. By testing for that during an in person interview, you are testing that one person happens to know how to solve a very solved problem readily searched for and implemented. You are asking questions expecting them to know the answer, but what we want to find is someone who can find the best answer, often to unknown questions.

By all means, give your candidates a test. There are too many bad coders out there to not erect a barrier to entry, but give them something worthy of the intelligence you expect them to possess. Make it worth their while by allowing them to show off.

Give them time to impress you. Keep it simple, keep it vague and then see what they can stand up.

Of the many programming tests that I have taken, three stand out. I had as much time as a weekend and a few reasonable days could allow. Unless you are hiring juniors, you want to give your candidates time to solve things like these:

  1. Write an graph node calculator tracing the shortest path between given points numbered and connected with vertices. Basic Eulher vertices and edges stuff, as a restful API, dockerized.

  2. Write an api that looks up the weather by calling an api of your choice.

  3. Write a Tic-Tac-Toe game in react with an unbeatable AI, in React.

  4. Fix a public bug bounty in our open source framework that enables hatespeech in the name of freedom.

The usual problems that require a lot of noodling to crack. They tick all the boxes too. Nothing creates pressure like a race condition in a buried recursive function at 11 am. Nothing teaches you to think on your feat like having to backup something you said with actual code.

Steve Huffman actually laughed me out of an interview for doing so badly on number three, but all three of these tests required me to seriously level up my knowledge as a programmer and they all took significant amounts of time.

Time well spent. Time I learned something. Time, I could chuck into another bitbucket repository. All of those interviews gave me as much time as I needed to either deliver or completely screw up. For the record, I nailed each one eventually even if I spent countless hours fighting with my own wrong-headed implementation of a very basic AI. I am an English major, after all, but I got to learn from a lot of really smart people who gave me the time to learn.

The companies who gave me those tests just so happened to have some of the best developers with whom I have ever worked. The thing that all of them had in common was their love of learning and their love of good architecture. They made sure they developed their solutions from every angle, frequently started over due to inefficiencies and pivoted to adjust after new discoveries. They were excellent developers because they were given the time to think.