March 26, 2010

New Projects: IndexBy, TagBuilder, and ProgressiveEnhance

I recently released 3 open source projects via Google Code: eblackwelder. Here they are:


IndexBy
Language: PHP 5+
Usage: Convert database results into arbitrarily nested arrays.
Download: IndexBy v1.0
Documentation: IndexBy wiki
License: MIT License
Target audience: Web-app/database developers


TagBuilder
Language: PHP 5+
Usage: Programmatically compose well-formed HTML fragments.
Download: TagBuilder v1.0
Documentation: TagBuilder wiki
License: MIT License
Target audience: (server-side) web-developers.


ProgressiveEnhance
Language: Javascript
Usage: Helper functions for progressively enhancing widgets
License: MIT License
Target audience: (client-side) web-developers/scripters.
Dependencies: My Library

March 23, 2010

My Library: a new way to Javascript!


My Library is a new, open source Javascript library (published on Google code Jan. 2010) that starts off doing things "the right way". It's not My as in mine, but My as in yours--something you can make your own!

The first (and only) cross-browser Javascript library
Unlike every other Javascript library out there (think: jQuery, Prototype, YUI, script.aculo.us, Dojo, MooTools, qooxdoo, etc.), My Library does no "user-agent sniffing" or "Object inference" (discussed in detail  here). It performs proper feature detection and presents a dynamic API at runtime, which is detected by your application and handled accordingly.

What does that mean? Instead of trying to guess which browser the library someone is using, My Library detects what the browser is capable of--and adapts accordingly "on the fly". (This is called "degrading gracefully".) Instead of "supporting" only a limited number of known web-browsers, My Library plays nicely with any web-browser, even web-browsers that haven't been released, yet! (This is something that the other "sniffing" libraries will never be capable of doing.)

Indeed, one of the My Library slogans is "Write once, do nothing, run anywhere, forever!", purposefully mocking jQuery's "write less, do more" slogan. ;)

Download builder: the smaller the better!
Not only does it offer a dynamic API at runtime, it offers a customizable download builder. Instead of overloading your clients with Kilobytes of Javascript libraries, you only have to download and serve the code your web-application requires. This makes your web-application more responsive at load time and spares the clients with slower download rates and resources (think: smartphones).

Fast!
Using "quasi-standard" industry tests like "SlickSpeed" and "TaskSpeed"....
  • In the latest web-browsers, My Library at least ties the fastest of the other Javascript libraries and CSS selection libraries--and on modern hardware, this difference is negligible. Although the errors some of the other popular libraries throw are not negligible!
  • In older web-browsers, it decisively dominates the competition.
  • In obscure browsers (ever heard of "Green" or "Sleipnir" browsers?), My Library is the only library that doesn't die from execution errors.
And you can try out the tests for yourself.

The down side?
The only down sides I am aware of is a current lack of community support (it's only 3 months old, OK) and that the documentation is at a minimal level. But with a few more months of growth, it should have a set of widget plugins, proper (and expanding) documentation, and a more active community.

So, where do I find it?
The home of My Library is at www.cinsoft.net/mylib.html. Check out the Examples, then head over to the "Builder" and give it a whirl.

Cheers!

March 22, 2010

Anyone can cook

I just watched Ratatouille (again) at my niece's house this past weekend... the theme is "Anyone can cook". (Meaning "Not everyone can become a great artist, but a great artist can come from anywhere.") With that in mind...

Anyone can be a web-developer!
Thanks to free and open source web-development tools, anyone can become a web-developer. I will mention a few of those free tools...

1) Apache Web Server
Tool 1: The Apache web server--actually called httpd (meaning the "HTTP Daemon" (a daemon is a background service)) but is often called "Apache" because it is supported by the Apache Software Foundation.

According to Netcraft, Apache has been the most popular web server since 2006 and currently (as of March 2010) serves over 54% of all websites. It serves 67% of the million busiest sites (the next is Microsoft's IIS at 17.4%). And it's free!

You can find it here: httpd.apache.org.

2) PHP: Hypertext Processor
Tool 2: The PHP scripting language. it currently stands for "PHP: Hypertext Processor". (It used to stand for "Personal Home Page", but the authors thought a recursive acronym was cooler.) By embedding PHP instructions into your HTML web-pages, you can create dynamic websites.

It's hard to tell how "popular" a programming language is, but PHP is pretty popular these days (it currently ranks 3rd on the TIOBE index of all languages).

Find it here: www.php.net

3) MySQL Database Engine
Tool 3: The MySQL database engine (pronounced "my es-queue-el", as opposed to SQL, which is pronounced "sequel"). SQL is a standardized, mathematically-grounded language for managing and querying relational databases. MySQL is an open-source SQL database engine.

