mardi 16 octobre 2012

Pattern Visitor, ne baissons pas les bras


Suite au post très intéressant de Xavier Nopre sur le Single Responsibility Principle et son approche beans+services, Nicolas Capponi a animé une séance du dojo du club agile pour explorer différents solutions qui s'offrent à nous pour ce problème.

Personnellement j'ai choisi d'utiliser le temps pour m'affuter en Visitor, car comme dis Xavier ce n'est pas le pattern le plus facile. D'autres personnes ont essayé d'autres solutions. 

Voici deux variantes du Visitor pattern. L'un qui expose les objets métier (et donc utilise des getters) l'autre qui fait passer des primitives pour résoudre ce problème (pas forcément mieux, juste différent). 

Extrait de la solution avec objets métier:


Les autres solutions explorés, dont j'aimerais bien voir le résultat, était délégation à une autre classe ou introduction d'une petite interface pour gérer le cas d'utilisation en question (par exemple Mailer pour contenir computeMailContent()). Ces deux solutions me semblent être des bonnes solutions temporaires en attendant de les extraire pour de bon. Par contre une fois extraite il me semble qu'on va tomber sur soit le visitor soit la solution que mentionne Xavier: beans+services. Non?

Conclusion
Les visitor qu'on trouve ici, est-ce vraiment trop complexe? Personnellement je pense que nous gagnerions à simplement pratiquer ce pattern pour savoir le mettre en oeuvre avec aise quand cela est préférable. Certes il faut le faire plusieurs fois pour avoir l'impression de maitriser, mais nous sommes nombreux  à être informaticiens plus de 10 ans, alors qu'il suffit avec ~10h de pratique étalé sur quelques mois pour le maitriser en profondeur. Qu'en pensez-vous?

mardi 24 janvier 2012

Tester entrées et sorties en Clojure

En faisant ce kata en Clojure j'étais sous pression de temps alors je n'ai pas fait une partie en TDD - l'interaction avec la console. Ca ne me dérange pas plus que ça mais je voulais voir comment on pourrait le faire en TDD. Il se trouve que c'est extrêmement simple!

Dans cet exercise on doit construire une caisse de primeur qui accepte en entrée (console) des fruits et qui pour chaque entrée affiche le total sur la sortie (console). Pour cela je vais construire une fonction buy  qui va s'appuyer sur la fonction read-line qui lit une ligne du console et println qui affiche une ligne sur la console

Premier besoin : je ne veux pas de boucle fini dans ma fonction - quand j'entre une ligne vide la fonction sort. La syntaxe ici vient de Midje - un framework de test qui a la particularité (pour un langage fonctionnel) d'être orienté outside-in.

Ici j'aime vraiment la facilité avec laquelle on arrive à faire un bouchon de read-line - on déclare simplement que ceci est un fait (fact) si read-line renvoie les valeurs énumérés

Deuxième besoin : On doit afficher le total de l'achat après chaque ligne d'entrée.

Ici c'est facile, court et ça reste lisible mais il y a du bruit :

  • on est obligé de déclarer la valeur de retour attendue de println (qui renvoie toujours nil), j'ai mis anything pour signifier que ce n'est pas important
  • chaque contrainte sur println (d'abord total 100 puis total 175) se déclare sur une ligne. Nous n'avons pas l'expressitivité de du bouchon avec =streams=>.  Dans mes rêves ça aurait été  

Et sinon le code ça rend quoi?

Ce à quoi je m'attendais pas en commençant cette exercise c'est que bien qu'on gère de la mutabilité (le prix total du panier s'incrémente) aucune fonction n'est mutable et aucun variable mutable n'est nécessaire. L'état du panier est contenu dans la recursion

Pour moi c'est fascinant de découvrir ce moyen de gérer l'état visible d'une application sans mutabilité.

dimanche 27 novembre 2011

mardi 18 octobre 2011

Pas si simple de faire simple

La version express de ce billet est que nous ne faisons pas assez la différence entre “construire avec des briques simples” et “faire des objets simples à utiliser”. Ce n’est pas du tout la même chose!
  • La différence :
    • La simplicité d’utilisation est
      • Contextuel
      • Composé
      • Plutôt fermé à l’évolution
    • Les briques simples sont
      • Généralistes
      • Unitaires
      • Ouverts à l’évolution
  • C’est possible d’avoir les deux.
Voici la version longue, avec des explications et, promis, des exemples.

Dans ce keynote Stuart Halloway explique que le mot simple veut dire quelque chose de très fondamentale. Il soutient que la définition du mot simple est non composé ou non assemblé (non compound en anglais).

Puis il continue à nous expliquer pourquoi il est primordiale de construire seulement à partir de choses simples. Notamment il dit
  • Essayez de faire quelque chose de simple à partir de choses non simples … C’est impossible
