The seven rules of unobtrusive JavaScript

Christian Decker wrote this terribly early in the morning:
Christian Heilmann has written a great article about why Unobtrusive JavaScript is the way to go and what the best practices are. I strongly recommend that you head over and read it through. For me the most important points are:
  • You don’t expect JavaScript to be available but make it a nice-to-have rather than a dependency: definitely true as JavaScript should be an enhancement rather than the show itself.
  • You expect other scripts to try to interfere with your functionality and keep the scope of your scripts as secure as possible: true, that’s one of my main criticisms about JavaScript. Not having clean separation seems a big step backwards in evolution.
  • Traversing the DOM is expensive and can be slow, that is why it is a good idea to leave it to a technology that is already in use in browsers. I like to spray hooks on the finished HTML when I need to have simple ways to access DOM-elements. Also I really like caching elements that I searched earlier in variables so I don’t have to search for them again.
  • Using CSS to do manipulation on many elements at once without having to search for the elements (section 3): this is really a great idea, new to me, but I’m sure it’ll come in handy.
  • A really important part of unobtrusive JavaScript is to understand how browsers work (and especially how browsers fail) and what users expect to happen. It is easy to go overboard with JavaScript and create a completely different interface with it. Drag and Drop interfaces, collapsible sections, scrollbars and sliders can all be created with JavaScript, but there is much more to those than just the technical implementation. Agreed! Don’t overdo it, or the users will find it hard to use.
  • The other thing to remember is that you can stop events from being reported to parent elements and you can override the default action HTML elements like links have. However, sometimes this is not a good idea, as browsers apply them for a reason. An example would be links pointing to in-page targets. Allowing for them to be followed makes sure that users can bookmark the state of your script. Oh how many times have I seen <a href=”#” onclick=”…”> to respond to an event. Don’t do it, please.
  • Wrapping functionality in objects provides namespaces and isolation of your code. Better yet: you can define public interfaces! (section 6)
So thank, you very much, Christian, for this article, let’s hope many developers start applying your tips, because they make the world a better place. I know I will :)

Simple PHP Object Persistence

Christian Decker wrote this mid-afternoon:

A while back I’ve been working on some PHP Projects that required me to create an abstraction layer for my objects. It should be easy to use it and it should be very short as I wanted to concentrate on the real program and not the repetitive work, which persistence still is with PHP. So I wrote my own little Database wrapper with basic functionality making it as lightweight as possible. The next step was modelling a BaseVO (Base Virtual Object) that the other would inherit from. This meant implementing a way to retrieve both many-to-one and one-to-many relations. So let’s get started with the code:

BaseVO.class.php

First of all let’s define the common variables that we will need in each and every class:

  var $table = null;
  var $className = __CLASS__;
  var $id = null;
The $table will tell us what table the instances of this type will be saved in, the $className will tell us what type of class we are working on (more on this later) and the $id should be pretty obvious :D While $id can be left as is in this class, $className and $table will have to be set in every descending class.

Next we need a way to retrieve the object from the database:

  /**
  * Loads an entry given it's id.
 */
  function load($id){
    global $db;
    $this->loadFromArray($db->queryArray("SELECT * FROM ".$this->table." WHERE id='".$id."';"));
  }
 
 /**
  * Loads the object from an array, possibly from an SQL-ResultSet.
  */
  function loadFromArray($arr){
    if(count($arr)&lt;2)
      return;
    foreach($arr as $k =>; $v){
      $this->$k = $v;
    }
  }
As you can see all the magic is in loadFromArray which assigns every value from the resultset to the corresponding variable in the object. load is simply there to make it easy to load the object without a preexisting resultset. Why did I choose to do it this way? Because, as you’ll see later, I will often have ResultSets of more than one row that have to be transformed into an object, and executing a query for each and every one of them is not practical. The idea is just to get a whole bunch of rows and then map them to objects. SQL is our friend remember? :)

Now that we can load the objects from the database, what would be more obvious than trying to save them back to the Database? Here you go:

  function save(){
  	global $db;
    // Get the fields.
	$rs =& mysql_query("DESCRIBE ".$this->table.";");
	while($t = mysql_fetch_assoc($rs)){
      $fields[$t["Field"]] = $this->$t["Field"];
	}
	$db->saveArray($this->table,$fields);
  }
Uhm, not much to see here, sorry. To understand this we’ll have to come back later when discussing the Database-Wrapper. For now just remember that all this does is filter out all the object variables that are not in the corresponding table, as MySQL will return an error when trying to set a variable that is not also in the table. Notice that this seems to be working only with MySQL, since most others don’t understand the DESCRIBE query

