RSpec : let() it be

5 novembre 2009

What I’ve found

A few minutes ago, I was watching a great screencast of Corey Haines doing a kata.
I stopped when he was refactoring a few similar assigments. There was something I’ve never seen elsewhere, particularly in the also great RSpec book ; he used the let() method.

Going back and forth a few times, I understood the the method was assigning the result of the given block to an object named after the argument of let().

I googled to see if there was an explanation ; is it a custom helper he wrote, is it built-in RSpec, … ? but “RSpec let()” is returning a lot of results, and none was close to the answer I was looking for.

I then looked at the Rdoc for the RSpec gem ; no luck either.

Finally, I open the whole gem in Textmate and looked for “let” as a word.

I’ve found a use of the method in a spec (RSpec is speced with itself, how great is it?) with a similar scenario. I’ve also found the method declaration, and I have to say that it’s pretty self-explanatory :

  def let(name, &block)
    define_method name do
      @assignments ||= {}
      @assignments[name] ||= instance_eval(&block)
    end
  end

You have to pass a name and a block. It defines a new method (named after what’s in ‘name’). This new method returns the result of the block (whatever it returns) but is memoizes it in a global hash.

You can use the let() method in a describe block, if you want to create a method that is always returning the same value, determined by the result of the passed block. It is something you can do with a traditional before block with a simple variable assignment, but it’d be evaluated each time, though it’s not necessary. A simple variable is also subject to change if it’s not frozen or a constant.
Here, it’s just what it is and only what it needs to be.

What I like

First, I like that some very simple but usefull tools are available. I really sounds like something build after hundreds of times of repeating the same calls, … It’s very concise and DRY.

But I also like very much the way the hash is created if it doesn’t already exist, and the value is set only once,even on subsequent calls of the new method.

The dynamically created method could have been defined this way :

  define_method name do
    @assignments = {} if @assignments.nil?
    if @assignments[name].nil?
      @assignments[name] = instance_eval(&block)
    else
      @assignments[name]
    end
  end

but it’s boringly verbose and repetitive. The first way is way more readable and elegant.

If I have remember just a thing from Corey’s screencast, it’s the existence and the use of this beautiful let() method and how well it is written.

About Corey Haines

Corey is a great guy, one of the few that I really admire.

Amongst the thing that I like about him, he’s doing something that I’d really like to do : he’s traveling all over the USA and is offering to share some working (and fun) times for hospitality and friendship.

You can find about what he does on his profile page.

Thanks Corey !


Update 1 : The entire Kata is available on GitHub. There are 3 branches : the first is the start of the kata, with only the setup and the cucumber expectations. The second and third are implementations.

It’s very useful to read the initial state of the Kata and see where it ends, with all the tests and the implementation code.


Ruby et Rails ou bien PHP et Symfony ?

3 novembre 2009

Dans le cadre de mon travail chez Autrement, je bosse principalement sur du développement web en Ruby, avec l’aide du framework Ruby on Rails.

Je suis focalisé sur le développement d’une appli web (encore un eu secrète pour le moment), mais là, Autrement édite par ailleurs le site web chambresapart.fr
Le développement de ce site a commencé bien avant que je rejoigne l’équipe et il s’appuie sur le framework Symfony, basé sur PHP.

Actuellement l’équipe Chambres à Part se compose de 2,5 personnes qui sont toutes les 3 des développeurs confirmés, spécialisés sur PHP / Symfony.

Avant le lancement de la “version 1″ de Chambres à Part, j’ai participé au développement de certaines fonctionnalités, mais principalement sur des aspects HTML, CSS, Javascript, cartographie Google + Maptimize, …
La dernière semaine a été uniquement consacrée à du debuggage et pour ça j’ai mis un peu plus mon nez dans le code source du site et donc dans la partie “vue” (le V de MVC).

Je ne peux surtout pas prétendre connaître Symfony dans ce qu’il a de particulier par rapport à d’autres framework web (et MVC en particulier), mais je peux comparer ce que j’ai vu et ce que l’équipe raconte au quotidien avec ce que je connais et vis au quotidien depuis 3 ans avec Ruby et Rails.