Autrement dit, pour avoir une librairie ou application simple, on doit l’assembler de choses simples. Puis il finit son keynote par dire.
  • Si un peu plus du code était écrit dans le respect de la simplicité le monde serait un peu meilleur.
Bon finalement c’était juste le Single Responsibility Principle dans une nouvelle sauce. Soit, seulement quelques jours plus tard, il m’est venu à l’ésprit qu’il y a un paradoxe. Car si j’écris tout mon code de cette manière alors il serait chiant à utiliser, même pour moi. Notamment lorsqu’on utilise fréquemment une fonction/objet avec les mêmes paramètres ce serait chouette de ne pas le répéter partout dans le code. Un code simple n’est pas toujours simple à utiliser.   En regardant de près il n’y a pas de paradoxe, mais la réflexion m’a fait comprendre quelque chose que je vais partager ici.

Pour rendre la vie facile pour ceux qui utilisent notre code (souvent nous mêmes) nous avons tendance à faire du code simple à utiliser. Je suis convaincu que si on échoue à faire quelque chose de simple c’est souvent parce qu’on veut faire quelque chose de simple à utiliser! Et pourtant ce compromis n'est pas nécessaire.

Si on revient à la définition de simple on constate que simple est une qualité intrinsèque et non contextuelle. Il est possible de juger de la simplicité de manière objective.

Avec Simple à utiliser c’est l’inverse. Par définition c’est simple pour l’utilisation prévue. Si on change un peu le contexte il y a toutes les chances que ce ne soit plus très simple à utiliser. Simple à utiliser est contextuel.

Souvent nous trouvons des choses simples à utiliser parce que ça ressemble à quelque chose de connu, par exemple un patron de conception que nous avons déjà utilisé. Simple à utiliser est subjectif.

Ce serait bien dommage de faire des compromis entre une qualité "absolue" et une qualité contextuelle et subjective !

Prenons par exemple cet objet qui fait partie d’une application de crawl basique.

BatchCrawler est simple à utiliser car nous n’avons pas à fournir beaucoup d’arguments pour l’instancier. Par contre il n’est pas Simple car il fait un tas de choses en plus de crawler une liste d’urls :

  • Il spécifie où est configuré le timeout de chargement d’une page.
  • Il contraint ce timeout à ne changer dans toute la JVM voire même on doit redéployer pour la changer.
  • Il contraint à utiliser un RetryingHttpCrawler – qui retente en cas de timeout et qui passe par le protocole HTTP.

Limitant ainsi fortement le potentiel de réutilisation de l’objet.

Pour que l’objet puisse être qualifié de Simple, le constructeur devrait ressembler à ça

Mais alors il deviendrait chiant à utiliser. Si cet objet est instancié de plusieurs endroits de l’application il y aurait de la duplication. Nous allons donc réintroduire ce constructeur sous forme de FactoryMethod avec un nom explicatif (documentation) parce qu’il s’agit d'une façon de configurer ce graph d’objets.

Comme avec tout exemple simplifié c’est n’est jamais trop grave. C’est encore suffisamment petit pour être corrigé après-coup. Seulement dans une application réelle ça peut être un cauchemar car régulièrement on se retrouve avec l’initialisation d’une grappe d’objets - ici BatchCrawler initialise un RetryingHttpCrawler etc. Presque à chaque fois l’initialisation des objets plus bas dans le graphe ont des conséquences indésirables, c’est souvent ça qui nous rend les tests après si difficiles ... Le remplacement d’un objet dans ce graphe n’est pas toujours aisé et le code nécessaire teintera le code d’initialisation avec complèxité.

En construisant uniquement avec des objets et fonctions Simples on arrive à l’enrober avec une simplicité d’utilisation… pour le besoin actuellement connu. Quand le besoin change (lire toujours) on est le roi du pétrole. On a le beurre et l’argent du beurre.

Note : je ne dis pas qu’il faut essayer d’imaginer le besoin futur, seulement qu’il faut décomposer son code actuel en des briques les plus simples possible. Par dessus on peut ensuite construire la simplicité d’utilisation avec par exemple des valeurs par défaut.

Conclusion
Je ne vais pas conseiller de toujours faire ainsi, car à vrai dire rien n’est toujours vrai. Simplement le message que j’essaie de passer est

  • Il y a une différence importante :
    • La simplicité d’utilisation est
      • Contextuel
      • Composé
      • Plutôt fermé à l’évolution
    • Les briques simples sont
      • Généralistes
      • Unitaires
      • Ouverts à l’évolution
  • C’est possible d’avoir les deux.

dimanche 3 juillet 2011

Symfony actions ARE easily testable

