So, at work we’re in this recruitment cycle again. This time it’s aggressive, and we’re really after the cream-of-the-cream. Those hard-to-find coding ninjas who generally don’t *ever* need to approach a recruitment agent, because of course, the second someone sniffs that they’re on the market, they’re wooed with shares and options and Wii’s and iPads and rubdowns. It’s a mad scramble.

The best way to finger these types is through someone you know who’s really good, who knows someone they worked with at some point who blew their socks off. Unfortunately the network method has failed us—sadly it looks like all talent has gone deep underground, or left the country. I’m partial to the latter because quite frankly, the quality of the meat that our corporate designated agent is passing our way has been found wanting … repeatedly.

But before I get ahead of myself—let’s approach this methodically, like we should a new project.

**Step 1: Clearly define what we require**

Enter the **Senior Developer**. As expected, this is all too subjective … a quick zoot over to SO confirms our fears and leaves us unsatisfied: *it depends*. I wish it *was* as easy as “Spanish male developer” (si señor!).

Being the “main technical peanut” using our PM’s terminology, the responsibility of defining the standard falls on my shoulders. I do subscribe to Joel Spolsky’s “smart and gets things done”, but the definition somehow falls short … it just isn’t complete.

Here’s my take on this one:

Senior Developer Quality 1: **Professionalism**

Now we all know that you can’t distil what makes a senior developer into one simple thing, but this is one of those undeniably big differentiators. Can you do a good job, consistently? If yes, then proceed to next assessment gate.

Senior Developer Quality 2: **Intelligence**

Where I come from, there seems to be this unspoken rule: “one doesn’t explicitly talk about smarts”. Because of course, smarts is one of those things that if you don’t have, no amount of experience is ever going to improve the situation. Let’s square up to this, for crying out aloud—if you want to be a senior developer you absolutely must be *smart*. Preferably, very smart.

Senior Developer Quality 3: **Passion**

Another big differentiator from the unwashed Mort-cast. You gotta wanna learn, all the time, during meals, on the can, driving to work, driving from work, on the treadmill, aside the water cooler and anywhere else you care to mention. Senior developers have technology in their veins, they live it and breathe it. Excitement isn’t derived from the promise of a ticket to the Super 14 final, but rather the appearance of a postal collection note for that 200MB/s write-rate SSD from Newegg.

Senior Developer Quality 4: **Humility**

Getting to the point of truly grokking that no matter how good you think you are, there’s always someone else out there who’s better than you are is a watershed moment. In all honesty though, no-one enjoys an arrogant git … it just isn’t conducive to greasing the cogs of the team dynamic. The more numerous the alpha-geeks in a team, the more critical the quality of humility becomes.

Senior Developer Quality 5: **Experience**

There’s a bit of cross-over here with quality 1, so let’s say that in this case we’re particularly interested in the sort of experience that gives you that technical “gut feel”. After a number of years, the neural pathways have been set up so that you can generally “smell” whether something sounds right or it doesn’t (when interacting with colleagues), and your hunch about where problems may lie tend to be more often right than wrong.

**Step 2: Screen ‘em**

When it comes to finding good people, and when you don’t have the luxury of a network-enabled direct route, it boils down to a numbers game.

Spolsky advocates the phone screen, but we’ve opted for a technical assessment. Do we really want to waste our time sitting down to chat with someone if they don’t make the bar? So to be sure, this is an effort to weed out those who think they represent our definition of Senior Developer, but who don’t.

A simple test should suffice. I drafted one this morning, and I’m going to publish one of the questions (with sample answer). Now you’ll notice that the problem posed isn’t very challenging (although some of my colleagues beg to differ), but you’d be surprised at how many people who sell themselves as senior developers who can’t do it.

My lazy side originally opted to go for one of those shrink-wrapped multiple choice online assessments ala Brainbench. I’m not going to mention the brand of assessment that is our corporate standard because I have nothing good to say about it—typographical errors, and code that wouldn’t compile in almost every single question? I wasn’t impressed either. Suffice it to say, it’s not Brainbench. Whatever the choice of assessor though, all of these tests suffer from the same problem; they tend to test stuff that we would naturally expect to Google these days. I don’t rate that as being particularly useful at all.