De plus, j’ai développé quasi-exclusivement en PHP depuis les premiers temps du PHP3 jusqu’à PHP5, donc même si j’ai passablement oublié certains réflexes de manipulation du langage et la plupart de noms de méthodes, je pense avoir un avis assez circonstancié sur PHP.

La question

Pour le développement de la partie visible du projet sur lequel je suis mobilisé, d’autres personnes de l’équipe vont participer activement et durablement. Une question se pose donc inévitablement : Ruby on Rails ou bien Symfony ?

Notre boss comprend bien quand on lui parle de technique, avec des arguments clairs, mais il ne se sent pas (à raison) en mesure de décider lui-même d’un framework ou d’un langage plutôt qu’un autre. Il nous a donc demandé de préparer une discussion sur cette question, en apportant surtout des faits et des remarques objectives afin de tout mettre sur la table et tenter en équipe de prendre la bonne décision.

Je suis convaincu qu’il ne s’agit pas de valider ou invalider les choix des uns et des autres, mais plutôt de faire un état des lieux et s’orienter dans la meilleure décision.

Comme je suis quelqu’un de passionné, et qui ne se lance dans les choses qu’avec une forte conviction, j’ai quand même envie de convaincre que mon choix de quitter le développement en PHP pour le faire en Ruby n’est pas juste “mon choix” mais un choix lucide et cohérent.

Alors j’ai sorti un bout de papier et un crayon (ou plutôt un document “untitled.txt” et mon beau clavier) pour pondre une liste d’arguments.

Et puis je me suis dit que garder tout ça pour nous, en interne, était un peu égoïste. Pourquoi ne pas partager mes observations et mon analyse. Je ne pense pas que quiconque (au delà de notre équipe et mes copains geeks) s’intéresse à mon avis sur la question, mais un avis, ça peut donner des idées, participer à une réflexion, …

Présentation factuelle de Ruby et Rails

Ici je ne présente que des points clés, du moins ceux auxquels j’ai pensé.
Je ne détaillerai pas ces points, d’autres l’ont fait bien mieux que moi.

Ruby

  • 100% objet, pas de primitives
  • langage concis et lisible : moins de code, moins de bugs
  • langage dynamique, fortement typé
  • imprégné des méthodes de tests TDD et BDD (nombreux frameworks disponibles)
  • synergie avec les méthodes agiles
  • Ruby en ligne de commande (IRB), pratique pour des essais, …
  • Rubygems : gestionnaire de paquets additionnels
  • vitesse d’apprentissage
  • syntaxe et idiomes riches et avancés
  • meta-programmation
  • inspiré des meilleurs langages reconnus : Smalltalk, Lisp, Python, Perl, …
  • forte implication et marques de confiance des ténors : IBM, Sun, Apple, Microsoft, SAP, …
  • de nombreux frameworks de premier plan : Rails, Sinatra, …

J’invite à la lecture de la page de Ruby sur Wikipedia, que je trouve assez complète et claire.

Rails

  • dédié au développement d’appli web
  • architecture MVC
  • naturellement REST
  • forte incitation à DRY
  • convention plutôt que configuration
  • grand variété de helpers
  • des outils annexes très utiles : débuggage, déploiement, monitoring, …
  • des environnements d’exécution bien définis et cloisonnés
  • WebServices-friendly
  • système strict de migration des bases de données
  • framework complet accessible en ligne de commande
  • variété de backend pour le cache et les sessions : mémoire, fichiers, BDD, memcached, …
  • I18n
  • communauté très active
  • documentation riche (en ligne, livres, …)
  • Rack middlewares => empilement de briques fonctionnelles dédiées et modulaires : cache, debug, auth, …
  • logging avancé et personnalisable
  • fortes opinions, mais autres choix possibles : ORM, templates, framework JS, …

Pour une introduction à Rails, je vous renvoie vers le le guide de démarrage pour Rails ou Rails in a Nutshell (qui est encore en beta).

Analyse subjective (mais convaincue) de Ruby & Rails vs. PHP & Symfony

