A SIMPLE INTERVIEW PROGRAMMING PROJECT FOR LARAVEL DEVELOPERS

August 11th, 2019 by Kevin Pimentel

I’ve started to see the importance of giving new developers an interview project. It helps me to understand the type of programmer that they are. I get more information by leaving the instructions somewhat open ended and vague. I want to see what assumptions they make, if they add a bunch of things I didn’t ask for, or if they keep it simple.


Many questions can be answered from a project. Do they ask questions? Do they work fast? Are they following any standards? Do they ask for clarification? What’s their communication like?


The purpose of my interview project is to determine if the person can:

  • write decent PHP code
  • use the Laravel framework
  • follow simple instructions


Here’s an example of instructions for a programming interview project.


LazyElePHPant / properties-test


Project Instructions


1) Create a page /properties that shows all property resources.
Add a redirect from / to /properties.
2) Implement the page /properties/{property} to show a specific property.
3) Add registration and authentication.
4) Implement a form at the endpoint /properties/create to create new properties. Only authenticated users can create new properties. 
5) Implement a form at the endpoint /properties/edit to update properties. Only authenticated users may update properties.


Additional Information


properties table

name
description
price
address
state 
city
zip
country
photo


  1. Implement a CMS to manage properties.
  2. All fields are required.
  3. Create a Database Seeder that generates 20 properties.


This Laravel programming interview project is a real set of instructions that has been previously given to potential employees. I want to take a stab at this interview project from a TDD point of view. 


There’s nothing telling us how to implement the project. Instead, we are told what the project should do. These instructions are a good set of candidates for writing a test suite. Let’s get started!


Project Setup


First thing I’ll do is build our project and fire up the Laravel framework.


laravel new properties



Configure PHPUnit


To avoid running tests on our real database we can configure an in memory SQLite database by adding the following two lines of code to our phpunit.xml file. The phpunit.xml file can be located at the root of our Laravel project.

<server name="DB_CONNECTION" value="sqlite"/>
<server name="DB_DATABASE" value=":memory:"/>

There are reasons why you should be using a database configured exactly like your production database. An in memory database is definitely not what we’d want to use for a large real world application. However, for our purposes it is perfect.


I use terminal to run my tests. To speed up the process here are a couple of aliases that I use:

alias pf='pu --filter='
alias pu='./vendor/bin/phpunit'


Before We Begin


We are ready to get started. The first thing we need to do is understand that in order to manage properties we need to be able to edit, create, delete and view the property resources. Also, creating and editing properties should only be available to authenticated users. 


Create a page /properties that shows all property resources.


Our first order of business is to create a feature test. We do this with the command:


$ php artisan make:test ManagePropertyTest
Test created successfully.


A file will be generated for us at tests/Feature/ManagePropertyTest.php. Here, we can put our first test together. This endpoins is responsible for displaying all properties. We need to generate properties and check that they are available on the /properties view page. 


The assertViewHasAll is exactly what we need. Our test will look like this:


    public function test_that_view_has_property_resources()
    {
        factory(Property::class, 20)->create();

        $this->get('/properties')
             ->assertStatus(200)
             ->assertViewHasAll(['properties' => Property::all()]);
    }


We don’t have a properties model yet, there’s no route /properties defined, there’s certainly no controller, and we have yet to define a factory. This test throws an error when we run it. When this test is passing we'll know know that we would have completed the first task item.


$ pf test_that_view_has_property_resources
PHPUnit 7.5.14 by Sebastian Bergmann and contributors.

E                                                                   1 / 1 (100%)

Time: 1.4 seconds, Memory: 14.00 MB

There was 1 error:

1) Tests\Feature\ManagePropertyTest::test_that_view_has_property_resources
Error: Class 'Tests\Feature\Property' not found

C:\xampp\htdocs\properties\vendor\laravel\framework\src\Illuminate\Database\Eloquent\FactoryBuilder.p
hp:228
C:\xampp\htdocs\properties\vendor\laravel\framework\src\Illuminate\Database\Eloquent\FactoryBuilder.p
hp:178
C:\xampp\htdocs\properties\tests\Feature\ManagePropertyTest.php:13

ERRORS!
Tests: 1, Assertions: 0, Errors: 1.


I have written many CRUD systems in Laravel. Reading those instructions I know that I need to create a model named Property, a factory PropertyFactory, a controller PropertyController, and a migration file. I can create everything I need with the following php artisan command.


