Confessions d'un Javaiste repenti

Cela fait maintenant 6 ans que je fais du Java de manière professionnelle, que je collectionne les jars et empile les frameworks tel un jeu de légo. Mais voilà c'est terminé ! Depuis 6 mois je fais du Ruby on Rails (aka Rails), aussi bien sur mes projets persos que professionnels ... laissez-moi vous expliquer pourquoi.

Ruby On Rails, un framework web

Lorsque l'on parle de Rails, on pense le plus souvent à ses caractéristiques totalement orientées vers la productivité du développeur :

  • un paradigme convention over configuration, reléguant les longs fichiers de configuration XML à la préhistoire
  • un langage interprété facilitant le rechargement de code à chaud et permettant ainsi de tester les modifications de son code au plus vite
  • l'utilisation d'un langage dynamique avec toutes les fonctionnalités modernes permettant (entre autre) de très facilement créer des méthodes à la volée ou permettant de manipuler les collections avec beaucoup de facilité
#Exemple de manipulation de collection avec une closure
print ["google", "yahoo", "bing"].map{|host| "http://www.#{host}.com" }
> ["http://www.google.com", "http://www.yahoo.com", "http://www.bing.com"]

Ces caractéristiques ont sans aucun doute marqué le monde du développement, mais elles ont désormais été intégrées par de nombreux langages. Ainsi, Spring ou JEE sont profondément emprunts de c****onvention over configuration et de d****on't repeat yourself permettant d'alléger les fastidieux fichiers de configuration XML. Les langages JVM de nouvelle génération (dynamiques ou non) comme Groovy ou Scala sont désormais matures. Et pour finir, l'outil JRebel propose une solution efficace au problème de "hot deploy" en Java.  Ces 3 points ne justifient donc pas en eux même de privilégier Rails à une stack Java.

Mais ne nous méprenons pas, la principale force de Rails est d'être un framework web ; en effet, point d'embarqué ou de client lourd en Rails. Mais cette spécialisation, qui correspond malgré tout à 95% de mon utilisation de Java en entreprise, est réellement un atout. En parlant de Java j'ai maintenant l'image d'un tank : ça fait tout, ça finit par passer partout, mais pas forcément de la plus efficace et la plus élégante des manières.

Le reste de cet article sera donc consacré à opposer Rails à Java en tant que frameworks web.

Mais au fait, Java peut il concourir dans la catégorie framework web ? Oui et non : Java n'est pas un framework web en tant que tel et l'on considérera en fait Java comme une pile de frameworks. On peut aussi bien utiliser la pile Java officielle (JEE), une pile alternative (comme Spring ou JBoss Seam) ou encore un assemblage à façon des nombreux frameworks existants.

Et en fin de compte, cette variété de frameworks nuit à Java : elle apporte beaucoup de complexité, aussi bien dans le choix des briques que dans leur assemblage. Ainsi la communauté Java s'est longtemps consacré à simplifier l'intégration entre les frameworks et entre les couches d'une application (l'IOC n'a jamais été aussi simple et peu verbeux). Cet objectif est aujourd'hui atteint et la pile standard Java est enfin devenue aussi légère à utiliser qu'elle devrait l'être.

Mais ceci s'est fait au détriment de ses fonctionnalités ! On s'estime aujourd'hui heureux en Java lorsque le framework que l'on utilise nous permet de mettre en oeuvre simplement le pattern MVC, de binder des objets sur des composants graphiques, de faire de la validation et éventuellement de faire un peu d'Ajax. C'est bien, mais c'est le b.a.-ba du web.

Si j'utilise aujourd'hui Rails, c'est parce que ce framework est définitivement plus abouti et plus riche en terme de fonctionnalités web. Rails (contrairement à Java) est le fruit de centaines de contributeurs oeuvrant tous dans le même sens : faire de ce framework le plus productif pour réaliser des applications web. Voici quelques exemples de fonctionnalités natives en Rails, et à mon sens vitales pour faire une application web en 2010 :

#controlleur MVC pour retourner un objet sérialisé en JSON
class BooksController < ApplicationController   def show     render :json => Book.find_by_id(params[:id])
  end
