lundi 18 novembre 2013

Test unitaires pur métier - Architecture Hexagonale

TLDR; Une forme de duplication subtile, que l'on rencontre souvent et qui a pour conséquence des tests unitaires trop techniques qui sont incapables de documenter les règles métier.  Je montrerai une technique pour séparer logique métier d'infrastructure et par conséquent réduire la compléxité du code, augmenter sa valeur pour le métier et utiliser les tests unitaires comme documentation des règles métier. J'ai créé un exemple plus complet pour s'entrainer à ce remaniement.

Le code que l'on va voir est une simplification d'un cas assez classique et tiré d'un projet ou je développais récemment.

Nous avons AccountCreationController (controleur classique mvc) ou l'on traite une requête de création de compte. La règle métier dit que les résultats possibles sont

  • "success" -> on en informe l'utilisateur et on le redirige vers une page où il peut naviguer en tant que connecté
  • "pending" -> la création automatique a échoué pour l'une des raisons suivantes
    • email déjà utilisé
    • siret "restreint"
    • erreur de traitement
Ci-dessous controleur et service. Ne vous attardez pas sur les détails, regardez  surtout la similitude entre le if-else et le try catch dans les deux classes. Bien que complèxe, cela ne ressemble pas à de la duplication, mais ça en est.



Les problèmes
  1. La règle métier se trouve éclatée entre deux classes dans des couches différentes (beurk ceci est une appli 3 couches). Il est donc peu réutilisable, peu clair pour les développeurs.
  2. Les tests unitaires n'arrivent pas à capter et documenter cette règle. Nous ne pouvons pas montrer nos tests au métier ou aux testeurs pour feedback. Nous pouvons pas les joindre à la documentation de l'application.
  3. Compléxité cyclomatique accrue due à la duplication des if-else et des try-catch.
Voici les tests (en vue réduit au noms des méthodes de test Junit), regardez comment ils parlent de true/false/throws/exception. Ainsi ils ne peuvent pas être utilisés pour communiquer avec le métier, ni en tant que documentation de l'application



La meilleure solution que je connaisse à ce problème est de passer un objet callback du controleur au service, grâce à quoi la logique conditionnel du controlleur a totalement disparu! 











Conclusion

Désormais on peut créer des tests unitaires qui captent le métier aussi bien, voire mieux qu'un test haut niveau. Ceci n'était pas possible avant. Comme quoi le code dicte la qualité de nos tests. Au fil du temps j'ai appris à chercher le mauvais design là où les tests me plaisent pas.

Ceci est un exemple de OnceAndOnlyOnce, de Model-View-Presenter et plus particulièrement d'architecture héxagonale côté utilisateur (et aussi ). Cette architecture nous dit de séparer la logique métier de l'infrastructure que l'on utilise pour servir des fonctionnalités. Cela me semble essentiel, pour plein de raisons, et en particulier pour créer une application qui sert au mieux des besoins métier qui évoluent

N'hésitez pas à commenter et prendre le code dans sa version plus complète pour vous entrainer!

lundi 1 juillet 2013

La qualité n'est pas une valeur en soi

Il y a quelque temps je trouvais que la qualité était bien. Tout simplement bien, bien pour tout le monde et dans la plupart de contextes. Je ne le pense plus! Enfin j'ai nuancé un peu mon approche à la qualité. Et même je commence à être un peu agacé quand j'entends mes collègues dire qu'il faut faire plus de qualité (point), qu'on nous laisse pas le temps de faire assez de qualité. Ou bien quand on me demande si je pense qu'il faut du 100% de couverture de test ou s'il faut s'arrêter à X%.

Ce genre de dialogue est aussi vide de sens qu'on l'entend très souvent! Aujourd'hui je réponds toujours avec des questions, quelque soit mon interlocuteur, "Que cherches tu à obtenir? Pourquoi?" afin d'engager un dialogue qui mettra en lumière des problèmes ou des risques sous-jacents au sentiment de nécessité d'améliorer la qualité.

L'autre jour un ami développeur se plaignait que son manager et son commercial se fichait de la qualité. Ok pour le commercial mais au moins son manager avait été développeur il devrait savoir ce que la non qualité emmène comme problème et coût! Mais de toutes façons leurs clients allaient jamais pouvoir être persuadés d'acheter la qualité. Et alors? C'est souvent comme ça et c'est à peu près normal!

Qui est-ce qui peut le mieux expliquer et comprendre les bienfaits de la qualité? Et bien c'est mon ami (plus largement personnel technique). Lui seul les comprend bien et est donc le mieux placé pour expliquer avec précision ces bienfaits, ou plus précisément de décliner une approche qualité en avantage concurrentiel, opportunité de marché ou assurance. Ok facile, il n'a qu'à dire : "En misant sur la qualité on aura pas de problèmes et on ira plus vite, aura moins de bugs etc". Sauf que ça ne convaincra personne, tout le monde l'a déjà entendu et les personnes qui restent ont besoin de preuves plus concrètes, plus contextualisées.

