Archive for April, 2007

Bring serendipity by vicinity

One thing that is really cool about living in the real world is serendipity: the ability to discover something that you were not looking for in the first place. How many times have you been looking for a book in a bookstore and finally leave the place with a book you never heard of before? (you buy books, right?)

A blind man

In the world wide web, this doesn’t exist. Apart from a few attempts to bring unexpected content in e-shops - aimed at having you spend more by cross-selling similar products - the web is just like the world as seen by a blind man. You go to where you want to, you sometimes get lost, but you rarely discover things you were not looking for.

Helpful neighbor

That’s why sites like digg, stumble upon, del.icio.us and brothers were born lately. To help you find something you are not looking for. But isn’t it ironic? You have to visit regularly a place to find things that you are not interested in in the first place. It’s just as if the blind man paid a neighbor to talk about the latest events in the neighborhood: Mr Smith just moved, a certain Miss Doe took his place, she seems well educated and nice.

That’s a very partial vision of things, and the blind man may never hear about this porn shop that just opened a few blocks away, and where he would love to go every once in a while, all that because his neighbor wouldn’t want to be seen there (by a blind man?).

Web vicinity

Back to the web. What if, every time you go to a site, you had to pass in front of some others? Not random sites, but a constant sequence of sites, depending on the place you’re at and the place your target is? When I say place, I think IP address. I’d love to see a widget which detects existing websites around the routers and proxies leading you to your target, and show each one of them briefly (one or two seconds) during the course of your request.

Of course, you would have to see quite often websites that you may not want to see, but it’s just like a mean neighbor that you have to greet when you cross his path, even if you know he beats his wife and watches TV all day long. And you know what? Life isn’t better when you only see nice things (that’s the big mistake of the Disney corp.). On the contrary, the more you see, the more you get to compare things with, and you vision of things becomes better established. In a word: the path to enlightenment.

It’s not that fun, but it’s good

Once again, it’s not about related sites, webrings or some other site deciding for you (according to user ratings or redactors review). It’s not about ad-paid fake randomness, and it’s not about giving you surprises. It is about recreating an environment, having time to discover something through repetition, and finding where you are in the giant map of the world wide web.

In the long run, if you really can’t stand your neighborhood, you can always move.

When Ajax can speed up your site

Many people think that adding Ajax interactions to a web application can cripple a website's performance. Of course, if you add remote periodical executers everywhere, or if you make three Ajax requests to update three parts of a page, the web server will just hate you (servers have feelings, you know). But there can be cases where Ajax can take some burden off the server, where it can be an architecture choice rather than a pure UI choice.

Does it sound familiar?

For instance, take the now classic "add a comment" Ajax form. The user enters data in a form, submits it, and the result is sent to the client in XmlHttpRequest. There is an immediate benefit for the server here: It only has to send back the updated part of the page (in that case, the new comment) rather than the entire page. That represents a notable bandwidth and CPU economy.

Super caching

Another example is an "almost static page", which means that the page contents depend on the user session only for some limited parts. Think of a news website where the only session-dependent part is the name of the connected user displayed on the upper part of the window. If this element wasn't present, the page would be a perfect candidate for super caching.

The super caching is the action to store a copy of the HTML response somewhere under the web root of the server, so that next time the page is requested, the server sends the HTML response without even using PHP. This is very fast, and it can even be done by a lightweight and specialized server like lighthttpd. Symfony has a super caching solution in the form of a plugin, it is called sfSuperCachePlugin.

Ajax comes to the rescue

But, because of the session-dependent element, the page I talk about cannot benefit from the super caching. Can't it, really? What if the session dependent element was removed, and added to the static page afterwards, by the web browser? That's where Ajax comes in. It is a great replacement for iframes, because the Ajax response can be any JavaScript code, used to do some complex DOM modification, and that is more powerful than just replacing an element's innerHTML.

Concretely, that's how you would design your pages to take advantage of the super cache:

  • The page is designed without session dependent element

  • The first time the page is requested, it is stored in the super cache

  • The page contains a static call to another action in Ajax.

For instance, if you use the jQuery Javascript framework, the end of the page can show something like:

<script>
$().ready(function () {
  $.getScript('/path/to/javascript/action');
});
</script>


The /path/to/javascript/action action gets the user's name from the session and database, and sends it back to the browser as a piece of JavaScript modifying the DOM of the static page to include the user's name.

But wait a minute. Modifying a page after it is loaded with JavaScript, isn't that just what unobtrusive behaviours do? That's true, the sfUJSPlugin is designed exactly with this process in mind. Build the static, session-independent, accessible version first, and add the dynamic, session-dependent, highly interactive sugar in JavaScript afterwards. Or, to put it differently, design fast pages first, add the performance penalty afterwards. There is no more limit to the number of pages you can put in cache - even the most session-dependent pages can benefit from super cache.

Pros and cons

The performance advantage is not huge in symfony, because the real cost of a request is the framework initialization. Whether you send one page with cached fragments or two pages with only one using symfony, you will always have to initialize symfony once. But using the solution described here will at least save you the time of deserialization of a complex response from the cache, and a better logic in your design.

One drawback of these techniques is that the load taken off the server ends up being transferred to the client. The web browser has more to do, and the full response to a request takes more exchanges with the server to display - in short, the answer is somehow slower for the end user. Besides, developers tend to forget accessibility when they code Ajax interactions, so the pages have to be though carefully.

Conclusion

To conclude, Ajax can make your website faster because it allows you to use super caching in pages that normally couldn't benefit from it. Symfony has already all the tools to put this idea into practice (namely sfSuperCachePlugin and sfUJSPlugin), so you should never have to buy a new server again.

Using the configuration cache in a symfony plugin

In a plugin that I recently published, the sfSimpleBlogPlugin, I used a new feature of the symfony framework that allows dynamic registration of a configuration handler. Why is this interesting? Because it allows plugin authors to use custom YAML files for the configuration of their plugin, and to take advantage of the configuration cache system to parse this YAML file only once in production.

Let's take an example. Your FooBar plugin can be controlled by a FooBar.yml file located in the application's config/ folder. This YAML file contains parameters for the plugin and is environment dependent:

all:
  lorem: ipsum

dev:
  lorem: dolor

What would be interesting would be to be able to read these parameters from the code, using the sfConfig registry. That's quite simple. In the plugin's config.php (which is executed during each request), write the following code:

$foobar_config_file = sfConfig::get('sf_app_config_dir_name').'/FooBar.yml';
sfConfigCache::getInstance()->registerConfigHandler($foobar_config_file, 'sfDefineEnvironmentConfigConfigHandler', array (
  'prefix' => 'foobar_',
));
include(sfConfigCache::getInstance()->checkConfig($foobar_config_file));


Now, to get the value of the lorem parameter from everywhere in the code, just type:

$lorem = sfConfig::get('foobar_lorem');


The very interest about using a config handler rather than parsing the YAML file directly is that the sfConfigCache::checkConfig() method will process the file and put the processed PHP code in cache. Performancewise, this is the good way to have a custom configuration file controlling a plugin.

As the sfConfigCache::registerConfigHandler() method is only available as of symfony r3703, this will only work with the latest trunk version.