end
  • Gestion intégrée d'un memcache ou encore gestion du cache pour des fragments de page
  • Compression automatique des ressources web
  • Accès transparent à la base de donnée (ie. pas besoin d'écrire de code SQL ou apparenté pour une bête recherche en base)
class User < ActiveRecord::Base
  #la classe est vide, les attributs de la classe sont induits depuis le schema de la base : schema.rb
end
 #exemple de méthode dynamique : Rails interprète dynamiquement le nom de la méthode pour exécuter le code SQL correspondant
User.find_by_name

Il y a aussi une gem pour ça !

Et ce n'est pas parce que Rails bénéficie d'une direction claire et contrôlée qu'il n'existe pas de communauté. La contribution externe est très riche, et les frameworks pululent sur github. Voici quelques exemples de gem (i.e. librairie Ruby) absolument bluffantes :

  • devise vous aide à gérer tous les aspects sécurité. Pas seulement le processus d'authentification, mais aussi toute l'ihm nécessaire à enregistrer un nouvel utilisateur, changer son mot de passe ou encore confirmer la création de son compte. Devise est extensible et s'intègre particulièrement bien à openid ou oauth (pour utiliser Facebook ou Twitter en SSO par exemple)
  • formtastic simplifie drastiquement l'écriture de vos formulaires en poussant au plus loin le paradigme "convention over configuration".
  • si vous trouvez que le HTML est verbeux, pas vraiment DRY et finalement peu maintenable, la gem HAML est faite pour vous. Elle a pour vocations à faire de vos pages web de véritables Haïku ;-)
  • pour finir typus ou admin_data vous aident à générer un back-office d'administration en deux coups de cuillère à pot.

Il y a bien entendu le risque de retomber dans une situation similaire à Java ou l'on se retrouve à assembler des stacks de gems totalement hétérogènes d'un projet à l'autre avec un surcoût d'intégration important. Mais Rails s'en sort mieux sur ce point car d'une part la "colonne vertébrale" d'un projet Rails est standard alors que ce n'est pas le cas en Java (où l'on peut être basiquement en  JEE, Spring ou Seam), et d'autre part les meilleurs innovations sont régulièrement injectées dans le coeur de Rails (tandis que la standardisation d'un Hibernate en JPA reste une situation exceptionnelle)

La communauté Rails est extrêmement importante et les contributions sont variées :

  • des foisons de gems et plugins sur github
  • d'excellents guides sur les concepts clés de Rails
  • quelques blogs majeurs ou encore quelques screencasts
  • de nombreux services sur le cloud
  • des milliers de questions et réponses sur stackoverflow

Un framework fait par des agilistes, pour des agilistes

Un critère devenu extrêmement important ces dernières années lors de l'évaluation d'un framework est sa testabilité. Qu'en est-il avec Rails ?

Et bien soyez rassurés, il n'y a aucun doute à avoir : Rails est le framework le plus testable que j'ai pu utiliser ces dernières années. La première raison est que par défaut un projet Rails embarque toute la mécanique permettant de mettre en oeuvre 3 stratégies de test différentes, toutes complémentaires, pour tester votre application :

  • la plus importante, le test unitaire, peut être utilisée pour tester n'importe quel objet de votre application : principalement les modèles mais aussi n'importe quelle librairie.
  • les tests fonctionnels permettent de tester unitairement un controlleur et fournissent le nécessaire pour injecter simplement des requêtes HTTP et vérifier le rendu HTML (ou autre)
  • pour finir les tests d'intégrations sont des sortes de super tests fonctionnels, permettant de tester un enchainement de pages et de controlleurs.
#exemple de test d'intégration
class UserFlowsTest < ActionController::IntegrationTest
   fixtures :users
   test "login and browse site" do
     https!
     get "/login"
     assert_response :success
     post_via_redirect "/login", :username => users(:avs).username, :password => users(:avs).password
    assert_equal '/welcome', path
    assert_equal 'Welcome avs!', flash[:notice]

    https!(false)
    get "/posts/all"
    assert_response :success
    assert assigns(:products)
  end
end

Et pas la peine de vous demander comment est géré l'état de la base de donnée pour ces tests : Rails gère pour nous toute cette configuration fastidieuse. Souvenez-vous donc ce que l'on doit faire en Java : configuration d'une base de données mémoire, génération automatique du schéma avec JPA, gestion des jeux de données DBUnit ...

La seconde raison est que la communauté Rails propose des outils de tests bluffants (et pour le coup, bien loin de ce qui existe en Java). Les deux que j'ai envie de retenir sont:

  • factory_girl, qui permet de définir des modèles d'objet et de les réutiliser facilement dans tous ses tests. Chaque test peut rester "ciblé" sur ce qui doit être testé.
  • cucumber, pour sa part est un outil de "spécifications exécutables" sur lequel nous avons déjà rédigé quelques articles. Il s'agit tout simplement de l'outil le plus expressif qui existe pour rédiger des tests (et en français dans le texte !)

Sans aucun doute, Ruby on Rails peut donc être utilisé en contexte agile. Et comme l'agilité ne s'arrête pas aux tests, Rails va plus loin :

  • le déploiement automatisé est extrêment aisé avec Capistrano. Et même encore plus simple si vous utilisez un hébergeur comme heroku (git push heroku et ça tourne sur le cloud !)
  • la gestion incrémentale des bases de données, longuement décrite dans cet article, existe nativement dans Rails. Et par exemple, si l'un de vos coéquipiers livre du code altérant la base de données il vous suffira de lancer la commande "rake db:migrate" pour appliquer ces modifications (bien entendu pas besoin de redémarrer le serveur, même si c'est un réflexe bien ancré chez les Javaistes ;-) )