Echec de convaincre, indicateur de maitrise à parfaire
Si on ne peut être plus précis c'est un signe qu'on n'a pas soi-même bien compris comment cela fonctionne ou quelle est la nature de comment cela va nous aider. Rien de pire pour démarrer un changement - de connaitre le moyen mais pas ce qu'on cherche à obtenir. Par contre on peut très bien se donner du temps à explorer une technique afin de mieux cibler comment il peut nous aider dans notre contexte. Nous sommes en perpétuel apprentissage sur les méthodes que nous utilisons, ainsi que le contexte dans lequel nos interlocuteurs se trouvent. Prenons l'opportunité que présentent ces échecs de "vente" comme indicateurs de ce que nous avons besoin de creuser.

D'un autre côté il n'y nul besoin d'apporter toute la solution soi-même. Il n'y a rien de plus naturel que d'explorer une idée avec son manager / commercial / marketeur. "J'ai lu ceci et experimenté telle et telle approche, c'est sensé quasiment supprimer les erreurs de spec. Imaginons que nous ayons ça, qu'est-ce que ça nous permettrait de faire?"

Le contexte est roi
Il faut aussi se rappeler que la meilleur chose qu'on doit espérer découle de la situation. Si notre client ne peut pas déployer l'application plus souvent que tous les 6 mois alors nous ne pouvons pas espérer l'intéresser avec la possibilité de livrer tous les jours (en terme de couverture de non-regression). Si notre client est un startup nous ne pouvons pas espérer l'intéresser avec une approche ZéroBugs. Il faut plutôt chercher ce qui peut être décliné en avantage clair et alléchant pour lui, le reste ne fera que polluer le dialogue et créer de la frustration. C'est dans cette déclinaison contextuelle que nous apportons une très grande valeur avec notre compétence technique.

Petite décharge, je ne dis pas qu'il faut appliquer partiellement le TDD, le BDD, Scrum, devops ... Non ce serait une erreur au début (n'oublions pas Shu-Ha-Ri). Ce que je dis est de chercher un pourquoi de plus en plus précis.

Condamnés à vendre?
Alors nous (personnel technique) sommes condamnés à vendre en permanence? Le métier qu'on voulait pas faire! Certain d'entre nous trouve même que le métier de commercial est malhonnête. Certes il y a des commerciaux malhonnêtes mais ça ne veut pas dire que la vente est malhonnête. Même nous passons beaucoup de temps dans la vie à vendre nos idées, si nous ne le faisions pas nous serions frustrés et même ce serait de priver notre entourage de notre contribution à l'intelligence collective! Vendre ses idées est sensiblement la même chose que de vendre, commercialement, une nouvelle solution.

Alors nous sommes pas commerciaux et nous n'aimons peut-être pas ça, mais nous avons un choix entre
  1. Continuer à ne pas vendre (ou du moins à mal vendre) nos idées et d'en assumer la frustration
  2. Ou à s'efforcer à comprendre les enjeux de nos interlocuteurs et ainsi exploiter notre compétence technique au mieux pour le bien de notre entourage.

Conclusion
La qualité ne se discute pas en quantité. Il n'est pas intéressant de discuter de quelle technique est la meilleure pour atteindre une bonne qualité avant d'avoir identifié les problèmes et opportunités. Il est beaucoup plus probable que tout le monde trouve un terrain d'entente si on adresse d'abord le pourquoi. Sans oublier que le pourquoi peut simplement être de mieux connaitre une méthode afin de savoir s'il est pertinent dans notre contexte.

Personnellement je ne dis plus "La qualité est bien/sacré". J'essaye de
  • Décliner les techniques de qualité en avantage/assurance tangible pour la personne en face. Notamment en cherchant les problèmes actuels.
  • Apprendre des éléments de vente et de comment convaincre (il ne s'agit pas de de meilleurs arguments)
  • Ne plus faire du zèle par rapport au contexte. Parfois il vaut mieux tenter de changer le contexte.
  • Utiliser mes échecs comme indicateur sur ce que je dois approfondir en techniques de qualité ou en compréhension de contexte.
C'est beaucoup plus dur, mais beaucoup plus intéressant et satisfaisant.

Et vous qu'est-ce que ces mots vous inspire? Merci d'avance pour vos retours.


jeudi 25 avril 2013

Développeurs Anonymes @ MixIT


Demain Rémy Sanlaville et moi animons un atelier d'entrainement de développement orienté objet à Mix-IT. 

L'objet me semble être le concept le plus mal compris dans notre industrie. Je parierais que c'est 1) parce que c'est vraiment pas évident, du tout! Et 2) parce que c'est très facile de croire qu'on a tout compris. En tout cas pour ma part cela fait au moins 5 fois dans ma vie de développeur (12 ans) que j'ai eu le aha-moment d'avoir compris le sens de la POO. Les premières fois naïvement je pensais que j'avais à peu près tout compris, aujourd'hui non! Par contre j'ai pu constater les énormes bénéfices d'avoir compris ce que j'ai compris. Alors je continue à m'entrainer pour aller chercher les bénéfices qu'il me reste encore à découvrir.