$ php artisan make:model Property -crmf


The command -c generates a controller and -r makes it a resource controller. A resource controller is pretty standard for a CRUD Laravel application. To create our migration file we use -m which generates the create_properties_table file. For the factory -f is used. Combine them all together and you get -crmf. All the things we need in one command.


Model created successfully.
Factory created successfully.
Created Migration: 2019_08_10_142502_create_properties_table
Controller created successfully.


Make sure the Property model is included in our test.


use App\Property;


At this point I like to incorporate the method withoutExceptionHandling() at the top of my test.


$this->withoutExceptionHandling();


This method will give us a more detailed output when a test fails.


If we run our tests now we get a weird properties table doesn’t exists error. This error is thrown because we need to tell PHPUnit to refresh the database.


By default Laravel includes two classes in every test in generates:


use Illuminate\Foundation\Testing\RefreshDatabase;
use Illuminate\Foundation\Testing\WithFaker;


All we need to do is tell our test class to use the RefreshDatabase trait.


use RefreshDatabase;


When we run our test we find that our route /properties has not been defined.


Let’s define the /properties route by visiting roues/web.php file.


$ pf test_that_view_has_property_resources
PHPUnit 7.5.14 by Sebastian Bergmann and contributors.

E                                                                   1 / 1 (100%)

Time: 452 ms, Memory: 20.00 MB

There was 1 error:

1) Tests\Feature\ManagePropertyTest::test_that_view_has_property_resources
Symfony\Component\HttpKernel\Exception\NotFoundHttpException: GET http://localhost/properties

C:\xampp\htdocs\properties\vendor\laravel\framework\src\Illuminate\Foundation\Testing\Concerns\InteractsWithExceptionHandling.php:118
C:\xampp\htdocs\properties\vendor\laravel\framework\src\Illuminate\Foundation\Http\Kernel.php:326
C:\xampp\htdocs\properties\vendor\laravel\framework\src\Illuminate\Foundation\Http\Kernel.php:120
C:\xampp\htdocs\properties\vendor\laravel\framework\src\Illuminate\Foundation\Testing\Concerns\MakesHttpRequests.php:375
C:\xampp\htdocs\properties\vendor\laravel\framework\src\Illuminate\Foundation\Testing\Concerns\MakesHttpRequests.php:170
C:\xampp\htdocs\properties\tests\Feature\ManagePropertyTest.php:20

ERRORS!
Tests: 1, Assertions: 0, Errors: 1.


Did you know?


As I recently learned while trying to create a Laravel Package, the web.php is automatically assigned the web middleware group. The web middleware group provides useful features like sessions and csrf protection.


In our routes/web.php file we could go step by step defining each route, and you probably should, but I know this is CRUD. I'm going to skip right to the resource route.


Route::resource('/properties', 'PropertyController');


In Laravel, the resource route defines all of the property endpoints that we will need for our properties application. 


At this point if we run our tests we are getting an error telling us that the response is not a view. This is because our controller is currently not returning a view. More information on that here.


$ pf test_that_view_has_property_resources
PHPUnit 7.5.14 by Sebastian Bergmann and contributors.

F                                                                   1 / 1 (100%)

Time: 490 ms, Memory: 20.00 MB

There was 1 failure:

1) Tests\Feature\ManagePropertyTest::test_that_view_has_property_resources
The response is not a view.

C:\xampp\htdocs\properties\vendor\laravel\framework\src\Illuminate\Foundation\Testing\TestResponse.php:864
C:\xampp\htdocs\properties\vendor\laravel\framework\src\Illuminate\Foundation\Testing\TestResponse.php:794
C:\xampp\htdocs\properties\vendor\laravel\framework\src\Illuminate\Foundation\Testing\TestResponse.php:821
C:\xampp\htdocs\properties\tests\Feature\ManagePropertyTest.php:22

FAILURES!
Tests: 1, Assertions: 2, Failures: 1.


Visit the PropertyController that we generated earlier. In that controller we are hitting the index method for the /properties endpoint. Here we will need to create and return a view.


public function index()
{
    $properties = Property::all();

    return view('property.index', compact('properties'));
}


For now, create the view but we can leave the file empty.


We want to focus on testing just below the user interface. I try to avoid getting into seeing and clicking elements at the UI level. Those sorts of tests are better done by humans.


When we run our test everything should pass!


$ pf test_that_view_has_property_resources
PHPUnit 7.5.14 by Sebastian Bergmann and contributors.

