Débutant

Les développeurs sont les plus mauvais juges de code

Tout d’abord, mes excuses pour un tel titre, le but n’est bien évidemment pas d’offenser qui que ce soit, mais simplement d’attirer un peu votre attention.

Maintenant que vous êtes ici, vous vous demandez peut-être ce que je vais bien pouvoir faire de cette attention… Et bien je vais vous parler d’un des problèmes que j’estime des plus fondamentaux dans notre industrie : on se complait dans notre zone de confort.

Et plus spécifiquement comme nous sommes habitués à déchiffrer le code des autres au travers des mots-clés natifs de nos langages de programmation, il est naturel de reproduire ce schéma lorsque nous écrivons le code à notre tour.

Mais avant de mettre en lumière quelques-unes de ces mauvaises habitudes, voyons en quoi cela peut en valoir la peine.

Pourquoi écrire du code compréhensible est important

Le coût de la maintenance

Le grand facteur de décision, quelle que soit l’industrie, est l’argent. Qu’il s’agisse d’acheter un produit externe, d’adopter une nouvelle technologie ou bien de revoir l’organisation interne, l’idée est d’être plus efficace pour au final, gagner du temps ou de l’argent.

Le sujet d’aujourd’hui ne fait pas exception à la règle. Il ne s’agit pas d’écrire du bon code compréhensible parce que c’est beau. On veut le faire parce que cela fait gagner du temps et de l’argent.

On trouve encore aujourd’hui très simplement des études concernant le coût de la maintenance faites durant les années 80 et 90, qui s’inquiètent de la capacité des systèmes à grossir de façon constante. À l’époque, les estimations faites évaluaient le coût de la maintenance entre 40 et 80 pourcent du coût total du système.

Depuis lors, le besoin en développeurs a incroyablement progressé. Les cabinets de conseil sont devenus la norme, augmentant la rotation au sein des équipes. L’accroissement de l’arrivée de nouvelles technologies semble ne pas avoir de limites.
Exprimé autrement, il y a peu de chances que le coût de la maintenance ait aujourd’hui baissé. Il est très fréquent d’avoir des systèmes comportant une logique métier compliquée et que ces systèmes tournent depuis une, voire deux décennies. Les nouveaux arrivants doivent alors appréhender à la fois la complexité métier, mais également la complexité technique du système.

Nous sommes ici face à l’un des paradoxes de notre industrie : alors que les technologies évoluant devraient nous permettre d’en faire de moins en moins, d’être de plus en plus concis et expressif, nous tentons en parallèle d’automatiser de plus en plus de processus avec de plus en plus d’outils, augmentant la complexité technique du système.

Les systèmes métier essentiels qui doivent vivre longtemps et les choix techologiques associés font de la maintenance un point critique sur lequel les entreprises qui veulent rester compétitives doivent constament s’améliorer.

Costs

La maintenance implique de lire du code

Maintenant qu’il est clair que de nos jours, la maintenance est une énorme part du coût total du système, il ne reste qu’à faire le lien avec l’activité qui consiste à lire du code.

Cela ne devrait pas être trop difficile pour quiconque ayant eu un peu d’expérience dans le domaine, mais pour ceux qui souhaiteraient tout de même une justification sur ce point, je vais énumérer les deux principales activités composant la maintenance que sont l’évolution métier et la correction d’erreurs.

Ces deux activités nécessitent de lire du code de manière intensive.

Maintenance

La correction d’erreur est la plus évidente. On commence par se faire une représentation mentale du comportement que le code devrait avoir, puis, on confronte cette représentation avec le message d’erreur, le journal, ou toute autre information venant décrire ce qui se passe réellement.
Si le code n’est pas suffisamment explicite, on peut même être amené à faire du debug. Ce qui revient simplement à lire très très attentivement le code tandis qu’une machine nous livre l’état du système.

L’évolution métier elle aussi nécessite de lire du code car nous attendons généralement une analyse indiquant quelle partie du code devrait évoluer, quels composants devraient être ajoutés, devenir publics, etc. Nous devrions pouvoir en théorie compter sur la documentation existante pour cette analyse, mais en réalité le peut-on vraiment ?

Si vous avez travaillé afin d’obtenir une documentation vivante, votre code est sans doute déjà suffisamment travaillé. Mais si ce n’est pas le cas, votre analyse ne peut que s’appuyer sur le code pour être exacte. De mon expérience, le premier réflexe des développeurs dans ce cas est de plonger dans le code et de le lire.

Certains pourraient me répondre qu’une connaissance globale du code et donc de son architecture est souvent suffisante pour produire une conception préliminaire qui permettrait au développeur de commencer à implémenter la nouvelle fonctionnalité et c’est vrai, je ne le conteste pas.

Mais toute la nuance est dans les attributs attachés aux mots. La conception est belle et bien préliminaire. Pas plus.

“Aucun plan de bataille ne survit au premier contact avec l’ennemi.”

