InfOsaurus

Aller au contenu | Aller au menu | Aller à la recherche

jeudi 3 novembre 2011

Agile(s) Tour(s) 2011

Cette année, j'ai eu la chance de participer à deux dates de l'Agile Tour : le 20 Octobre à Montpellier suivi de celui de Bordeaux le 21. Voici un petit retour sur les 2 événements.

Agile Tour Montpellier


Agile Tour Montpellier

Le lieu

Ce premier Agile Tour montpelliérain avait lieu à l'école Polytech sur le campus de l'Université Montpellier 2. Quatre salles dont un grand amphi avaient été réservées pour l'occasion. Du côté du programme, la volonté affichée était de cibler 2 types de publics : les décideurs ("boss") et les développeurs ("geeks") plus les étudiants et universitaires.


Sessions

Software Craftsmanship par Jean-Laurent de Morhlon

J-L de Morlhon
Beaucoup de choses intéressantes dans cette présentation qui couvrait plein de sujets sur la théorie et la pratique de Software Craftsmanship, de l'historique du mouvement au manifeste en passant par les pratiques comme TDD et SOLID. Quelques morceaux choisis :

  • Ne pas s'en tenir au Craftsmanship Manifesto, flou et difficile à comprendre, voire même l'oublier.
  • Besoin de rétablir l'équilibre entre process et pratiques de développement, ces dernières sous-estimées notamment dans certaines implémentations actuelles de Scrum.
  • Une des techniques d'apprentissage les plus efficaces reste le mentoring ("conduite accompagnée").
  • Notion "d'heures de vol" accumulées nécessaires pour atteindre un certain niveau, comme un pilote d'avion.
  • Pair Hero et Ping Pong Programming permettent de pratiquer en s'amusant.

A noter que la slide "! Art" (le développement n'est pas de l'art) a fait réagir et suscité un vif débat philosophique sur la signification de l'art ;-)

Au final, une session maitrisée et fort sympathique ; même si on connait déjà un peu le sujet, c'est toujours enrichissant d'avoir le point de vue de personnes éclairées surtout sur un domaine peu exploré en France comme Software Craftsmanship.

Le pilotage par les tests par Jérôme Avoustin

Cette session présentait TDD, ATDD et BDD avec des démos et en filigrane un retour d'expérience sur un projet piloté par les tests. Jérôme nous avait prévenu que le rythme allait être élevé pour tout faire tenir en une heure, et en effet le contenu était riche.

  • J'ai bien aimé l'approche "top-down" mise en place sur le projet qui est une sorte de méta-cycle red-green-refactor où on crée un test BDD rouge avant d'écrire les tests de plus bas niveau en TDD, et on reboucle sur le passage à vert du test BDD pour finir.
  • Enseignement instructif sur l'évolution de la façon de développer : avec cette approche, le temps passé en tests a beaucoup augmenté mais celui passé à debugger a énormément diminué.
  • Définition de la qualité qui me plait bien : c'est quand le coût d'ajout d'une fonctionnalité est stable.

En tout cas, encore une présentation qui donne envie de faire du BDD :) Il est intéressant d'avoir des retours d'expérience sur de vrais projets qui l'ont mis en place, finalement pas si nombreux.

Contractualisation agile par Jean-Francois Jagodzinski

La session de cet Agile Tour qui m'a laissé le plus perplexe. J'ai l'impression que toute la présentation tournait autour du pot des contrats agiles sans jamais vraiment attaquer le sujet. Jean-Francois Jagodzinski était un peu en mode questionnement socratique et je n'ai pas vraiment vu où il venait en venir...
Heureusement des membres du public ont posé les "questions qui fâchent" à la fin en allant droit au but, ce qui a permis d'amorcer une discussion sur les difficultés des contrats agiles.

Une autre présentation de Jean-François est disponible sur slideshare mais ce n'est pas exactement celle de l'AT Montpellier.

Bref, je sors mon joker pour celle-là, je devais être trop endormi après le buffet...

Transformation agile au delà des équipes projet, par Romain Vignes

Un retour d'expérience instructif sur la transformation agile menée au sein de la société Wyplay, éditeur de logiciels de TV numérique, avec notamment comme clients SFR et Vodafone. Voici ce que j'ai noté :

  • Points de difficulté dans l'adoption de Scrum : organigramme à revoir, auto-organisation et discipline, transparence, disponibilité du client.
  • Autre difficulté importante : passage d'équipes multi-projets mais mono-métier à des équipes mono-projet mais inter-disciplinaires.
  • Une métrique intéressante utilisée chez Wyplay pour limiter l'éparpillement : Team Turn Over = Nb développeurs à cheval sur 2 projets ou + / nb total de dev.
  • Point d'accord avec la présentation de Jérôme Avoustin : le temps de debug s'est rapidement raccourci suite à l'adoption de l'agilité.

Projet et Cycle de vie agile par Thierry Cros


Thierry Cros

Une présentation classique mais efficace sur le cycle de vie des projets agiles. Quelques points que j'ai relevés :

  • Nécessité d'apprendre le "jeu de la planification agile"
  • La phase projet et la phase maintenance d'une application ne formeraient qu'une seule phase de pilotage par feedback
  • "Estimation belote" est plus proche de la réalité que Planning Poker :)


Ce que j'ai aimé

  • L'accueil très pro des organisateurs
  • Bonnes présentations "Geek"
  • Pas mal d'ateliers
  • Le buffet servi à midi
  • Les conférences de l'amphi retransmises sur Lanyrd


Ce que j'ai moins aimé

  • Peut-être moins de mélanges entre "populations" du fait de la séparation très marquée des sessions "geeks"/"boss"

Quoi qu'il en soit, pour une première c'était très réussi, chapeau bas aux organisateurs et orateurs qui ont parfaitement su faire prendre la mayonnaise !


Agile Tour Bordeaux


Agile Tour Bordeaux

Le lieu

Pour la seconde fois, l'AT Bordeaux se déroulait à l'Enseirb. Là aussi, 4 salles dont un grand amphi étaient réservées, avec un sympathique espace ouvert au rez-de chaussée. Le programme était un peu plus orienté ateliers que les années précédentes, avec un coding dojo, un Kanban Game, un atelier Billes Rouges, l'espace ouvert... mais les présentations techniques ou orientées projet étaient bien entendu présentes.


Sessions

Kata Marrant par Emmanuel Gaillot et Jonathan Perret


E. Gaillot et J. Perret

Si vous n'avez pas encore vécu une prestation de ces deux hurluberlus, je vous conseille vivement d'en faire l'expérience. On assiste à une vraie pièce de théâtre d'impro, où le public participe en déposant des suggestions de thèmes ou de manières de coder dans une corbeille.

Chaton interstellaire, arc-en-ciel de sodium... difficile de décrire ce qui est sorti de ce kata mais le fun était bien là !

J'ai découvert par la même occasion CoffeeScript, un petit langage sympa qui dépouille JavaScript de ses accolades et points-virgules.

Ni gladiateurs, ni bisounours par Christophe Thibaut

