debuggable

 
Contact Us
 
33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41

Wanted: UI Designer for PostTask.com

Posted on 13/4/08 by Felix Geisendörfer

Hey folks,

I just wanted to announce that Tim and I are looking for somebody to help us with creating a completely new interface for PostTask. We want to move the application into a very different direction (social project management) and even so we have some ideas on how the new interface could look like we would consider entirely different ideas as well.

So if you are interested in working with us on the relaunch and find the artistic freedom we are offering compelling, please contact me at felix@debuggable.com or add me on any of the instant messagers listed here.

Payment will depend on your negotiation skills and this could also be an opportunity to permanently join us on our way to world domination in future ; ).

What we are looking for is basically somebody who is passionate about application interfaces and knows his way around html and css. Basic (Cake)PHP programming skills would be considered a plus.

-- Felix Geisendörfer aka the_undefined

 

Run intense JS without freezing the browser

Posted on 23/3/08 by Felix Geisendörfer

Hey folks,

this is probably one of the most exciting things I've come up with since I started playing around with JavaScript. If you ever wrote a somewhat complex JS snippet you might have noticed that slower computers / browsers (like FF2 on mac) will freeze if you run through a big loop that does some heavy operations (event bindings, dom manipulations, etc.).

For me at a user this has always been very annoying since it just gets into your work flow and if you get unlucky might even crash your browser. So far I thought the only way to avoid this was by simply writing less intense JavaScript and/or optimizing the hell out of it.

However, with the recent upgrades coming for PostTask we've reached the point were we often need to bind up to 300 events (!) on page load as well as perform a whole bunch of other operations. It got to the point where loading the side would freeze FF2 on mac for an insane ~16 seconds - absolutely unacceptable by any standard. This post is about how a simple trick reduced initialization time down to 5 seconds while avoiding any browser freezing whatsoever at the same time.

The big secret - Using JavaScript to partition workload

The key problem I identified that is responsible for browser freezing is that JavaScript runs in a single thread. This means while there is some JS code executing, no other code can run at the same time. From my old VB days I remembered that there used to be a function called doEvents() which you could put into big loops to keep your apps from freezing. What it did was essentially to see if there was any other code that needed to run, execute it and then go back into your loop. JavaScript doesn't have such a function, but something that comes very close - timers. John recently did a good post about them that confirmed my previous experiments with them: If you set an interval or timeout of lets say 50ms in JavaScript there is no guarantee whatsoever to when the event will fire. The only thing JS promises you is to not fire the event *before* 50ms are over. Other then that it just tries to execute the event ASAP. That means if there is any JS code currently running then no event will fire until the block of code finished executing. It also means that several events (interval / timeout / click / etc. callbacks) can queue up over a while and then fire back to back. What seems like a very annoying problem that you have to work around if you want to do lets say smooth animations, it turns out that this also opens a broad series of possibilities of writing "asynchronous code" in JS. And by asynchronous I mean code that will not execute as part of your normal program flow, but whenever it is convenient for JS / the browser to execute it. You might already have come to the conclusion I made a little while ago: This is a perfect mechanism to split a big operation up into smaller chunks that the browser can process whenever its convenient and will not cause any freezes. This always works best if you leave the some room to "breathe" for the browser in between executing the code chunks (1-5ms usually are enough).

Here is some code that can accomplish this in an easy-to-use fashion:

$.queue = {
    _timer: null,
    _queue: [],
    add: function(fn, context, time) {
        var setTimer = function(time) {
            $.queue._timer = setTimeout(function() {
                time = $.queue.add();
                if ($.queue._queue.length) {
                    setTimer(time);
                }
            }, time || 2);
        }

        if (fn) {
            $.queue._queue.push([fn, context, time]);
            if ($.queue._queue.length == 1) {
                setTimer(time);
            }
            return;
        }

        var next = $.queue._queue.shift();
        if (!next) {
            return 0;
        }
        next[0].call(next[1] || window);
        return next[2];
    },
    clear: function() {
        clearTimeout($.queue._timer);
        $.queue._queue = [];
    }
};

Late event binding

One of the things we use this for in PostTask is what I call late event binding. Lets say you have the following code: (Note: This could be simplified a lot, but this way its easier to understand how the refactoring works)

$(document).ready(function() {
    // a lot of li's, lets say 500
    $('li').each(function() {
        $(this).bind('click', function() {
            alert('Yeah you clicked me');
        });
    });
});

You will probably notice that it already has a noticeable impact on your pages initialization time while freezing the browser during it. To avoid it can be as easy as:

$(document).ready(function() {
    // a lot of li's, lets say 500
    $('li').each(function() {
        var self = this, doBind = function() {
            $(self).bind('click', function() {
                alert('Yeah you clicked me');
            });
        };
        $.queue.add(doBind, this);
    });
});

This should minimize your pages initialization time down to almost its non-JS speed while also binding the events in a timely fashion. Essentially instead of binding the event on directly with the document ready invent, you simply encapsulate each bind into its own closure that you add to a queue for later execution. This means that the user will see the page very fast while in the background every 2ms a new li element gets its binding done. Of course the user could now do something really annoying and click on an element before its bind finishes which might screw things up. However, this is very unlikely. Fore one, the user needs to be very fast, because he'll need to click in < 1 second on one of the last elements (which is likely outside the current viewport because of the amount of elements). But also its very unnatural behavior for the user. And even if you have to make 100% sure the user is not able to interact you can use this technique to avoid freezes. You can for example start with all elements being hidden and only start showing them 1 by 1 after they've been processed. Or you can also use an overlay like the jquery blockUI plugin to block any interaction. Either way you'll give the user a better experience by not freezing the browser and allowing him to see the page as fast as possible (even if people can't use something right away, visual response of the page loading up is very important).

Async calculations

One other usage case I had with a client a couple days ago was that he was using a jquery UI slider which was supposed to dynamically filter a list of keywords depending on the selected value and doing some calculations. My first implementation of this would constantly freeze the browser b/c the values where live updated as you moved the slider and moving it over 20 values caused 20x intense loops to occur right after each other. The solution? Use the time queue from above. I simply split the keyword filtering loop up into distinct chunks, and whenever the slider was moved I ran $.queue.clear() first so if the previous filtering hadn't finished yet it would simply be discarded. This does two things at the same time: It allows the user to freely drag the slider back & forth without any freezing, while also easing work load by being able to discard ongoing operations for the previous value. If the operation for each value takes more then a second you can also easily add an ajax spinner that indicates activity. It also makes sense b/c working with this trick really feels like suddenly being able to use "ajax" for loops locally executed on the client ; ).

Other usage cases

I'm sure there are many other situations where you can use this. I've comen up with a rough draft for dramatically improving the responsiveness of jQuery UI's sortable plugin on slower browsers and am working on some other neat things. One could also write a jQuery plugin to ease late event bindings and other operations with a syntax like: $('li').delayed('bind', 'click', function() {}).

Alright, I hope this is useful to those of you writing heavy JavaScript applications and maybe interesting for the rest as well. I wish I had more time to provide a more comprehensive solution, but I'm leaving for a week of non-computer fun to Thailand tomorrow.

Let me know what you think and what other usage cases you can think of,
-- Felix Geisendörfer aka the_undefined

 

New router goodies

Posted on 3/3/08 by Felix Geisendörfer

Hey folks,

here are a couple cool things that the Router class can do for you in the latest SVN:HEAD of CakePHP.

Reverse routing

You might have heard that instead of the good old $html->link('My post title', '/posts/view/5') you are now supposed to use the much more verbose:

$html->link('My post title', array(
   'controller' => 'posts',
   'action' => 'view',
   5
));

But have you also been told what the advantage is? Because come on, '/posts/view/5' makes a lot of sense and is much less of a hassle to type. So there must be a reason for going the verbose route (no pun intended ; ).

The reason for the new syntax can be found in a new feature for the Router called "reverse routing". Essentially it does the exact oposite of what the Router normally does for you. Instead of taking a string url and mapping it to a controller:action, it takes a list of parameters and looks for the route matching them and spits out the corresponding url string. Confused? Don't be, its easy. If we take our example from above and assume that we have a route like this:

Router::connect('/hot_posts/*', array('controller' => 'posts', 'action' => 'view'));

Then our 'My post title' link will suddenly point to '/hot_posts/5' instead of '/posts/view/5'. What happened is that the router did a reverse lookup and noticed that you'd like to map your Posts::view($id) action to a different url than CakePHP normally would. So instead of returning you the default one, the router returned your own customized url to you.

Route parameters

Another cool thing supported by the 1.2 Router are route parameters. Essentially they are the ':something' parts you might have seen in Router::connect calls before. Lets say you got sick of your wordpress blog and want to convert it to CakePHP. One of the things you need to take care of is to make sure that you don't break any legacy urls because otherwise Google will stop loving you. The most common url pattern one should try to keep is the '/yyyy/mm/dd/post-title' one. With the new Router this can easily be accomplished using route parameters:

Router::connect('/:year/:month/:day/:title', array('controller' => 'legacy_urls', 'action' => 'map'),
   array(
      'year' => $Year,
      'month' => $Month,
      'day' => $Day,
      'title' => '.+',
   )
);

