Tuesday, June 16, 2009

Jouons avec Pharo et Seaside

J'ai assisté il y a quelque temps a une conférence de Stéphane Ducasse à l'Institut de Management d'Annecy. Co-créateur de projet Pharo et développeur actif de la communauté Smalltalk, Stéphane nous a présenté différents outils dont Seaside, un framework dédié à l'écriture d'applications Web (en insistant sur le terme application).

Pharo est une implémentation Open Source du langage Smalltalk, qui se veut moderne, agile et cohérente. Pharo est né comme un fork de Squeak, puis a évolué en nettoyant l'implémentation des parties obsolètes, bancales ou instables, en simplifiant l'intéraction avec l'environnement de développement et en intégrant des outils de développement efficaces. De plus, chose essentielle, ils ont créé un joli logo.




La première version stable 1.0 ne devrait plus trop se faire attendre (vers l'automne ?)

J'avais déjà assisté a une présentation de Seaside aux RMLL à Mont-de-Marsan. Mais je voulais d'abord découvrir Smalltalk et du coup je suis passé à côté d'un des principaux fonctionnements novateurs qu'apporte Seaside au développements Web.

Stéphane a parcouru un diaporama de Lukas Renggli "The Heretic Web Framework" disponible ici.

Prenons un exemple simple d'application "classique": nous voulons demander deux nombres et afficher le résultat dans une console. En python nous pourrions coder comme suit:

value1 = input("Premier nombre: ")
value2 = input("Second nombre: ")
print(value1+value2)

Tant que l'utilisateur n'a pas saisi de nombre, le programme reste en attente sur la fonction input Nous utilisons le retour de la fonction pour stocker les deux valeurs.

Imaginons la même application en environnement Web. Le programme de calcul fonctionne côté serveur et l'utilisateur se sert de son navigateur Web pour saisir les valeurs. La plupart des systèmes actuels nous propose de créer une vue ou template pour définir l'interface utilisateur, un contrôlleur pour exécuter les requêtes client et renvoyer le résultat. Nous devons généralement implémenter un graphe d'état et manipuler les sessions pour savoir si nous en sommes à la demande de la première ou seconde valeur.

Seaside permet de programmer de la même manière qu'une application classique. L'équivalent Seaside/Smalltalk du code python précèdent est:

| value1 value2 |
value1 := self request: ‘Premier nombre’.
value2 := self request: ‘Second nombre’.
self inform: value1 asNumber + value2 asNumber.

On n'est pas dépaysé....


Maintenant un peu de concret. Téléchargez la machine virtuelle Pharo et l'image intégrant Seaside sur le site du projet.



Sous Linux, on doit malheureusement bricoler un peu. Décompressez la machine virtuelle puis activez le bit d'exécution du binaire squeak:
unzip pharo-vm-0.15.1b-linux.zip
chmod +x pharo-vm-0.15.1b-linux/squeak
On peut ensuite décompresser l'image et la lancer:
unzip pharo0.1-10324web09.06.1.zip
pharo-vm-0.15.1b-linux/squeak pharo0.1-10324web09.06.1/pharo0.1-10324web09.06.1.image

L'image ouverte, Seaside tourne sur le port 8080. Vous pouvez le vérifier en pointant votre navigateur Web à l'adresse http://localhost:8080/seaside.



Dans Seaside, les points d'entrée de nos applications doivent être définis. Nous allons créer une nouvelle classe de type WATask, un "contrôlleur" Seaside, et l'assigner à une URL.

Les classes peuvent être définies un utilisant le Class Browser, via le menu World ouvert par un clic sur le bureau Pharo. Dans la première colonne, sélectionnez Unpackaged (tout en bas) pour créer une nouvelle classe sans la placer dans un package particulier. Dans la zone de saisie du bas, saisissez le code suivant pour déclarer la classe Additionneur qui hérite WATask.
WATask subclass: #Additionneur
    instanceVariableNames: ''
    classVariableNames: ''
    poolDictionaries: ''
    category: 'Unpackaged'

Ouvrez le menu contextuel de la zone de saisie via un clic droit et sélectionnez accept pour enregistrer la classe.




Ceci fait, notre classe doit se déclarer comme application accessible directement via un point d'entrée. Pour trouver ce type d'application, Seaside parcours toutes les classes héritant WAComponent (qu'hérite WATask et donc Additionneur) et sélectionne celles dont le retour de la méthode canBeRoot est true.

(Mise à jour: d'autres moyens sont disponibles, voir le commentaire de Damien)

Pour ajouter une méthode de classe, sélectionnez la classe Additionneur dans la seconde colonne puis cliquez sur le bouton class pour visualiser les méthodes de classe. Sélectionnez la catégorie -- all -- dans la troisième colonne, puis entrez le code suivant dans la zone de saisie:
canBeRoot 
    ^true
Enregistrez alors la méthode via la commande accept du menu contextuel.

Vérifions que notre Additionneur peut être accessible depuis l'interface de configuration de Seaside. Ouvrez la page en question depuis votre navigateur Web à l'adresse suivante: http://localhost:8080/seaside/config. Le compte par défaut est admin / seaside.

Dans la section Settings, Add an entry point, saisissez le nom de votre nouveau point d'entrée, par exemple additionneur. Je précise que ce nom est indépendant du nom de la classe (au cas où vous seriez un développeur Rails ;) ). Sélectionnez Application comme Type puis cliquez sur Add.



Vous entrez alors dans la page de configuration de l'application. Sous la section Configuration/General, modifiez le paramètre Root Component pour sélectionnez la classe Additionneur dans la liste déroulante. Cliquez enfin sur Save en bas de la page.

En cliquant sur Close vous revenez à la page principale de configuration de Seaside.

Vous devriez voir apparaître le point d'entrée additionneur associé à la classe Additionneur dans la liste /seaside/.


Si vous cliquez sur le lien maintenant, vous aurez une erreur car nous n'avons pas encore implémenté le fonctionnement de notre application, ce que nous allons écrire de suite.


Retournez dans Pharo. Seaside cherche à évaluer la méthode go d'une instance de notre classe Additionneur. Pour l'ajouter, sélectionnez d'abord les méthodes d'instance en cliquant sur le bouton instance en dessous de la seconde colonne du Class Browser. Cliquez ensuite sur la catégorie -- all -- et saisissez le code présenté précédemment:
| value1 value2 |
value1 := self request: ‘Premier nombre’.
value2 := self request: ‘Second nombre’.
self inform: value1 asNumber + value2 asNumber.
puis enregistrez-la (clic droit, accept).




Maintenant pointez votre navigateur sur l'application à l'adresse suivante: http://localhost:8080/seaside/additionneur et goûtez à la joie d'avoir une application qui fonctionne du premier coup.




Si ce n'est pas le cas, je décline toute responsabilité quant aux dommages irréversibles que pourraient causer mes indications sur la santé de votre ordinateur...

2 comments:

  1. Excellent post, merci. Pour enregistrer une application sur une URL (on dit déployer l'application), on peut aussi faire

    Additionneur registerAsApplication: 'additionneur'

    Ça marche quelque soit la valeur de #canBeRoot.

    ReplyDelete