xteam-review

Review: X-Team developer hiring process (hint: it sucks)

Continuing on the theme of how job hunting sucks, here’s another example of exactly what I’m talking about: X-Team International.

No, I’d never heard of them before either.

I found X Team through this job posting on Authentic Jobs.  It sounded like a good fit, so I applied, including a brief message why I thought I’d be a good fit.  Like you do.

Step 1 – Interview via two weeks of emails back and forth

I got an automated acknowledgement email immediately, and a real human email about an hour later.  The guy introduced himself as an “Ambassador from X-Team”, thanked me for my application, then asked:

If you have a quick second, what web/mobile technology are you working with that interest you the most right now? Thanks again for signing up, I’m looking forward to chatting more.

That was it.  I was of the impression he hadn’t actually read my application, but they probably get tons of ’em anyway, so who can blame them.  I replied nicely.

It turned into a series of emails back and forth between me and Mr. Ambassador, where he would ask interview-type questions and each time I replied in kind.  After each of my replies, a day or two later (they were obviously in no hurry) Mr. Ambassador would respond with glowing praise:

Thanks for getting back to me!  Very very impressive work!  Kudos on that :)

Honestly probably one of the best responses I’ve received for these questions :)

At no point in the entire process did I ever actually talk to anyone — over the phone, Skype, or otherwise.  It’s the first job I’ve ever applied to that, apparently, has a 100% email interview process (although they never explained that up front, it just worked out the way in the end).

I did, however, notice their weekly email newsletter started showing up in my inbox only 2 days after I applied.  That was kind of annoying — the newsletter came faster than the replies from Mr. Ambassador, which is all I really cared about.

Step 2 – Coding Test

Finally, I was introduced (by email) to their CTO, who sent me the coding test, which turned out to be a “mock code review”.  They sent me a dummy php file which I would review, comment the issues, and return back to them. If you know a little PHP read on, otherwise skip ahead to Step 3…

example.php:

<?php

/**
 * Social network site where you can see a list of users and "follow" them.
 */

// setup the `Db` object:
require_once 'lib/db.php';

// setup the `Session` object:
require_once 'lib/session.php';

if (!Session::isLoggedIn()) {
 throw new Exception('You must be logged in to view this page');
}

// display a user as html
function displayUser ($user, $tag='div') {
 $full_name = $user->first_name . ' ' . $user->last_name;

 // get user's avatar from 3rd-party avatar service, based on which environment we're running in
 if (strpos($_SERVER['SERVER_NAME'], 'localhost') !== false) {
 $avatar_data = json_decode(file_get_contents('http://dev.avatars.com/user/' . $user->id));
 }
 else {
 $avatar_data = json_decode(file_get_contents('http://www.avatars.com/user/' . $user->id));
 }

?>
 <<?= $tag ?> class="user">
 <a href="/users/<?= $user->id ?>">
 <img src="<?= $avatar_data->url ?>">
 <?= $full_name ?>
 </a>
 <a href="?follow=<?= $user->id ?>">Follow</a>
 </<?= $tag ?>>
<?php
}

// check that a user ID is valid
function validateUserId ($id) {
 if (!is_numeric($id)) {
 // log invalid user IDs to help us track down bugs.
 error_log("Invalid user id: {$id}");
 return false;
 }

 return true;
}

// load the user's custom theme config
$theme_filename = dirname(__FILE__) . 'themes/' . Session::getLoggedInUser()->theme_id . '.php';
if (file_exists($theme_filename)) {
 require $theme_filename;
}