Whereas some SQL databases have been around for years (e.g. Oracle started in 1979), MySQL is relatively new (1995) and only really worth talking about as of MySQL 5 (2005), with the addition of the InnoDB storage engine. But it installs on practically everything and has a number of useful (and free) tools. And it's free! (Note: I can't find any usage notes, but MySQL claims that it's the most popular open source database.)

Find MySQL here: www.mysql.com

XAMPP, LAMP, WAMP, MAMP, etc.
So... with Apache, PHP, and MySQL, anyone can develop websites (YMMV). But how long does it take to download, install, configure, and test everything--especially if you're new at this? Because these tools play so nicely together some of the open source community decided to package them together--just to make your life easier. (Although getting something working yourself can be more instructive.)

  • LAMP stands for "Linux, Apache, MySQL, and PHP" (packages depend on your OS)
  • WAMP stands for "Windows, Apache, MySQL, and PHP"
  • MAMP stands for "Mac, Apache, MySQL, and PHP"
  • XAMPP stands for "Any OS, Apache, MySQL, PHP, and Perl"
  • etc. (Wikipedia has a better list of "*AMP" packages here)
Using WAMP to build web-sites on my Windows laptop and upload them to my Linux web-server (running LAMP) means I can choose the cheapest hosting plan (windows vs. linux, etc) and still get the job done. And it's all free!


In my experience: WAMP is fine for Windows machines--it has an installer for configuring MySQL and Apache services; everything is based inside a single folder to keep things clean. XAMPP, however, can be run from a thumb-drive, if need be (see PortableApps.com). In fact, I've been able to run Trac off a thumb-drive (Apache, MySQL, Python, and Subversion) via XAMPP!

February 17, 2010

The Art (and Joys) of Profiling... a real-world example

This article will outline my experiences profiling a Javascript table-sorter widget that I recently developed.

Profiling an application takes practice and a little dedication—but it can be fun, too!  I recently had a wonderful time profiling a new Javascript widget for dynamically sorting HTML tables. I will use my recent experience to provide a few tips to novice profilers (if there be any).

We're running out of plugins here!
The other day, I hunted around for a jQuery plugin to sort raw <table> rows that required a minimum level of code to enable it. I was looking for something that could automatically find HTML tables, detect how to sort the columns, and that had lots of default options.

I found one such plugin here: the jQuery Tablesorter plugin. It works very fast, even on large data-sets; it even has full-text filtering and paging add-ons. Unfortunately, I ran into problems: there are a few usability issues (particularly with the pager plugin) and a lack of real programmatic access to the data. For example, I wasn't able to append or delete rows to the table because the pager didn't recognize them and would immediately discard them when changing the page or changing the sorting column... A new jQuery plugin was definitely called for!!!

Taking a whack at it...
As an intermediate Javascript developer, half of my goal was to see if I could get something to work. Another half of my goal was to make something worthy of re-distribution (to help "get my name out there"). And another half of my goal was to correct the lack of table-sorting plugins (to make the world a better place).

My first step was to take a simple <table> and decorating it with CSS classes so that it looks pretty and has the little "sort-me" images beside the column headers. With jQuery, the jQuery-UI manual, and a nice table-sorting theme to be found here, this was pretty straight-forward. I then added some "click" listeners to the column headers that determined which column should be sorted, and in which direction by looking at the current active/direction classes assigned to the headers (not a big deal for jQuery).

The next big step was to sort the data. I referred back to the original table-sorter plugin for guidance. I saw that they interacted solely with a cache of the original table rows. I ported the cache-construction code. They did some funky eval'ing to create a multi-column sorter, so I wrote my own sort-by-column function (as a call-back to Arrays.sort). I used jQuery's built-in functionality to remove and append table-body rows, like so:

//removes all "tr" children from the tbody DOM element
jQuery(tbody).children().remove(); //I hadn't found jQuery(...).empty(), yet.
...
//appends a single "tr" row to the tbody
jQuery(tbody).append(jQuery(some_html)); //repeated over, and over
...

I fired up the web-browser and tried it out. It worked! I hastily added functionality to programmatically sort, re-sort, filter, and reset the data. Things were looking mighty fine! I noticed that table-sorter had an example with about 1000 rows, just to show off their speed. I decided that was just the thing to test out the budding plugin, so I copied their data (1023 rows, 7 columns) and attached my sorter...