Là, je sors un peu des faits indéniables pour m’aventurer dans ma propre analyse des différences entre ces 2 frameworks (et leur langage sous-jacent respectif). Cette analyse est forcément subjective et je serai ravi d’entendre des avis contraires ou complémentaires.

PHP vs. Ruby

Prenons la métaphore de la caisse à outils.

PHP est une énorme caisse, dans laquelle il y a des outils pour presque tout, tellement que ça devient difficile de tout connaître. Il n’y a qu’à voir le site de la documentation officielle où le nombre de méthodes est impressionnant, sans parler de celles des librairies standards.

Il y a souvent plusieurs outils ou variantes pour faire presque la même chose. C’est pas forcément facile de savoir lequel choisir.

Cette boîte grandi très vite, il y a régulièrement de nouveaux outils, d’autres évoluent et certains disparaissent.

Ruby est une caisse beaucoup plus modeste, qui permet de faire tout autant de chose, mais il y a très peu de doublons ou recoupements.

Les outils sont robustes, stables et surtout cohérents entre eux. Le contenu de la boîte évolue peu, rarement et uniquement en cas de forte nécessité. Même entre les versions majeures (1.8 et 1.9) il y a très forte compatibilité. Au sein de la branche 1.8 il n’y a eu presqu’aucune perte de compatibilité importante depuis plus de 3 ans (sortie de la 1.8.5 en août 2006).

Les mises à jour de Ruby, en tant que langage, sont rares (12 à 18 mois entre chaque version stable) car il n’y a pas ou extrêmement peu de bugs, elles ne concernent que des nouveautés ou améliorations de fond. La raison de ce très faible nombre de bugs et failles de sécurité sont simples : le code est soumis à des tests systématiques et poussés (c’est dans la culture de la communauté Ruby) et le code étant simple lisible et clair, il est facile de l’auditer et le comprendre et donc d’en débusquer les failles.

À l’inverse, PHP est mis à jour beaucoup plus souvent (plusieurs fois par an) et contient de nombreux correctifs de bugs en plus de nouvelles fonctionnalités. Il est reconnu que les failles de sécurité importantes ou critiques sont relativement fréquentes.

La raison d’être de PHP n’était pas d’apporter une approche nouvelle du développement mais de répondre à un besoin simple et bien identifié : traiter les données issues d’un formulaire web. La simplicité et les fonctionnalités de ce nouveau langage l’ont rendu rapidement populaire chez les développeurs web car il n’y avait plus besoin de faire des CGI en Perl pour rendre des sites dynamiques.

Face à ce gain de popularité, le langage a grandi et permis de faire de plus en plus de choses assez facilement, mais rapidement on a constaté le manque de fondations solides, en particulier sur l’aspect Objet.

PHP rivalise alors, en terme de popularité et d’audience, avec Perl, Java, … et cherche alors à combler les manques et répondre aux critiques. Le résultat est plutôt efficace, mais les outils du début restent là et les mauvaises pratiques qui vont avec aussi.

Au final on a un langage riche, mais brouillon, fourre-tout, qui évolue par stratification et pas par transformation. Les fondations manquent de rigueur et de profondeur.

Ruby est un langage qui a été conçu avec une approche plus scientifique et globale. Son créateur voulait un langage moderne, plus proche des attentes de l’humain que de celles de la machine, mais qui reconnaisse et embrasse l’état de l’art, ce qui s’est fait de mieux. Il s’est donc contenté (si on peut dire) d’appliquer la parole des vieux sages dans un contexte moderne.

Ruby adopte le principe de la moindre surprise (au sens de la cohérence maximale) selon lequel le langage doit se comporter de manière à minimiser la confusion. Lorsqu’on découvre Ruby, qu’on vienne de Java, PHP ou Python, on est forcément surpris par la syntaxe, les idiomes, … mais avec le temps on adopte la “manière Ruby” et plus rien n’étonne. Dans d’autres langages, même après plusieurs années d’utilisation, on est parfois étonné ou dérouté par certains fonctionnements.