Pourquoi pas venir avec Rémy et moi demain pour vous entrainer à la POO! Pour nous, la préparation de cet atelier était un excellent entrainement, qui nous a appris de nombreuses choses que nous attendions pas à apprendre :) 

D'ailleurs ne ratez pas ce petit échauffement, pas de OO just du bon code procédurale! L'objet est réservé pour demain.

Et aussi préparez votre environnement avec ce code importé dans votre IDE!

mercredi 10 avril 2013

Git's branches are Sticky-notes

Take this quote that circulated on twitter
"Git gets easier once you get the basic idea that branches are homeomorphic endofunctors mapping submanifolds of a Hilbert space"
Now that is probably true but it is a most complicated way of explaining something very simple. This post will try to explain it in more human friendly terms and offer a useful metaphor (IMHO) for thinking about Git which is that of sticky notes for branches and tags.

The problem
It can be scary to do a merge ("what if I mess up the history"), and when you do get it wrong it's not very simple to undo that the first couple of times. Rebasing can also be quite awkward and seem like magic. And finally how can synchronisation between multiple repositories work (If I mess something up, I won't know how to get it right again). In short I was very careful in my first steps with git because I didn't want to mess things up, in particular with public repos. The following insights have helped me work more in harmony with Git and harness some of it's power. I'm writing this in hope they might useful to someone else.

Commits
First some basics. Git has commits. Commits are pointers to a full snapshot of the contents of the tracked files. They are identified by a sha1. It's very much like if you made a checksum of the checksums of all files.

A commit also contains a pointer to the its parent (i.e. the preceding commit). A commit with two or more parents is a merge commit, it has pointers to the commits that it merges.

Sticky notes
Git has sticky notes that you can stick to a commit. They're just a way of giving a commit a meaningful name. They are actually just a file with the sha1 of the commit as its sole . Lets look at the master branch, as (almost) all branches it is just a file residing in .git/refs/heads/

$ cat .git/refs/heads/master

ed31dcf89563d51010bca1620fbdef53a05c47a6



That's all there is to it! Now there are two types of sticky notes, tags and branches. Just like Post-Its you can move them around at your leisure. So lets say we want to move the master Post-It from where it is now to the commit with sha1 d23521... 
$ git branch --force master d23521da12cca757fac7c5f6b4729308b329c8ff

now the content of the master Post-It has changed
$ cat .git/refs/heads/master

d23521da12cca757fac7c5f6b4729308b329c8ff


Simple eh? You can even mess with the Post-Its of the team repository, but that will probably make your team mates just about as angry as if you moved around the Post-Its of your scrum board!

As I said there are two types of Post-Its: tags and branches. Tag Post-Its live in .git/refs/tags/ and there's not much more to them than that. Branch Post-Its live in .git/refs/heads/. What's special about branch sticky notes is that if you do a checkout on them they will follow your commits, so as to always point to the last commit - an example.
$ git checkout master
$ cat .git/refs/heads/master
d23521da12cca757fac7c5f6b4729308b329c8ff
$ ... modify some files
$ git commit

$ cat .git/refs/heads/master

6013c8f4133c175ff4bfeaf6af8bf3419f6bb6ba



In essence tags and branches are just pointers to a single commit.

Undoing a merge or rebase
Then it follows that if you mess up a merge you can easily redo it by checking out the commit you were on before the merge and then move the branch Post-it back. For instance lets say we're on the master
$ git merge somefeature

Let's undo!
$ git checkout HEADˆ                # HEAD means current commit, and the ^ means "the one before", we're no longer on the branch master.
$ git branch -f master HEAD      # moves the postit
$ git checkout master                 # we need to move back to the branch master

In practice you would rather do git reset --hard HEAD^, wich does all the above in one command. Btw there's an amazing doc about git reset.

Also if you messed up a rebase, even after it completed you can easily undo it by checking out the commit you were on before the rebase and moving along the branch Post-it, then checkout the branch Post-it at its new location.

Synchronisation with remotes

We're ready for some clarity about how pull and push to and from remote repositories work. When you do
$ git push origin master

That's a short for
$ git push origin master:refs/heads/master

That is, push any local commits on my master to the master branch on the remote repo origin. Or as we now see it : push my commit named master to the repo origin, and move the remote post-it (to the right of the colon) master to that commit. Under the hood Git will make sure that the commit-graph (all reachable parents from master) on both sides are identical and upload any missing commits.

Conclusion

In Git branches are just a way to name a commit.

I hope this post has taken away some of the strangeness and scariness of Git and that it has helped to see some of the commit-centric nature of git. I use this way of thinking all the time, in particular for merging, rebasing, reverting and in working with remotes. It has certainly made things easier and relieved me from the stress of doing something wrong.

In short I use this mental model should help when:
  • you merge two branches - you're just merging two commits using their name instead of their sha1
  • you're pushing or pulling to/from a remote repository -  there is absolutely no need for the names of the sticky notes on your repo and the remote repo to be the same. 
  • you're rebasing you're creating entirely new commits, then the the Post-It is moved to the tip of the new commits.
  • you do a bad merge, you can just move the Post-It down to where it was before and try again.
I just discovered Think like a git which provides very easy to read documentation

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