Sans doute la présentation la plus radicale et la plus propice à réflexion à laquelle j'ai eu l'occasion d'assister lors de ces Agile Tour. La première partie recensait des anti-patterns d'équipes très bien vus ("Nez dans le guidon", "Maillon faible", "Feu de camp"...) dans lesquels je pense la majorité du public s'est reconnu. Venaient ensuite des propositions de solutions avec les Core Protocols. Je ne vais pas tous les décrire mais il s'agit de techniques (dont certaines assez déconcertantes) favorisant la communication d'équipe. Je ne sais pas si elles sont toutes applicables telles quelles partout, mais c'est en tout cas certainement une bonne source d'inspiration.

2 moments de "déclic" parmi d'autres :

  • "On peut influer sur la motivation d'une personne uniquement négativement"
  • "Les membres d'une équipe sont comme les cartes composant une quinte flush, elles n'ont d'intérêt que par les relations qui les lient"

Quarante ans de crise, dix ans d'agilité par Laurent Bossavit


Laurent Bossavit

J'avais déjà vu cette présentation en vidéo, mais en vrai, c'est quand même vachement mieux... Laurent y met en perspective - ce qui à ma connaissance a rarement été fait auparavant - l'histoire du génie logiciel depuis ses origines à une conférence de l'OTAN en 1968 jusqu'à nos jours, avec l'état actuel de la discipline. L'exercice est riche en enseignements et force est de constater que la plupart des questions posées il y a 40 ans n'ont toujours pas trouvé de réponse.

La présentation explique ensuite pourquoi Agile est une innovation de rupture et s'ouvre enfin sur la perspective de l'avenir de l'agilité et la proposition de passer d'une culture agile orale à une culture plus formalisée avec l'Institut Agile et une prise en compte accrue de l'agilité dans les programmes des universités.

Si vous n'avez pas encore vu cette vidéo, je vous la conseille vivement.

TDD, je commence demain ! par Fabien Bézagu