Anyway let’s move on to relations. First there is the many-to-one relation which means that the table has a foreign key pointing to another table. This is quite easy to implement, but I decided to give it an extra feature: caching. Let’s see how it’s done:

  function setForeign($className,$key,$value){
  	$cacheName = "_".$key;
  	if(is_numeric($value)){
	  $this->$key =& $value;
	  $this->$cacheName = null;
	}else{
	  $this->$key = $value->id;
	  $this->$cacheName =& $value;
	}
  }
 
  function getForeign($className,$key){
  	$cacheName = "_".$key;
  	if(empty($this->$cacheName)){
  	  $o =& new $className();
	  $o->load($this->$key);
	  $this->$cacheName =& $o;
  	}
	return $this->$cacheName;
  }
This may look a bit tricky but it isn’t. getForeign take a $className that will be used to create the instance of the object we are trying to get, if it has not yet been cached, and it gets a $key, this is mainly the name of the variable inside the current object. It then construct the $cacheName which will be used to access the cached version inside this object and if the object has not yet been cached it retrieves it from the database, using the load function described above.
setForeign works in a similar fashion, but unsets the cache if the passed value is an id and not an instance of the object.

Ok, we’re almoset done with the BaseVO, last thing we have to look at is getMany which represents the one-to-many relation:

  function &getMany($className,$options){
  	global $db;
  	$data =& $db->queryAllArray("SELECT * FROM ".(empty($options['table'])?$className."s":$options['table'])." WHERE ".(empty($options['foreign'])?$this->className:$options['foreign'])."='".$this->id."';");
	$res = array();
	foreach($data as $d){
		$o =& new $className();
		$o->loadFromArray($d);
		$res[]=& $o;
	}
	return $res;
  }
This code is pretty straightforward as it just gets a bunch of rows that have the foreign key set to the current objects id (the usual way to do this in relational mapping), and then creates object instances from them. The new thing is that now we have an options argument which is supposed to be an array containing optional variables such as table and foreign that will tell us which table to use and what column in that is to use as foreign key. That’s about it for the BaseVO class, later I’ll show an example on how to use it.

Database.class.php

As this is simply a wrapper to the mysql-functions I’ll just post it here and comment only the saveArray function.

< ?php
/**
 *  BaseVO, Basic Virtual Object, abstraction for object persistence.
 *  Copyright (C) 2007 Christian Decker
 *
 *  @author Christian Decker <decker.christian@gmail.com>
 *
 *  This program is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation, either version 3 of the License, or
 *  (at your option) any later version.
 *  
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program.  If not, see <http ://www.gnu.org/licenses/>.
 */
 
class Database {
	
	var $fd = null;
	
	function Database($host, $username, $password, $dbname){
		$this->fd =& mysql_pconnect($host, $username, $password) or die(mysql_error());
		mysql_select_db($dbname,$this->fd) or die(mysql_error());
	}
	
	function close(){
		return mysql_close($this->fd);
	}
	
	function &query($sql){
		print($sql."\n");
		$rs =& mysql_query($sql) or die(mysql_error());
		return $rs;
	}
	
	function queryArray($sql){
		return mysql_fetch_assoc($this->query($sql));
	}
	
	function exec($sql){
		$this->query($sql);
	}
	
	/**
	 * @return bool - Was the saved array new or did it matched an existing one?
	 */
	function saveArray($table, $arr){
		$atoms = array();
		foreach($arr as $k => $v){
			$atoms[] = $k."='".$v."'";
		}
		$sql = "";
		$new = !$arr['id'] || $arr['id'] == null;
		if($new){
			// INSERT
			unset($arr['id']);
			$sql = "INSERT INTO ".$table." SET ".implode(',',$atoms).";";
		}else{
			// UPDATE
			$sql = "UPDATE ".$table." SET ".implode(',',$atoms)." WHERE id='".$arr['id']."';";
		}
		$this->exec($sql);
		return $new?mysql_insert_id():null;
	}
	
	function &queryAllArray($sql){
	  $res = array();
	  $rs =& $this->query($sql);
	  while($t = mysql_fetch_assoc($rs))
	  	$res[] = $t;
	  return $res;
	}
}
?>

saveArray takes an array of key-value-pairs and saves it into the table. If the id is not set it inserts a new row, otherwise the existing row is updated.

Example

