Codementor Events

I Just Finished a Company’s Coding Challenge, and Here’s What I Learned

Published Jun 22, 2017Last updated Dec 18, 2017
I Just Finished a Company’s Coding Challenge, and Here’s What I Learned

I was given good instructions, simple designs, and 48 hours.

Read my update here.

What is worth the time?

Yes.

This time.

The Good

If you’ve ever dismissed a job because of a coding challenge, I recommend you give it a second thought next time.

When I was presented with the challenge, I decided that, at the very least, I would get some good experience.

I thought I may even end up with something I could show off or write about.

It turned out to be a good way for me to get to know the hiring company a bit better; it gave me an understanding of what they might expect for the role and from their developers in general.

The challenge also gave me chance to try a new framework — CodeIgniter.

Most of my backend experience is with Laravel and WordPress.

I enjoyed the change.

The Not-So-Good

It took me nearly two days to complete the assignment, and that’s a big investment when you need a job in a certain amount of time.

My advice would be to only consider doing a challenge if you know you really want the job.

Fortunately, before the challenge, I was able to speak with a developer at the company and get some real insight into how they like to do things. I liked what I heard, so I chose to give it a shot.

My advice would be to do the same before investing time in a lengthy interview process. Going through all that trouble only to find out you won’t like the company would be a big let down.

If a prospective company is going to ask you to do a coding challenge, I don’t think it would be too out of line to ask to speak with one of their developers for a few minutes first.

The Challenge Begins

The challenge was to build an app to manage customers.

  • display a list of stores for a chosen country / city
  • display a list of customers at a selected store
  • create / edit / delete customers

While it didn’t look like much, I remembered how easy it is to get bogged down in details and non-essentials.

I determined to not waste time configuring the perfect build system or designing the most robust architecture.

I was going to focus on writing clean and easy-to-read code.

Time Left: 48 hours

Setup and Tools

I was given a fresh install of CodeIgniter and a database to get setup.

My instructions were to use jQuery, underscore / lodash, and Bootstrap only.

This meant no fancy JS framework me, and that was probably the most frustrating part of the whole challenge; the amount of code I had to write to do what I wanted to the UI was exhausting. I sorely missed the conveniences of a nice framework (my favorite is Vue.js).

Step 1: The Front End Workflow

Modules and ES6 are a must, so I put together a very simple Webpack setup. Nothing fancy. All it did was transpile and bundle the JS.

I then downloaded Bootstrap and jQuery and put the minified versions in my project. If I had time I would see about managing those dependencies properly, but my focus was on the big unknown — CodeIgniter.

Time Left: 47 hours

Step 2: Getting into Uncharted Waters

Getting started with CodeIgniter wasn’t too bad.

At first, I had those butterflies that always appear when I’m about to start something new. But CI is very approachable, and I was up and running pretty quickly.

I managed to find some playlists on YouTube that got me acclimated to how CI likes to do things. In about 20 minutes I had some basic routes set up, and had a working understanding of configuration, models and controllers.

Time Left: 46 hours

Step 3: How to load my JS modules?

Not having the convenience of a front end router, I decided to try another approach to loading my modules on their proper pages.

This is what I came up with:

import main from './assets/main'
import stores from './assets/stores'
import customers from './assets/customers'
$( document ).ready(function() {
const page_id = document
                    .getElementById('page_id')
                    .getAttribute('data-module')
const modules = {
        home : main,
        about : main,
        stores_index : stores,
        store_customers : customers
    }
modules[page_id] ? modules[page_id].run() : false
});

I had the CI Controller inject a unique identifier on each view file loaded.

On ‘ready’ I would grab the id from the page and load the appropriate module.
This worked rather well.

I had a stores module to handle the main store listing page, and then a customers module to handle the manage customers page.

Time Left: 45 hours

Step 4: Reviewing the Requirements

Now that I had a decent foundation laid, I needed to focus on understanding the app and how I was going to put it together.