Le pari de cette session était osé - faire découvrir Test Driven Development et convaincre les développeurs présents de franchir le cap dans leur job. Tout cela en commençant par une démonstration en PHP (qui a dit qu'il y avait des sous-langages ?...) L'ensemble était bien mené par Fabien malgré un public que j'ai senti pas aussi avide d'échanges qu'espéré.


Ce que j'ai aimé

  • Beaucoup de sessions techniques orientés "geek" (même si je n'aime pas ce mot) et d'ateliers
  • Le mot des sponsors beaucoup plus agréable, avec moins de concours de qui a la plus grosse agilité que l'année dernière (qui a dit normal, il n'y avait pas de SSII ?...)
  • L'organisation toujours au poil
  • Les orateurs toujours disponibles pour discuter, un plaisir


Ce que j'ai moins aimé

  • L'espace ouvert qui manquait de prise en charge des nouveaux arrivants
  • Le coding dojo dur à rattraper en cours de route si on n'avait pas suivi au début
  • Les coups de gong du Sky Castle Game qui ont semblé perturber les acteurs du Kata Marrant (qui ont quand même essayé de rivaliser, avec leur petite sonnette !)
  • Les 2h de retard du TGV de la nuit précédente, heureusement j'ai pu tenir avec moult café pendant la conférence ;)


L'équipe de l'Agile Tour Bordeaux


Pour conclure, un grand merci à tous les organisateurs et participants des deux Agile Tour et à l'année prochaine !

mardi 5 octobre 2010

L'auto-organisation : analyse d'un concept subversif

« The best architectures, requirements, and designs emerge from self-organizing teams. »

Cet extrait du Manifeste agile met en lumière un des points importants de la réussite d'une démarche agile : la capacité d'une équipe projet informatique à s'organiser elle-même. Mais même si la notion est connue et souvent évoquée comme qualité première d'une équipe agile, qu'entend-on précisément par auto-organisation et quelles peuvent être ses limites ?

Auto-organisation 3

Un phénomène émergent

Voici la définition que donne Wikipedia de l'auto-organisation dans le domaine des sciences physiques et de la systémique :

« Le terme auto-organisation fait référence à un processus dans lequel l'organisation interne d'un système, habituellement un système hors équilibre, augmente automatiquement sans être dirigée par une source extérieure. Typiquement, les systèmes auto-organisées ont des propriétés émergentes (bien que cela ne soit pas toujours le cas). »

Il est amusant de constater une certaine ressemblance avec la définition agile de l'auto-organisation, bien qu'elle recouvre d'autres réalités. L'auto-organisation n'est pas une valeur, ni une pratique ou même une compétence. Le manifeste agile la classe parmi les principes, mais on peut aussi parler de phénomène d'auto-organisation car c'est en réalité le résultat de plusieurs façons de fonctionner qui se mettent en place progressivement au sein d'une équipe :

Répartition collective des tâches. Alors que dans un système hiérarchisé traditionnel de type command and control c'est le plus souvent le chef de projet qui assigne individuellement les tâches aux développeurs, les équipes agiles se répartissent le travail de manière collective. Plus exactement, il s'agit d'une auto-attribution libre du travail avec accord tacite du collectif : le membre de l'équipe choisit lui-même sa prochaine tâche mais il le fait en présence et avec l'approbation de tous ses coéquipiers. Le moment précis pour cette attribution est celui du standup meeting / daily scrum dont la fréquence journalière permet un ajustement du partage du travail au plus près de la réalité du moment. Effet collatéral : exit les diagrammes de Gantt planifiés des semaines à l'avance ; une partie importante des prérogatives du chef de projet disparait, ce qui n'est pas sans poser problème à certains comme nous le verrons plus loin.

Engagement collectif. Dans un mode de fonctionnement agile, l'équipe s'engage auprès du client à produire au cours de l'itération suivante un certain nombre de fonctionnalités représentant une valeur métier pour ce dernier. C'est un des moments importants où l'équipe en tant que bloc solidaire prend ses responsabilités vis-à-vis de l'extérieur. Cela contraste fortement avec la gestion de projet classique où la responsabilité est plutôt individuelle, chaque développeur s'engageant à respecter l'estimation qu'il a chiffré (ou que quelqu'un d'autre a chiffré pour lui !) et des "fusibles" hiérarchiques successifs sont en place : si quelque chose dysfonctionne, c'est d'abord le chef de projet qui est responsable puis il va chercher le membre de l'équipe qui a fauté pour en tirer les conséquences.

Appropriation collective du projet. Une équipe auto-organisée se caractérise ensuite par une cohésion interne forte assortie d'une réelle prise en main des enjeux du projet, obligatoire du moment où l'équipe ne reçoit plus d'ordres extérieurs directs sur la façon de faire. Ce sentiment d'appartenance à la une même tribu, d'adhésion à une même cause est renforcé par les "rituels" agiles tels le daily standup (et qui gravitent autour du task board, comme le décrit très bien Tobias Mayer) ainsi que des pratiques comme le pair programming qui permettent de propager la connaissance du logiciel efficacement parmi les membres de l'équipe.

Amélioration collective. Ce point rejoint la deuxième partie de la définition scientifique de l'auto-organisation : "Typiquement, les systèmes auto-organisées ont des propriétés émergentes". En effet, un système auto-organisé ne naît pas avec un fonctionnement parfait, il l'adapte et l'améliore au fil du temps. En agilité, ce sont bien sûr les rétrospectives et autres dispositifs inspect & adapt qui jouent ce rôle en vue d'une évolution continue.


Auto-organisation4

Les raisons du débat

Voilà pour les traits principaux d'une équipe auto-organisée, mais force est de constater que le concept est loin de faire l'unanimité parmi les acteurs de l'informatique et suscite beaucoup de réticences. Pourquoi cette subversivité alors que les méthodes agiles se veulent être de plus en plus courantes ? Je pense que cela tient essentiellement à trois raisons :

  • Comme je l'ai dit plus haut, le déplacement vers l'équipe de beaucoup des prérogatives du chef de projet (pouvoir d'assigner et de planifier les tâches de développement comme bon lui semble, interface avec le client...) fait grincer des dents, en particulier chez les premiers concernés. On peut les comprendre, d'autant plus qu'en étant tout à fait honnête, il reste quand même aujourd'hui un gros flou autour de ce qui se passe une fois que la méthode a dit "le Scrum Master/coach n'est pas un chef de projet", voire "il n'y a plus de chef de projet du tout". A qui reviennent les responsabilités comme le suivi budgétaire et comptable, les aspects administratifs, les procédures internes, le recrutement... ?
    Piste intéressante : dans un récent billet, Laurent Bossavit, fondateur de l'Institut agile, fait appel à une théorie de l'économiste Ricardo sur la spécialisation du travail pour apporter un début de réponse à cette crainte. Il pose la question suivante : dans un environnement agile, est-il obligatoire de conserver des rôles personnels rigides regroupant un cortège de responsabilités bien fixées, ou s'il ne serait pas plus judicieux de les éclater en répartissant les responsabilités en fonction des compétences de chacun ?
  • Deuxième crainte soulevée par l'auto-organisation : le renversement de paradigme que cela implique. Aplatissement de la hiérarchie, bouleversement des canons de l'organisation du travail et des rôles de chacun, et pas seulement à l'intérieur des équipes de développement... C'est tout le problème de la douloureuse transition d'une structure pyramidale de type command & control à un contexte agile où l'encadrement s'apparente plus à du servant leadership, ce qui touche uniquement les équipes projets dans un premier temps mais a vocation à être assez viral dans toute l'entreprise. A ce propos je vous recommande la très bonne présentation de Roman Pichler sur le changement de rôle des managers dans Scrum.
  • En dernier ressort, inutile de se le cacher, l'idée d'auto-organisation déclenche chez beaucoup et surtout les anglo-saxons, par un réflexe quasi-psychologique, un rapprochement avec des concepts revendiqués par des mouvements d'extrême-gauche : pouvoir au peuple, anarchisme, libertarisme... et aussi l'auto-gestion, cousine lointaine de l'auto-organisation. La crainte implicite sous-jacente est que l'équipe devienne un électron libre, hors de contrôle de l'entreprise, ou, pire, que le rapport de contrôle s'inverse.

Auto-organisation2

Le spectre de l'auto-gestion

Apparu à la fin du XIXème siècle, le concept d'auto-gestion caractérise un groupe, souvent producteur de biens ou services en petite quantité, dont le principe est justement d'être un électron libre. Les décisions se prennent exclusivement parmi ses membres qui sont en général sur un pied d'égalité. Au cours de l'histoire, l'auto-gestion a été expérimentée dans des environnements multiples : coopératives ouvrières, agricoles, jardins partagés, regroupements de salariés... Certaines entreprises d'ingénierie informatique s'y essaient même de nos jours.
Malgré le succès d'un certain nombre de ces entreprises, on retient souvent les mésententes fréquentes entre membres de l'organisme auto-géré ou l'embourbement dans des pourparlers interminables qui peuvent paralyser l'activité du groupe et faire avorter l'initiative. Souvent qualifiés d'utopistes, de doux rêveurs, les participants de ce type d'aventure n'ont malheureusement pas une grande réputation de sérieux. Et c'est précisément cela que craignent les managers : remettre un pouvoir de décision entre les mains de l'équipe ne revient-il pas à le confier à des personnes peu habituées à la responsabilité et trop nombreuses pour trancher, résultant en un "grand n'importe quoi" ? Quels que soient les termes, la question mérite d'être posée.

Dans la même mouvance sociale, il est aussi intéressant de voir que certains agilistes se définissent explicitement comme anarchistes et contribuent activement à porter les méthodes agiles à d'autres domaines que l'informatique, comme par exemple Tobias Mayer (oui, encore lui). Ils restent pourtant rares.

Pour finir

Revenons à la définition de l'auto-organisation en agilité : il est utile de noter que le manifeste agile ne s'aventure pas à la prôner en-dehors de l'équipe projet et des "architectures, requirements, and designs". Pas de volonté affichée de révolution sociale à l'échelle de l'entreprise toute entière de la part des "pères fondateurs", donc. Mais essayer de faire fonctionner le phénomène auto-organisation au niveau développement ne serait déjà pas si mal. Si davantage d'entreprises engagées dans une démarche agile faisaient preuve de confiance et de lâcher-prise vis-à-vis de leurs équipes et abandonnaient pour de bon le sacro-saint besoin de contrôle et de pilotage individuel, sans doute ferait-on un grand pas dans la réussite des projets, la qualité du logiciel livré et le bien-être des collaborateurs.

dimanche 15 août 2010

FreakAngels

Bon, c'est vrai qu'il est un peu tard pour les recommandations de livres d'été. Mais je me devais de vous signaler une BD moyen format qui pourrait être votre parfait compagnon sur la plage en cette fin de vacances (si vous avez la chance d'en avoir) : FreakAngels.

FreakAngels

Le pitch :

Londres, dans un futur pas si lointain. Une catastrophe sans précédent a ravagé la ville, la submergeant en partie sous l'eau de mer. Dans le calme post-apocalyptique du quartier de Whitechapel, les survivants se sont organisés tant bien que mal mais le manque d'eau potable et de vivres se fait cruellement ressentir.

Heureusement, les FreakAngels veillent.

Ces onze jeunes hommes et femmes aux étonnants pouvoirs télépathiques qui ont organisé le ravitaillement et la défense du quartier sont la seule lueur d'espoir de la population. Mais quels que soient leurs mérites, on comprend très vite que ces anges ont aussi leur part d'ombre et des travers bien humains, à commencer par Mark, le douzième membre renégat exilé dans le Nord. Tout commence lorsqu'une jeune fille, Alice, est envoyée à WhiteChapel par Mark pour abattre l'un des autres FreakAngels...

page15 page16 page17 page18


Réalisé par deux Anglais, Warren Ellis et Paul Duffield, dont le style mêle manga européen, comics et ligne claire, FreakAngels se déroule dans un monde de disaster fiction désabusé mais inventif, à l'image de ses habitants qui doivent faire preuve d'ingéniosité pour survivre. Un peu comme dans la classique BD Neige, un petit groupe d'individus détient la clé du désastre qui a frappé la région, et, qui sait, pourra peut-être réparer les dégâts.
Ce qui fait l'intérêt de FreakAngels, c'est que malgré les pouvoirs de super-héros des personnages pricipaux, on est loin d'avoir affaire à des sauveurs au-dessus de tout reproche. Les membres de la bande sont tour à tour violents, paranoïaques, nymphomanes, parasitiques, névrosés, et passent une bonne partie de leur temps en franches engueulades (dialogues savoureux signés Ellis) avec des conséquences fâcheuses, pouvoirs psy obligent. Loin d'être entièrement axé sur le paranormal, le comic fait la part belle à l'humanité des personnages. Avec ou sans pouvoirs, ce sont avant tout de jeunes adultes paumés qui tentent tant bien que mal d'assumer (ou pas) les responsabilités qui leur incombent dans ce monde bouleversé.

FreakAngels 1 est sorti il y a peu en français aux éditions du Lombard mais c'est à l'origine un webcomic hebdomadaire gratuit proposé par les auteurs sur www.freakangels.com. La VO est donc disponible gratuitement jusqu'au tome 5... de quoi craquer en attendant le deuxième livre en VF ;)

lundi 5 juillet 2010

Surplus cognitif et contraintes sociales

Je me balade souvent sur le site de la fondation TED, bien connue pour ses conférences. On y trouve des vidéos de présentations très inspirantes sur des sujets comme les nouvelles technologies, l'environnement, les sciences...

Cette fois-ci, je suis tombé sur une intervention récente de Clay Shirky : "How cognitive surplus will change the world", que j'aimerais vous faire partager :

 

Quels enseignements peut-on tirer de ce que dit Shirky ?

  • L'ère d'un peuple de "couch potatoes" vautrées devant la télé est sur le déclin. Grâce à Internet et aux nouvelles technologies, la motivation dispose d'un nouveau carburant, les initiatives sont permises et chacun devient capable de créer et de partager - pour le meilleur et pour le pire.
  • Les contraintes contractuelles sont souvent bien moins efficaces que les contraintes sociales. Les contraintes contractuelles peuvent paradoxalement fausser le jeu en déculpabilisant les acteurs qui les subissent au détriment du bien général de l'organisation, et ainsi déteriorer durablement la culture de celle-ci.
    "Social collaboration over contract negotiation" en quelque sorte... ça ne vous rappelle rien ? ;)

 

