easierbycode
11/1/2012 - 6:42 PM

Michael Myers, or JavaScript, which scares your team more?

Michael Myers, or JavaScript, which scares your team more?

If Michael Myers came into your office and asked for a quote on his slick new web app, would your backend team be more scared of his empty stare and 10" inch bloody serrated blade, or the idea that they might have to learn something new?

Let's imagine we somehow managed to get past the obvious red flags, and agreed to take on his unique request.

We sit down and begin to define the minimum viable product. It's a location-based app that will allow our customer to track time, place, and events, information he can use to create reports which will help him to optimize his serial killer activities.

With a Fitbit strapped to our masked man, and an off the shelf gateway we bought from a Silicon Valley startup, we can now get to work on the web app which will make use of the realtime, aggregated, and inferred events now flowing into our database.

since it's 2012, our app might look something like this:

locations = new Locations;    new LocationList({ collection:locations });    locations.reset([{ lat:56.46113, lng:-2.96906, speed:5.299973156764494, timestamp:1343964421000, event_type:"DODGING" }, ...]);

So far so good. Time for iteration 2.

Our first user story is to add additional tabs which list events, and chart speed information.
But wait, the developer who created the initial app is at a Deftones concert in Canada..
and although the developer who picks up the slack has never stopped to learn JavaScript, he has proven himself in other areas, so why not?

Since it's obvious to the developer that 'Rails already has models and views', he whips up something like this:

$("#events-and-details-volatile").html('<table class="events-list-container">  <tr>  <td>  <table class="events-list-title">  <thead>  <tr colspan="3">  <th>Events</th>  </tr>  <tr>  <th>Date</th>  <th>Time</th>  <th>Event</th>  </tr>  </thead>  </table>  </td>  </tr>  <tr>  <td>  <div class="events-list-content">  <table class="table">  <tbody>  <tr>  <td>08/03/12</td>  <td>03:27:01</td>  <td>DODGING</td>  </tr>  </tbody>  </table>  </div>  </td>  </tr>  </table>');
$("#speed-profile-volatile").html('<div id="speed_profile_chart" class="speed-profile-chart">3</div><script>drawSpeedProfileChart([[1343964421000, 5.299973156764494]]);</script>');

side note: the above code is not in a JavaScript file.. It's the response from Rails that's generated when we send our AJAX request to '/killer_scores/show_stalk_details?stalk=3'

What's wrong with this approach?

  • the same data exists in 3 places
  • there is NO clean way to add any interaction
    • in case you missed it, this is because we are using Ruby strings to call JavaScript methods
      • if you don't see/understand why this is a problem:
        • A. learn JavaScript before continuing to use it
          • read 'JavaScript: The Good Parts' by Douglas Crockford
        • B. remove all references to the word 'web' from your resume
          • FedEx is currently hiring for several warehouse positions which do not require you to learn JavaScript, DOM, or any other basic web competency

How can we fix it?

first, let's take a stab at it without Backbone:

  • we create a place to store our events in JavaScript

    var events = []
    
    function Event( latitude, longitude, eventName ) {
      this.eventName = eventName;
      this.mapItem = new google.maps.Marker({
        // ...
      });
    }
    
  • next, we load our application data
    side note: at this point we could do something like this in Rails

    html = "<script>"
    
    @events.each do |event|
      html += "new Event(<%= event[:latitude] %>, <%= event[:longitude] %>, <%= event[:event_type] %>);</script>"
    end
    
    html += "</script>"
    
    return html
    

    but we're better than that, so we use:

    $.ajax({
      url: '/events',
      dataType: 'json',
      success: function (events) {
        for(event in events) {
          new Event( event );
        }
      }
    });
    
  • next, we define our 'showOnMap' behavior

    Event.prototype.showOnMap = function() {
      infoWindow.setContent( this.eventName );
    }
    
  • the last step is to add a listener to the event's element

    # using an inline script for brevity
    <td>+<a href="javascript:events[' + event[:index] + '].showOnMap()">DODGING</a></td>
    

    Q. why are you using 'location[:index]'?
    A. Because there is no clean way to tie static html to behavior or state. we get around this by adding a common ID to both our client-side element and our inline script

now, with Backbone: