A Side Project

Today I’m ‘launching’ a side project I’ve been working on intermittently for the last 3 months or so. I say ‘launching’ only because it’s a pretty niche, limitedly useful website, but nonetheless a passion project, and a project that’s taught me plenty of things about a bunch of things. It’s not the new hot app, it’s not a revolutionary product, but this is the week I’ve decided to let other people check it out anyway. Here it is — ultraboosthype.com

Tldr; ultraboosthype.com is a complete catalogue of Adidas Ultra Boost sneaker releases, built as an Ember app, consuming an Express API, deployed to Heroku and managed with Forest Admin. I’m no 10x developer, but the whole thing seems to hold together ok— read on if you’re curious.


For sneakerheads and hypebeasts

Ultraboosthype.com is intended to be a definitive resource to catalogue every release and every colorway of the Adidas Ultra Boost running shoe. If you’re at all into your sneakers you’ll likely know that this shoe more than any other (apart from the ubiquitous Yeezy or the most prestigious Jordans) has dominated the shelves of sneakerheads through 2015 and even 2016, with no signs of slowing down into 2017.

Adidas has been relentless in putting out new releases of the sneaker in new colorways most months, using new materials, new styles and in new collaborations with an array of fashion brands. As of publication, there are 95 releases of the Ultra Boost, and every single one is catalogued in this silly side project I’ve worked up.

Why is this a thing?

I’m afflicted with some form of this sneaker obsession, though thankfully mine is limited to the Ultra Boost and not as acute as some others. The itch I’m scratching is having a way to showcase every release of this specific shoe in a single place. There are plenty of websites that have shoe databases but none have complete coverage nor an attention to detail in capturing every release.

The other part to all this (the saner part), is wanting to expand my knowledge of building web apps and APIs, deploying a real-world stack and learning more of a programming language and a framework I use every day for my real job.

Combining these two things, I arrived at this thing. Part 1 is the API on top of a complete datastore of all these releases, and Part 2 is the web client that queries this API and presents those releases in a good-looking front-end.


The API

I wanted to follow best practices and really build out the whole service so serving all the data from an API seemed like a sensible route. This also means that the client could be solely concerned with consuming and presenting the data, rather than generating it. Building out an iPhone app next really appeals to me and that could consume this same API.

This was the one part of the project that was entirely new to me. I’ve worked in plenty of apps that are backed by APIs and have always had a grasp of how they work in principle, but have never built one out by myself. The one absolute I had going in was that I’d want to use Ember Data when it came to the client, so whatever I got back from the API should play nicely with that.

The Ember docs themselves deal a lot with data formats and APIs and is a good place to get started. In the end I opted for building the API out with Express, a framework for Node.js. There are plenty of tutorials for this scenario specifically and following along and implementing the API was relatively straightforward.

I decided early on to have a very simple ‘flat’ API that would essentially just be a collection of ‘releases’. Each release would have attributes to define things like name, colour (primary, secondary & tertiary), date of release, and some attributes to identity the specific type of release, model and finish.

I had a lot of back and forth on exactly how to break down some of these type attributes; specifically, how to classify the variations of Ultra Boost model (regular vs uncaged) and also the different styles of Ultra Boost (the prime knit pattern/material has changed 3 times but has never been delineated by Adidas in this way). Ultimately I solved for the variations by assigning a type attribute so that I can set ‘caged’ or ‘uncaged’ or even a future variation (like the upcoming ‘mid’) and used a style attribute that accepts the same ‘season’ nomenclature that most fans and publications use (1.0, 2.0, 3.0).

var ReleaseSchema = new Schema({
name: String,
code: String,
primary: String,
secondary: String,
tertiary: String,
released: Boolean,
date: String,
image: String,
content: String,
series: Number,
type: String,
style: String,
consortium: Boolean,
limited: Boolean
});

The other key piece of data for a release is the image. These images are picked from promotional photos, edited in Photoshop to standardise the presentation, and then uploaded to Amazon S3. This is the single most time-consuming piece of maintaining this project, but hey, it’s a passion project.

The API is then authenticated with Basic Auth, which isn’t a terrific practice but does what I need it to do for now, and then deployed to Heroku as a Node.js app available at api.ultraboosthype.com.


The admin

I actually have Nick Jones to thank for this one. Originally I had intended on building out an additional app, or extending the Express API app to handle the general CRUD of data. Thankfully none of that was required becuase Forest Admin and Lumber exist.

Editing a release in Forest on top of the API

Forest basically sits on top of the API as the admin system, so I can login to my account and view all my releases in the Forest Dashboard, edit existing ones, create new ones, or remove releases as neccesary. Forest then relays those commands to my existing API.

It’s a really elegant solution that also happens to be nicely designed, and has made handling the time consuming part of curating a catalogue much easier and a little less time consuming than it could have been.


The web app

For the last 3 years at Heroku, I’ve been far more involved in the implementation of features from front-end to back-end, meaning from initial design mockups to functioning interface in the browser.