**Solver**, above, may seem overly mathematical and unrepresentative of typical “throw-stuff-in-a-database-and-pull-it-out-again” business requirements, but what it does do is very quickly highlight the sort of person we don’t want.

- Do we want someone who can’t understand the question because it contains “nasty unknowable symbols”? Even if you didn’t do maths at university,
*surely*you did algebra at school? That’s all you need to know. - Do we want someone who can’t do research on the Internet? Jeepers, I even provided the exact Wikipedia search. The corresponding article, predictably, contains pseudo-code for various algorithms—would you honestly need more than that?
- Do we want someone who can’t be stretched to understanding an iterative algorithm to which they haven’t previously been introduced?
- Do we want someone who doesn’t know enough to fire up the browser and
*at least*try “+”root-finding” +C#” on Google? (Yes, I*do*check the browser history afterwards :)

Of course I’m not expecting Newton’s method here, simple bisection will suffice. Even if our prospective senior has *never* attended a calculus class, I would expect her to be able to fathom this one *unassisted.*

Here’s my bisection code, written up and tested in 20 minutes—too much time, I might add, for what I would consider a senior who lives and breathes code:

class Program { static void Main(string[] args) { var lhs = (Func<double,double>) (x => x * x - 3); var rhs = (Func<double, double>)(x => x * Math.Log(x)); var diff = (Func<double,double>) (x => rhs(x) - lhs(x)); const double threshold = 1e-5; Func<double,double,double> findRoot = null; findRoot = ((l, r) => { if (Math.Abs(l-r) < threshold) return l; var mid = (r+l) / 2; return (Math.Sign(diff(l)) == Math.Sign(diff(mid))) ? findRoot(mid, r) : findRoot(l, mid); }); Console.WriteLine(Math.Round(findRoot(1,50), 2)); Console.ReadLine(); } }

Now the big problem with bisection, of course, is local minima, but that is a non-issue because I *even provide a graph* illustrating that there aren’t any local minima.

It’s time to wrap this post up, and defer description of the how testing against qualities 1 to 5 should be done to another one. Today we presented our first senior candidate with **Solver***, *but you can probably guess what the outcome was when I tell you that he couldn’t nail **Fibonacci** which was to print out the first 30 terms of the sequence of the same name.

Pingback: Weekly Link Post 132 « Rhonda Tipton’s WebLog

Pingback: Senior Developer Assessment Revisited « The Limber Lambda

zuchodrigWhat if the exact root is 2.154999 ? With given threshold of 1e-5 you can stop at 2.15501. Or at 2.15498 . The result of rounding will be different.

Eric SmithPost authorIf the exact root was 2.154999, and using a threshold of 1e-5, then the choice of stops wouldn’t be 2.15501 or 2.15498, but rather something like 2.155001 or 2.154998. I guess what you’re saying is that one *may* get a different answer, depending on choice of threshold? This is actually a good point, and for that reason, rounding isn’t a great idea. Using a different threshold sure as heck wouldn’t be grounds for penalty though. I need to change the wording to something along the lines of: “calculate to an accuracy of 1e-2 …”. Thank you for the feedback.

hk82const PRECISION = 0.001;

var x : real;

begin

x := PRECISION;

while abs (x * ln(x) – (x*x – 3)) > PRECISION do

x := x + PRECISION;

ShowMessage(Format(‘%1.2f’,[x]));

end;

// it prints 2.16, dunno, is my code good enough?

Eric SmithPost author@hk You solved the problem, didn’t you? The main thing is, you

understoodthe problem, and that’s a whole lot more than most people do. That reminds me; I need to request it be to at least 8 places :)Pingback: Desperately Seeking Senior « The Limber Lambda

Rob FulwellThanks for the article. I like your Five Qualities criteria which overlap with a lot of other useful advice I have seen on finding good people. I would say those qualities are desirable in any software developer and I agree that such folks are hard to find.

I mention the following only because you make a point of taking issue with typographical errors (although this nit is not exactly a typo, per se).

The word ‘threshold’ is one word, with one ‘h’ in it. It requires no CamelCasing.

Eric SmithPost author@Rob – :D Thanks for that … I’ll update.

AnharHello Eric, I just couldn’t resist having a quick go at this, but this is going to sound daft.

Instead of the bisection method, I opted to go for the Newton–Raphson method. Now since I’m short on time, I decided to bash it out in excel (yes I could write a program to do it, by the time my IDE loads up..) anyhow my excel routine always converges at 1.873 regardless of what initial guess value I put in. I must have done the derivate wrong!

