Yoan Blanc’s weblog

Another lost swiss guy

June 2008

Lessons from the Desktop to the Browsers

Yoan BlancMon 30 June 2008, , , , ,

There were a lot of buzz recently about Sproutcore and Objective-C, a desktop architecture and language from the Apple platform that are adapted (or ported) to the JavaScript world. There is one great idea in Cocoa (built using Objective-C): yes it’s MVC but I want to talk about the Key-Value Observer. It offers a great abstraction for creating RIA from my point of view, but let’s start at the beginning.

aHtmlElement.onclick = function() { } formerly DOM level 0 is how you can handle native events in a very simple manner. I reminds me the C# delegates (that are using the += operator thus). Very simple and useful (but only one at the time, so very restrictive).

DOM level 1 introduces the addEventListener (or attachEvent for MSIE). I’m sure that the Java-guys will reminds the java.util.EventListener that you are using everywhere in any AWT/Swing application. The main difference is that JavaScript works at the function level and not object one. Java is not a functional languae.

Then some JavaScript framework/libraries offers a different kind of handling events. YUI, Dojo or jQuery have interesting ones. The great advantages of messages passing over function calls is that you separate the producer from the consumer (decoupling) and become more robust; if no one care about a message, it’s simply lost, but if something linke ten differents processes cares about it, they will for sure get it.

If you made a little bit of Qt®, Dojo have the connect method: dojo.connect(myObject, "onclick", function() {}); It’s still DOM level 0 method overloading, not very clean but simple. It has the advantage to works with non-native events (or with any functions call in that particular case).

YUI pandora box contains the CustomEvent, a very simple implementation of the Gang of Four (GoF) Observer pattern. It’s used in more or less in every single YUI widget.

var event = new YAHOO.util.CustomEvent("my type");
event.subscribe(function(type, data){
  alert(type + ": " +data)
});
event.fire("Hello World!");

jQuery has also a custom event handling system included. It’s very powerful and kind of no so documented. It reminds me the GObject signal used by GTK.

$(document).
  bind("my-type", function(event, data) {
    alert(event.type + ": " + data);
  }).
  triggerHandler("my-type", ["Hello World!"]);
    

I’d like to see a centralized system for messaging passing. I toke example on how Bayeux is made, some XMPP parts too, and wrote a pubsub class. It has the advantage that you don’t have to keep track of the object that manages the events and can subscribe to meta-channels (using the star *).

new pubsub().
  subscribe("/test/first", function(data) {
    alert("first got: "+data);
  }).
  subscribe("/test/second", function(data) {
    alert("second got:" + data);
  }).
  subscribe("/test/*", function(data) {
    alert("a message has been sent: "+data);
  }).
  publish("/test/first", [1]).
  publish("/test/second", [2]).
  publish("/test/third", [3]);

Now, what are offering Sproutcore or Objective-J to JavaScript? Key-Value Observer. That means you aren’t creating specific custom events, or channels but will observe objects’ values directly. It’s a very simple to do, the only trade off is to access them with getters and setters only (which sucks).

var label = function(name, value) {
  this.name = name||"";
  this.value = value||"";
};
// label inherits from observable
label.prototype = new observable();
label.constructor = label;

// you can also chain the followings.
var my_label = new label("my label");

my_label.observe("value", function(value) {
  alert(this.name + " is: " + value);
});

my_label.set("value", "Hello World!");

With all those tools, it’s very easy to imagine a complex rich internet application made of independent modules. Those modules don’t know each other directly, gets notified when something they are looking for happens. You can transform it into a MVC-like architecture with one kind of module for each type; displaying with HTML/CSS, reacting to HTML events, reacting to asynchronous events like XHR, storing data information.

All those issues have been handled by desktop software for years. I think it’s time to learn from it and get the best in terms of simplicity, reliability and strength. It’s also a lot easier to unit test small modules or to create brilliant mash-ups upon them. Being unobtrusive is maybe still the first step that many JavaScript applications have to face (with event delegation all over the place), the second one could be to not act as spaghetti code with as few cross references as possible. Rich internet application is becoming serious, so make sure it’s also as kind as possible to everyone, with ARIA for example.

La planète JavaScript a bougé (voire tremblé) récemment avec les annonces faites par Apple concernant Sproutcore (qui selon certain part en guerre contre Adobe Flash, je ne partage pas cette avis) ou 280 slides et leur Objective-J (une implémentation d’Objective-C pour JavaScript). L’univers Apple semble avoir son mot à dire concernant l’univers Internet.