As the above makes no sense at all by itself here comes a bit of code I’m currently working on that uses it. First is a User-class that is used to represent the sites users. A user has many bank accounts:

require_once('BaseVO.class.php');
require_once('Account.class.php');
 
class User extends BaseVO {
  var $username = null;
  var $password = null;
  var $email = null;
  var $accounts = null;
 
  var $table = "users";
  var $className = "User";
 
  function getAccounts(){
  	return $this->getMany("Account",array('table' => 'accounts','foreign' => 'owner'));
  }
}

This uses the getMany-function to retrieve all the accounts a user may have. Let’s see these accounts:

require_once('BaseVO.class.php');
require_once('User.class.php');
require_once('Entry.class.php');
 
class Account extends BaseVO {
  var $owner = null;
  var $name = null;
 
  // Cached items
  var $_owner = null;
 
  var $table = "accounts";
  var $className = "Account";
 
  function setOwner($user){
  	return $this->setForeign("User","owner",$user);
  }
 
  function getOwner(){
  	return $this->getForeign("User","owner");
  }
 
  function getEntries(){
  	return $this->getMany("Entry",array('table' => 'entries'));
  }
}

Besides the normal variable and function declaration there are the functions that rely on setForeign, getForeign and getMany to work on the related objects. Pretty simple, huh?,
Now to complete the relations I’ll just put the Entry class too, but by now you should be able to write it yourself :)

require_once('BaseVO.class.php');
require_once('User.class.php');
 
class Entry extends BaseVO {
  var $account = null;
  var $amount = 0;
  var $description = '';
 
  // Cached items
  var $_account = null;
 
  var $table = "entries";
  var $className = __CLASS__;
 
  function setAccount($account){
  	$this->setForeign("Account","account",$account);
  }
  
  function getAccount(){
  	return $this->getForeign("Account","account");
  }
}

Ok, that’s it for now. Any feedback is very welcome :D
And for all of those that don’t want to reconstruct my files using the above here’s all the code in their files:

There is a worldwide significance of microsoft certification exams which give the training in the practical manner. The apprentice knowledge about network design is provided by ccda, Cisco Certified Design Associate which is the best exams to give perfect training. The secuirity+ certification exams provide knowledge how to secure all databases and networking systems successfully. The exams of ccna are designed to assess the inherent talents of technicians and system administrators. The itil training provides technical services for all IT organizations to establish infrastructures. The mcdba certification exams are very valuable for the Database Administrators, Network Technicians and Technical Support Specialists. There is great importance of mcse certification training for IT engineers and system analysts.

Google adds JSON interfaces

Christian Decker wrote this mid-afternoon:
Great news for all the Google-Addicts: the GData group has just added JSON interfaces for their services! From the official post:
For those of you who have been trying to build client-side GData mashups but have been thwarted by the same-origin policy, we have some good news for you: you can now get public Base, Blogger, and Calendar feeds as JSON! This means that you can start displaying GData in your web page with a little JavaScript.
In other words it is now possible to define a callback function and simply add a script-tag to your page, and the browser will go and fetch the data, that will then be handled by that function. No need for the server to proxy the data through, eliminating the need of complex caching mechanisms, just fetch the data from the source :)
 function handleJson(json) {   alert("The title of the feed is: " + json.feed.title.$t); }
It’s as simple as it gets. Being the browser the one who fetches the data greatly improves speed and reduces bandwidth for the originating server. Supported Services for now are: but I’m sure more will follow soon :DJust take a look at the official post for more information.

Keeping up with the rest of the world

Christian Decker wrote this in the early evening:
It has become very busy lately and I couldn’t keep up with all the new stuff that was pubblished during these last few days, so, once again I have to do a quick roundup of what hapened and most of all, what’s worth reading :) To start things off I would recommend taking a look at the (lenghty) article of Andy Bakun about Race conditions with Ajax and PHP sessions, which focuses on the downside of doing things asynchronously, namely synchronization issues on both sides of the wire. I remember a post some time back that discussed exactly the other way round (synchronization problems on the client) with suggest boxes, the problem was that sometimes when you haven’t entered a long string yet the response would take really long to complete (because of the sheer amount of data) while shorter responses would take much shorter, thus it might happen that the slower (older) response completes after the shorter (younger) overwriting the result. Andy discusses in depth the issues you might encounter on the server side. GWT on the other side has got some new stuff: And for all those of us who hate having to load and reload static things over and over again from the server, here’s JSOC (JavaScript Object Cache):
The JSOC framework is a a pluggable, extensible, open source client-side caching framework for Web 2.0 applications. JSOC offers Web developers a straightforward way to perform common caching techniques (add, replace, remove, flush, etc.) inside any JavaScript-enabled browser. Since JSOC is a standalone JavaScript module, incorporating JSOC into a Web development project is a matter of including a script reference, and working with common caching methods. Low-level methods are contained in the JSOC JavaScript module so that developers can focus on the Web development task at hand.
Fancy some nice effects for your application? Then take a look at the JavaScript Particle Engine by Jason Harwig (the post includes a fully functional version of the code). It’s cool, but I simply can’t see where it might be usefull, so until somebod proves me wrong I’ll just put it into the “Proof-of-Concept” drawer :D Also there were plenty of releases: Ok I think this should be enough for now, I’ll cover the rest in some more detail later :)

