29 Mar 2012

Generic solutions and specific solutions

From certain points of view, programming is fairly easy.  Most of the common problems have known solutions.  Often, programming is simply applying common solutions to specific problems.

I have a web app whose sole purpose is to create thumbnails of images whose URLs are given.  It took a few seconds for serving each request, so I applied a common solution to the “my program is too slow” problem: caching.  With two levels of caching, I brought down the average response time to around 150ms.  (Caching code is in boldface.)
if PICASA_URL_REGEX.matches(original_url):
  # Resizing Picasa URLs is child's play.
  # All we need is some URL tweaking.
  response.Redirect(resize_picasa(original_url))
  return

if FLICKR_URL_REGEX.matches(original_url):
  original_url = mid_size_flickr_url(original_url)
# local_cache is a simple hash map.
if original_url in local_cache:
  response.Redirect(local_cache[original_url])
  return

thumb_url = memcache.Get(original_url)
if not thumb_url:
  thumb_url = data_store.Get(original_url)
  if not thumb_url:
    image_bytes = http_client.Fetch(original_url)
    thumbnail_bytes = image_resizer.Resize(image_bytes)
    thumb_url = data_store.Store(original_url, thumbnail_bytes)
  memcache.Set(original_url, thumb_url)
local_cache[original_url] = thumb_url
response.Redirect(thumb_url)
Though 150ms isn’t too bad, I had been wanting to optimise this further for several months.  Only I couldn’t figure out how.  Yesterday, something dawned on me: I was using the caches all wrongly!  I was unnecessarily repeating a bunch of string operations and regular expression searches for every request before even touching the caches.  A better approach would be to hit the cache as early as possible.  I changed the algorithm to be like:
# response_cache is a a simple hash map.
if request.query_string in response_cache:
  response.Redirect(response_cache[request.query_string])
  return

if PICASA_URL_REGEX.matches(original_url):
  # Resizing Picasa URLs is child's play.
  # All we need is some URL tweaking.
  thumb_url = resize_picasa(original_url)
  response_cache[request.query_string] = thumb_url
  response.Redirect(thumb_url)
  return

if FLICKR_URL_REGEX.matches(original_url):
  original_url = mid_size_flickr_url(original_url)
thumb_url = memcache.Get(original_url)
if not thumb_url:
  thumb_url = data_store.Get(original_url)
  if not thumb_url:
    image_bytes = http_client.Fetch(original_url)
    thumbnail_bytes = image_resizer.Resize(image_bytes)
    thumb_url = data_store.Store(original_url, thumbnail_bytes)
  memcache.Set(original_url, thumb_url)
response_cache[request.query_string] = thumb_url
response.Redirect(thumb_url)
Immediately the average response time came down to around 40ms.  Plus, it’s not unusual now to find requests that get served in less than 5ms!

Algorithmic difference between the two code snippets is subtle, yet the performance difference is substantial.  What makes programming interesting is the fact that knowing the solution is not always sufficient.  Ability to adapt a generic solution to specific problems is one of the things that makes one a good programmer.

Appendix
Sample logs before code change:
Sample HTTP request log before code change
After code change:
Sample HTTP request log after code change

24 Mar 2012

Disable automatic updates for your crucial Android apps

Android Market has a per-app preference for automatically updating the app when a newer version is available.  It’s convenient, and is usually a good security measure to keep this option enabled for all your apps.  However, if there’s an app that’s “crucial” — i.e., if you cannot afford to have this app not running, you may want to disable automatic updates for that app.

I use Sleep as Android to track my sleep.  I turned on sleep tracking last night and went to sleep.  Woke up this morning and saw that the Sleep app wasn’t running.  Instead there was a notification from Android Market that it had updated the Sleep app overnight.  The app got killed when it was updated and was never started again.  Had it been a weekday, I would have missed my wake up alarm and could have slept longer than usual.

I have now disabled automatic updates for this app.  Disabling automatic update for this app would require that I manually update it every time there’s a new version.  It’s a pain, but it’s much better than oversleeping and being late to work.

16 Mar 2012

Generating data URIs in Go language

I wrote FotoBlogr to make blogging easier for a friend.  The main goal was to make it easy to add Flickr photos to Blogger blogs.  As time went by, I added support for adding recipe microformats to blog posts, since that’s what she primarily posts.

The app is fairly simple, it’s just one HTML file; but most of the UI is constructed at client side using JavaScript.  As soon as the page loads, it’d send out a number of AJAX requests to fetch the list of blogs, list of Flickr photos, any saved draft post, etc.  Adding features always implied adding more images (i.e. icons) to the interface.