.                                                                   1 / 1 (100%)

Time: 474 ms, Memory: 22.00 MB

OK (1 test, 2 assertions)


Notice we haven’t had to run our application in the browser and we haven’t added any fields to the properties migration file.


Add a redirect from / to /properties.


This one is easy, so easy.


public function test_that_welcomepage_redirects_to_properties()
{
    $this->get('/')->assertRedirect('/properties');
}


In our routes/web.php file we can simply update this:


Route::get('/', function () {
    return view('welcome');
});


To the following:


Route::get('/', function () {
    return redirect('/properties');
});



Implement the page /properties/{property} to show a specific property. 


Stepping right into our TDD workflow:


1) Write the test


public function test_it_can_view_specific_property_resource()
{
    $this->withoutExceptionHandling();

    $property = factory(Property::class)->create();

    $this->get("/properties/{$property->id}")
         ->assertStatus(200)
         ->assertViewHas('property');
}


2) Fail the test


$ pf test_it_can_view_specific_property_resource
PHPUnit 7.5.14 by Sebastian Bergmann and contributors.

F                                                                   1 / 1 (100%)

Time: 492 ms, Memory: 20.00 MB

There was 1 failure:

1) Tests\Feature\ManagePropertyTest::test_it_can_view_specific_property_resource
The response is not a view.

C:\xampp\htdocs\properties\vendor\laravel\framework\src\Illuminate\Foundation\Testing\TestResponse.php:864
C:\xampp\htdocs\properties\vendor\laravel\framework\src\Illuminate\Foundation\Testing\TestResponse.php:794
C:\xampp\htdocs\properties\tests\Feature\ManagePropertyTest.php:33

FAILURES!
Tests: 1, Assertions: 2, Failures: 1.


3) Pass the test


We can make the test pass by returning and creating a view with the specific property resource from our show method in our PropertyController. (Make sure to create property.show view.)


public function show(Property $property)
{
    return view('property.show', compact('property'));
}


Add registration and authentication


$ php artisan make:auth


Done.


Implement a form at the endpoint: /properties/create that creates new properties. Only authenticated users can create new properties.


We need to test that guest users are not able to access the /properties/create endpoint or submit to /properties/store.


To write that test we check that guest users cannot access the endpoints.


public function test_guest_cannot_create_properties()
{
    $this->get("/properties/create")->assertRedirect('login');
    $this->post('/properties', [])->assertRedirect('login');
}


The test fails because the guest can access the endpoints.


$ pf test_guest_cannot_create_properties
PHPUnit 7.5.14 by Sebastian Bergmann and contributors.

F                                                                   1 / 1 (100%)

Time: 431 ms, Memory: 18.00 MB

There was 1 failure:

1) Tests\Feature\ManagePropertyTest::test_guest_cannot_create_properties
Response status code [200] is not a redirect status code.
Failed asserting that false is true.

C:\xampp\htdocs\properties\vendor\laravel\framework\src\Illuminate\Foundation\Testing\TestResponse.php:166
C:\xampp\htdocs\properties\tests\Feature\ManagePropertyTest.php:40

FAILURES!
Tests: 1, Assertions: 1, Failures: 1.


Assigning the auth middleware to the property resource route will fix this. However, the index and show need to be public facing. A solution is to add the following code to our controllers construct method.


public function __construct()
{
    $this->middleware('auth', ['except' => ['index', 'show']]);
}


Now all of our tests should be passing. 


$ pu
PHPUnit 7.5.14 by Sebastian Bergmann and contributors.

...                                                                 3 / 3 (100%)

Time: 590 ms, Memory: 22.00 MB

OK (3 tests, 8 assertions)


Let’s write a test to see if our authorized user can access the /properties/create endpoint.


public function test_authorized_user_can_access_create_a_property_form()
{
    $user = factory(User::class)->create();

    $this->actingAs($user)->get("/properties/create")->assertStatus(200);
}


Here we import the User model and everything should be passing. 


Next on the list is creating the actual property. For this I use the WithFaker trait.


use RefreshDatabase, WithFaker;


Our instructions say that we need to use all of the following required fields:


name
description
price
address
state 
city
zip
country
photo