Optimizing Page Load Time

Christian Decker wrote this mid-afternoon:
Aaron Hopkins of Google has released an article on Optimizing Page Load Time which came out of his experience optimizing page load times for a high-profile Ajax application. Clearly Google developers are along the best known ones in the Web 2.0 movement and the tips Aaron gives might just squeeze out the last few milliseconds from your application and improve the user experience. He makes a really extensive discussion on both problem sources and their solutions:
  • Turn on HTTP keepalives for external objects. Otherwise you add an extra round-trip for every HTTP request. If you are worried about hitting global server connection limits, set the keepalive timeout to something short, like 5-10 seconds. Also look into serving your static content from a different webserver than your dynamic content. Having thousands of connections open to a stripped down static file webserver can happen in like 10 megs of RAM total, whereas your main webserver might easily eat 10 megs of RAM per connection.

  • Load fewer external objects. Figure out how to globally reference the same one or two javascript files and one or two external stylesheets instead of many; try preprocessing them when you publish them. If your UI uses dozens of tiny GIFs all over the place, consider switching to CSS, which tends to not need so many of these.

  • If your users regularly load a dozen or more uncached or uncacheable objects per page, consider evenly spreading those objects over four hostnames. This usually means your users can have 4x as many outstanding connections to you. Without HTTP pipelining, this results in their average latency dropping to about 1/4 of what it was before.

    When you generate a page, evenly spreading your images over four hostnames is most easily done with a hash function, like MD5. Rather than having all <img> tags load objects from http://static.example.com/, create four hostnames (e.g. static0.example.com, static1.example.com, static2.example.com, static3.example.com) and use two bits from an MD5 of the image path to choose which of the four hosts you reference in the <img> tag. Make sure all pages consistently reference the same hostname for the same image URL, or you’ll end up defeating caching.

    Beware that each additional hostname adds the overhead of an extra DNS lookup and an extra TCP three-way handshake. If your users have pipelining enabled or a given page loads fewer than around a dozen objects, they will see no benefit from the increased concurrency and the site may actually load more slowly. The benefits only become apparent on pages with larger numbers of objects. Be sure to measure the difference seen by your users if you implement this.

  • Possibly the best thing you can do to speed up pages for repeat visitors is to allow static images, stylesheets, and javascript to be unconditionally cached by the browser. This won’t help the first page load for a new user, but can substantially speed up subsequent ones.

    Set an Expires header on everything you can, with a date days or even months into the future. This tells the browser it is okay to not revalidate on every request, which can add latency of at least one round-trip per object per page load for no reason.

    Instead of relying on the browser to revalidate its cache, if you change an object, change its URL. One simple way to do this for static objects if you have staged pushes is to have the push process create a new directory named by the build number, and teach your site to always reference objects out of the current build’s base URL. (Instead of <img src=”http://example.com/logo.gif”> you’d use <img src=”http://example.com/build/1234/logo.gif”>. When you do another build next week, all references change to <img src=”http://example.com/build/1235/logo.gif”>.) This also nicely solves problems with browsers sometimes caching things longer than they should – since the URL changed, they think it is a completely different object.

    If you conditionally gzip HTML, javascript, or CSS, you probably want to add a “Cache-Control: private” if you set an Expires header. This will prevent problems with caching by proxies that won’t understand that your gzipped content can’t be served to everyone. (The Vary header was designed to do this more elegantly, but you can’t use it because of IE brokenness.)

    For anything where you always serve the exact same content when given the same URL (e.g. static images), add “Cache-Control: public” to give proxies explicit permission to cache the result and serve it to different users. If a local cache has the content, it is likely to have much less latency than you; why not let it serve your static objects if it can?

    Avoid the use of query params in image URLs, etc. At least the Squid cache refuses to cache any URL containing a question mark by default. I’ve heard rumors that other things won’t cache those URLs at all, but I don’t have more information.

  • On pages where your users are often sent the exact same content over and over, such as your home page or RSS feeds, implementing conditional GETs can substantially improve response time and save server load and bandwidth in cases where the page hasn’t changed.

    When serving a static files (including HTML) off of disk, most webservers will generate Last-Modified and/or ETag reply headers for you and make use of the corresponding If-Modified-Since and/or If-None-Match mechanisms on requests. But as soon as you add server-side includes, dynamic templating, or have code generating your content as it is served, you are usually on your own to implement these.

    The idea is pretty simple: When you generate a page, you give the browser a little extra information about exactly what was on the page you sent. When the browser asks for the same page again, it gives you this information back. If it matches what you were going to send, you know that the browser already has a copy and send a much smaller 304 (Not Modified) reply instead of the contents of the page again. And if you are clever about what information you include in an ETag, you can usually skip the most expensive database queries that would’ve gone into generating the page.

  • Minimize HTTP request size. Often cookies are set domain-wide, which means they are also unnecessarily sent by the browser with every image request from within that domain. What might’ve been a 400 byte request for an image could easily turn into 1000 bytes or more once you add the cookie headers. If you have a lot of uncached or uncacheable objects per page and big, domain-wide cookies, consider using a separate domain to host static content, and be sure to never set any cookies in it.

  • Minimize HTTP response size by enabling gzip compression for HTML and XML for browsers that support it. For example, the 17k document you are reading takes 90ms of the full downstream bandwidth of a user on 1.5Mbit DSL. Or it will take 37ms when compressed to 6.8k. That’s 53ms off of the full page load time for a simple change. If your HTML is bigger and more redundant, you’ll see an even greater improvement.

    If you are brave, you could also try to figure out which set of browsers will handle compressed Javascript properly. (Hint: IE4 through IE6 asks for its javascript compressed, then breaks badly if you send it that way.) Or look into Javascript obfuscators that strip out whitespace, comments, etc and usually get it down to 1/3 to 1/2 its original size.

  • Consider locating your small objects (or a mirror or cache of them) closer to your users in terms of network latency. For larger sites with a global reach, either use a commercial Content Delivery Network, or add a colo within 50ms of 80% of your users and use one of the many available methods for routing user requests to your colo nearest them.

  • Regularly use your site from a realistic net connection. Convincing the web developers on my project to use a “slow proxy” that simulates bad DSL in New Zealand (768Kbit down, 128Kbit up, 250ms RTT, 1% packet loss) rather than the gig ethernet a few milliseconds from the servers in the U.S. was a huge win. We found and fixed a number of usability and functional problems very quickly.

    To implement the slow proxy, I used the netem and HTB kernel modules available in the Linux 2.6 kernel, both of which are set up with the tc command line tool. These offer the most accurate simulation I could find, but are definitely not for the faint of heart. I’ve not used them, but supposedly Tamper Data for Firefox, Fiddler for Windows, and Charles for OSX can all rate-limit and are probably easier to set up, but they may not simulate latency properly.

  • Use Google’s Load Time Analyzer extension for Firefox from a realistic net connection to see a graphical timeline of what it is doing during a page load. This shows where Firefox has to wait for one HTTP request to complete before starting the next one and how page load time increases with each object loaded. The Tamper Data extension can offer similar data in less easy to interpret form. And the Safari team offers a tip on a hidden feature in their browser that offers some timing data too.

    Or if you are familiar with the HTTP protocol and TCP/IP at the packet level, you can watch what is going on using tcpdump, ngrep, or ethereal. These tools are indispensible for all sorts of network debugging.

  • (Optional) Petition browser vendors to turn on HTTP pipelining by default on new browsers. Doing so will remove some of the need for these tricks and make much of the web feel much faster for the average user. (Firefox has this disabled supposedly because some proxies, some load balancers, and some versions of IIS choke on pipelined requests. But Opera has found sufficient workarounds to enable pipelining by default. Why can’t other browsers do similarly?)

The last tip in my opinion is not a really good one, Browser developers will most likely just ignore you, and you wont be able to change the world. For the full analysis, with graphics and the full discussion please see the entry by Aaron, it’s definitely one of the best readings in the last months, with all the technical details :)
[via Ajaxian]