samedi 2 mars 2013

Anonymous Developers @JoyOfCoding - feedback


Here's a compilation of the extensive feedback we got from the just under 60 people that attended Developers Anonymous at the absolutely excellent 1st edition of the JoyOfCoding conference. Btw the organisers rock!

This is a compilation, we've selected statements with no particular rationale other than to put in bold statements that represent an idea shared by at least 3 people.

What have you done differently than usual?
  • Run the tests systematically
  • I had tests!
  • Making classes out of primitives
  • Took smaller steps in refactoring, a more structured approach (bigger steps, more mistakes)
  • Focusing on details instead of the bigger picture, to start with.
  • Lean more on the compiler / IDE
What suprised you the most?
  • Amount of thinking involved in OO design
  • The plugin auto running unit tests on save
  • Code became readable quite quickly
  • Not analysing just extracting logic in small steps
  • How small the resulting code was
  • The power of refactoring tool in Eclipse, what more tooling am I not using!?
  • Ease of refactoring when you have 100% coverage and following a few rules
  • Ease, fun
  • How many different solutions are available for the same problem
Name one question that this workshop has raised
  • When is it OK to have getters and setters?
  • Is this actually faster than extracting the different cases?
  • Why the heck this code works as is!?
  • Will this work with our code?
  • What more do I need to know to apply this more rigorously?
  • I wonder what my design is going to look like using classes with only 2 instance variables
  • Amount of work to get 100% coverage
Does it match your expectations? 
  • Yes, I want to know more 
  • Yes it is nice to see a design evolve using these small steps
  • Expected it to be less difficult 
  • It was fun
Would this be useful at work? How? Why not?
  • We will talk much about it to our colleagues
  • Yes it is a better way of refactoring
  • If I didn't know the business domain, yes.
  • Yes, it helps me figure out how to attack complicated functions in our legacy code
  • Yes, our largest "zzz" class suffers a lot from Feature Envy
Miscallaneous
  • It would have been good to have a session about how to write tests for this kind of code
  • It was a very nice learning experience

As presenters we're particularly fond of that last phrase! A great thanks to all the participants, we had a great time!

If you didn't attend and you would like to know a bit more about this session there's a github repository with the exercise in several languages, along with documentation that'll give you some idea about the content. With Rémy Sanlaville we'll also prepare a screencast with the live demos.

You can rate this talk/workshop at http://spkr8.com/t/20171


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!