If we were to run the test below it will fail.


    public function test_authorized_user_can_create_a_property()
    {
        $this->withoutExceptionHandling();

        $user = factory(User::class)->create();

        $attributes = [
            'name' => $this->faker->text(5),
            'description' => $this->faker->text,
            'price' => $this->faker->randomNumber(6),
            'address' => $this->faker->streetAddress,
            'city' => $this->faker->city,
            'state' => $this->faker->stateAbbr,
            'zip' => $this->faker->postcode,
            'country' => $this->faker->countryCode,
            'photo' => $this->faker->imageUrl,
        ];

        $this->actingAs($user)
             ->post("/properties", $attributes)
             ->assertRedirect('/properties');

        $this->assertDatabaseHas('properties', $attributes);
    }


First, we make sure we create and return a view from our edit method.

    public function edit(Property $property)
    {
        return view('property.edit', compact('property'));
    }


Next, validate that we are receiving all of the required fields I’ll create a PropertyRequest by running the command:


php artisan make:request PropertyRequest


Since only authorized users can create properties we will check for that in the authorize method. We already have the auth middleware properly being applied, but instead of just writing true, I’ll go ahead and add an extra layer of protection with auth()->check().

    

public function authorize()
{
    return auth()->check();
}


The requirement is that all fields are required. However, this is where you would want to set any additional validation rules for property.


public function rules()
{
    return [
        'name' => 'required',
        'description' => 'required',
        'price' => 'required',
        'address' => 'required',
        'city' => 'required',
        'state' => 'required',
        'zip' => 'required',
        'country' => 'required',
        'photo' => 'required',
    ];
}


Make sure that the PropertyRequest class is imported in our controllers store method. 


public function store(PropertyRequest $request)
{
    if (Property::create($request->validated())) {
        return redirect('/properties');
    }

    abort(503);
}


We need to make sure that our fillable model properly is defined to avoid an error like this one:


$ pf test_authorized_user_can_create_a_property
PHPUnit 7.5.14 by Sebastian Bergmann and contributors.

E                                                                   1 / 1 (100%)

Time: 704 ms, Memory: 22.00 MB

There was 1 error:

1) Tests\Feature\ManagePropertyTest::test_authorized_user_can_create_a_property
Illuminate\Database\Eloquent\MassAssignmentException: Add [name] to fillable property to allow mass assignment
 on [App\Property].


Even after all that work our test will still fail. The reason is that we have yet to define our properties migration file:


Schema::create('properties', function (Blueprint $table) {
        $table->bigIncrements('id');
        $table->string('name');
        $table->text('description');
        $table->string('price');
        $table->string('address');
        $table->string('city');
        $table->string('state');
        $table->string('zip');
        $table->string('country');
        $table->string('photo');
        $table->timestamps();
});


After the final step of defining our fields in the property migration file our test will pass. 


However, our earlier tests that are using the factory class will fail. Since we added required fields to the migration file, we are going to need to update our PropertyFactory.


We can copy the code from our create property test and paste it into our factory. In the test we can replace the use of faker with a call to the factories raw method, like so:


<?php

use App\Property;
use Faker\Generator as Faker;

$factory->define(Property::class, function (Faker $faker) {
    return [
        'name' => $faker->text(5),
        'description' => $faker->text,
        'price' => $faker->randomNumber(6),
        'address' => $faker->streetAddress,
        'city' => $faker->city,
        'state' => $faker->stateAbbr,
        'zip' => $faker->postcode,
        'country' => $faker->countryCode,
        'photo' => $faker->imageUrl,
    ];
});


public function test_authorized_user_can_create_a_property()
{
    $this->withoutExceptionHandling();

    $user = factory(User::class)->create();

    $attributes = factory(Property::class)->raw();

    $this->actingAs($user)
         ->post("/properties", $attributes)
         ->assertRedirect('/properties');

    $this->assertDatabaseHas('properties', $attributes);
}


Give it a run. Everything is back to passing.


$ pu
PHPUnit 7.5.14 by Sebastian Bergmann and contributors.

.....                                                               5 / 5 (100%)

Time: 1.02 seconds, Memory: 24.00 MB

OK (5 tests, 12 assertions)


Implement a form at the endpoint: /properties/edit to update properties. Only authenticated users may update properties.


Dive right into a test for our guests.


public function test_guest_cannot_update_a_property()
{
    $property = factory(Property::class)->create();

    $this->get("/properties/{$property->id}/edit")->assertRedirect('login');
    $this->put("/properties/{$property->id}", [])->assertRedirect('login');
}


The test will pass since we’ve already protected our routes using auth middleware.

Next step is testing that a user can update a property.


