Il y a 6 ans -
Temps de lecture 7 minutes
Développement Agile et Craft
Vous êtes développeur mobile pour un journal d’information bien connu. Les articles paraissent sur un site web et l’application Android correspondante est utilisée par des centaines de milliers d’utilisateurs. Elle permet de réagir sur les articles, et les utilisateurs ne s’en privent pas : c’est le théâtre de débats d’un haut niveau émotionnel, si ce n’est orthographique.
Mais un matin, aucune réaction postée depuis l’application ne paraît plus sur le site. Les avis défavorables s’accumulent sur le Play Store :
« Impossible de réagir depuis l’application. Aucune réaction envoyée depuis l’application ne parvient aux modérateurs, alors que les réactions envoyées depuis le site passent sans problème. » –Raphaël H.
« Je suis abonné mais aucun des messages que je dépose avec mon smartphone ne s’affiche lorsque je commente l’actualité… » –Michel K.
« […] Censure des commentaires n’allant pas dans le sens des articles, je me suis donc désabonné… […] » –Adrien V.
Cette situation demande d’agir vite et bien. C’est l’occasion d’illustrer une approche de développement qui mêle agilité et savoir-faire (craftsmanship).
Voici le comportement de l’application en matière de commentaires :
- L’application permet de poster un commentaire en réaction à l’article lui-même (indicateur
response
àfalse
) - Elle permet de répondre au commentaire d’un autre utilisateur (indicateur
response
àtrue
)
Avant de vous distraire de votre tâche en cours, votre leader technique a pris le temps d’analyser l’anomalie : l’application ne poste pas les commentaires correctement. Le mapping entre l’indicateur response
et la valeur envoyée à l’API est incorrect. C’est un « if » qui a été codé à l’envers.
Le code en question révèle l’erreur de mapping concernant la valeur du paramètre responseFlag
attendu par l’API.
[java]sendReaction(message, item, response);[/java]
[java]public void sendReaction(String message, String answeredItem, boolean response) {
int responseFlag;
if (response) responseFlag = 0;
else responseFlag = 1;
api.postReaction(message, answeredItem, responseFlag);
}[/java]
Agilité
Compte tenu de l’importance du bug, vous mettez de côté vos développements en cours. Vous committez vos changements et vous passez sur une nouvelle branche issue de la version de production.
Votre premier réflexe est d’ouvrir le test unitaire (TU) du code en question. Qui n’existe pas. Damned. Le bug aurait pu être repéré si un test avait été rédigé lors du développement initial.
Le code est dans une Activity
Android. Vous évaluez l’investissement que constitue la rédaction d’un nouveau test unitaire dans cette situation, et vous préférez laisser le TU de côté le temps de produire un correctif démontrable afin de rassurer votre client.
Vous appliquez le correctif qui consiste à inverser les branches du if
. Dans l’immédiat, vous privilégiez la correction du bug par rapport au refactoring.
[java]public void sendReaction(String message, String answeredItem, boolean response) {
int responseFlag;
if (response) responseFlag = 1;
else responseFlag = 0;
api.postReaction(message, answeredItem, responseFlag);
}[/java]
Vous testez le correctif sur votre poste de développement, puis vous publiez le code sur une branche du dépôt de votre organisation. Le leader technique valide vos changements, vous faites le merge dans la branche d’intégration.
Votre serveur d’intégration continue met automatiquement à disposition du reste de l’équipe une version de recette. Votre équipe pratique le dogfooding : c’est quand les membres de l’équipe sont les premiers utilisateurs de leur propre application. Cette pratique permet de confirmer l’absence de régression dans des conditions réelles d’utilisation. Vous montrez le correctif à votre client qui confirme la correction.
Jusqu’à maintenant, vous avez respecté les valeurs agiles :
- Vous avez privilégié l’interaction avec votre leader technique pour prendre en compte rapidement un bug sensible
- Vous avez favorisé la remise en condition opérationnelle de votre application en laissant de côté le refactoring et la documentation
- Vous avez collaboré avec votre client pour corriger l’anomalie sans vous attarder sur la nature du développement (bug ou évolution)
- Vous avez adapté vos priorités suite à la remontée de l’anomalie au lieu de continuer vos développements en cours
Craftsmanship
Et maintenant ? Le processus minimal est respecté, du point de vue de votre client, vous pourriez donc livrer une nouvelle version hotfix de votre application et passer au ticket suivant, mais votre travail n’est pas terminé. Dans la méthode sendReaction
, au moins un refactoring vous démange. Et votre beau correctif n’est toujours pas testé unitairement.
Compte tenu de la simplicité du correctif, vous pouvez tout reprendre du début.
Vous commencez par écrire un test automatisé. Ici, le plus approprié est un test unitaire qui vérifie la logique du if
.
Mais avant de pouvoir écrire ce test unitaire, le code doit être repensé. La classe impactée par le correctif est fortement couplée avec le framework Android qui est difficile à simuler dans un test unitaire. Vous avez deux solutions :
- Mettre en place le framework Robolectric pour simuler le framework Android dans votre TU
- Appliquer le pattern Passive View pour sortir la logique du
if
dans une classe séparée, qui serait testable facilement car non dépendante du framework
Vous choisissez la Passive View car vous pensez que Robolectric ralentirait l’exécution de vos tests, et à cause du délai des mises à jour de Robolectric suite à celles du SDK Android.
Dès que le test passe, vous en profitez pour transformer le paramètre response
en enum
, petit refactoring qui vous démangeait :
[java]public void sendReaction(String message, String answeredItem, CommentType commentType) {
api.postReaction(message, answeredItem, commentType.getApiFlag());
} [/java]
[java]enum CommentType {
INITIAL("0"), ANSWER("1");
private String mApiFlag;
CommentType(final String apiFlag) {
mApiFlag = apiFlag;
}
public String getApiFlag() {
return mApiFlag;
}
}[/java]
Vous adaptez votre test unitaire au changement de signature de la méthode sendReaction()
.
Ensuite vous faites en sorte que votre développement puisse être repris et maintenu facilement par un autre développeur, grâce à une séance de revue de code. En support écrit, vous préparez une pull request détaillée sur GitHub dont la description rappelle :
Le besoin fonctionnel | Correction d’un bug au niveau des réactions |
La spécification technique |
|
Le scénario de test |
|
Ce niveau de détail par écrit permet de garder une documentation écrite et indexée au sujet du correctif au cas où un autre besoin impacterait ce périmètre de code.
NB : l’idéal serait d’intégrer la documentation au code afin de la rendre plus « vivante » et pour qu’elle puisse évoluer avec le code. Mais ce type d’approche est coûteux à mettre en place sur du code existant ; vous laissez donc de côté ce chantier pour l’instant.
Quelques heures plus tard, la version corrigée est publiée sur le Play Store, certains utilisateurs l’ont installée, et les premières réactions des utilisateurs arrivent sur les articles. Vous retrouvez enfin leur douce prose, les trolls, la créativité orthographique.
Ici vous avez appliqué votre savoir-faire et respecté les valeurs Craft :
- Vous avez soigné votre code en le refactorant après avoir appliqué un correctif
- En ajoutant un test automatisé, vous avez garanti la non-régression pour éviter de corriger toujours les mêmes bugs. Ainsi vous pourrez continuer d’ajouter de la valeur.
- En documentant votre code et en le montrant à un autre développeur, vous avez favorisé l’appropriation collective du code
- Vous avez établi une relation de partenariat avec votre client en prenant la responsabilité de soigner l’aspect technique (tests unitaires, refactoring) au delà d’un correctif minimal
Conclusion
À partir d’une situation vécue, dans le contexte du développement mobile, cet article illustre l’application des valeurs agiles et craft.
Dans le contexte d’un bug sensible, cette approche s’appuie sur les valeurs agiles pour prendre en compte les attentes du client en termes de rapidité de mise au point d’un correctif.
Elle s’appuie aussi sur les valeurs craft pour permettre à la base de code de rester saine et compréhensible par les autres développeurs, présents et futurs.
Commentaire