PS : j'ai aussi réalisé une version française de la vidéo, mais le lecteur TED avec sous-titres ayant refusé de se laisser embedder, vous pouvez la retrouver [ici].

mercredi 2 juin 2010

Persistez votre domaine avec Raven DB

 

RavensIl y a peu, je vous parlais d'une possible synergie entre les bases de données NoSQL de type document et les Agrégats de Domain Driven Design.

Entretemps est sortie la base NoSQL pour la plateforme .NET d'Ayende Rahien, Raven DB, et elle confirme ces suppositions. Voici un extrait de la documentation de la base au corbeau :

« When thinking about using Raven to persist entities, we need to consider the two previous points. The suggested approach is to follow the Aggregate pattern from the Domain Driven Design book. An Aggregate Root contains several entities and value types and controls all access to the objects contained in its boundaries. External references may only refer to the Aggregate Root, never to one of its child objects.
When you apply this sort of thinking to a document database, there is a natural and easy to follow correlation between an Aggregate Root (in DDD terms) and a document in Raven. An Aggregate Root, and all the objects that it holds, is a document in Raven. »

Avec Raven, les données sont stockées dans des documents JSON qui ressemblent à ça :


Document

Contrairement à une base relationnelle dans laquelle les données résident dans des tables fragmentées qu'on peut relier par l'intégrité référentielle, il est possible de stocker dans ce type de document tout un graphe d'objets complexes et typés. Les préconisations pour la conception de documents Raven sont donc à l'inverse de celles qui président au design d'une base de données relationnelle : il s'agit de regrouper au sein d'un seul document les objets formant un tout logique. Par exemple, un Livre regroupe à la fois un titre mais aussi les objets que sont son Auteur et sa Catégorie. Il se trouve que la notion d'Agrégat et de Racine d'Agrégat de DDD recoupe en tous points ce concept.

Un des bénéfices qu'on constate immédiatement avec Raven DB est l'élimination pure et simple de la couche de mapping objet-relationnel, parfois source de bien des complications. En effet avec Raven, plus de défaut d'impédance entre les objets de l'application et leur équivalent persisté relationnel. La couche persistance s'en trouve bien allégée.


Exemple en C#

Comme un bon exemple vaut tous les discours, voici comment on peut implémenter un Entrepôt avec Raven et son client C# natif :


   1:      public class Livre
   2:      {
   3:          public string Id { get; set; }
   4:          public Auteur Auteur { get; set; }
   5:          public string Titre { get; set; }
   6:          public Categorie Categorie { get; set; }
   7:      }


   1:      public class EntrepotLivres
   2:      {
   3:          public EntrepotLivres(IDocumentSession documentSession)
   4:          {
   5:              session = documentSession;
   6:          }
   7:   
   8:          public void AjouterLivre(Livre livre)
   9:          {
  10:              session.Store(livre);
  11:              session.SaveChanges();
  12:          }
  13:   
  14:          public void SupprimerLivre(Livre livre)
  15:          {
  16:              session.Delete(livre);
  17:              session.SaveChanges();
  18:          }
  19:   
  20:          public Livre GetLivreParId(string id)
  21:          {
  22:              return session.Load<Livre>(id);
  23:          }
  24:   
  25:          private IDocumentSession session;
  26:      }


   1:  class Program
   2:  {
   3:      static void Main(string[] args)
   4:      {
   5:          var documentStore = new DocumentStore { Url = "http://localhost:8080" };
   6:          documentStore.Initialize();
   7:   
   8:          using (var session = documentStore.OpenSession())
   9:          {
  10:              EntrepotLivres entrepotLivres = new EntrepotLivres(session);
  11:              ...
  12:          }
  13:      }
  14:  }

Pas de fichier de mapping à gérer à côté de ça, l'entité Livre et tout ce qu'elle contient se persistera de façon immédiate... Simple, non ?

On remarque qu'on manipule une Session Raven. Il s'agit d'une implémentation du pattern Unit of Work assez similaire à ce qu'on trouve dans des frameworks d'ORM comme NHibernate. En fait, bon nombre de concepts et dénominations dans l'API client C# de Raven sont directement issus de NHibernate.


Index et requêtes

Pour l'instant, notre Entrepôt ne fait qu'ajouter des entités, les supprimer et les hydrater à partir de leur ID, ce qui se fait nativement avec Raven. Pour exécuter des requêtes plus complexes sur nos documents, il faut passer par des index. Les index sont des vues stockées sur disque semblables aux vues matérialisées des SGBDR. Ils sont taillés pour un type de recherche particulier.

Voici comment on définit en C# un index qui porte sur les catégories des livres :


   1:          documentStore.DatabaseCommands.PutIndex("LivresParCategorie", 
   2:              new IndexDefinition<Livre>
   3:              {
   4:                  Map = livres => from livre in livres
   5:                                  select new { livre.Categorie }
   6:              });

Cet index ne doit être créé qu'une fois, il peut aussi être défini via l'interface d'administration de Raven en utilisant la même syntaxe.

On peut maintenant ajouter une méthode à notre entrepôt qui retourne tous les livres d'une catégorie. Elle effectue une requête LuceneQuery sur l'index précédemment défini :


   1:          public IList<Livre> GetLivresParCategorie(Categorie categorie)
   2:          {
   3:              return session.LuceneQuery<Livre>("LivresParCategorie")
   4:                  .Where(l => l.Categorie == categorie)
   5:                  .ToList();
   6:          }