The bad and the ugly... (Step 1 profiling)
On Firefox 3.5 (and a dual-core Centrino), it took about 7 seconds of a frozen browser (I counted) before the data was initially sorted. Maybe a little better to change sort columns, but it still froze the browser. What to do? :(

I'm not familiar with any Javascript profiling tools (I'm sure they're out there), but I am familiar with "alert()"... the poor man's profiler. (Or you could use console.log). I added some benchmarking statements, shamelessly copied from the other plugin's benchmark function: (dual-licensed under MIT and GPL)

//give it a message (String) and a starting time (Date), it will compute and display the time delta

function benchmark(message, startTime) {
    alert(message + ": " + (new Date().getTime() - startTime.getTime()) + "ms"); //or you could log it
}

//used like this:

var startDate = new Date();

... run some code

benchmark("Time to construct my table-sorter", startDate);


To get a better understanding of what was taking so long, I put benchmarking statements around the major methods: building the cache, sorting, replacing the table rows, colourizing the rows (striping), and "activating" the sorted column(s). I got inital numbers something like this:
  • building cache: ~230ms
  • sorting:  2ms
  • replacing rows: ~6200ms
  • colourizing rows: ~180ms
  • activating rows: ~370ms
  • Total time: approx: 7200ms (I skipped other trivial steps).
I was absolutely amazed that it took only 2ms to do the sorting. I was appalled that it took more than 6 seconds to replace some table rows. So, I broke that step down further:
  • removing table rows: 5469ms
  • build+append rows: 896ms
Very interesting results... one jQuery method ($tbody.children().remove()) was taking 75% of the time!

A Better Mouse-trap... (Step 2 profiling)
I did a little bit more homework. I happened upon this wonderful live demo of various ways to append/delete table rows. I found that the DOM interface tbody.removeChild(tbody.firstChild) method worked very quickly. It dropped my time to deconstruct table rows down to ~180ms! We were back in business!

I tried a number of other ideas to speed-up the slowest parts of the code:
  • By concatenating a string-representation of all the table rows and setting the innerHTML property on the tbody, the time to build+append rows dropped from 900ms to 230ms.
  • To remove old row, setting the innerHTML of tbody to empty-string took only 90ms.
  • By iterating over the table rows and using DOM manipulation, dropped the time to activate the sort column from 370ms down to around 100ms (meaning, I add a decorator class to the corresponding cell of each tr).
  • By removing a ":visible" filter in a jQuery chain, I was able to remove 100ms from the time it took to apply row-striping (horizontal zebra-striping).

Lessons to be learned:
With only a small amount of work and some attention to detail, I was able to drop a 7-second script down to around 0.8 seconds. If I had tried to pre-optimize any part of the script, it probably would have been the wrong part (most likely my sorting implementation—which turned out to be fastest code in the whole plugin!).

Instead, I was able to quickly get a working prototype off the ground using jQuery and then—with guidance from various profiling runs—focus my efforts on what needed the most help (it happened to be my over-exuberance for jQuery). As a result, I found that explicitly interating over the <tbody> DOM was light-years faster than the (un-optimized) jQuery calls.

But there were cross-browser complications and further improvements to be made... So stay tuned!

The author is growing rather fond of Javascript, thanks in large part to jQuery. The more he gets to know Javascript, the more he wants to write in Lisp.

February 16, 2010

Announcing...

Natural Parenting
xkcd.com/674/

Turn on mod_deflate!

This article is a quick bit of advice for those developer-turned-web-admins out there.
This article is specifically about the Apache "httpd" web-server, but the same advice applies to other web-servers.

While looking into Javascript compressors (minfiers and packers), I bumped into HTTP compression. I knew about HTTP compression, but it wasn't something I'd really thought about.

After a quick read-up at Wikipedia and after scanning a few HOW-TOs, I checked out the web-server that I maintain at my place of work. What do you know, but it (Ubuntu 9.x + Apache2.2) already came with mod_deflate.c enabled and marginally configured.

According to Danny Vogler's advice, I changed the following:

<IfModule mod_deflate.c>
AddOutputFilterByType DEFLATE text/html text/plain text/xml
</IfModule>

... into this: (modifications in red)

<IfModule mod_deflate.c>
AddOutputFilterByType DEFLATE text/html text/plain text/xml application/javascript application/x-javascript text/css
</IfModule>

The web-server will now attempt to compress Javascript and CSS content-types—if the client's web-browser supports it, of course.


I then turned my browser to an internal reports page, one that uses jQuery, jQuery-UI, and a (custom) jQuery-UI theme. Counting the site's own CSS theming (including media=print stylesheet), there are four stylesheets and four javascript files attached.

With text/html compression already turned on, the whole mess of content came out to 222,745 Bytes (around 218 KB), including pictures. With text/css and application/javascript content-types being compressed, the content came down to 69043 Bytes (67 KB)—only 30% of the original size! ... Yep, it made my day.