L’univers de l’application web se met à ressembler, à imiter du moins, de plus en plus à celui des applications desktop, les outils et recommandations s’étoffant, comme ARIA. Le point qui m’intéresse est d’explorer à quel point on peut apprendre de ce monde là, qui est déjà codifié, qui a sû trouver des solutions aux problèmes étant les siens.

Pour ceux ayant une petite expérience avec différents toolkits graphiques, on peut voir les parallèles entre :

Sinon, en refaisant l’Observer pattern, il m’a été facile de réaliser un système dit de pub/sub organisé en canaux. On retrouve cette organisation au sein du protocole Bayeux ou dans certaines bibliothèques pour XMPP (Jabber) où les canaux sont des chemins XPath. J’aime bien ce système car il fonctionne de manière centralisée, connaître qui émet quand on est un récepteur ne nous intéresse pas, ne n’est même pas accessible. Il n’y a pas d’avantage ou de désavantage clair sur un mode utilisant le pattern observateur si ce n’est qu’il ne faille pas se marcher dessus avec les canaux utilisés.

Et pour revenir à Sproutcore, Objective-J, Objective-C, Cocoa; ils contiennent une idée intéressante nommée Key Value Observer (KVO). Le principe est d’observer les modifications des objets directement et d’éviter d’avoir à passer par un tier, qu’il soit écouteur ou observateur. Simple et efficace, même si avoir à utiliser des getters/setters ne me plait qu’à moitié, et encore, la moitié vide du verre.

Une application web à présent doit en avoir terminé avec son besoin d’être non-obtrusif, c’est une vieille rengaine devant être dépassée avec les outils actuels comme low-pro (oui il faut bien placer Prototype aussi, le pauvre). Elle doit se concentrer sur une modularité la rendant, plus simple, plus maintenable, plus testable, plus ouverte également aux mash-ups.

Je vous laisse jouer avec la page suivante, qui contient différents exemples, c’est un peu brut de fonderie; mais peut-être intéressant.

Web chat: CouchDB as a backend using eCouch

Yoan BlancTue 10 June 2008, , , , , ,

I previously made a little proof-of-concept web chat using MochiWeb (the MochiMedia toolkit to build HTTP servers). The conclusion was; I still had to explore different fields like:

  • the management of multiple rooms;
  • the informations about who joined and left;
  • and the history.

And it’s what I did recently, there is a screencast (but no source code this time because there is too much work in progress in it). The big task was to enrich the data format with nick names, informational messages (rename, join and leave) and multiple rooms. That was only adding more complexity to the backend and front end site a little step forward.

The major thing I did is offering a history of the messages. To go that way, there is obviously a need of having, somewhere, a storage infrastructure. Erlang has Mnesia (which is used by Erlycomet and Twoorl (for handling sessions)). Mnesia is a distributed storage system either in memory or on disk with 4 different way of managing datas (as key/value pairs). One of them is exactly how Memcached works, unsurprisingly.

But I didn’t choose Mnesia because I wan’t my data to be accessed from outside the Erlang world and having a query interface avoids a lot of extra work. My work comet chat was built using web.py and memcached and it quickly became over complicated. So, CouchDB, the rising star, which according to this video presentation by Jan Lehnardt solves the replication limitations MySQL have (yes, the slave-master thing) by saying that everyone is a gentlemen that knows how to deal with conflicts.

The other thing I really heart about CouchDB is that you put in it whatever you want and have only to deal with that when you query them: store and don’t care.

To access CouchDB data from MochiWeb server, I used the very fresh eCouch library (formerly OTP application) released as an Open Source project by the tarpipe team. Grab it and test, it’s very simple.

$ curl http://localhost:5984/
{"couchdb":"Welcome","version":"0.7.3a"}
$ erl -pa ebin/
Erlang (BEAM) emulator version 5.6.2 [source] [async-threads:0]

Eshell V5.6.2  (abort with ^G)
1> inets:start().
ok
2> application:start(ecouch).
ok
3> ecouch:db_list().
{ok,[<<"test_suite_db">>,<<"test_suite_db_a">>,
     <<"test_suite_db_b">>,<<"chat">>]}
4> ecouch:db_info("test_suite_db").
{ok,{obj,[{"db_name",<<"test_suite_db">>},
          {"doc_count",0},
          {"doc_del_count",0},
          {"update_seq",21},
          {"compact_running",false},
          {"disk_size",14830}]}}