La syntaxe du langage est au service de son utilisateur, en favorisant la lisibilité et la concision. La simplicité des outils de base permet d’apprendre vite et de savoir rapidement lequel utiliser.

Ruby est bâti sur des fondations robustes et très strictes ; celles du tout Objet (il n’y a pas de primitives), de la meta-programmation, du typage dynamique mais fort, …

Symfony vs. Rails

Ruby on Rails est issu du développement d’une application web (Basecamp). Son créateur voulait se lancer dans le développement web et a cherché le langage avec lequel il se sentait le plus à l’aise et il s’est arrêté sur Ruby. Il a ensuite échafaudé un framework dédié au web en tirant réellement parti de ce que permet Ruby.

La démarche partait d’un objectif/besoin connu, il fallait trouver l’outil adapté pour l’atteindre.

Rails ne serait pas ce qu’il est sans Ruby. On ne peut pas recréer Rails sur un autre langage sans faire des tours de passe-passe et en perdre l’essence.

Symfony est issu du manque de bon framework web en PHP. Son créateur a voulu reprendre les bonnes idées d’autres frameworks (surtout Rails) sur d’autres langages pour les adapter sur PHP.

La démarche semble différente et partir d’un langage connu sur lequel construire en s’inspirant de références.

Pour ce que j’ai pu en voir et pour que Symfony ait le succès qu’il a, son développeur principal et la communauté qu’il a agrégée ont forcément accompli quelque chose de remarquable.

Pour autant, j’ai le sentiment que le plus grand handicap de Symfony, c’est PHP.

Conclusion

Au final, on sent que j’ai les idées bien arrêtées. J’espère ne pas avoir faire preuve de mauvaise foi ni avoir dit trop de bêtises.

Il m’arrive de dire que telle techno ou tel produit sont nuls. Mais pour le cas de PHP (et donc de Symfony), je ne dis pas que c’est nul et bon aux orties, au contraire.

Je dois certainement mon parcours de développeur web à PHP et à ce que j’ai pu faire avec. J’ai juste l’intime conviction d’avoir trouvé une évolution, une suite, qui me permet d’aller plus vite, plus loin, avec plus de plaisir/passion.

C’est un peu comme de passer de CVS ou Subversion à Git ou Mercurial. Vu de loin c’est la même chose, mais de près, ce sont 2 générations d’outils sui marquent un véritable progrès.


Soirée PLUG le 5 juin ‘09

24 mai 2009

Comme tous les mois depuis bien longtemps, le PLUG organise sa soirée mensuelle.

Ouverte à tous les fans de technologie, informatique, logiciels libres, … c’est la bonne occasion pour discuter de ses passions, rencontrer du monde, discuter de sujets connus ou pas et dans un endroit particulièrement sympa et confortable (La Bo[a]te).

Au programme de juin :

  • quelques sujets courts et libres inspirés de l’actualité et/ou de découvertes (l’improvisation est encouragée)
  • introduction pour la série sur le “Contrôle de version” ; c’est quoi ? pour quoi faire ? …

Et comme à chaque fois :

  • convivialité
  • apéro, pizza, …
  • rencontres, découvertes, …

Tous les détails sont dispo sur le site du PLUG : http://plugfr.org/


Migration vers Passenger

28 janvier 2009

Je viens de terminer et (assez longuement) raconter la migration que j’ai effectuée au boulot.

J’ai transformé le fonctionnement de plusieurs sites web à base de Nginx/Mongrel/Rails et Nginx/PHP-FCGI en Apache/Passenger et Apache/mod_php.

Tout est là :
- préambule
- Ruby Entreprise Edition
- VirtualHosts
- épilogue

Je me suis régalé à faire ça tranquillement, mais avec tout de même une bonne pression, car c’est sur un serveur de prod et c’était une première dans le genre pour moi.


Réunion du PLUG le 6 février

21 janvier 2009

Un petit post rapide pour signaler que le PLUG, tel un vieux garçon, tient à ses habitudes.

La prochaine réunion aura lieu à La Boate le 6 frévrier 2009 à partir de 19h.

Tous les détails sur le site du PLUG.