La conception finale est donc du ressort de l’implémenteur, qui ne la finalisera qu’après s’être confronté avec le code existant et donc l’avoir lu et compris. Le plan initial est souvent incompatible avec la réalité ; cela peut être à cause des choix et des adaptations locales qui ont été faits tout au long de la vie de l’application.

Et si vous connaissez par cœur toutes ces subtilités, c’est que vous avez nécessairement lu le code énormément, si ce n’est écrit vous-même.

Écrire et lire le code est avant tout un transfert de connaissance

Combattre les mauvaises habitudes

Si vous êtes toujours en train de lire cet article, j’ai pour espoir que c’est parce que vous êtes convaincus qu’il est important que le code soit parfaitement clair sur ce qu’il fait.
Mais peut-être estimez-vous que votre code est déjà bon. Certes, je ne vous connais pas personnellement, mais si vous ne découvrez le sujet du clean code que maintenant, je suis prêt à prendre le pari qu’il reste de la place pour vous améliorer.

Mais avant tout, je voudrais vous donner la règle fondamentale que je tente de suivre lorsque je pense en matière de lisibilité :

Il faut communiquer l’intention

C’est sans doute la règle la plus essentielle à propos de la lisibilité du code. Et pourtant, elle est très souvent délaissée. C’est aussi sans doute l’une des plus difficiles à satisfaire.

Nous allons explorer quelques biais que nous expérimentons lorsque nous écrivons du code et qui nous empêchent de nous améliorer.

Enlightened Brain-bulb

On ne pense pas long terme

Une compréhension rapide doit être une propriété du système

Le premier biais auquel je m’attaque est assez simple à appréhender : lorsque l’on vient de finir d’écrire le code, on le comprend.

Mais il s’agit souvent là d’un état des choses très temporaire.
Il est fréquent de revenir six mois plus tard sur son propre code et de se creuser les méninges à tenter de le lire de nouveau.

Au moment où vous en avez fini avec le code, que vous avez travaillé quelques heures voire quelques jours sur le problème, vous avez eu le temps de vous familiariser avec le métier, vous êtes capable d’expliquer si besoin car tout est encore très frais.

Il s’agit ici d’une vue court terme des choses.

Une fois le code terminé, il faut s’assurer qu’il faut un temps d’un ordre de grandeur inférieur pour lire le code qu’il n’en a fallu pour l’écrire.
S’il faut de nouveau plusieurs jours de lecture pour comprendre le fonctionnement d’une partie du code, sa maintenance risque de coûter cher.

Le problème réside dans le fait que l’on laisse le code pourrir.
Dans les premières fonctionnalités, aucun effort spécifique n’est fait. La base de code grandit et les méthodes grossissent. Les fonctionnalités se mixent et les corrections commencent à prendre des jours plutôt que des heures.
Ce scénario est très commun et est directement lié au manque de discipline de l’équipe dans le maintien du fait que le code puisse être compris rapidement.

Des efforts continus doivent être faits pour assurer une compréhension rapide

Pour cela, assurez-vous d’exprimer le besoin métier au plus haut niveau d’abstraction et séparez avec soin votre code en petites méthodes.

Nous avons appris un faux langage

Voici un autre biais que nous partageons entre programmeurs, nous avons appris un langage commun. Certains le pratiquent depuis des années et y sont très familiers. Certains sont encore en phase d’apprentissage.

Pour ces derniers, ce que j’entends par apprentissage est la capacité à manipuler les outils bas niveau que nous procurent les langages et à en faire bon usage. Ce n’est généralement pas ici que se situe le problème.

Le problème vient du fait que nous n’apprenons pas que ces outils bas niveau appartiennent aux couches d’abstraction basses du système.

Pour ceux dont le langage de code est déjà dans leur zone de confort, il est désormais relativement aisé de décrypter n’importe quelle implémentation de bas niveau. Les boucles for, les try/catch et les if imbriqués sont déjà très familiers.

Dès lors, si l’on exclut la phase d’apprentissage car temporaire, et que nous sommes d’accord sur le fait que nous sommes capables de nous lire et de nous relire, il ne devrait pas y avoir de problème, si ?

Alors pourquoi est-il si difficile de déchiffrer ce que l’autre a voulu faire dans son code ?

incomprehension

Plusieurs raisons :

  • Il est difficile de garder quelque chose simple lorsque que tout est conçu au plus bas niveau.
  • Il y a toujours une part importante de développeurs en phase d’apprentissage à cause de la demande croissante.
  • Nous pensons que nos langages de programmation, aussi expressifs soient-ils, sont réellement des langages

Il y a sans doute un tas d’autres raisons mais je vais ici me contenter à développer cette dernière.

Nos langages ne possèdent en réalité qu’un nombre très limité de mots-clés qui leur sont propres. Tout le reste du vocabulaire, des verbes, et globalement de ce qui compte pour comprendre l’intention n’existe pas nativement.
Le langage métier doit être réinventé dans chaque projet.