// show all users
if (isset($_GET['show-all'])) {
 echo '<ul>';
 foreach (Db::getUsers() as $user) {
 displayUser($user, 'li');
 }
 echo '</ul>';
}
// show a single user
else if (isset($_GET['id'])) {
 $id = $_GET['id'];
 validateUserId($id) or throw new Exception('Please select a valid user ID');
 $user = Db::getUserById($id);
 if (!$user) throw new Exception('Sorry, user not found');

 displayUser($user);
}
// follow a user
else if (isset($_GET['follow']) {
 $id = $_GET['follow'];
 validateUserId($id) or throw new Exception('Please select a valid user ID');
 $user_to_follow = Db::getUserById($id);
 if (!$user_to_follow) throw new Exception('Sorry, user not found');

 $current_user = Session::getLoggedInUser();
 try {
 $current_user->follow($user_to_follow);
 } catch (Exception $e) {
 throw new Exception('Unable to follow at this time');
 }

 // inform the user that they have a new follower.
 mail(
 $user_to_follow->email,
 'You have a new follower!',
 "{$current_user->username} is now following you.",
 'From: notifications@awesome-social-network.com'
 );

 // also update the activity feed, so users can see what others are doing on the site.
 Db::updateActivityFeed(array(
 'action' => 'follow',
 'from' => $current_user->id,
 'to' => $user_to_follow->id,
 'timestamp' => time(),
 ));

 echo 'Followed! <a href="/">Return to home</a>';
}

?>

The first thing you’ll notice is the file requires two outside files, lib/db.php and lib/session.php, neither of which are provided. The instructions I was given acknowledge this and say to “pretend they exist”. Actually it would be important to see those files, because it could have a big impact on things later on.

For example, look at line 67. Here we have a query string variable from the client side (read: not safe) populated into the variable $id. Next $id is run through a function called validateUserId() which only checks $id using PHP’s is_numeric(), which isn’t a great idea. Then $id is sent off to the Db object, presumably defined in lib/db.php, which we don’t have access to. Is it interacting with the database using mysqli or PDO (good), or is it sending $id raw in a mysql_query() call (terrible)? We don’t know, and it’s kind of a big deal.

Well, anyway, I pointed out these things along with several other issues in my “code review”. In total I ended up wasting about 3 hours going through this silly code with a fine toothed comb — far more time than I should have — just to make sure I identified every possible issue.  Feeling confident I had done so, I sent back the code with my comments (a lot of them) and waited.

Step 3 – Douchey rejection email

Five days go by, then I get this:

Hi *****, thanks for completing the exam and for your patience while we got through all of the reviews.

For this position we have the bar set very high, and unfortunately you haven’t placed among the top candidates.

Thanks so much for your time and I wish you the best of luck in future.

Huh?

“Ouch”, I said to myself as soon as I read that. What’s their basis for saying I’m not a top candidate? I have 15 years of experience in PHP after all, so I do have *some* idea what I’m doing.  If they disagree, I’d love to have known what they thought I’d missed, or how I could have done better in their eyes.

But instead of that, they just insult me without any explanation?  Really?  Mr. Ambassador tried to build me up with praise at every turn, telling me my answers are  some of the “best responses” he’s ever received…. and then they want to tear me down and tell me I’m not “among the top candidates”, just like that?

I’ve hired and fired people over the years, so I know it’s tough.  I also know these things should be handled with a little tact.  A better rejection letter would have been something like “Dear ****, Thank you for applying and taking our exam.  I’m sorry to say we’ve decided to go with another candidate.  We had several strong applications, including yours, but unfortunately only one job opening and we had to make a tough decision.  Sorry again, but thank you for considering us.  I will gladly keep you in mind if any other positions open up in the near future.”

Even if none if it is true, that’s JUST WHAT YOU SAY.

Unless you’re a douchebag.

Or young and inexperienced with these kinds of things.

Or both.

Epilogue: Step 4 – Land a better job anyway

All during this time I was progressing through the hiring process for Toptal, which is just plain hard.  Toptal makes a big deal about their rigorous hiring process, and the fact that they only hire the top 3% of developers.

Two days after the douchey rejection from X-Team, I got this message from Toptal:

Welcome to Toptal!

X-Team said they “set the bar very high”.  I guess the top 3% isn’t high enough.

All X-Team ever did to assess my skills was one silly “mock code review”.  Toptal, on the other hand, really put me through my paces.  It was seriously the most difficult hiring process I’ve ever gone through for a programming job.  I definitely had to earn my spot in the top 3%.

Read more about my Toptal experience here.

11 thoughts on “Review: X-Team developer hiring process (hint: it sucks)”

  1. I applied and got the same canned question about what technology interests me the most right now. I mentioned React + Redux but made it clear I’m more interested in creating great user experiences than using any particular technology. They then rejected me by saying they only hire people they’d want to have a beer with at a hack-a-thon. Fuck you too, bro!

  2. @Chris I got exactly the same answer, after exchanging a couple of emails with them. What a waste of time and what a disrespectful way to answer to anyone.

  3. I saw an front end dev position ad in the Frontend focus newsletter so I thought I followed the link and tried out one of their coding test. It turned out to be a Nodejs backend test without any docs/specs to outline what is to be done. It looks like they are looking for a JS full stack developer. I wonder if this is a joke.

  4. Glad to see this, in a way. I was going back and forth with them answering absurd questions in emails when I finally said to myself… this is crap. Its completely one sided and artificial.

    I honestly think they may not be hiring at all but are just gathering data for something.

    “xteam xcrement”

  5. They are also incredibly poor compensators. A true senior developer should never charge less than $100/hour, especially given the value provided. X-Team’s rates are more in the $40-50/hour range – on a full-time schedule this would equate to about $95K a year. And this is without benefits or other in-office perks. Given the profit-making nature of their clientele, such a low rate is an insult. So I question how “great” their developers really are to begin with.

  6. This is an old post, and I don’t work for x-team, but… I am developer so… Here’s my two cents to balance things a bit…

    [rant]First, sorry mate but I’d rather have a blunt answer that I can use and understand than some soft worded answer intended to make me feel better. Maybe that’s just me. If nothing else they were honest with you. I’ve worked in a place where I was told comforting things and then had my own job plotted away from me by management that ended up resenting…something (they never quite were clear what) and then after exemplary performance fired me without even giving me a reason (and you can bet I asked). So, for me, I’ll always take straightforward dealings over the PC don’t hurt anyone’s feelings “professional” HR don’t want anyone sueing us model of today. If someone, personally, thinks I’m not up to their standards, I would actually LOVE that they tell me! If it’s actually the case that I was up to your standards but you actually had too many candidates, tell me that! Both answers give me something to gain from the experience. So I just can’t sympathize with you on that. There’s always someone better no matter how amazing we are, even if it’s our own future self. Least that’s how I see it.[/rant]

    Second, and far more pertinent, there are issues with that code that are far more architectural and really your post doesn’t indicate any were addressed… (and you never updated it so sorry it’s fair game)

    For a very simple example, your post was done in 2015. Composer has existed since 2012 I believe? Plus PHP5 (released around 2005) has had autoloading. So those require calls are at least a code smell, especially because they just load class files of the same name.

    displayUser is obviously an intentionally designed bad function. It mixes so many concerns and is pretty damn difficult to test right which is itself a code smell.

    You wouldn’t want to use PDO directly unless you had a damn good reason: ORMs exist for a reason. That you didn’t distinguish between PDO (database agnostic) and mysqli doesn’t bode well either.

    And just…a lot more… Not to be mean but come on… At least consider the Cardinal Doctrines of the Faith: Be SOLID, get DRY. Code should be written to be tested, self explanatory, do one thing and do it well. Generally not mix concerns. They gave you bad code and expected it to be trash talked like the fester of code smells (being slightly hyperbolic but still) that it was. At least that’s my opinion.

    I’ll get off my Dev soapbox now….

    1. I agree I would also rather have a blunt answer that I can use. But that’s not what I got from X-team.

      The initial replies from their recruiter guy were all flowery PC stuff (from which I was already thinking “yeah yeah yeah, whatever” in the back of my mind). What was surprising to me was how they went all of sudden from flowery PC to ice cold rejection. I’m fine with being rejected, but the rejection email definitely didn’t give me any information I could use. If they had said “you don’t meet our standard because you didn’t mention X, Y, and Z”, that would have been different. But as it is, I don’t know if they even read my code review at all!

      Sadly I can’t find what I originally submitted now, I wish I still had it. I just remember it was long.

      One quick note to defend my mention of PDO/mysqli a little bit. The point was just to show there could be potential SQL injection issues, which would be pretty terrible. If this code was part of a framework with an ORM that’s fine, but that information wasn’t given to us. So I can’t make assumptions about what framework they *might* be using. Since they gave zero background info or context, and nothing in the code itself points to any particular framework (at least that I know of), I have to stick with core PHP (hence PDO/mysqli). If they want a different kind of code review, they need to say so.

Leave a Reply

Your email address will not be published. Required fields are marked *