Javascript tip: nifty use of the console.log function in Firebug

November 7, 2010
2 comments JavaScript

A classic blunder in Javascript client side apps is heavy use of the incredibly useful Firebug feature that is console.log() and then forgetting to remove any such debugging and thus causing Javascript errors for people without Firebug. To remedy this use this little nifty function:


function log() {
  if (window.console && window.console.log)
  for (var i = 0, l = arguments.length; i < l; i++)
    console.log(arguments[i]);
}

That way you can do plenty of debugging and if you accidentally leave a logging line in your code it won't break anything even if they don't have Firebug installed/enabled. Also you can easily "annotate" your debugging by writing two things in one line. Like this:


function foo(bar) {
   log("bar is:", bar);
   return bar * 2;
}

In Django, how much faster is it to aggregate?

October 27, 2010
5 comments Django

Being able to do aggregate functions with Django's QuerySet API is really useful. Not because it's difficult to write your own loop but because the summation is then done inside the SQL database. I had this piece of code:


t = Decimal('0')
for each in some_queryset:
   t += each.cost

Which can be rewritten like this instead:


t = qs.aggregate(Sum('cost'))['cost__sum']

For my 6,000+ records in the database the first one takes about 0.7 seconds. The aggregate takes 0.02 seconds. Blimey! That's over 30 fold difference in speed for practically the same thing.

Granted, when doing the loop you can do some other stuff such as counting or additional function calls but that difference is quite significant. In my current application those 0.7 seconds isn't really a problem but it quickly becomes when it has to be done over and over for multiple sets.

How I made my MongoDB based web app 10 times faster

October 21, 2010
1 comment Python, MongoDB

MongoKit is a Python wrapper on top of pymongo that adds structure and validation and some other bits and pieces. It's like an ORM but not for an SQL database but for a document store like MongoDB. It's a great piece of code because it's thin. It's very careful not to molly cuddle you and your access to the source. What I discovered was that I was doing an advanced query and with the results they we instantiated as class instances and later turned into JSON for the HTTP response. Bad idea. I don't need them to be objects really so with MongoKit it's possible to go straight to the source and that's what I did.

With few very simple changes I managed to make my restful API app almost 10 times faster!!

Read the whole story here

Why I gave up on JQuery UI's autocomplete

October 20, 2010
3 comments JavaScript

I was happily using Jörn Zaefferer's jQuery autocomplete plugin but then I found out that it had been deprecated and I should instead use the jQuery UI's autocomplete plugin instead.

After "upgrading" I started getting suspicious. Is it actually worse than the old one?

First, about the CSS. If you're not already loading the jQuery CSS you would have to add an extra 21,000 bytes file (which loads 80Kb of images) as opposed to the old jquery.autocomplete.css which was only 810 bytes.

Secondly, the new jQuery UI Autocomplete plugin didn't support any nice highlighting so you have to write your own and it can quickly get ugly. I wrote one myself and it gets nasty and you have to do your own escaping.

Thirdly, if you just need the autocomplete you'll also need UI core, UI position and UI widget. The minified file weighs in on 19Kb. The packed jquery.autocomplete.pack.js weighs in on just 8Kb.

Fourthly, speed. The jQuery UI Autocomplete feels more sluggish in loading and rendering. Granted, in my work I often have Firebug switch on but just generally it feels slower when using. Perhaps I've made it extra slow with my hackish attempt to make it highlight.

But... Although the list of options available in the old Autocomplete the number of options available in the new jQuery UI Autocomplete seems pretty nifty too. You mileage will vary. Another benefit of the jQuery UI Autocomplete is that it now seems the more maintained project. I don't see a lot of activity but at least it doesn't say "Deprecated" like it does on the old Autocomplete.