Il existe une autre technique d'indexation plus sophistiquée, map/reduce, dont je parlerai peut-être dans un autre billet.


Raven DB

Impressions


Ce que j'aime dans Raven DB :

  • Simplicité de persistance des objets et affranchissement complet de la couche d'ORM.
  • Les données sont accessibles sous forme RESTful (chaque document dispose d'une URL) et lisible par un humain.
  • Sans doute bien plus facilement scalable qu'un SGBDR du fait de la nature atomique et autonome d'un document.
  • API .NET et requêtage sur les indexes en Linq.
  • Raven se marie bien avec DDD et une partie de l'effort de design de la base est déjà fait si on a découpé ses Agrégats.

Ce qui me plait moins :

  • Pour exploiter pleinement Raven en termes de performances, il faut idéalement ramener un seul document de la base et que celui-ci contienne tout ce dont on a besoin. Cela peut mener à une tendance à calquer les documents sur les IHM.
  • Raven DB a peut-être un petit impact sur la persistance ignorance de notre domaine. Il semble qu'une entité qui fait référence à la racine d'un autre agrégat (donc située dans un autre document, en termes Raven) ne peut pas avoir une référence directe à cet objet mais est obligé de contenir son ID à la place. Dans notre exemple, l'Auteur d'un Livre est un objet entièrement contenu dans l'agrégat Livre parce qu'on ne stocke que son nom et prénom. Mais si l'Auteur devait faire l'objet d'un agrégat séparé à lui (par exemple si l'auteur est un Utilisateur du système), le Livre devrait alors contenir la clé de l'Auteur et plus l'Auteur lui même. Sachant que les IDs natifs de Raven sont très typiques ("auteurs/465" par exemple), on se retrouve avec une trace de Raven dans le graphe d'objets du domaine, et aussi la nécessité de passer par un entrepôt pour réhydrater l'objet dont on n'a que la clé.

Les doutes à lever à l'avenir :

  • Les performances. Ayende a publié des mesures de perfs prometteuses mais il va falloir qu'elles soient confirmées sur des projets à plus grande échelle. En particulier, il serait intéressant de voir comment le système de concurrence optimiste de Raven se comporte dans un contexte transactionnel intensif.
  • L'adoption. Je pense que les bases NoSQL ne survivront pas sans un écosystème solide à la fois en termes de communauté et d'outillage disponible. Si on ne peut pas faire avec les bases non relationnelles tout ce qu'on fait avec les SGBDR (monitoring, tuning, reporting, analyse de données...), elles resteront une bonne idée sur le papier mais un choix pauvre sur le terrain.

lundi 17 mai 2010

Bientôt l'été ! Quelques recettes pour faire mincir... ses TU

Régime

 

  1:  [Test]
  2:  public void GetTousLivres_Retourne_Tous_Livres()
  3:  {
  4:      EntrepotLivres entrepotLivres = new EntrepotLivres();
  5:      Auteur evans = new Auteur("Evans", "Eric");
  6:      CategorieLivre categorie = new CategorieLivre("Développement");
  7:      Adresse adresse = new Adresse("55 rue des Pommiers");
  8:      Librairie librairie = FabriqueLibrairie.Creer("Librairie la Pomme d'Or", adresse);
  9:      IList<Librairie> librairies = new List<Librairie>() { librairie };
 10:      Livre domainDrivenDesign = FabriqueLivre.Creer("Domain Driven Design", evans,
 11:          categorie, librairies);
 12:      Livre autreLivre = FabriqueLivre.Creer("autre livre", evans, categorie, librairies);
 13:      entrepotLivres.Ajouter(domainDrivenDesign);
 14:      entrepotLivres.Ajouter(autreLivre);
 15:   
 16:      IList<Livre> livresRetournes = entrepotLivres.GetTousLivres();
 17:   
 18:      Assert.AreEqual(2, livresRetournes.Count);
 19:      Assert.Contains(domainDrivenDesign, livresRetournes);
 20:      Assert.Contains(autreLivre, livresRetournes);
 21:  }

 

Mais que fait donc ce test unitaire ?

C'est la question que je me suis posée récemment en relisant un test du même genre.

Le titre peut nous donner une indication, mais le corps de ce test est lui-même peu lisible. Et même sans rentrer dans le détail du code, il y a fort à parier que la maintenabilité et la performance ne seront pas au rendez-vous avec ce gros bloc d'initialisation (le Arrange de Arrange Act Assert) qui plombe le test.

Le problème derrière tout ça, c'est que pour tester un comportement basique d'un objet (ici un Repository de livres), on est obligé de le remplir en initialisant toute une grappe d'autres objets (des livres, des auteurs, catégories...) assez complexes à construire. DDD ne nous facilite pas vraiment la tâche puisque si l'on veut assurer les invariants et garantir l'état valide du domaine, le seul point d'accès pour créer un objet complexe est normalement la Fabrique. Celle-ci va initialiser l'objet dans un état valide et demander beaucoup de paramètres, dont potentiellement d'autres objets qui doivent être construits eux aussi et... vous l'avez compris, le test devient rapidement surchargé.

 

Respectons l'esprit de TDD

 

Dans son livre XUnit Test Patterns et sur le site xunitpatterns.com, Gerard Meszaros met un nom sur ce genre de code smell : Obscure Test. Il propose une approche de l'écriture de tests fidèle aux principes de TDD pour éviter cet écueil :

« Ecrire les tests d'une manière "outside-in" peut nous éviter de produire des test obscurs qu'il faudrait ensuite refactorer. Dans cette approche, on commence par tracer les contours d'un Test à 4 Phases en utilisant des appels à des Méthodes Utilitaires de Tests non existantes.
Une fois qu'on est satisfait des tests, on peut commencer à écrire les méthodes utilitaires dont on a besoin pour les exécuter. En écrivant les tests d'abord, on obtient une meilleure compréhension de ce que les méthodes utilitaires doivent nous apporter pour rendre l'écriture des tests aussi simple que possible. »

En d'autres termes, on va créer le test le plus simple et le plus lisible possible dès le départ en s'aidant de méthodes utilitaires très expressives. Adieu la grappe d'objets, sa complexité sera cachée dans nos méthodes :

 

  1:  [Test]
  2:  public void GetTousLivres_Retourne_Tous_Livres()
  3:  {
  4:      Livre domainDrivenDesign = CreerLivre("Domain Driven Design");
  5:      Livre autreLivre = CreerLivre("Autre livre");
  6:      EntrepotLivres entrepotLivres = CreerEntrepotAvecDeuxLivres(domainDrivenDesign,
  7:          autreLivre);
  8:   
  9:      List<Livre> livresRetournes = entrepotLivres.GetTousLivres();
 10:   
 11:      Assert.AreEqual(2, livresRetournes.Count);
 12:      Assert.Contains(domainDrivenDesign, livresRetournes);
 13:      Assert.Contains(autreLivre, livresRetournes);
 14:  }

 