I make it:

xn+1 = X0 – [x0*log(x0)-x0^2+3 / log(x0)-2x0+1]

I feel embarrassed and like a school dunce, I’ve left my mathematics go rusty!

Someone please correct

Eric SmithPost authorAnhar – that’s because in Excel, “log” means “log to base 10″, but the problem above uses the natural logarithm (“ln” in Excel).

Of course, Newtons method relies on one having the analytical derivative of the function to solve (but never fear, WolframAlpha to the rescue! :)

AnharMany thanks Eric!

That did the trick, the Newton–Raphson method solved it really fast. e.g when I put an initial guess of 6, it converges in 4 iterations. Naturally a better guess like 3 does it in 3 iterations.

Your right about having the derivative, thankfully apart from my Log vs Ln mistake my derivate (calculated on the back of mail envelope) was correct :)

Steve SperandeoHere’s my hideous c++ solution (I’m a php web developer by day, but thought it’d be fun to solve this with c++):

@main.cpp contents:

#include

#include

using namespace std;

/**

* Takes a double and returns and int that has been rounded to the given precision

* eg. 115.165, 2 returns 11517

*

* @return int

*/

int round( double number, int precision ){

double returned = pow( 10.0, precision );

returned *= number;

if( (returned + 0.5) >= (int(returned) + 1) ){

return int(returned + 1.0);

}else{

return int(returned);

}

}

int main(){

double x;

double y;

const double precision = 2;

const double step = pow( 10.0, precision * -1 );

for( x = 0.0; x < 1000; x += step ){

y = x * log(x) – x*x + 3;

if( round(y, precision) == 0 ){

cout << x << " " << y << " Solved" << endl;

}

}

return 1;

}

Compile in shell with g++:

$ g++ -Wall -O3 -o Solver main.cpp

$ time ./Solver

2.16 -0.00216624 Solved

real 0m0.012s

user 0m0.010s

sys 0m0.000s

Criticisms and improvements are very welcomed. Anyone know of a good place for more little problems like this? Had been eying http://www.springer.com/computer/theoretical+computer+science/foundations+of+computations/book/978-0-387-30770-1 for some time, but haven't gotten around to buying it yet.

Nice article, btw :-).

AnharHello Again, decided to implement into actual code:

here is the RootFinder Class:

public class RootFinder

{

private double _x0 = 100;

public void CalculateRoot(double Px)

{

if (Math.Round(EvaluateSolution(Px), 4) == 0) {

Console.WriteLine(string.Format(“Solution :{0}”, Px));

return;

}

object _x0 = Px – ((Px * Math.Log(Px) – Math.Pow(Px, 2) + 3) / (Math.Log(Px) – 2 * Px + 1));

Console.WriteLine(string.Format(“Xn+1 :{0}”, _x0));

CalculateRoot(_x0);

}

private double EvaluateSolution(double Px)

{

//To do: Use Maths Parser to pass evalution function as a parameter

return (Px * Math.Log(Px)) – (Px * Px) + 3;

}

}

and inside a console:

class SolverOutput

{

void Main()

{

string tmpStr;

RootFinder fx = new RootFinder();

Console.WriteLine(“Please enter an intial guess”);

tmpStr = Console.ReadLine;

if (IsNumeric(tmpStr.ToString)) {

fx.CalculateRoot(Convert.ToDouble(tmpStr));

}

Console.ReadLine();

}

}

test it out, only takes around a few iterations to solve.

SomeoneMight as well uselessly provide my Java solution:

public double solveEquation() {

// Initial Equation: x * log(x) = x * x - 3

// Which is:

// f(x) = -x ^ 2 + x * log (x) + 3

// Derivative (for Newton's appproximation):

// f'(x) = -2x + 1 + log(x)

double initialGuess = 1.1;

for (int i = 0; i < 10; i++) {

logger.debug("Current guess: " + initialGuess);

initialGuess = initialGuess -

(-1 * initialGuess * initialGuess + initialGuess * java.lang.Math.log(initialGuess) + 3) /

(-2 * initialGuess + 1 + java.lang.Math.log(initialGuess));

}

initialGuess = roundToDigit(initialGuess, 2);

logger.debug("Returning: " + initialGuess);

return initialGuess;

}