Nasty JavaScript wart (or rather, don't take shortcuts)

October 18, 2010
0 comments JavaScript

I had a piece of code that looked like this:


function add_to_form(f, all_day) {
  console.log(all_day);
  if (all_day)
    $('input[name="all_day"]', f).val('1');
  else;
    $('input[name="all_day"]', f).val('');
  console.log($('input[name="all_day"]', f).val(''));
  return f; 
}

When I ran it, the console output was this:


true
(an empty string)

What had happened was that I had accidentally put a semi-colon after the else statement. Accidentally as in stumbled on the keyboard. I didn't spot it because semi-colons are so common in JavaScript that you sort of go blind to them.

The wart was that it didn't cause a syntax error. IMHO it should have because you'd expect there to always be something happening after the else.

So instead of using the shortcut notation for if statements I've decided to write it out in full instead:


function add_to_form(f, all_day) {
  if (all_day) {
     $('input[name="all_day"]', f).val('1');
  } else {
     $('input[name="all_day"]', f).val('');
  }
  return f; 
}

Optimizers like Google Closure will do a much better job optimizing the code than I ever will anyway.

My tricks for using AsyncHTTPClient in Tornado

October 13, 2010
1 comment Python, Tornado

I've been doing more and more web development with Tornado recently. It's got an awesome class for running client HTTP calls in your integration tests. To run a normal GET it looks something like this:


from tornado.testing import AsyncHTTPTestCase
class ApplicationTestCase(AsyncHTTPTestCase):
   def get_app(self):
       return app.Application(database_name='test', xsrf_cookies=False)

   def test_homepage(self):
       url = '/'
       self.http_client.fetch(self.get_url(url), self.stop)
       response = self.wait()
       self.assertTrue('Click here to login' in response.body)

Now, to run a POST request you can use the same client. It looks something like this:


   def test_post_entry(self):
       url = '/entries'
       data = dict(comment='Test comment')
       from urllib import urlencode
       self.http_client.fetch(self.get_url(url), self.stop, 
                              method="POST",
                              data=urlencode(data))
       response = self.wait()
       self.assertEqual(response.code, 302)

That's fine but it gets a bit verbose after a while. So instead I've added this little cute mixin class:


from urllib import urlencode

class HTTPClientMixin(object):

   def get(self, url, data=None, headers=None):
       if data is not None:
           if isinstance(data, dict):
               data = urlencode(data)
           if '?' in url:
               url += '&amp;%s' % data
           else:
               url += '?%s' % data
       return self._fetch(url, 'GET', headers=headers)

   def post(self, url, data, headers=None):
       if data is not None:
           if isinstance(data, dict):
               data = urlencode(data)
       return self._fetch(url, 'POST', data, headers)

   def _fetch(self, url, method, data=None, headers=None):
       self.http_client.fetch(self.get_url(url), self.stop, method=method,
                              body=data, headers=headers)
       return self.wait()

Now you can easily write some brief and neat tests:


class ApplicationTestCase(AsyncHTTPTestCase, HTTPClientMixin):
   def get_app(self):
       return app.Application(database_name='test', xsrf_cookies=False)

   def test_homepage(self):
       response = self.get('/')
       self.assertTrue('Click here to login' in response.body)

   def test_post_entry(self):
       # rendering the homepage creates a user and sets a cookie
       response = self.get('/')

       user_id_cookie = re.findall('user_id=([\w\|]+);', 
                                 response.headers['Set-Cookie'])[0]
       cookie = 'user_id=%s;' % user_id_cookie
       import base64
       guid = base64.b64decode(user_id_cookie.split('|')[0])
       self.assertEqual(db.users.User.find(
           {'_id':ObjectId(user_id_cookie)}).count(), 1)

       data = dict(comment='Test comment')
       response = self.post('/entries', data, headers={'Cookie': cookie})
       self.assertEqual(response.code, 302)
       self.assertTrue('/thanks' in response.headers['Location'])

So far it's just a neat wrapper to save me some typing and it makes the actual tests look a lot neater. I haven't tested this in anger yet and there might be several interesting corner cases surrounding headers and POST data and what not. Hopefully people can chip in and share ideas on this snippet and perhaps I can fork this into Tornado's core