5> ecouch:view_access("chat", "messages", "all", [{count, 1}]).
{ok,{obj,[{"total_rows",18},
          {"offset",0},
          {"rows",
           [{obj,[{"id",<<"08ae6beaeca9a0509ef838dce9d4303d">>},
                  {"key",<<"2008-06-10T07:30:44.0781Z">>},
                  {"value",
                   {obj,[{"_id",<<"08ae6beaeca9a0509ef838dce9d4"...>>},
                         {"_rev",<<"3175880002">>},
                         {"type",<<"info">>},
                         {"posted_at",<<"2008-06-10T07:30"...>>},
                         {"message",<<"Guest joined">>},
                         {"room",<<"Welcome">>}]}}]}]}]}}
6> q().
ok

So inside MochiWeb, make sure inets:start() is ran somewhere in your application (near mochiweb:start appears to be a good idea and working for me) and ecouch has to be added to the applications that yours relies on (yours.app.

CouchDB also introduced a complete map/reduce API. If you tried it a while ago, it’s worth a second look. I.e. map is know called emit, so any examples using map are outdated.

I don’t know if MochiWeb alone is enough to fit all the development needs a normal project has. I’ll investigate the creation of less Ajaxy pages like browseable and searchable chat archives, user profiles, OpenID authentication and so on. Many people are discussing about creating combinaison of different languages, but if I look at Twoorl (powered by ErlyWeb) it doesn’t seem to need any other languages/framework to rock.

Dans le post précédant, j’ai expérimenté un web chat construit avec MochiWeb (la boite à outils de MochiMedia permettant de créer des serveurs HTTP). Dans la conclusion, j’ai évoqué d’explorer les pistes : d’avoirs une meilleure gestion des canaux, archiver les messages, etc.

Chose faite (screencast) aux moyens de CouchDB pour les archives, son interface REST colle parfaitement avec ce qui est déjà en place pour faire du Comet, ça se déroule simplement à un autre niveau (serveur - serveur). J’apprécie beaucoup son approche sans schéma/modèle où il est possible d’y ajouter ce que l’on veut comme on veut, le travail étant à faire ensuite grâce aux vues.

Erlang a un système inclu, distribué, permettant de faire du stateful (chose non permise par le langage intrinsèquement) nommé Mnesia. Un usage simple serait, par exemple, un système de type Memcached, mais il pourrait également servir à faire des queues de traitement à la Starling ou Amazon SQS. Mnesia est utilisé, notamment par Twoorl, pour stocker les sessions utilisateurs, mais il ne serait pas impossible de s’en servir comme un stockage sur disques plus vital.

CouchDB, s’il est écrit en Erlang, n’est pas lié au langage ce qui est un avantage sur Mnesia. Ensuite, face à MySQL par exemple, il permet de ne pas se soucier de la célèbre relation maître-esclave permettant d’avoir plusieurs serveurs répondant à un grand afflux de requêtes (type Twitter). CouchDB fonctionne de manière gentleman et sait régler les éventuels conflits de manière transparente avec ses pairs.

Pour accéder aux données depuis MochiWeb, je suis allé me servir dans la boite à outils de tarpipe (un Yahoo! Pipes-like ultra web 2.0/microblogging) et y ai trouvé eCouch, une application Erlang (OTP) avec une interface simple à CouchDB. Le projet est encore tout jeune, n’hésitez pas à mettre la main à la patte (chose que j’ai dû faire pour les vues par exemple).

Étape suivante : distribution du système, réalisation de pages dynamiques côté serveur (actuellement uniquement avec Comet) pour, par exemple, pour naviguer dans les archives des discussions, des profils utilisateurs avec authentification OpenID. On peut voir différentes discussions à propos d’utiliser Erlang conjointement avec un autre framework, je ne suis pas sûr de ce besoin mais ça reste à tester. Si vous désirez un accès aux sources, laissez-moi un email.

About

meYoan Blanc is a web developer that lives in Lausanne (rue Couchirard 15, 1004 Switzerland) worked for Yahoo! and comes from La Chaux-de-Fonds. This web site is for this weblog, a playground for random stuffs and can help keepingmeconnected with some friends out there.

Get my vCard or contact me by phone (+41 21 625 82 09) or email ().

Misc

RSS, list.blogug.ch

This site reflects only my opinion and is not affiliated with anyone else.

copyright 2006-2008 — doSimple.ch