To explain, :year/:month/:day/:title are placeholder variable that are called route parameters. For each one of those placeholders you can define your own regex to match them in the 3rd param of Router::connect. CakePHP also provides you with some default regex to make your life easier. Currently those are: $Action, $Year, $Month, $Day, $ID and $UUID. An easy way to find out what they do is to look at the Router::__named property.

Getting fancy with passing route parameters

If you've been reading my blog for a while then you might know that I'm in love with a certain url pattern. For those who don't, here is the synopsis. Instead of /posts/view/5 I like my urls to look like /posts/5:my-post-title. I don't want go into the many advantages of those urls right now (this will be a separate post). But instead I want to show you how they can be accomplished using the 1.2 router without any custom hacking:

Router::connect('/posts/:id::url_title', array('controller' => 'posts', 'action' => 'view'), array(
   'pass' => array('id', 'url_title'),
   'id' => '[\d]+'
));

To explain: What I do here is to define a url with two route parameters (id, url_title) which I separate using a colon (:id::url_title). Then I tell the router to map all matching /posts/<id>:<url_title> urls to the PostsController::view action. In the next parameter I specify that a valid id is made up of digits only (I could also use $ID for that). Now the interesting part is the new 'pass' key in the 3rd param. What it essentially does is to tell the router to take the matched 'id' and 'url_title' and pass it into the PostsController::view($id, $url_title = null) action. This is very convenient since you can now directly pass any route parameter into an action instead of having to access it via $this->params['url_title]. It also means you can use the same code to handle /posts/view/5 as you use for /posts/5:my-post-title.

Reverse Routing, again

Oh well, but what is if I ever change my mind about the entire /posts/<id>:<url_title> thing? The answer is to use reverse routing in all your links:

$html->link('My post title', array(
   'controller' => 'posts',
   'action' => 'view',
   'id' => 5,
   'url_title' => 'my-post-title'
));

This will as you might already expect return a link pointing to '/posts/5:my-post-title'. If you ever want to change your url style, all you have to do is to change the route, and voila, all links will follow. But it gets even better if you apply a little abstraction with creative usage of your Post model as a namespace:

class Post extends AppModel{
   static function url($id, $base = false) {
      if (is_array($id)) {
         $post = $id;
         if (!isset($post['Post'])) {
            $post = array('Post' => $post);
         }
      } else {
         $post = ClassRegistry::init('Post')->find('first', array(
            'conditions' => array('Post.id' => $id),
            'fields' => array('id', 'url_title'),
            'recursive' => -1,
         ));
      }
      if (empty($post)) {
         return false;
      }
      return Router::url(array(
         'controller' => 'posts',
         'action' => 'view',
         'id' => $post['Post']['id'],
         'url_title' => $post['Post']['url_title'],
         'base' => $base,
      ));
   }
};

Now you can simply link to any given Post in your application with the following code:

$html->link('My post title', Post::url(5));

Or if you loop through a series of posts:

foreach ($posts as $post) {
   echo $html->link($post['Post']['title'], Post::url($post));
}

Note that in the second example no database query will be issued (which is very desirable if you are inside of a view).

Alright, I hope this is useful for those of you who didn't look into all of the new Router stuff. I'll also do a post on the new REST functionality soon, so stay tuned.

-- Felix Geisendörfer aka the_undefined

PS: Feel free to ask any router related questions in the comments section.

 

With jQuery & CakePHP to World Domination (Slides)

Posted on 26/2/08 by Felix Geisendörfer

Hey folks,

sorry this took so long, but here you can download the PDF or the much better Keynote version of my slides.

For your convenience, I've also uploaded my slides to my slideshare account.

If you are wondering when the jayDom library is going to be released: I'm trying to get an alpha version out in < 2 weeks.

Meanwhile feel free to ask any questions using the comment function of the blog.

-- Felix Geisendörfer aka the_undefined

 

First Version of Debuggable.com launched

Posted on 24/2/08 by Tim Koschützki

Hey folks,

just wanted to let you know, that the website for the company of Felix and me has been launched. Debuggable Ltd.'s website contains a blog and some static pages introducing you to what we do, who we are and how we can help you out. It's quite cool because we both listed around 20 bullets that explain who we are. They are quite funny, check them out.

Soon ThinkingPHP.org and this very website here will be merged and displayed on debuggable.com. : ) We haven't done it yet, because the blog backend is not fully finished. However, it has come a long way and I am currently working on code syntax hiliting. So we should be ready pretty soon. Please check it out and tell me what you think: Debuggable Ltd..

 
33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41