The product I spend perhaps more than 80% of my time on is an ambitious Ember app — the Heroku Dashboard. I know much of the framework just from exposure to it, and can tackle some deeper technical challenges than ones involving pixels, though frequently send up distress flares when I get truly stumped. That said, the Heroku Dashboard is a huge application and I work only in a few specific parts of it.

A goal of this project then, was to build an Ember app from scratch and in doing so learn more of the ins and outs from the foundations up. Again, the Ember docs themselves are a great place to start, and filled in a lot of the gaps in my knowledge that I hadn’t picked up from working inside the Heroku Dashboard, particularly some of the technical fundamentals.

The release template for the Ember app

The app, like the API is pretty straightforward — I made the decision early on to make it a read-only app, which is to say there are no user accounts and no interactions that are persisted; the app serves as a presentation layer only. There is a /releases route which serves up every single release, each release is then available at /releases/:release. For categorisation there are additional routes for /1.0, /2.0, /3.0 and /uncaged, where each page filters the available releases by those types. There’s also a /search route where you can filter all releases by a keyword matching attributes including name, code, colour and whether they’re a consortium release (a collaboration).

The homepage surfaces releases from a few different categories and includes some visual links to those categories alongside links to some curated community resources (some relevant Instagram, Twitter and YouTube accounts; all of which are worth a follow if you suffer my same Ultra Boost obsession).

Deployment

Deploying the apps to Heroku, and having them just run, is the easiest part. I’m kinda biased here (given I work for Heroku) but it was super easy to deploy both the API and the Ember app to Heroku and have a workflow to make subsequent deploys trivial.

The pipeline on Heroku

The API app automatically uses the Node.js buildpack, and once you define the Ember and Static buildpacks using App.json, the Ember app is up and running too. The code for both is hosted on GitHub and linked with Heroku Pipelines so I can create review apps for pull requests of new features, and have my staging app sync with master and then just promote to production.

The Ember app even uses Fastboot so it can be rendered server-side — this is useful for performance gains, for assigning metadata for URLs on social media, and making every release indexable by search engines). Getting things running nicely in Fastboot was one of the larger stumbling blocks I fell face-first over, but I had a lot of help from Andy Appleton and, given Fastboot still isn’t at 1.0 yet, I think this should become easier in the future.


Upcoming

One notable omission from this version of the web app is a feed of upcoming releases. Ideally I’d like to be able to catalogue upcoming versions of Ultra Boosts that have not yet been released by Adidas, or in some cases not even announced yet. Samples leak early and getting a peek at unreleased colorways is all part of the fun for any collector or fan. Original incarnations of the website had a top-level /upcoming page and each anticipated release on there was available at /upcoming/:release.

My reason for axing this feature was technical and practical. On the technical side it’s an unresolved issue for the design of the API. By design each release has a date (used to sort releases) and a code which is the SKU Adidas identify a shoe by and which I use as the primary key and in the URL (/releases/B27171 for example).

Most of the time this date is unknown, and a lot of the time the code isn’t known until release. I wanted to use the same model for either case though, so that an upcoming release can be turned into an actual release when the time comes. I actually have a boolean attribute called released which I use to make that distinction.

The trouble then is all the extra logic required to present them in the web app. I can’t rely on the code so I have to define the route some other way. The image name should be the same as the code attribute. How do I define the order the releases should appear in when there is no date? The date format has to be different too because it’s a timeframe not a moment.

The practical side is simply the editing process. Frequently the name of the release changes, or the code isn’t available until it releases, or it introduces a new color that I don’t have defined, or it’s a new style that I haven’t accounted for. I can’t make the transition from unreleased to released truly automatic — there’s too many variables there.

None of these issues are insummountable but it gave me a whole bunch of headaches, and led to a whole lot of back and forth in both the app and in the API, which ultimately just kept pushing things back and causing further frustration.

Thinking about this feature in isolation now, I probably just want a photo feed with a codename and a timeframe for each release, and an order defined by just the time it was published. They should be decoupled from the releases model entirely and just exist as a separate route. This is the next feature I want to implement as it’s a big part of cataloguing the Ultra Boost.


What’s next?

As far as the API goes, having some way to define upcoming releases seems like it needs to happen. Whether I do this by solving the inconsistencies for the existing single release model, or whether I introduce a new endpoint for upcoming releases I’m not sure. I have a feeling I’ll end up going down both rabbit holes.

With the app, at some stage I’d like to introduce some interactivity to the site and some persistence. Given a lot of folks are going to be collectors, being able to manage a virtual collection seems like it’d be neat. For that I’d need to add users, and user authentication, and for that I’d need to do some more graft in API land — but once I have users, I can build out all sorts of things. The first step might simply be authenticating users and letting them upvote releases, as a proof of concept anyway.


As for the Ultra Boost? Well, it’s showing very few signs of slowing down.