Publié par
Il y a 3 semaines · 6 minutes · Mobile

Développement Agile et Craft

développement agile

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.

sendReaction(message, item, response);
public void sendReaction(String message, String answeredItem, boolean response) {
 
    int responseFlag;
    if (response) responseFlag = 0;
    else responseFlag = 1;
                    
    api.postReaction(message, answeredItem, responseFlag);
}

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.

public void sendReaction(String message, String answeredItem, boolean response) {
 
    int responseFlag;
    if (response) responseFlag = 1;
    else responseFlag = 0;
                    
    api.postReaction(message, answeredItem, responseFlag);
}

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.

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 :

public void sendReaction(String message, String answeredItem, CommentType commentType) {
 
    api.postReaction(message, answeredItem, commentType.getApiFlag());
} 
enum CommentType {

    INITIAL("0"), ANSWER("1");

    private String mApiFlag;

    CommentType(final String apiFlag) {
        mApiFlag = apiFlag;
    }

    public String getApiFlag() {
        return mApiFlag;
    }
}

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
  • Extraction de la logique dans une classe découplée
  • Inversion du sens du if
Le scénario de test
  1. Brancher l’application sur un environnement de recette
  2. Poster un commentaire sur un article
  3. Poster une réaction à un autre commentaire
  4. Observer qu’ils sont bien reçus par le backend et que leur type est correct

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.

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.

Références

Laisser un commentaire

Votre adresse de messagerie ne sera pas publiée. Les champs obligatoires sont indiqués avec *