Et voici l'implémentation des méthodes utilitaires :

 

   1:  protected Livre CreerLivre(string titre)
   2:  {
   3:      Auteur auteur= new Auteur("Nom", "Prénom");
   4:      CategorieLivre categorie = new CategorieLivre("Une catégorie");
   5:      Adresse adresse = new Adresse("Une adresse");
   6:      Librairie librairie = FabriqueLibrairie.Creer("Une librairie", adresse);
   7:      IList<Librairie> librairies = new List<Librairie>() { librairie };
   8:      Livre livre = FabriqueLivre.Creer(titre, auteur, categorie, librairies);
   9:      return livre;
  10:  }
  11:   
  12:  protected EntrepotLivres CreerEntrepotAvecDeuxLivres(Livre livre1, Livre livre2)
  13:  {
  14:      EntrepotLivres entrepot = new EntrepotLivres();
  15:      entrepot.Ajouter(livre1);
  16:      entrepot.Ajouter(livre2);
  17:      return entrepot;
  18:  }

 

Coupons les cordons

 

Notre test est déjà beaucoup plus lisible, mais une autre question se profile à l'horizon. Est-il vraiment unitaire ? Peut-on dire qu'il est atomique alors qu'il s'appuie intensivement sur le bon fonctionnement d'objets externes, à savoir des Fabriques ?

Meszaros préconise de s'affranchir des dépendances aux objets annexes en recourant à des valeurs par défaut, ou en utilisant des Dummy Objects, des objets creux qui ne contiennent rien ou juste l'information nécessaire au test. Concrètement, on extrait une interface du vrai objet en question pour pouvoir créer des dummies sans contrainte de remplissage. Dans notre exemple c'est le Livre qui sera "dummifié" puisque l'Entrepot à tester contient directement des Livres :

 

   1:  public interface ILivre
   2:  {
   3:      ...
   4:  }
   5:   
   6:  public class DummyLivre : ILivre
   7:  {
   8:      //On construit un objet minimal
   9:      public DummyLivre(string titre)
  10:      {
  11:          this.titre = titre;
  12:      }
  13:  }
  14:   
  15:  //Nouvelle méthode du helper
  16:  protected DummyLivre CreerLivre(string titre)
  17:  {
  18:      return new DummyLivre(titre);
  19:  }

 

Cette solution ne me satisfait pas pleinement parce qu'il faut créer un interface ILivre et la faire implémenter à Livre, ce qui n'est pas forcément élégant au regard de la nécessité d'expressivité des classes du domaine dans DDD. A la place, on peut recourir à un framework d'isolation qui va instancier un proxy de notre Livre pour l'utiliser dans les tests sans besoin de recourir à une interface. Un exemple avec Moq :

 

   1:  protected Livre CreerLivre(string titre)
   2:  {
   3:      var mockLivre = new Mock<Livre>();
   4:      mockLivre.Setup(livre => livre.Titre).Returns(titre);
   5:      return mockLivre.Object;
   6:  }

 

NB : cela nécessite une petite modification de la classe Livre. Il faut rendre la property Titre virtual afin que Moq puisse la surcharger.

 

Stratégies d'extraction

 

Tout cela est très bien, mais nous avons toujours des méthodes utilitaires à l'intérieur de notre classe de test, ce qui n'est pas l'idéal pour la lisibilité et la réutilisabilité. Une solution pourrait être de rendre ces méthodes statiques et de les externaliser dans un Helper à part (on parle aussi de pattern ObjectMother) :

 

  1:  public static class LivreTestHelper
  2:  {
  3:      public static Livre CreerLivre(string titre) { ... }
  4:      public static EntrepotLivres CreerEntrepotAvecDeuxLivres(Livre livre1,
  5:          Livre livre2) { ... }
  6:  }

 

Voici maintenant à quoi ressemble le test :

 

  1:  [Test]
  2:  public void GetTousLivres_Retourne_Tous_Livres()
  3:  {
  4:      Livre domainDrivenDesign = LivreTestHelper.CreerLivre("Domain Driven Design");
  5:      Livre autreLivre = LivreTestHelper.CreerLivre("Autre livre");
  6:      EntrepotLivres entrepotLivres = LivreTestHelper.CreerEntrepotAvecDeuxLivres(
  7:          domainDrivenDesign, autreLivre);
  8:   
  9:      IList<Livre> livresRetournes = entrepotLivres.GetTousLivres();
 10:   
 11:      Assert.AreEqual(2, livresRetournes.Count);
 12:      Assert.Contains(domainDrivenDesign, livresRetournes);
 13:      Assert.Contains(autreLivre, livresRetournes);
 14:  }

 

Imaginons maintenant qu'on ait d'autres tests à écrire sur l'EntrepotLivres. Chacun va avoir besoin de son contexte d'initialisation particulier (livres avec une certaine catégorie, un certain auteur, un nombre de livres fixé...) Chaque test va ajouter ses méthodes au TestHelper et il y a fort à parier qu'on va vite se retrouver avec un helper obèse et beaucoup de duplication de code, chaque test ayant besoin d'un environnement légèrement différent des autres mais avec des choses communes.

C'est là que nous pouvons appeler le pattern Test Data Builder à la rescousse. Il va nous permettre de rendre modulaire la construction de notre contexte de test, sans trop nuire à la lisibilité.

Voici à quoi pourrait ressembler un test avec des DataBuilder :

 

   1:  [Test]
   2:  public void GetLivresParNomAuteur_Retourne_Bons_Livres()
   3:  {
   4:      Livre domainDrivenDesign = new LivreBuilder()
   5:          .AvecTitre("Domain Driven Design")
   6:          .AvecAuteur("Eric",  "Evans")
   7:          .Creer();
   8:   
   9:      Livre autreLivre = new LivreBuilder()
  10:          .AvecTitre("Autre titre")
  11:          .AvecAuteur("Autre", "Auteur")
  12:          .Creer();
  13:   
  14:      EntrepotLivres entrepotLivres = new EntrepotLivresBuilder()
  15:          .AvecLivre(domainDrivenDesign)
  16:          .AvecLivre(autreLivre)
  17:          .Creer();
  18:   
  19:      List<Livre> livresRetournes = entrepotLivres.GetLivresParNomAuteur("Evans");
  20:   
  21:      Assert.AreEqual(1, livresRetournes.Count);
  22:      Assert.Contains(domainDrivenDesign, livresRetournes);
  23:      Assert.IsFalse(livresRetournes.Contains(autreLivre));
  24:  }

 

Je ne sais pas ce que vous en pensez, mais je trouve ça plutôt agréable à l'oeil. Sous le capot, cela donne ça :

 

   1:  public class LivreBuilder
   2:  {
   3:      Mock<Livre> mockLivre = new Mock<Livre>();
   4:   
   5:     public LivreBuilder AvecTitre(string titre)
   6:      {
   7:          mockLivre.Setup(livre => livre.Titre).Returns(titre);
   8:          return this;
   9:      }
  10:   
  11:      public LivreBuilder AvecAuteur(string prenomAuteur, string nomAuteur)
  12:      {
  13:          var mockAuteur = new Mock<Auteur>();
  14:          mockAuteur.Setup(au => au.Prenom).Returns(prenomAuteur);
  15:          mockAuteur.Setup(au => au.Nom).Returns(nomAuteur);
  16:          mockLivre.Setup(livre => livre.Auteur).Returns(mockAuteur.Object);
  17:          return this;
  18:      }
  19:   
  20:      public Livre Creer()
  21:      {
  22:          return mockLivre.Object;
  23:      }
  24:  }
  25:   
  26:  public class EntrepotLivresBuilder
  27:  {
  28:      EntrepotLivres entrepotLivres = new EntrepotLivres();
  29:   
  30:      public EntrepotLivresBuilder AvecLivre(Livre livre)
  31:      {
  32:          entrepotLivres.Ajouter(livre);
  33:          return this;
  34:      }
  35:   
  36:      public EntrepotLivres Creer()
  37:      {
  38:          return entrepotLivres;
  39:      }
  40:  }

 

