- Dan Phiffer [email protected]
- Code Test, July 2015
This is a small web application that displays a list of articles based on JSON & JSONP published to an Amazon S3 bucket. The implementation is in PHP, which is the language I'm most familiar with on the back-end.
- Setup and preamble
Some things to ensure when setting up this web app:
- Software requirements:
- PHP 5.4+ (it might run on 5.3, but I wouldn't recommend it)
- cURL module enabled
- Node.js
- Writable directories:
- /log (only used when debugging is enabled)
- /cache (for keeping a local copy of JSON data)
- index.php should be configured as the directory index
- If DEBUG is defined, and set to a non-empty, errors will be logged publicly to log/error.log.
npm install
grunt
You may also want to take a look at setup.php, in case you want to fiddle with any knobs. Other than that, you should be able to just unzip this to a public web directory and it will work without further configuration.
I've written the PHP code using WordPress style, mainly because we've adopted this at TNY, and I'm trying to get used to all the extra whitespace inside the parens. In the interest of time, I'm going to consciously not make tests for this, although I do believe in the importance of test-driven programming.
- Getting the data
The Section_Front object takes care of downloading and caching data upon instantiation. Since going to disk is much faster than the network (even fast networks!), data files will be cached briefly to the 'cache' directory.
Network requests are sent with an 'If-Modified-Since' header to further reduce how much time is spent waiting on the network.
This just gets us off the starting line slightly faster. It's the difference between 7ms from disk, 70ms from an HTTP 304, or 300ms from an HTTP 200.
- Back-end Data Structures
The PHP class hierarchy is roughly modeled after how data is structured in the JSON source files:
+ Section_Front (the page)
|
+--+ Section_Front_Content (a-column, b-column)
|
+--+ Section_Front_Collection (aka a column group)
|
+--+ Section_Front_Asset (an individual story)
- Front-end treatment
I fell into a bit of a trap on this section and spent too much time trying to make my visual appearance consistent with existing NYT styles. However, I did learn a lot about how stories are assembled.
In the interest of time I fudged a little bit on the front-end implementation:
- I am willfully ignoring Internet Explorer and other potentially unfortunate browsers.
- I only implemented a single breakpoint, so things will look a bit off on tablet-size widths.
- All my text sizes are set in px units, but I probably should've used rems.
- Translation
I added some top-level tabs that let you toggle between English and an obscure Martian dialect ("boinga boinga"). The translation occurs on the back-end and is modeled so it could plug into some kind of actual translation service.
I used a mix-in style feature of PHP (introduced in version 5.4) so that all
the data structure objects have a translate method available.
- Pagination
Additional content can be loaded onto the page using a JSONP request. There's an unfortunate amount of code duplication in JS vs. PHP. Given more time, I would opt for a unified templating system on the back-end and front-end.
I also introduced a simple web service to translate new content as it loads in. I used a TreeWalker object to find all the text in each story and translate its text on the fly. This process queues up a whole lot of AJAX queries, which is a bit wasteful in terms of resources. I'd probably want to group lookups into larger groups, so long as we're not pushing up against the limits of what you can send over a query string.
One simple optimization I made was to favor stories that are higher up on the page, since I was noticing a significant wait time for the B column stories as they waited on all stories in A column to finish their translation process.
- In conclusion
This is definitely a work in progress. I think you'll notice the JavaScript side of things is slightly more thrown together in terms of organizing code, and attending to all the details (e.g., column group header/footer content is ignored when loading another page). It's unfinished, but finished enough that I would send it around for feedback, and consider changes from stakeholders in another round of refactoring.