Kudos to the company for giving some pretty clear instructions. I was even allowed some creative freedom provided I met all minimum requirements for functionality.

  • display a list of stores for a chosen country / city
  • display a list of customers at a selected store
  • create / edit / delete customers

I grabbed a piece of paper and started sketching out ideas.

I learned long ago that one should spend a generous amount of time thinking through a feature before writing any code. Proper planning will save you many hours of unnecessary refactoring.

Time Left: 44 hours

Step 5: REST API with CodeIgniter

This is easily where most of my time went.

I got tripped up on the following:

  • CI Query Builder (I really missed Eloquent — Laravel’s ORM)
  • Returning a proper response with status, data and message.
  • Accessing the payload on a PUT / PATCH request.

Like some, I am guilty of getting comfortable with certain tools without ever rolling something myself to understand what happens under the hood. I am looking forward to grabbing some time to properly understand why I was having such difficulty accomplishing this with CI.

In the end, I figured out how to do all the above with the tools I was given.
Maybe some devs more familiar with CI could take a look at what I came up with as the model for listing customers:

public function list($store_id) {
$results = $this->db
                   ->from('customer')
                   ->where('customer.store_id', $store_id)
                   ->join('rental', 'rental.customer_id = customer.customer_id', 'left')
                   ->join('inventory', 'inventory.inventory_id = rental.inventory_id', 'left')
                   ->join('film_text', 'film_text.film_id = inventory.film_id', 'left')
                   ->select('customer.customer_id, customer.first_name, customer.last_name, inventory.inventory_id, inventory.film_id, customer.create_date, customer.last_update, customer.active, rental.return_date, rental.rental_date, customer.email, customer.address_id, film_text.title, film_text.description')
                   ->get()
                   ->result_array();
// rental details grouped by customer_id
$customers = group_by($results, 'customer_id');
$customer_list = array_map(function ($customerData) {
    $rentals = array_filter($customerData, function ($data) {
        return !empty($data['film_id']);
    });
    // alpha sort
    usort($rentals, function ($a, $b) {
        return strcmp($a["title"], $b["title"]);
    });
    $rental_count = count($rentals);
    $customer = [
        'active'           => $customerData[0]['active'],
        'create_date'      => $customerData[0]['create_date'],
        'last_update'      => $customerData[0]['last_update'],
        'rental_date'      => $customerData[0]['rental_date'],
        'return_date'      => $customerData[0]['return_date'],
        'address_id'       => $customerData[0]['address_id'],
        'email'            => $customerData[0]['email'],
        'customer_id'      => $customerData[0]['customer_id'],
        'first_name'       => $customerData[0]['first_name'],
        'last_name'        => $customerData[0]['last_name'],
        'rentals'          => $rentals,
        'rental_count'     => $rental_count,
    ];
    return $customer;
}, $customers);
$customer_list = array_values($customer_list);
usort($customer_list, function ($a, $b) {
    return strcmp($a["last_name"], $b["last_name"]);
});
return !empty($results)
    ?   [
            'status' => 200,
            'message' => 'Success',
            'data' => $customer_list
        ]
    :   [
            'status' => 204,
            'message' => "There aren't any customers at this location.",
            'data' => []
        ];
}

and I found this little helper for formatting my json response:

function json_output($response) {
    $ci =& get_instance();
    $ci->output->set_content_type('application/json');
    $ci->output->set_status_header($response['status']);
    $ci->output->set_output(json_encode($response));
}

Time Left: 40 hours

Life, Rest & Sleep

Step 6: Building a Smooth UI sans Framework

Time Left: 24 hours

After I got a better grip on setting up API endpoints, I was finally ready to focus more on the UI.

This was comfortable and familiar territory, and I was excited to produce something slick.

I tried to avoid obsessing too much over names and css class organization, and just got to work.

Here are some snapshots of the code:

1.PNG

2.PNG

