The price of comfort

I am serving a ton of data to Angular for my app Graffito, like 3000 geocoded ‘graffiti incident’ reports from NYC Open Data via the SODA API. I use the data to plot markers on Google Maps, as well as overlay a heatmap with Heatmap.js.

Performance has always been an issue.

One way I’ve improved user experience is to plot the map only once, and use jQuery to toggle its visibility depending on the route. Angular’s UI-router has a nifty OnEnter callback to manage that gracefully.

Today, I focused on improving performance via comparing different query implementations –  JBuilder vs. customizing Rails’ as_json(options={}) method. JBuilder provides a DSL that can be used stand-alone or directly as an ActionView template language.

Let’s compare request times by descending order of duration.

I use rack-mini-profiler to audit performance. It creates a handy little window in your browser for assessing the performance of each query in the request with caching disabled.

JBuilder in a template (index.json.jbuilder):

Screen Shot 2016-08-26 at 3.25.11 PM

JBuilder as standalone DSL:

Screen Shot 2016-08-26 at 2.59.13 PM

as_json patch:

Screen Shot 2016-08-26 at 2.58.56 PM

Wow. The extra overhead JBuilder imposes on your app as a template language is huge – about 10 seconds more than customizing Rails’ as_json. The the time it takes to render index.json.jbuilder is impractical for my huge data set.

But even as a standalone language, JBuilder is slower by nearly one second. And this makes sense, JBuilder essentially wraps Rails in another language.

The argument for using JBuilder is comfort – a DSL is more semantic. But in my experience, that’s only when using it as a template language. As a standalone DSL, its less clear than Rails.

JBuilder introduces the unfamiliar class method encode, initializes a json object, and sets the graffito attributes to that object. It takes some brain power to figure that out, slowing down the development process.

It’s worth nothing that rails does all this too under the hood with Active Model Serialization. That’s why when we call super, it returns a json object. Both JBuider and Rails do it in O(n) time, but Rails does so more efficiently, without a DSL wrapper to slow everything down.

I’m glad I compared these approaches. For now, I’m sticking with plain Rails. Only when an API becomes super vast, with many levels of nesting, would I pick a semantic DSL like JBuilder, and even then, I’d only use it as a template language for smaller queries.

 

Advertisements

How to build an Arpeggiator

It’s been far too long since I blogged. I’ve been super immersed in my first job as a RoR developer at Custom Solutions Group and making music. As it turns out, I’m bringing my two most urgent passions, coding and songwriting, together.

For an upcoming performance at my friend’s salon in Brooklyn, NY, I’m weaving the leitmotif from the 1992 film Cape Fear into my set using an online synth and a simple script I wrote to introduce the theme.

The script relies on the js setTimeout() function to execute code after a delay of 950 milliseconds. The delay allows a note to continue playing until the next time the script fires.

After inspecting the synth’s source code, I discovered I could call its keyUp() and keyDown() functions to automate playback. The tricky part was tracking which notes to keyup or keydown, and when to use a delay between notes or not. To achieve seamless playback, I store the arpeggio notes in an array, and use the index to identify which note in the arpeggio should be keyed up or down; in other words, the current and previous note, or i and i-1.

As well, I use a counter, independent of any particular arpeggio, to measure total notes played. In this example, I limit the program to play 10 arpeggios consecutively for a total of 40 notes (see line 25), at which point the program terminates.

Most important, when the remainder of the counter % 4 is 0, the last note in the current arpeggio has been played (it will always be a multiple of 4). At that point, I reset the index to 0 and use a callback to restart the code and play the first note in the arpeggio without a delay to avoid a gap between arpeggios.

Here’s the code! Have fun and give it a try. Just follow the instructions up top. Coding gives you semi-super powers to do beautiful things.