All Symfony experts I've met have told me that I'd better not bother with unit testing the actions because it's difficult enough that it just isn't worth it. Even an official Sensio Labs trainer that wisited our company said the same thing (I find that quite surprising). Only when you're doing TDD it's rather annoying not to be able to test the first lines of a new feature as it breaks your flow.

I should never have believed them. Luckily a colleague of mine didn't. In fact it turns out it's strikingly easy so I'd like to share it with you.


Here's an example of a how to unit test a standard action “executeHelloWorld” and an ajax action “executeGoodEvening”. It takes two simple lines in the setUp to prepare instantiation of the action.



The rest of the non-magic is in the fact that Symfony actions do not directly return the values we are interrested in. Ordinary (non-ajax) actions do not return anything they just prepare the execution of the template by storing values in a var-holder, we access it by action->getVar('name'). Ajax actions generally directly compiles the partials with parameters passed in an array and adds all that to action->response->content.

Credits go to Marc Nazarian and Sebastien Fromont without whom I still wouldn't TDD my actions.

For reference the action code

and the partial used

samedi 28 mai 2011

Software Craftsmanship 2011 - décoiffant!


Je dois dire qu'une conférence où l'on a l'occasion de parler directement avec Gojko Adzic, Steeve Freeman, Michael Feathers, Jason Gorman, etc est forcément passionnante! C'est sans mentionner des sessions d'un très bon niveau où l'on a l'occasion de pair-programmer avec d'autres passionnés! Puis toutes les conversations entre participants.
Voici un petit résumé des sessions auxquelles j'ai assisté.
How object oriented are you feeling today?
Il fallait résoudre un petit problème tout en respectant 9 principes qui mènent infailliblement à un code orienté objet.

Ce que j'aime bien avec les exercices bornés par des règles fortes est que ça permet de sortir de ses habitudes et avoir un inspecteur de code derrière le dos pour nous aider à nous mettre en cause. Aussi lorsqu'une alerte est levée par la violation d'une des règles alors c'est souvent pas important quelle règle a été violée mais signe d'un problème plus profond. Par exemple pendant cette session nous nous sommes trouvés à vouloir avoir 3 collaborateurs (le max étant 2) dans un objet Account: Client, Bank et Money. La banque était nécessaire pour autoriser ou pas un transfert (autorisés uniquement au sein de la même banque). Le problème n'était pas d'avoir un troisième collaborateur, mais que le compte allait gérer trop de choses – le transfer ET la demande de l'autorisation. Une meilleure solution est que la banque autorise le transfert puis délégue le transfert au compte (Single Responsability Principle). Les règles nous ont permis de le voir plus tôt.

Les règles que je compte appliquer strictement au jour le jour
  • first class collections (wrapper chaque collection une classe métier)
  • one level of indentation
Celles que je vais essayer d'appliquer un peu plus
  • no else statements (même pas dans les factories).
  • Wrap all primitives and string in their own class
Détail intéressant, tous les développeurs java à qui j'ai parlé ont adoré, mais j'ai parlé avec deux développeurs Ruby qui trouvaient que ça rendait leur code dégueulasse!


Functional programming with Michael Feathers
Session pas très bien préparée et pas très avancée. Plutôt dirigée sur la question quels éléments de la programmation fonctionnelle devons nous utiliser dans les langages objet. Il a essentiellement montré les expressions lambda (opérations sans état sur collections), avec la conclusion que parfois ça facilite mais parfois elles manquent un peu d'expressivité (même avec un bon nommage).