3.PNG

4.PNG

All this work just to update UI on the fly made me appreciate just how good we have it with frameworks like Vue, React and even Angular.

Some key features:

  • first and last names were required to add / edit a customer. The specs called for a warning on submission if either was missing, but I instead opted to just disable the save button until both inputs were filled out.
  • I added some error and success messaging after most operations.
  • I used Bootstrap modals for add, edit and deletion of customer data.

I’m not a designer, so I was happy to have Bootstrap.

Have a look:

5.PNG

6.PNG

7.PNG

8.PNG

9.PNG

After lots of work and some sleep…

Time Left: 0 hours

Would I do this again?

Yes.

While this simple CRUD app barely scratches the surface of what makes a competent developer, it gave me a clear path to demonstrating some of what I can do.
I wouldn’t want to do this for every job I apply for, but I think it was a good use of my time.


Found this interesting / helpful?

If this short post has helped you in any way, please remember to give this a recommendation below and post a brief comment to support me.

Comments, questions and constructive feedback are always welcome.

My name is Patrick O’Dacre, and I am a software developer that loves building great things with great people.

I have had the pleasure of creating ground-breaking e-commerce order systems, beautiful sales dashboards, and complex data grids with some incredibly talented people that made sure work never felt like work.

Some of my favorite tools include Vue.js, React.js, Node.js and Laravel, and I’m always excited to learn new things.

I am currently available for new opportunities, so don’t hesitate to get in touch.

Discover and read more posts from Patrick O'Dacre
get started
post commentsBe the first to share your opinion
Nicolas Bonnici
7 years ago

I prefer a more generic CRUD approach dealing with entities of any type tightly coupled with a generic REST API.

bob k
7 years ago

Patrick - thanks for taking the time to write the process of the coding challenge you experienced. From a neophytes perspective, I enjoyed reading through the code to see if I can follow the logic, along with taking notes so I can go back and lookup what functions, commands and proper structure purposes are.
For me, being able to get an insight into what and how (under the hood) and actually understanding parts of it just encourages me to keep learning.
Thanks again!

Patrick O'Dacre
7 years ago

Thanks, Bob!

It was my hope that some would get something out of seeing how I got through the challenge. These little looks behind the curtain were great for me when I was getting started, too.

I’ll have to put the project up on github.

Donald Oktrova
7 years ago

I don’t think that’s a good practice for hiring. We as developers should stop giving our time for free to this challenges so they change their hiring practices. I have done a few in the past and have always gotten the job so my issue it’s not that i’m not good at them rather is that they waste my time. In 48 hours you could have had a few sessions and made a few hundred. Or you could have worked on building an app for yourself that would have been more challenging and exiting solving a real problem. I no longer consider jobs that have “homework assignment” unless compensated or a short exercises in front of the managers that way we are both investing time. If they want to see how i code they can check my GitHub or i can provide them something from my portfolio or even my past exercises. Maybe as a junior it is fine but once you have had a few years and jobs it is unacceptable.

Patrick O'Dacre
7 years ago

Thanks for sharing your experience.

I will be investing a lot more time in pruning my Github profile, and now that I’ve had a bit more time on the market, I’m seeing that I can afford to be a bit choosey; there’s definitely no shortage of work out there.

Laszlo Marai
7 years ago

Absolutely. The problem with coding challenges, especially with entry challenges is that they are free for the employer. Which means that they can throw it at people without thinking twice (too junior, too senior, not really our stack, we don’t really like his linkedin profile anyway, etc.) Also, before the candidate knows too much about the company. That’s why I liked Patrick’s advice: try to talk to people from the company. You can actually use it as a kickback as well. Tell them that you’d prefer to talk to someone first, so that you get to know each other. Should be a good signal for a good company (the guy is interested in us, they are actually picky and don’t just want to be hired).

A few hour test after an initial call, or even better, a pair programming session OTOH definitely makes sense.

Show more replies