public function test_user_can_update_a_property()
{
    $this->withoutExceptionHandling();

    $user = factory(User::class)->create();
    $property = factory(Property::class)->create();

    $property->name = 'Changed';

    $this->actingAs($user)
         ->put("/properties/{$property->id}", $property->toArray())
         ->assertRedirect('/properties');

    $this->assertDatabaseHas('properties', $property->toArray());
}


This test will fail because we are expecting to redirect to the /properties endpoint. However, we still have an empty edit and update method.


$ pf test_user_can_update_a_property
PHPUnit 7.5.14 by Sebastian Bergmann and contributors.

F                                                                   1 / 1 (100%)

Time: 466 ms, Memory: 22.00 MB

There was 1 failure:

1) Tests\Feature\ManagePropertyTest::test_user_can_update_a_property
Response status code [200] is not a redirect status code.
Failed asserting that false is true.

C:\xampp\htdocs\properties\vendor\laravel\framework\src\Illuminate\Foundation\Testing\TestResponse.php:166
C:\xampp\htdocs\properties\tests\Feature\ManagePropertyTest.php:84

FAILURES!
Tests: 1, Assertions: 1, Failures: 1.


Testing workflow feedback tells us it’s time to define those edit and update methods.


    public function edit(Property $property)
    {
        return view('property.edit', compact('property'));
    }

    public function update(PropertyRequest $request, Property $property)
    {
        if ($property->update($request->validated())) {
            return redirect('/properties');
        }

        abort(503);
    }


After defining our methods the tests will be back to passing.


$ pf test_user_can_update_a_property
PHPUnit 7.5.14 by Sebastian Bergmann and contributors.

.                                                                   1 / 1 (100%)

Time: 532 ms, Memory: 22.00 MB

OK (1 test, 3 assertions)



Database Seeder


One of the requirements is for the application to boot up with data. To do this we can use Laravel Table Seeder. Let's create a seed for our properties:


$ php artisan make:seed PropertyTableSeeder


In our database/seeds/PropertyTableSeeder.php file that was just generated, add the following line of code into our run method.


factory(Property::class, 20)->create();


Last thing to do is call PropertyTableSeeder when the user asks for the database to be seeded. We do this by adding this line of code into our database/seeds/DatabaseSeeder.php:


$this->call(PropertyTableSeeder::class);


Design


I’ve completely neglected the design so far. In fact, I have yet to configure let alone seed my real database.


To fire up the application I can run the migration and seed command.


$ php artisan migrate:fresh --seed


We’ve created all of our view files but we haven’t taken the time to code them up. I’ll paste all of those below, they should be self explanatory. 


Because ain't nobody got time for no design.


property/index.blade.php


@extends ('layouts.app')

@section ('content')
	<div class="card">
		<ul class="list-group">
			@foreach ($properties as $property)
				<li class="list-group-item">
					<a href="{{ route('properties.show', $property->id) }}">
						{{ $property->name }}
					</a>
				</li>
			@endforeach
		</ul>
	</div>
@endsection


property/show.blade.php


@extends ('layouts.app')

@section ('content')
	<div class="card p-3 col-8 col-offset-2">
		<h1>{{ $property->name }}</h1>

		<img src="{{ $property->photo }}">

		<h4 class="py-3">${{ number_format($property->price) }}</h4>
		<p>{{ $property->description }}</p>

		<p>{{ $property->address }}</p>
		<p>{{ $property->city }}, {{ $property->state }} {{ $property->zip }} {{ $property->country }}</p>
	</div>
@endsection


property/index.blade.php


@extends ('layouts.app')

