Tuesday, October 11, 2011

Grammatical Personalization in JS

In EatDifferent, I have various places where I describe something about a user. For example:

  • "Pamela Fox filled out her logs 3 days in a row.
  • "In the last week, you haven't logged any measurements."

I wanted to be able to construct those sentences in JavaScript with some sort of mini templating language. I didn't find any existing libraries for it, so I wrote my own. Now to generate the above strings, I can write stuff like:

personalize('{{ They|name }}' filled out {{ their }} logs 3 days in a row.', 
   {gender: 'male', person: 'third', name: 'Pamela Fox'});
personalize('In the last week, {{ they|name }} {{ have|not }} logged any measurements.',
    {gender: 'male', person: 'first'});

You can see the code for the library in this gist and check out a live demo on jsfiddle.

Friday, October 7, 2011

Ada Lovelace Day: Women that Inspire Me

Today is Ada Lovelace Day, a day to celebrate the women of math, science, and technology, and the challenge today is to write a blog post highlighting a woman that inspires us. I blogged an interview with my mum a few years ago (the first woman in tech I ever knew!), so this year, I thought I'd highlight a few women that inspire me today.

  • Sara Chipps:

    Sara started GirlDevelopIt in New York, with the goal of getting more women in web development by actually teaching them how to do it. She inspired me to run a GirlDevelopIt in Sydney, and I still remember those months as some of my favorite down under. In addition to being the force behind GDI, Sara still develops - just yesterday, she wrote an uber-useful Chrome extension that I installed instantly.

    Follow Sara online: Twitter | Google+ | sarajchipps.com

  • Gina Trapani:

    I first knew of Gina for starting lifehacker, a popular blog of tips for using tech and optimizing your digital life (and the biggest source of traffic for my little Profane Game). I then knew her as the author of "The Complete Guide to Google Wave", an attempt to explain how to use Wave to the average joe. I was on the Wave team then, and I knew that was no small feat. And now, I know her as a developer, working on an open-source web app for social media analysis. Blogger, author, coder, speaker - Gina does it all.

    Follow Gina online: Twitter | Google+ | ginatrapani.org

  • Leigh Fonseca:

    I met Leigh just this week, at the WITI Next-Gen Summit, where Leigh and I talked to high school girls about how we got into tech and why we love it. Leigh started off with a history degree, but when she realized she had a thing for analyzing customer data, she started data science departments at Rhapsody and then BookRenter, where she is now. Most companies don't have data scientists nor realize they need one, so Leigh is paving the way for others with her interest. When she's not analyzing data, she's preparing for triathlons. Impressive.

    Follow Leigh online: Twitter | Google+ | dataparty.blogspot.com

  • Kendall Ronzano:

    I also met Kendall this week - she's actually one of the girls that Leigh and I talked to at the conference. She's a high school junior who's already started programming for her robotics team (C++!) and wants to learn more. She's also set a fun challenge for herself: build a house. I hope Kendall represents the next generation of women in tech!

So, who inspires you?

Wednesday, October 5, 2011

User Stats Visualization with HighCharts

For the first few months of EatDifferent's existence, it was only a small set of users -- family and friends -- and half of them were my buddies on the app. But then a food blogger tweeted it, and over the course of a day, there were 10x the number of users -- all strangers. Since I wasn't buddies with the new users and wouldn't see their updates in my stream, I needed a way of understanding who all these users were and how they were using the app

I wanted simple visualizations of my user demographics & usage data, and after a bit of research on what type of chart to use (i.e. not pie charts), I came up with this stacked horizontal bar chart visualization:

All the bars add up to 100%, the bar parts show their value and percentage on hover, and the bar parts are colored according to their value. For example, true is green and red is false, browsers and OSes are colored according to their debuggability (Ghrome is green since that's my browser of choice, guess which one is red?), and numeric values are colored in a monotone gradient. The charts are made using HighCharts, my favorite charting library.

It's nice being able to understand more about my users in a glance. :)

Tuesday, October 4, 2011

Client-Side Error Logging

After setting up my Python code to send server-side errors to my inbox, I wasn't satified. I wanted to know about JavaScript errors, too! So I set up my base template to send JavaScript errors to my server and log those as errors. Now I find out about all errors immediately in my inbox, and I can deploy a fix before it affects users for too long. So far I've found a couple errors this way that otherwise I wouldn't have known about (due to different user behaviors + browsers).

I use this JavaScript for sending errors to a handler on the server, which then logs them as an error using logging.error:

When I tweeted about my solution, I was pointed to a few related projects and techniques:

  • An article with various tips on logging JS errors.
  • jserrlog.appspot.com: A solution hosted on App Engine, where you just drop in the JS and view the logs on their server.
  • Errorception: A startup devoted to "painless javascript error tracking" and will include more cross-browser logging, emails, and web hooks. Sounds promising!

Since deploying my solution, I've discovered that window.onerror doesn't work in all browsers (even some "modern" ones like Android), so if you are looking to catch every error, you should checkout those links to see the workarounds they employ.

Update (2/20/2012): I've updated my function to ignore errors that I know aren't mine, like those generated from 3rd party scripts. I could also update it to just only show errors from my server's JS, but for now I'm interested in what other errors folks encounter. You can see that updated code in this gist.

Friday, September 30, 2011

Pre-Deploy Git Check

Since I'm the only one developing EatDifferent, I've been content to store it in a Dropbox folder and use a local git repository for version control. But I got nervous thinking about what would happen if something went horribly wrong while I was unavailable (like on a plane), and decided I needed a backup collaborator -- someone who could quickly checkout the code and deploy a fix.

I probably could have shared the Dropbox folder with them, but I instead opted for a private Github plan for $7 a month, which lets me share my code repository with my backup collaborator. Plus, I now get to browse my code history and commits via Github's slick online interface.

I often forgot to git commit and push my changes, so I added this check to my Makefile which errors if there are uncommited changes. I run the check everytime I deploy my code to App Engine, to make sure the code always reflects what's deployed.

So far, the workflow seems to work...and now I can fly a plane in peace. ☺

Thursday, September 15, 2011

Sending Errors to Email in App Engine

When my EatDifferent server-side code results in an error or exception, it gets logged in the App Engine dashboard. I was getting anxious wondering if there are new errors in the logs, refreshing the dashboard every few hours, so I decided to make sure all errors get immediately emailed to me and researched how best to do that.

First I checked out the App Engine ereporter module , but it was set to aggregate errors and email reports once a day -- not frequent enough for anxious me.

I then found a developer that wrote loggers to send errors over Channel API, PubNub, and XMPP, with a throttling mechanism built-in to prevent getting spammed when many errors happen at once.

I took his XMPP logger and converted it to send email instead, and set the throttling threshold to 5 minutes instead of 1 second. Now I feel much less anxious! You can grab the code from this gist:

Thursday, September 8, 2011

Switching from jQuery Mobile to Twitter Bootstrap

I've been using jQuery mobile (jQM) to make a mobile-enhanced version of EatDifferent for the past few weeks and though I have much respect for the team behind it, I've grown increasingly frustrated with it. Why?

  1. It typically enhances by adding additional DOM elements to the original elements - which can help in making them easier to use on a mobile device, but it means that whenever you want to tweak the styles of an enhanced element, you need to dig into the DOM and apply CSS overrides at various levels. If the DOM or inner CSS names change in later jQM versions, you may have to update those CSS overrides.
  2. If you dynamically update an enhanced DOM element (like a form input, for example), you often have to tell jQM to force refresh that element, since it needs to redo the added DOM. That means you need jQM-specific JavaScript calls in your code.

I was fine with those issues when I used jQM for an earlier project, but for the EatDifferent app, they are becoming bigger issues because: 1) I'm doing more customization, and 2) I'm doing more dynamic form creation and updating.

And most importantly, I'm trying to re-use my HTML/CSS/JS across both my the desktop web version and mobile app, and I want minimal difference between them - both so users have a consistent user experience across them, and so that I can write the code just once.

So today I scrapped jQM and decided to use just HTML/CSS. And since I suck at making pretty CSS, I'm using Twitter's bootstrap library. It's pure CSS (no JS!), it's simple to use, and it's pretty. It's not specifically designed for mobile, but it works well enough on it and is easy to customize when it doesn't quite work.

Here's what the app looked like using jQuery mobile and the default black theme:

Here's what it looks like using Twitter bootstrap and some basic customization:

As you can see, jQuery mobile does create more mobile-optimized form input interfaces (larger areas for clicking, e.g.), but Twitter bootstrap creates clean CSS that I can easily add my own mobile-optimized CSS on top of when necessary. I'm happy I made the switch.