At one point, rendering the UI needed more than 40 HTTP requests, all to the same domain.  The app that used to load instantly started taking a second or two to fully load.  I wanted to bring back the old speed while retaining all existing features.

I have seen data URIs generated by frameworks like Google Web Toolkit.  When you replace an <img src='/img/my-icon.png'> with something <img src='data:image/png;base64;image-data-inline'>, it cuts off one HTTP request from the load time[1].  I decided this is what I’d do, and this post is to document how I did it.

FotoBlogr is written using Go language and runs on Google App Engine.  One possible implementation is I can run my HTML files through some tool that will replace all (or selected) images with inline image data.  It could work, but I wanted something easier.  This is when I found out how powerful the Go language is.

Generating data URIs for images is literally one line of code:
func dataUrl(data []byte, contentType string) string {
  return fmt.Sprintf("data:%s;base64,%s",
      contentType, base64.StdEncoding.EncodeToString(data))
}
Now I have to connect this code with my HTML.  Enter Go’s template package.  Go’s templates can call functions[2].  If I can make this function callable from my templates, it’s job done.  I’ll first show you how this is used and then the implementation.

Instead of instantiating the template by parsing the file directly, now I need to call a helper function.  I.e., I had to replace calls like
  tmpl := template.Must(template.ParseFile("tmpl/home.html"))
with
  tmpl := gaesupport.NewTemplate("tmpl/home.html")
(gaesupport is the name of the package where I have some App Engine support code.)

To request inlining of images, I replaced HTML like
  <img src='/img/plus.png' width='16' height='16'>
with
  <img src='{{inline "img/plus.png" "image/png"}}' width='16' height='16'>
That’s all a caller has to.  It’s hardly any extra work, so I am happy with this solution.  Implementation of gaesupport.NewTemplate function is straightforward too.  It instantiates a new template.Template object, adds the inline function to its context so templates can call it, and then parses the template file as usual.  Here’s the full code:
package mgae

import (
  "encoding/base64"
  "fmt"
  "io/ioutil"
  "os"
  "template"
)

// Encodes data into a 'data:' URI specified at
// https://developer.mozilla.org/en/data_URIs.
func dataUrl(data []byte, contentType string) string {
  return fmt.Sprintf("data:%s;base64,%s",
      contentType, base64.StdEncoding.EncodeToString(data))
}

func inline(fileName, contentType string) (uri string, err os.Error) {
  data, err := ioutil.ReadFile(fileName)
  if err != nil {
    return "", err
  }
  return dataUrl(data, contentType), nil
}

func NewTemplate(fileName string) *template.Template {
  funcs := template.FuncMap(map[string]interface{} {
    "inline": inline,
  })

  tmpl := template.New(fileName)
  tmpl.Funcs(funcs)
  template.Must(tmpl.ParseFile(fileName))
  return tmpl
}
[1] On the other hand, it bloats up your bootstrap HTML and makes it impossible for clients to cache your image.  FotoBlogr is tiny; even with all image inline, the bootstrap is only about 70kB, so this would work for me.
[2] I’ll be honest and admit that I first thought “wow, that’s like PHP!” when I first heard it.  But it’s actually cleaner than that.  Templates can only call functions that you explicitly export.

9 Mar 2012

When to get your eyes tested: before work or after?

Over the past few months, I have been observing something.  At mornings, when I enter work, my vision is blurred.  This usually means I need to change my glasses because the power has changed.  However, when I leave work at evenings, my eyesight would be like normal... as if I am wearing the right glasses.

I asked my optometrist today about this and he said it’s because my eye muscles are a bit too tired to squint enough at mornings.  As the day goes by, the body gets more energy and the eyes squint more easily.  What this means is I should always schedule my eye tests at mornings, when my eyes are more natural.

(All this while, I’d been scheduling the tests at evenings, after work.  And almost always I was a bit dissatisfied with new glasses.  This is probably the reason.)

3 Mar 2012

Being loved

Not being loved by anyone is probably better than being aggressively loved by people we can't like.

Scared and confused

I have an internal conflict.  I have committed to do something — something pretty big — that I don’t like one bit.  Every time I am reminded of it, I become afraid and angry.  Ain’t a great feeling to be angry and upset, so I changed my world slightly so that I can hide that terrible thing from my sight... and I can pretend as if everything is just normal.

I wonder now, what’s the path of lesser pain?  Postponing the real problem until last minute, or facing it today and finding a solution sooner?  The latter definitely sounds more honest... maybe that’s the better of the two?

Statelessness

Stateless is better than stateful.  Be it the objects you define in your computer programs, or how you live your life.  Statelessness is good.