Je peux le faire aussi en Java !

Alors vous pourriez me rétorquer que des frameworks similaires à Rails ont vu le jour en Java (ils sont nommés "frameworks productifs" en Java, le sous-entendu pour le reste de l'écosystème Java est on ne peut plus clair !) :

  • Play Framework fait beaucoup parler de lui ces derniers temps. Il s'agit d'un clone de Rails très élégant dont la caractéristique première est d'utiliser Java, langage maitrisé par de très nombreux développeurs. Play séduit mais émerge encore.
  • Grails (pour Groovy On Rails) s'inspire en directe ligne de Rails, mais utilise le langage Groovy et met en oeuvre les frameworks standards de Java comme Spring ou Hibernate. Après déjà quelques années, Grails est loin de bénéficier d'une communauté aussi large que Rails.
  • Pour finir Spring a récemment créé Roo, son framework de productivité. Mais ce dernier peine à séduire et laisse perplexe quant à la stratégie de Spring sur le sujet (car rappelons que Grails est aussi un projet SpringSource).

Ces frameworks productifs sont certes intéressants, mais  vous vous mettriez clairement en retard de quelques années en utilisant un framework qui court derrière Rails. Et d'autre part vous vous priveriez d'une communauté extrêmement importante ...  Rails est pour sa part un projet toujours extrêmement actif et la version 3.0.0 du framework vient tout juste de sortir. Un prochain article sera consacré à l'utilisation de Ruby on Rails en entreprise.

Quelques mots pour conclure

Cet article aura pu vous sembler partisan, mais il est difficile de contenir son enthousiasme lorsque l'on écrit sur une technologie aussi séduisante. Sachez tout de même que les principaux manques que j'ai pu constater tournent autour de l'industrialisation (qui pour le coup est un sujet très mature en Java) :

  • le release management (gestion de releases avec dépendances multi-projets) n'est pas aussi carré qu'aven Maven. L'arrivée récente de Bundler est bénéfique, mais Rails demeure en retard sur ce sujet.
  • Metric-Fu est une solution de qualimétrie sympathique, mais de même ce n'est pas aussi agréable à utiliser qu'un Sonar.
  • Une autre partie de l'industrialisation concerne le poste de développement : si l'installation d'un poste de développeur Rails se déroule sans problème sur Mac, et de manière correcte sous Linux, le processus peut devenir extrêmement laborieux sous Windows !

J'espère que j'aurai su vous éveiller votre curiosité au sujet de Ruby on Rails. Pour ma part, je n'ai pas autant pris plaisir à développer que depuis que j'ai découvert cet outil !

Alors, vous vous y mettez quand ?