Bon point : tant que l'interface d'une fonction est pure (pas d'effet de bord, toujours le même résultat pour les mêmes entrées) peu importe si tu utilises la mutabilité à l'intérieure.

J'ai posé la question à Michael Feathers et à Steeve Freeman qui était là aussi « Why should we still develop with object oriented languages today ». C'est une question que je me pose depuis environ un an. Et toutes les réponses que j'ai trouvé sont à mon avis insatisfaisantes (performance, habitude des développeurs, moins de pouvoir = moins de risque) c'est certainement pas parce que l'objet est plus facile à maitriser! J'avais trop hâte de connaître le point de vu de ces cadors. Seulement aucun des deux avaient une réponse à part « I haven't yet seen a project of size written in a functional language ». On manquerait seulement de recul?

Lean code challenge
C'était absolument fabuleux! Chris Parsons a traduit 4 des principes de Lean, (waste, deliver fast, build quality in, customer value) dans un défi ludique de développement.
A travers 6 itérations de 10 minutes nous avons construit un calculateur de prix de panier de fruits avec des stratégies de prix évolutives et franchement changeantes(!). Je ne peux m'empêcher de dire que les stratégies, quoique réalistes, n'étaient absolument pas lean, où il vaut mieux éliminer la complexité que l'automatiser...

Nous avons terminé toutes les exercices et avec un code plus qu'acceptable. Si on n'avait pas fait du TDD j'imagine pas comment on aurait pu y arriver. Bel exemple du ROI sur le TDD en seulement 60 minutes! Gojko Adzic a dit qu'il n'avait commencé le TDD qu'au bout de la deuxième ou troisième itération – avant il ne trouvait pas que c'était utile, intéressant.


L'année prochaine j'y retourne!

jeudi 7 avril 2011

Agile Team Agreement

L'année dernière j'ai vécu dans une équipe qui marchait particulièrement bien. En essayant de comprendre les raisons de ce succès avec un autre des membres, Bernard Huguet, on a mis le doigt sur un pattern qui nous semble prédominant que l'on avait appelé l'Agile Team Agreement - l'ATA. On va essayer de décrire ce qu'on entend par ATA et partager la rétrospective que nous en avons fait. Mais avant d’aller plus loin je voudrais dire que nous ne l’avons pas inventé, l’idée derrière les Team Agreements ou Working Agreements existe sans doute depuis l’aube de l’homme et il n’y a rien d’obligatoirement agile, cela pourrait fonctionner dans n’importe quelle équipe. Le contenu serait juste différent.

Quoi de mieux que la photo de notre ATA pour décrire ce que c'est?


L'équipe a travaillé ensemble pour trouver et partager les pratiques qui lui paraissent être les facteurs clés de son bon fonctionnement. Il est essentiel que ce soit le résultat d'une participation active et équilibrée des membres de l'équipe, peut-importe comment vous y arrivez (pratiques de rétrospectives agiles peuvent aider ici). Exprimé sur un simple bout de papier, ce consensus est un réel contrat d'équipe et on s'attend à ce que tout le monde s'implique à 100%.

Au fil des mois on a pu observer un certain nombre de comportements que l’on pourrait imputer à l’ATA:

Fort sentiment d'appartenance à une équipe
Partager des valeurs, être fier de ce qu’on fait et savoir qu’on peut compter sur les autres membres de l’équipe crée un fort sentiment d’appartenance à cette équipe. C'est un élément important de motivation que d’avoir l’impression de faire parti de quelque chose de plus grand que soi.

Les équipiers ont du courage quand il le faut
Quand on a pris du retard sur un tâche ou que l’on subit une forte pression du management et du business, il est très tentant de discrètement prendre des raccourcis pour finir plus vite. Il y a deux avantages immédiats, 1) on tient les délais prévus et 2) on ne donne pas l’impression d’être lent ou mauvais. Certes on peut choisir de prendre des raccourcis mais ça doit certainement pas être pour sauver sa propre fierté. Les effets négatifs des raccourcis se font généralement sentir assez vite et on les paye souvent sur toute la durée de vie du projet.

Les post-its "Healthy Code", "Rendre problèmes visibles" et "As a team". Aident justement à donner du courage à rendre les problèmes visibles afin qu'un décision lucide puisse être prise par l'équipe.

Confiance partagée en chacun des équipiers
Puisque tes coéquipiers partagent tes valeurs tu peux avoir confiance dans leur travail. Par exemple, nous avions “rendre les problèmes visibles” et “DoD” (Definition of Done) dans notre ATA. Ayant confiance dans le travail de nos coéquipiers on pouvait se concentrer sur notre travail avec l’assurance que ça allait bien se passer et que si un problème survenait, il serait rendu visible rapidement et une action serait prise.

Tout le monde va dans le même sens
De manière générale on est tous influençable. On a envie de plaire aux gens de notre entourage. Autrement dit on va naturellement tendre vers ce que valorise notre entourage … du moment qu’on sait ce que c’est!

Puisque l’ATA rend visible ce qui a beaucoup de valeur pour les équipiers, alors il agit comme un centre de gravité comportemental qui soude l’équipe et qui l’aide à avancer dans le même sens.

Défini dans un contexte facile et utilisé dans un contexte difficile
SI quelqu’un vient régulièrement 5 min en retard aux stand-ups, ou si quelqu’un joue cavalier seul devant le PDG au détriment de quelqu’un d’autre, il est beaucoup plus facile de rappeler l’ATA que d’initier une discussion sur la ponctualité, ou de dire à qu’il a fait le beau devant le management.

Conclusion
Cela a bien marché pour nous et nous n’imaginons pas construire une nouvelle équipe sans cet ingrédient. C’est pour ça qu’on avait envie de partager ce bout de recette avec vous.

D’ailleurs nous sommes à nouveau tous les deux dans une nouvelle équipe et la construction de notre ATA est prévue pour demain :)