Un mot sur SetUp

 

On pourrait aussi être tenté d'instancier une partie du contexte des tests dans la méthode de SetUp de la classe de test (attribut [SetUp] avec NUnit).

Ce n'est pas forcément l'idéal en termes de lisibilité, et en tout cas on ne devrait construire dans cette méthode que les données qui sont le plus petit dénominateur commun entre tous les tests. En général, je préfère réserver le SetUp (et le TearDown) pour des opérations de plomberie générale des tests qui ne touchent pas au données, comme le démarrage et le rollback d'une transaction.

Dans ce sens, je suis assez d'accord avec Roy Osherove, auteur de The Art Of Unit Testing, qui écrit (p. 191) :

« Ma préférence personnelle est que chaque test crée ses propres mocks et stubs en appelant des méthodes de helpers dans le test lui-même, de façon à ce que le lecteur du test sache exactement ce qui se passe, sans avoir besoin de sauter du test au setup pour comprendre le tableau d'ensemble. »

Recette

Une alternative originale

 

Le Danois Mark Seemann propose une approche légèrement différente, qui fait partie d'un cortège de design patterns et conventions qu'il a appelé ZeroFriction TDD. Bien que je ne sois pas totalement persuadé par tous les patterns présentés (certains sont très orientés programmation défensive), un d'entre eux mérite qu'on s'y attarde : Fixture Object.

Seemann part du constat qu'en utilisant des helpers de tests statiques, on a forcément un contexte de test stateless, ce qui nous prive de certaines commodités. L'idée est de constituer un objet Fixture contenant l'état actuel des données de test et aussi la référence au système à tester (SUT). Ainsi le corps du test garde sa lisibilité et sa maintenabilité :

 

   1:  [Test]
   2:  public void GetTousLivres_Retourne_Tous_Livres()
   3:  {
   4:      EntrepotLivresFixture fixture = new EntrepotLivresFixture();
   5:   
   6:      fixture.AjouterPlusieursLivres();
   7:   
   8:      // System Under Test
   9:      EntrepotLivres sut = fixture.Sut;
  10:      List<Livre> resultats = sut.GetTousLivres();
  11:   
  12:      Assert.AreEqual(fixture.Livres, resultats);
  13:  }

 

On remarque que deux conventions de Zero Friction TDD censées reposer l'oeil et le cerveau du lecteur du test sont utilisées : Naming SUT Test Variables, qui préconise de nommer toujours de la même manière la variable de l'objet testé, et Naming Direct Output Variables, qui conseille la même chose pour le résultat qui va être asserté.

Voici l'implémentation du Fixture Object :

 

   1:  internal class EntrepotLivresFixture
   2:  {
   3:      public EntrepotLivresFixture()
   4:      {
   5:          Sut = new EntrepotLivres();
   6:          this.Livres = new List<Livre>();
   7:      }
   8:   
   9:      internal EntrepotLivres Sut { get; private set; }
  10:      internal IList<Livre> Livres { get; private set; }
  11:      internal int Plusieurs { get { return 3; } }
  12:      internal Livre PremierLivre { get { return Livres[0]; } }
  13:      internal Livre DeuxiemeLivre { get { return Livres[1]; } }
  14:   
  15:      internal void AjouterPlusieursLivres()
  16:      {
  17:          for (int i = 0; i < Plusieurs; i++)
  18:          {
  19:              Livre livre = new Mock<Livre>().Object;
  20:              Livres.Add(livre);
  21:              Sut.Ajouter(livre);
  22:          }
  23:      }
  24:  }

 

 

Voilà, ceci n'est qu'un échantillon des différentes stratégies de factorisation de tests imaginables. Il y a probablement des milliers de solutions possibles.

Et vous, quelle est votre régime minceur préféré pour vos tests ?

vendredi 5 mars 2010

Règlement de comptes à Données Corral

Il va y avoir du sport

Derrière le jeu de mots vaseux de ce titre se cache une réalité beaucoup moins fun. Celle de la guerre que se livrent, depuis quelques temps déjà, les partisans d'une approche des bases de données novatrice et iconoclaste et les défenseurs de la tradition des SGBD relationnels.

Si vous suivez l'actualité du monde du développement, vous avez déjà compris de quoi je veux parler. Il ne vous a pas échappé que ces derniers temps, l'hégémonie des systèmes relationnels sur le marché des bases de données a été quelque peu chahutée : en 2009 sont apparues un certain nombre de bases regroupées sous le nom parapluie de "NoSQL". Ces systèmes (CouchDB, Big Table de Google, Project Voldemort...) sont des key-value stores, des document stores ou des bases fondées sur les graphes qui ont en commun de partir d'un constat de lourdeur du relationnel, du langage SQL et de ses jointures. Elles se veulent plus simples d'approche, plus scalable pour de gros volumes de données, plus adaptées au web et moins sclérosées par les schémas de données.


La rébellion gagne des voix

Il est intéressant de voir qu'en ce début d'année, il y a un regain de tension dans le débat qui oppose les deux visions et que celui-ci s'est invité chez les développeurs .NET. Plus particulièrement, deux acteurs importants de la communauté et qui n'ont pas a priori d'intérêt particulier à soutenir les bases NoSQL, ont pris position pour les défendre.

Le premier est Ayende Rahien, contributeur du projet NHibernate et créateur entre autres du framework d'isolation RhinoMocks. Dans un article nommé Slaying Relational Dragons, il remet en cause l'hégémonie des SGBDR et cite une session de support client à l'issue de laquelle il a recommandé de ne pas utiliser de base relationnelle. S'en suit un exemple de type d'application pour laquelle selon lui, il est tout à fait justifié d'opter pour un document store du style CouchDB. Plus étonnant, Ayende a également démarré un projet de base document, Rhino DivanDB, alors même qu'une grande partie de son travail des dernières années a été dévoué indirectement aux bases relationnelles par le biais d'NHibernate.

Une autre chose a piqué ma curiosité dans le billet d'Ayende : pour décrire les grappes de données pêchées dans une base NoSQL, il utilise le terme d'Agrégats. Oui, c'est à peu près la même notion d'Agrégat que dans Domain Driven Design. Visuellement, cela peut donner ceci (2 racines d'agrégat Book en l'occurrence) :

Agrégats

Si on cherche un peu, on s'aperçoit aussi que des frameworks DDD comme Jdon prévoient d'entrée l'utilisation d'une base NoSQL pour la persistance. Y aurait-il une synergie entre DDD et NoSQL dans la forme sous laquelle les entités sont appréhendées ? Intéressant, à creuser en tout cas.