public double roundToDigit(double number, int digit) {

double power = java.lang.Math.pow(10, digit);

return java.lang.Math.round(number * power) / power;

}

cherylYou don’t expect Newton’s method?

When I was a freshman engineer at Cornell, our CS100 course required solving a problem just like this for homework.

What do you call someone who can write a program to solve for the roots of some basic equations?

(a) “Senior Developer

(b) Freshman Engineer.

SHEESH. I’m a GIRL and I could do that when I was frickin’ SEVENTEEN.

Eric SmithPost authorKnowing what I know now, pretty-much no-one who’s done the assessment so far would have managed to get this one. Only four out of around 40 candidates have managed to get the Quicksort question right.

AnharThere is a difference between knowing how to solve a problem and solving a problem.

Sure I learnt about LASER theory and built radio’s when I was only seven BUT I thats only because I had learnt to do that.

So the real question is not what you how to solve, its how you solve what you don’t know.

AnharContinued..

Another difference is ‘learnt’ vs ‘understanding’, I remember for one of my Engineering Degree examinations, I had a brain freeze and forgot all the important equations (Mathematical Modelling and Analysis of Mechanical Systems). Lucky for me I understood the topic enough to derive the equations from first principles.

Further, to add being a ‘Girl’ is logically irrelevant!

PS apologies about my grammar, English is only my third language. I only learnt to read/write English in two weeks.

Henning MakholmMy first instinct would be to simply try for all relevant N whether the sign of the difference reverses between N*0.01-0.005 and (N+1)*0.01-0.005. This was prompted directly by the “rounding not truncating” comment, which tells me that correct rounding is of particular importance for this customer.

I would avoid the standard floating-point based algorithms because they might yield a result whose uncertainty happened to straddle a x.xx5 boundary, which I’d need to correct and/or check for explicitly, complicating things beyond what a quick test of basic programming ability ought to require.

If a linear search were deemed too inefficient, I’d probably escalate to integer bisection to find the right N in N*0.01-0.005.

(No, actually my FIRST first instinct would be

10 PRINT “2.16″

given that the program takes no input anyway and I already know the correct output).

"Fish" (David B. Trout)#include

#include

void main() { printf(“2.16\n”); _getch(); }

(why waste time coding an algorithm (or cpu time executing it) to calculate a value that is already known?)

Unnamed Hackerperl -le ‘$x=0.001; while(1) { $r = $x * log($x); $l = $x**2 – 3; $d = abs($r – $l); last if $lastd and $d > $lastd; $lastd = $d; $x += 0.001; } print int($x*100 + 0.5)/100′

It took me under 60 seconds to write that, but there’s no way I could get an interview for a programming job! I’m a little saddened to hear that even incompetents can get interviews.

Related: http://www.imdb.com/title/tt0104212/

cronuscronusI think this is a pretty good question to ask. After reading your follow up post where you decided to ask a QS question, I’d say this one is actually less confusing during an interview, but that’s just me.

My last interview was a bit simpler as far as an assessment goes, but it was “closed book”. My laptop had no internet access, and no documentation. However, the problem was more similar to FizzBuzz, and another that required basic knowledge of aggregate functions in SQL. I got the job, and I’ve been surprised at the array of those who know a ton, and those who know very little.

I don’t consider myself a senior developer, at all. However, after interviewing some recent candidates, I believe I should definitely NOT consider myself a junior developer. Perhaps I have high expectations of myself. I am going to use this question for sure.

As is tradition, I’ve provided my solution in my beloved Ruby below. I would say it took me 30 minutes or so, but that included reading up on using the bisection method.

1 def root a,b

2 (1..1000000).each do |n|

3 x = ( a + b ) / 2

4 a_result = function a

5 b_result = function b

6 x_result = function x

7

8 return if solution? a, a_result

9 return if solution? b, b_result

10 return if solution? x, x_result

11

12 if ( a_result + x_result ) < a_result

13 b = x

14 else

15 a = x

16 end

17

18 end

19 end

20

21 def solution? x, result

22 if result == 0

23 puts "Found a solution at #{x.round(2)}"

24 return true

25 end

26 false

27 end

28

29 def function x

30 x * Math.log(x) – x**2 + 3

31 end

32

33 root 1.0,3.0