De plus, l’usage du langage de programmation est souvent très personnel.

Vous devez donc consciemment faire en sorte que le code que vous créez possède suffisamment d’éléments pour pouvoir recréer le langage métier de manière expressive. C’est une des raisons pour lesquelles le DDD et son langage omniprésent sont aussi appréciés une fois qu’on a commencé à y goûter. Il met l’équipe en accord sur le vocabulaire à apprendre et sur ce qui est lisible.

Nous aimons suivre les modèles

comfort zone

S’il est bien une chose que nous apprenons à aimer, ce sont nos manières de faire. Nous découvrons un modèle et suivons ensuite ses concepts dans tous les projets rencontrés.

Prenons l’exemple de l’architecture en couche. Il s’agit simplement d’un outil avec ses forces et ses faiblesses, et l’adopter, c’est choisir d’amener avec lui les deux.
Mais il a été si dominant que je rencontre des développeurs qui n’ont été en contact qu’avec ce modèle, et sont aujourd’hui prisonniers de certains schémas de pensées que ce modèle amène avec lui.
On nous a tellement familiarisés avec cette couche de ‘service’ que c’est aujourd’hui un terme que je rencontre fréquemment.
L’architecture en elle-même n’a rien à voir avec l’utilisation que l’on en fait. Il ne s’agit que d’un outil. Ce qu’il faut combattre, c’est la zone de confort dans laquelle nous aimons paresser.

Ce que je vois, ce sont des ProductService. Ce que je vois, ce sont des classes anémiques. Ce que je vois, c’est beaucoup de couplage. Ce que je vois, c’est peu de cohésion.

Mais ce n’est pas l’architecture qui amène tout cela.

C’est nous.

Nous sommes si habitué au terme de service qu’il vient naturellement s’imbriquer dans nos schémas de pensée et de conception, quand bien même il n’apporte aucune indication réelle sur la responsabilité de la classe.

Il ne s’agit ici que d’un exemple du vrai problème mais il se décline de nombreuses façons. Chaque fois que je rencontre IAccount ou AccountImpl, il s’agit d’un pattern que nous suivons, et qui nous empêche de nous arrêter et de réfléchir à un meilleur nom. Chaque fois que l’on appelle une méthode applyChange ou fillProperties, on ne révèle pas clairement son intention. On oblige le lecteur à un effort supplémentaire pour comprendre le comportement sous-jacent.

On ne doit considérer les méthodes que comme des outils que l’on choisit d’utiliser

Conclusion

J’espère que vous vous êtes un peu reconnus dans cet article, car j’espère qu’il vous sera utile. Prendre conscience de ses propres travers est le meilleur moyen de commencer à les mettre de côté, pour tenter de changer les choses.

C’est ce que j’aime dans cette communauté craft, elle tente de revenir à l’essentiel de ce qui fait du bon travail, comme nommer correctement ou faire de notre code une œuvre lisible, qui sont les premières choses que l’on apprend en tant que développeur. Mais qui sont aussi les premières choses que l’on oublie.

© SOAT
Toute reproduction interdite sans autorisation de l’auteur

Nombre de vue : 723

COMMENTAIRES 3 commentaires

  1. Lamiroté dit :

    Très intéressant cet article. Grand Bravo.

  2. Steeven Ramaheridianina dit :

    Très bon article sur l’importance de la lisibilité du code !
    Dans la même intention, si le sujet vous intéresse, Laura Savino à fait une excellente présentation au NCraft l’année dernière.
    Je ne vais pas mettre de lien direct, mais tapez sur Google “lisibilité ncraft” et vous trouverez 😉.

    Pour aller plus loin et aider vos pairs, pourriez vous écrire un second article avec des exemples ? ☺️

    Sinon Thomas Pierrain, Bruno Boucard et Jérémy Grodziski ont présenté quelques fois une session live coding “Du DDD dans mon legacy” que vous pouvez trouver facilement sur YouTube.

    Merci pour le partage de votre pensée !

  3. Dorian Bussi dit :

    Merci pour ces retours !

    La keynote de Laura Savino était en effet très intéressante. J’avais adoré le parallèle entre la poésie et le code : le deux peuvent être difficile à déchiffrer et cacher leur sens lors d’une première lecture. Il faut souvent s’y reprendre à plusieurs fois pour en extraire l’essence.

    Pour la question concernant un second article avec des exemples, c’était en effet l’idée de départ mais comme nous le disent souvent nos chers coachs agiles, il faut avant tout chercher le “why?”. C’est donc ce que j’ai voulu partager avec l’article actuel. Une second peut donc arriver plus tard.
    Mais si vous le souhaitez, vous pouvez trouver dès à présent, des exemples dans la ref. card nommage sur la page des publications SOAT :
    https://www.soat.fr/partageons/publications

    Sinon les vidéo d’uncle bob sont des très bonnes bases pour se faire une idée des chose à embrasser et des choses à éviter.

AJOUTER UN COMMENTAIRE