Notre deuxième homme est Greg Young, très impliqué dans DDD justement, et qui a popularisé l'approche Command-Query Separation. Greg a comparé dans un billet récent l'utilisation d'un ORM au fait d'embrasser sa soeur (expression américaine désignant une action dénuée d'intérêt)... Pour lui, nous devrions plus souvent nous arrêter et nous demander si le choix d'un ORM couplé à un modèle de données relationnel pour notre projet, est bien justifié. Plutôt que de faire de l'ORM + SGBDR le choix par défaut, pourquoi ne pas envisager une base objet ou une base document à la place ? Dans certains cas, c'est beaucoup plus adapté au contexte et ça évite les problèmes de décalage d'impédance entre l'application objet et le modèle de données.


L'Empire contre-attaque

Bien sûr, les défenseurs des SGBD relationnels ont tôt fait de réagir. Un des plus virulents dans la contre-offensive a certainement été Frans Bouma, curieusement acteur de la scène ORM lui aussi (avec LLBLGen). Dans des commentaires et sur son blog, il avance trois arguments principaux pour contrer les enthousiastes du NoSQL :

  • Les cas évoqués par Ayende sont des anti-pattern, on essaie de créer un modèle de données qui est directement calqué sur la mise en forme d'un écran de l'application, ce qui est une mauvaise pratique.
  • Un modèle de données a pour vocation de représenter la réalité, et pas juste de refléter des entités utilisées dans une application (on retrouve un peu ici l'approche bottom-up vs l'approche top-down). Pourquoi ? Parce que dans un contexte d'entreprise, de multiples logiciels accèdent aux mêmes données et c'est de plus en plus vrai au fil du temps. Il faut donc un modèle qui représente parfaitement le métier et en est le garant quelle que soit l'application qui y puisera.
  • Les bases relationnelles existent depuis plusieurs dizaines d'années, elles sont fondées sur une théorie solide et ont fait l'objet d'innombrables recherches, ce qui en fait les outils incontournables et aboutis qu'on connait aujourd'hui. Toute concurrence est donc pour l'instant anecdotique.


Verdict

Conceptuellement, on voit bien le clivage entre les bases de type document store qui recèlent le strict nécessaire permettant à une application de fonctionner (le tout taillé sur mesure pour elle seule : une sorte de YAGNI de la donnée), et un modèle relationnel qui essaie de capturer la réalité de manière parfaite pour disposer d'une clé qui déverrouillera tous les situations à venir.

Sans prendre parti pour un camp ou l'autre, j'ai peur qu'à l'heure actuelle les bases NoSQL manquent de maturité face aux mastodontes relationnels. Mais elles restent une alternative à explorer et à mon avis, elles n'ont pas dit leur dernier mot. La guerre est loin d'être finie.

lundi 4 janvier 2010

En 2010, sachons lâcher du lest !

Ballon

En ce début d'année, je vous propose de prendre un peu de hauteur en nous élevant au-dessus des nuages.

En Juillet dernier, l'aéronaute suisse Bertrand Piccard était invité à la conférence TedGlobal 2009. Dans la vidéo de sa présentation récemment publiée sur le site de TED, Piccard nous raconte son tour du monde en ballon avec Brian Jones et en tire une leçon que je trouve étonnamment en phase avec les valeurs agiles.

Dans cette discipline, explique le navigateur, s'opposer frontalement à un fort vent contraire en voulant garder la même direction coûte que coûte, c'est comme résister obstinément au changement dans la vie : cela peut rapidement devenir un cauchemar.
Comment y remédier ? En comprenant que l'atmosphère est faite de couches dans lesquelles le vent circule dans des directions diverses, et qu'il faut se servir de l'axe vertical pour naviguer entre ces couches, par exemple en lâchant du lest.
Pour Piccard, les pionniers, les découvreurs ne sont donc pas ceux qui font face avec le plus d'acharnement aux difficultés rencontrées, ni même nécessairement ceux qui ont les idées les plus nombreuses ou les plus brillantes. Ce sont avant tout ceux qui osent jeter par-dessus bord leurs convictions, leurs certitudes, leurs habitudes pour accéder à des courants qui les mèneront à ce qu'ils cherchent par des voies de navigation différentes.
On apprend que c'est aussi cet esprit précurseur et un peu utopiste qui a gouverné le prochain projet de Bertrand Piccard, Solar Impulse, un avion fonctionnant uniquement à l'énergie solaire et qui pourrait bientôt prendre son envol autour du monde.

Voici la vidéo :

Voilà, je vous souhaite donc vous aussi de pouvoir lâcher tout le lest nécessaire en cette nouvelle année afin de piloter votre ballon dans la direction de vos rêves :)

dimanche 6 décembre 2009

DDD Vite Fait, notions avancées

DDD Vite Fait Partie 2

Comme promis, voici la deuxième partie de la traduction de DDD Quickly : DDD Vite Fait, partie 2, notions avancées.

On y retrouve des techniques pour mettre en oeuvre DDD sur de gros projets impliquant plusieurs équipes, mais aussi pour refactorer un domaine et gérer sa croissance, notamment à travers la distillation et l'identification d'un Coeur de Domaine.

Bonne lecture ;)

(Mise à jour) : et voici le fichier complet avec les deux parties.

samedi 21 novembre 2009

Muramasa, the Demon Blade

Muramasa, the Demon Blade

Un fois n'est pas coutume, je vais vous parler d'un jeu vidéo. En fait, LE jeu vidéo du moment pour moi, celui qui a débarrassé ma Wii de la grosse couche de poussière qui s'y accumulait faute de titres intéressants ces derniers temps : Muramasa, the Demon Blade.

Muramasa, c'est d'abord des graphismes sublimes, un petit joyau en 2D qui s'approche de ce qui s'est fait de mieux artistiquement parlant sur cette console. Des champs de blés dorés aux montagnes enneigées en passant par les cerisiers en fleurs et les sombres forêts de bambous, ses décors typiquements japonais nous en mettent plein la vue.

Des décors chatoyants

Ce qui est aussi intéressant avec ce jeu, c'est qu'il fait le pari que dans les vieux pots on continue à faire les meilleures soupes (aux vermicelles). Muramasa marque un retour à un genre old school, le bon vieux beat'em all par tableaux avec des cohortes d'ennemis à tuer et à la clé des boss plus hideux et retors les uns que les autres. L'un des deux héros ninjas que vous aurez choisi, Momohime ou Kisuke, part donc à l'aventure en enchainant des combats aux règles très simples (seulement 4-5 coups différents) mais aux possibilités démultipliées grâce aux caractéristiques propres des 108 (!) sabres qu'il est possible d'acquérir. Il en résulte un gameplay vitaminé, intuitif et fluide qui conserve tout de même une bonne dose de difficulté et d'exigence héritée des jeux d'antan - surtout en mode Shura, le plus ardu.

On note en plus de cela des petites touches d'originalité bienvenues qui viennent agrémenter les parties, comme les recettes de cuisine qui permettent de se "crafter" des bons petits repas pour regagner de l'énergie, ou des singes menant à des sources chaudes où délasser et régénérer son corps.

Bref, Muramasa démontre que c'est souvent en combinant des règles de base très simples à des idées originales que l'alchimie peut opérer et qu'on arrive à un résultat passionnant et unique... Si vous êtes fan d'atmosphère médiévo-nippone et de combats virevoltants, je vous conseille de courir vous le procurer si ce n'est déjà fait.

Momohime en action Kisuke contre un samourai Paysage enneigé

- page 2 de 3 -