@section ('content')
	@if ($errors->any())
		<div class="alert alert-danger">
			<ul class="">
				@foreach ($errors->all() as $error)
					<li class="">{{ $error }}</li>
				@endforeach
			</ul>
		</div>
	@endif

	<form class="form" action="{{ route('properties.store') }}" method="POST">
		@csrf
		<div class="form-group">
		    <label for="name">Headline</label>
		    <input type="text" class="form-control" value="{{ old('name') }}" name="name" placeholder="Enter name">
	  	</div>

	  	<div class="form-group">
		    <label for="price">Price</label>
		    <input type="text" class="form-control" value="{{ old('price') }}" name="price" placeholder="Enter price">
	  	</div>

	  	<div class="form-group">
		    <label for="description">Description</label>
		    <textarea class="form-control" name="description">{{ old('description') }}</textarea>
	  	</div>

	  	<div class="form-group">
		    <label for="address">Street Address</label>
		    <input type="text" class="form-control" value="{{ old('address') }}" name="address" placeholder="Enter street address">
	  	</div>

	  	<div class="form-group">
		    <label for="city">City</label>
		    <input type="text" class="form-control" value="{{ old('city') }}" name="city" placeholder="Enter city">
	  	</div>

	  	<div class="form-group">
		    <label for="state">State</label>
		    <input type="text" class="form-control" value="{{ old('state') }}" name="state" placeholder="Enter state">
	  	</div>

	  	<div class="form-group">
		    <label for="zip">Zipcode</label>
		    <input type="text" class="form-control" value="{{ old('zip') }}" name="zip" placeholder="Enter zipcode">
	  	</div>

	  	<div class="form-group">
		    <label for="country">Country</label>
		    <input type="text" class="form-control" value="{{ old('country') }}" name="country" placeholder="Enter country">
	  	</div>

	  	<div class="form-group">
		    <label for="photo">Photo</label>
		    <input type="text" class="form-control" value="{{ old('photo') }}" name="photo" placeholder="Enter photo">
	  	</div>

	  	<button class="btn btn-primary">Submit</button>
	</form>
@endsection


property/edit.blade.php


@extends ('layouts.app')

@section ('content')
	@if ($errors->any())
		<div class="alert alert-danger">
			<ul class="">
				@foreach ($errors->all() as $error)
					<li class="">{{ $error }}</li>
				@endforeach
			</ul>
		</div>
	@endif


	<form class="form" action="{{ route('properties.update', $property->id) }}" method="POST">
		@csrf
		@method('PUT')

		<div class="form-group">
		    <label for="name">Headline</label>
		    <input type="text" class="form-control" value="{{ old('name', $property->name) }}" name="name" placeholder="Enter name">
	  	</div>

	  	<div class="form-group">
		    <label for="price">Price</label>
		    <input type="text" class="form-control" value="{{ old('price', $property->price) }}" name="price" placeholder="Enter price">
	  	</div>

	  	<div class="form-group">
		    <label for="description">Description</label>
		    <textarea class="form-control" name="description">{{ old('description', $property->description) }}</textarea>
	  	</div>

	  	<div class="form-group">
		    <label for="address">Street Address</label>
		    <input type="text" class="form-control" value="{{ old('address', $property->address) }}" name="address" placeholder="Enter street address">
	  	</div>

	  	<div class="form-group">
		    <label for="city">City</label>
		    <input type="text" class="form-control" value="{{ old('city', $property->city) }}" name="city" placeholder="Enter city">
	  	</div>

	  	<div class="form-group">
		    <label for="state">State</label>
		    <input type="text" class="form-control" value="{{ old('state', $property->state) }}" name="state" placeholder="Enter state">
	  	</div>

	  	<div class="form-group">
		    <label for="zip">Zipcode</label>
		    <input type="text" class="form-control" value="{{ old('zip', $property->zip) }}" name="zip" placeholder="Enter zipcode">
	  	</div>

	  	<div class="form-group">
		    <label for="country">Country</label>
		    <input type="text" class="form-control" value="{{ old('country', $property->country) }}" name="country" placeholder="Enter country">
	  	</div>

	  	<div class="form-group">
		    <label for="photo">Photo</label>
		    <input type="text" class="form-control" value="{{ old('photo', $property->photo) }}" name="photo" placeholder="Enter photo">
	  	</div>

	  	<button class="btn btn-primary">Submit</button>
	</form>
@endsection



Conclusion


Using an interview project can be a great way to get real insights into a developer. Being able to follow instructions and implement a simple CRUD application is important. Keeping the software development process simple is what separates a good programmer from an inexperienced programmer. You have to give the end user what they ask for and not what you think they need.


For this writing I cut the task items short but I have noticed that time is a huge factor. Originally I didn’t think time would matter all that much, but I find that the completion time is usually tied to skill level. 


A new and more Jr. level developer will take 6–10 hours to complete, a mid-level 2–4, and a Sr. level less than two hours. Again, I left out the relationship of home types and the uploading of images. Aside from the time, the workflows, styling, and work ethic become very obvious.


This is a very simple interview project and I believe that there is value in using it as practice prior to an interview.


LazyElePHPant / properties-test

Kevin Pimentel

There are two types of people in the world: those that code, and those that don’t. I said that! Quote me. My name is Kevin and I’m one of the ones that codes.