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

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)

Truncated! Read the rest by clicking the link below.

Local Django development with Nginx

October 11, 2010
15 comments Django

When doing local Django development with runserver you end up doing some changes, then refreshing in Firefox/Chrome/Safari again and again. Doing this means that all your static resources are probably served via Django. Presumably via django.views.static.serve, right? What's wrong with that? Not much, but we can do better.

So, you serve it via Nginx and let Nginx take care of all static resources. You'll still use Django's own runserver so no need for mod_wsgi, gunicorn or uWSGI. This requires that you have Nginx installed and running on your local development environment. First you need to decide on a fake domain name. For example mylittlepony. Edit your /etc/hosts file by adding this line:


127.0.1.1       mylittlepony

Truncated! Read the rest by clicking the link below.

In jQuery, using the :visible selector can be dangerous

September 14, 2010
0 comments JavaScript

In jQuery, using the :visible selector can be dangerous And by "dangerous" I mean super slow to the point of making your browser shake of over exhaustion.

I have a big fat table where on the left hand side of each row there's a little toggle to open up an initially hidden sub-table. And there are toggles for those sub-tables to open up further sub-tables. It might sound complicated but it works great. The code for each toggle looks something like this:


$('a.toggle-order-on').click(function() {
   var tbody_parent = $(this).parents('tbody');

   $('tr.printdisplay:hidden', tbody_parent).show();
   $('tr.outdoor-marketing:hidden', tbody_parent).show();
   $('tr.digital:hidden', tbody_parent).show();

   // expand the little table too
   $('a.toggle-printdisplay-on', tbody_parent).click();

   var td_parent = $(this).parents('td');
   $(this).hide();
   $('a.toggle-order-off:hidden', td_parent).show();

   return false;
});

Note the heavy use of the super useful :hidden selector which is basically a reversing wrapper on the :visisble selector

What I then needed was a way to open up every single row in the whole table with one click. Here was the code I wrote:


$('a.toggle-order-on:visible').trigger('click');

See? Makes sense does it?

Problem with this was that when the table was big sometimes clicking this would make my otherwise fast browser (Chrome or Firefox) stutter and sometimes stall or at worst the alert pop-up about "a script is slowing this page down" would appear.

So I started the Firebug Profiler and clicked a couple of times and collected some numbers. On average it took 3-4.5 seconds!! and about 20,000-35,000 calls to complete the full expansion. Yikes! About 90% of the time spent by jQuery was on the visisble() function.

Solution: Instead of using the click trigger I simply just called the .show() effect on all things manually without using any :visible or :hidden operators. Here's the new code:


$('tr.printdisplay').show();
$('tr.outdoor-marketing').show();
$('tr.digital').show();
$('tr.printdisplaydetail').show();

$('a.toggle-order-off').show();
$('a.toggle-order-on').hide();

$('a.toggle-printdisplay-off').show();
$('a.toggle-printdisplay-on').hide();

This time, with the profile again, I it took on average 0.2-0.3 seconds and required about 2000-4000 calls. HUGE difference.

So, remember that next time. Don't just re-use working code en mass if it's using a much of :visible or :hidden selectors somewhere in there.

wkhtmltopdf and font size shrinkage

September 10, 2010
0 comments Web development

wkhtmltopdf is by far the best tool available to make PDFs. Yes. I have tried ReportLab and PISA. ReportLab might be more powerful but what you gain in fine-grained control you lose in hours and hours of productivity.

Anyway, I've learned something about font-size shrinkage and using wkhtmltopdf. Basically, if use percentage to change a font size (Arial in this case) you get a PDF where the letters are unevenly spaced between. It took me a while to figure out what the hell was going on until I changed the font-size from 90% to exactly 11px.

font-size: 90% ('font-size:90%'; the spots of red are my highlights of the ugly spacings)

font-size: 11px ('font-size:11px'; not perfect but much better)

So, at first I thought this was the first time wkhtmltopdf has disappointed me but I guess I'll just have to remember not to use percentages and continue to favor wkhtmltopdf as my choice of weapon in the PDF production world.

I just discovered wikiHow

September 8, 2010
0 comments Misc. links

I just discovered wikiHow I can't believe I haven't seen this before. wikiHow is a great site. Just look at this article about how to spice up waffles for example.

Interestingly though, gone are the days of surfing. People don't take what's offered, they take what the search for. However, with wikiHow I'm eager to pop back in, throw a few articles on my Instapaper and then read them later on my Kindle.

Now I'm going to read about How to Be a Slacker Mom. Very relevant.