Soirée PLUG : Les services web et leur infrastructure d’hébergement

23 octobre 2008

J’annonce rarement les réunions du PLUG, ce qui est une honte vu mon role dans cette association, mais cette fois, ça vaut encore plus le coup que d’habitude.

Nous organisons une soirée spéciale sur le thème : les services web et leur infrastructure d’hébergement.

Le domaine est très vaste et relativement peu documenté vu la vitesse à laquelle les choses évoluent. L’idée est de réunir des gens qui souhaitent faire part de leur expérience et écouter celle des autres pour enrichir leur connaissance du sujet.

La soirée aura lieu en 2 temps, les vendredi 7 novembre et 5 décembre, à La Bo[a]te à Marseille.

Pour plus d’info, référez vous au site du PLUG et la page dédiée à l’annonce de cette soirée.

N’hésitez pas à m’écrire directement ou par les commentaire à ce post pour donner des idées, poser des questions sur la soirée, …


Montage NFS qui décroche sur Mac OS X

26 août 2008

Je viens de m’artracher les cheveux pendant 2 bonnes heures pour un problème tout con, qui vient de moi en plus, mais comme le ridicule ne tue pas, j’en fais profiter.

Je travaille sur un Mac OS X (10.5.4) avec TextMate et j’ai un point de montage NFS provenant d’un serveur sous Debian Etch.

Ce matin, alors que je testais un plugin pour TextMate qui l’empêche de faire la mise à jour (très lente car sur le réseau) des metadonnées de chaque fichier de mon projet, la sauvegarde du moindre fichier met plusieurs dizaines de secondes et le montage NFS fini par disparaître, puis réapparaître.

J’ai commencé par désinstaller ce plugin, l’incriminant immédiatement de toutes les fautes du monde. J’ai rebooté mon serveur ET mon client mais rien n’y faisais

L’exploration des logs me dit que lockd ne réponds pas.

J’ai fini par comprendre incidemment que c’est l’activation de mon firewall local (hier soir alors que j’étais fatigué) qui empêchait le dialogue de se faire correctement. Evidemment après l’avoir désactivé, plus de soucis.

Il me reste encore à trouver comment régler manuellement mon firewall pour autoriser le dialogue au niveau de NFS, mais ça sera pour plus tard.


Réunion du PLUG le 4 juillet

13 juin 2008

Contre toute attente, le PLUG tient sa réunion mensuelle le 4 juillet à partir de 19h à La Bo[a]te.

Vous êtes tous invités.


Astuce pour “ssh-copy-id” sur un port ssh différent

29 mai 2008

Bon, a priori vous connaissez la commande “ssh-copy-id” pour copier sa clé publique sur un serveur distant afin de s’identifier par clé et plus par mot de passe.

Le principe est d’avoir une paire de clés privée/publique, le plus souvent dans “~/.ssh/id_rsa(.pub)” et de la copier à l’intérieur du fichier “~/.ssh/authorized_keys” sur la machine distante.

$ ssh-copy-id -i ~/.ssh/id_rsa.pub user@host

Mais si la machine distante n’accepte pas les connexions sur le port 22 ou bien qu’il y a une redirection de ports sur le routeur, il faut lui indiquer ce port, par exemple :

$ ssh-copy-id -i ~/.ssh/id_rsa.pub -p 2222 user@host

Mais ça ne marche pas car ssh-copy-id ne comprend que 2 paramètres et si on met “-p 2222″ en second, ça n’est pas un motif de type “[user@]host”, et si on le met après, en troisième, il est ignoré.

Et bien il suffit d’entourer les infos de connexion ssh par des guillemets pour qu’ils soient vus comme un seul paramètre :

$ ssh-copy-id -i ~/.ssh/id_rsa.pub “-p 2222 user@host”


Réunion du PLUG le 6 juin

19 mai 2008

J’oublie souvent de l’annoncer ici,mais comme chaque premier vendredi du mois, le PLUG oganise une réunion à La Bo[a]te.

Cette fois ci c’est le 6 juin, à partir de 19h.

Tous les détails sont sur le site du PLUG.