Skip to content

Instantly share code, notes, and snippets.

@bencates
Last active August 29, 2015 14:21
Show Gist options
  • Save bencates/12ae3b97c5e67003c9a0 to your computer and use it in GitHub Desktop.
Save bencates/12ae3b97c5e67003c9a0 to your computer and use it in GitHub Desktop.
  1. What frameworks or libraries do you generally pull in when starting a fresh PHP project? Why do you use them?

    My only must have is either phpspec or PHPUnit. I prefer phpspec, but it makes rather opinionated assumptions about project structure, so PHPUnit is much easier to set up on older projects.

    Beyond that, I've had good luck with both Silex and Twig. They're both simple, focused libraries to provide the Controller and View components, respecitvely, of a MVC framework.

    To be honest, though, most of my fresh projects aren't in PHP. I prefer either Ruby or NodeJS when given the choice. Most of my experience with PHP has been picking up existing projects and using whatever framework and tools already exist on them.

  2. If I told you that we needed to use a third party API to get some arbitrary data, would you prefer XML or JSON? Why?

    JSON, as it is easier to parse, easier for humans to read, and slightly smaller over the wire (though the last point is mostly cancelled out by gzip). JSON is a much closer match to the internal semantics of array() and to PHP's list of primitive types, meaning that there's usually only one naive way to translate a PHP data structure to a JSON object or vice versa.

  3. Do you have any preferred design patterns? What is your argument for implementing it? Do you have examples?

    I'm not sure I understand the question. Design patterns tend to be oriented toward relieving specific code smells. I don't prefer any one in particular as much as I try to choose the right pattern for the problem at hand.

    If forced to choose a favorite, I've found the Extract Method and Replace Method with Method Object patterns to be extremely effective at untangling large and difficult to understand knots of code.

  4. What is the benefit of using version control? How would you use it to setup a build / test / stage / production environment?

    Verson control provides several benefits. It provides a sense of history and documentation (via commit messages). It greatly simplifies working on multiple features, either individually or collaboratively. It helps to structure work in progress by forcibly breaking it into discrete commits. And last but not least it allows changes to be easily reverted, freeing developers to comfortably embark on larger and more ambitious changes.

    I like to set projects up using a system similar to git flow, with a master branch for production-ready releases, a staging branch for the staging and test environments, and numerous feature branches forked from and merged back into staging for development.

  5. What’s the most clever hack you’ve done with PHP?

    That's a difficult question to answer. I try to make a point to avoid "clever hacks" in my code, and to refactor them away when I find them in projects I'm working on. I'm of the opinion that clever belongs in the design and architecture and that the actual code should be as boring and obvious as possible.

    The coolest PHP hack I've done is probably the Reed & Barton personalization tool (click on any item in the section, then click "Personalize" on the item's page). It's several years old at this point, but I think has held up pretty well. Users provide arbitrary text and the site uses a per-product 3d mesh to composite it onto the stock photo to show how the item would look after being engraved.

  6. Review these two API services. Broadly speaking, what are the strengths and weaknesses of them? Do you think they’re well designed? What would worry you about implementing them? Do they teach you anything about designing a well-formed API?

    • Stripe Payments: https://stripe.com/docs/api

      Stripe has been singled out as an example of how to do APIs right, and for good reason. It's extremely complete without feeling excessive. It uses JSON as a transfer encoding and leans heavily on HTTP verbs and error codes, all of which serves to make it relatively easy to both understand and implement. It provides numerous, well-defined endpoints, which serves to keep the request and response objects for each endpoint relatively small and simple. And it's extremely well documented.

      My only concern with Stripe integration would be with the scope of the service. Online payments are a complicated domain with numerous edge cases. The API (and Stripe's service in general) do an excellent job of minimizing the complexity, but there's only so much they can mask.

    • UPS Rating: http://ncc1701.system76.com/misc/rating_xml.pdf

      This is less good. It's centered around a single massive request and response object, both of which have numerous optional fields. The request requires two complete XML documents in the message body (one for auth and one for the actual request), which is likely to require special handling in pretty much any client-side HTTP library. Errors are via apparently arbitrary error codes, requiring more special casing to catch them client-side and preventing any generic error handling.

      On the bright side, the documentation is actually pretty complete, if a bit dry. They don't use XML attributes, which simplifies parsing considerably. They have a full testing environment. And at a glance it appears that they're using ISO standard country and currency codes, which is nice.

  7. Create a JSFiddle/Codepen/Gist ( or attach a source file ) that will do the following:

    • Have the user select a number of images to show ( between 2 and 20 ).
    • Query http://ncc1701.system76.com/images/ for that number of images.
      • Optional parameters: /images/[length]/[offset]
    • Draw each of the returned images into a canvas element.
      • Make sure that all of the images are visible and are evenly spaced apart.
    • If the user changes the value of the number of photos to show, repeat the process, setting the offset to increment by the previously selected amount.

    Please see attached file.

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>System76 Questionnaire</title>
<style>
#number_of_images, #c { display: block; margin: 10px; }
</style>
</head>
<body>
<select id="number_of_images">
<option value>How many pictures do you want to load?</option>
<option value="2">2</option>
<option value="3">3</option>
<option value="4">4</option>
<option value="5">5</option>
<option value="6">6</option>
<option value="7">7</option>
<option value="8">8</option>
<option value="9">9</option>
<option value="10">10</option>
<option value="11">11</option>
<option value="12">12</option>
<option value="13">13</option>
<option value="14">14</option>
<option value="15">15</option>
<option value="16">16</option>
<option value="17">17</option>
<option value="18">18</option>
<option value="19">19</option>
<option value="20">20</option>
</select>
<canvas id="c" width="520" height="415"></canvas>
<script>
(function () {
'use strict';
var $select = document.getElementById('number_of_images');
var $canvas = document.getElementById('c');
var offset = 0;
function loadImages(numberOfImages) {
var xhr = new XMLHttpRequest();
var url = 'http://ncc1701.system76.com/images/' + numberOfImages + '/' + offset;
offset += numberOfImages;
xhr.onreadystatechange = function () {
if (xhr.readyState < 4) return;
if (xhr.status === 200) {
var data = JSON.parse(xhr.responseText);
var images = data.data.images.map(function (item) {
return item.url;
});
showImages(images);
} else {
console.error('XHR error ' + xhr.status + ': ' + xhr.responseText);
}
};
xhr.open('GET', url);
xhr.send('');
}
function showImages(images) {
var ctx = $canvas.getContext('2d');
ctx.clearRect(0, 0, $canvas.width, $canvas.height);
images.forEach(function (imageSrc, idx) {
var image = new Image();
image.onload = function () {
ctx.drawImage(
image,
(idx % 5) * 105, // reset every 5th item
Math.floor(idx / 5) * 105, // move down every 5th item
100,
100
);
};
image.src = imageSrc;
});
}
$select.addEventListener('change', function () {
if ($select.value !== '') {
loadImages(parseInt($select.value, 10));
}
}, false);
})();
</script>
</body>
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment