Les barrières mentales du développeur junior

Quand on débute dans la programmation, on est souvent victime de son manque d’expérience. Par exemple, on est rarement conscient au départ de la pléthore d’outils qui s’offre à nous. J’ai ainsi souvenir d’avoir codé à mes débuts une fonction permettant de calculer la date de la veille, avant de découvrir quelques semaines plus tard que le Framework .NET propose une fonction toute faite pour cela (DateTime.AddDays(), à laquelle il suffit de passer un nombre négatif pour retrancher des jours).

Mais il y a aussi un certain nombre d’idées préconçues et de mythes auxquels il est bon de tordre le cou si l’on veut progresser rapidement. Nous allons ici en examiner quelques-uns.

Ce n’est pas parce qu’un code est long qu’il est lent

Le développeur junior a tendance à croire que plus les lignes de code s’empilent, et plus son application va prendre de temps pour s’exécuter. Cela paraît logique de prime d’abord, mais il faut toutefois nettement relativiser cette affirmation.

Tout d’abord, il faut parvenir à se mettre en tête que plusieurs milliers de lignes de code peuvent tout à fait s’exécuter en quelques millisecondes. Certains se sont amusés à mesurer que sur un ordinateur actuel, il est possible d’initialiser en l’espace d’une seule seconde plusieurs millions d’objets.

En réalité, les performances d’un programme sont liées d’une part à la manière dont celui-ci a été conçu, et d’autre part à quels types d’opérations celui-ci est dévolu. Il est évident qu’un programme qui en l’espace de quelques lignes de code effectue plusieurs opérations d’input/output (comme lire un fichier, ou requêter une base de données) sera plus lent qu’un autre qui se contente de manipuler des types primitifs.

Croire que la quantité de lignes de code tapée est directement corrélée à la vitesse d’exécution d’un programme est donc faux, et le programmeur débutant doit apprendre à se concentrer sur la qualité du code, et non sur la quantité, car c’est cette qualité et la manière dont le programme est conçu qui vont réellement influencer ses performances.

Rajouter des niveaux d’indirection se fait généralement au bénéfice du code

Dans le même esprit, le fait qu’un programme soit conçu avec de nombreux niveaux d’indirection (des méthodes, qui appellent d’autres méthodes, qui appellent d’autres méthodes, etc), et fasse appel à de nombreuses abstractions, ne contribue pas forcément à rendre celui-ci plus compliqué ou plus inintelligible. Bien sûr, certains paradigmes de programmation, comme les design patterns, nécessitent une solide expérience pour être compris et manipulés. Mais ces outils architecturaux sont avant tout là pour rendre le code mieux articulé, plus efficace et assurer sa pérennité; en un mot : à le rendre plus propre.

Que ce soit ces design patterns, les principes de programmation SOLID, ou tout simplement le vieux principe voulant qu’on ne doit pas copier/coller du code mais le factoriser pour mieux le réutiliser, tout tend à encourager le développeur à multiplier les niveaux d’indirection.

Constatant que j’avais tendance à écrire des fonctions faisant plusieurs centaines de lignes, un collègue de MCNext m’a un jour obligé à me limiter à un maximum de 50 lignes par fonction. En me pliant à cet exercice, j’ai appris à mieux découper mon code, à abstraire ce qui pouvait l’être, et plus généralement à voir les niveaux d’indirection comme autant de points d’articulation dans mes programmes.

Le code est à tout le monde…

Un autre point important qu’il est bon de garder en tête, est que le code d’une application appartient à tous ceux qui travaillent dessus.

Concevoir une application professionnelle est rarement le travail d’un seul homme, et chaque membre de l’équipe devrait donc pouvoir s’approprier la base de code en entier.

Cette affirmation a plusieurs conséquences. Tout d’abord, il convient qu’une équipe de programmeurs se mette d’accord sur un vocabulaire commun, qui sera réutilisé tout au long du développement. Par exemple, il y a une différence sémantique entre parler d’image et d’illustration. J’ai eu l’occasion d’utiliser cette différence dans un projet afin d’enrichir les interactions avec les autres membres de l’équipe. Cette notion de vocabulaire peut même être élargie au commanditaire de l’application, afin d’améliorer là encore la qualité des échanges.

Toujours autour de la notion de compréhension, se pose généralement la question de : on code en français ou en anglais ? En effet, la plupart des langages de programmation utilisent des mots-clefs en anglais, et le .NET ne fait pas exception. Toutefois, il est tout à fait concevable d’utiliser des noms d’entités en français. Beaucoup de développeurs préfèrent coder entièrement en anglais, toutefois cette question devrait être systématiquement débattue en équipe. Personnellement, j’ai tendance à préférer coder en anglais, mais avec les commentaires rédigés en français, afin de s’assurer qu’aucun détail technique (que l’on transmet généralement dans ces commentaires) ne soit perdu. Par contre il est préférable d’éviter d’imposer l’anglais à une équipe où le niveau dans cette langue serait plutôt faible; les fautes d’orthographe et de grammaire ne sont généralement pas d’une grande aide lorsqu’il s’agit d’améliorer la compréhension d’un programme.

Mais le point le plus important de cette notion de le code est à tout le monde, c’est que chaque membre de l’équipe devrait pouvoir intervenir comme bon lui semble sur n’importe quelle partie du programme. Bien sûr telle ou telle fonctionnalité qui aura été codée par tel ou tel développeur sera mieux comprise de celui-ci. Toutefois, aucun développeur ne devrait considérer un code qu’il a écrit comme son code, et chacun devrait pouvoir contribuer à améliorer continuellement la base de code. Il ne faut donc pas hésiter à réécrire le code d’un autre si l’on pense que celui-ci peut être amélioré, que ce soit en terme de compréhension ou de performances.

Toutefois, il s’agit de savoir se montrer diplomate. Il est facile de vexer les autres lorsqu’on remet en cause la qualité de leur travail. Par ailleurs, j’ai souvent vu des développeurs modifier le code d’un autre non pas pour l’améliorer, mais par pure maniaquerie (en l’indentant d’une manière particulière par exemple). Même si nous sommes tous un peu maniaques, ce genre de pratiques est à proscrire.

En outre, renommer des entités pour garder une base de code homogène est un bien, mais ne doit pas aboutir à des aller/retour continuel pour décider qui de Michel ou Jean-Pierre a choisi le meilleur terme. Les règles de nommage, qu’on établi au début d’un projet, sont aussi là pour éviter ce type de situation.

Un développeur junior ne doit en tout cas pas avoir le moindre scrupule à « bousculer » le code des autres s’il juge que ses changements sont opportuns.

…et tout le monde est susceptible de travailler dessus

Un développeur ne devrait jamais oublier que d’autres personnes sont susceptibles d’intervenir sur le code qu’il écrit, et donc de s’assurer que celui-ci respecte les canons de lisibilité et de maintenabilité du métier. Un code se doit d’être conçu de manière à expliciter de la manière la plus claire possible son fonctionnement et sa finalité.

Pourtant, parvenir à atteindre un tel niveau de qualité n’est pas chose aisée, surtout pour un débutant, et même en y mettant la meilleure volonté du monde, il n’est pas rare lorsqu’on a plusieurs mois de recul d’éprouver soi-même des difficultés à se replonger dans un code qu’on avait pourtant programmé soi-même.

Comparez les deux bases de code suivantes. Laquelle vous paraît la plus compréhensible ?

public int GetResult(string number)
{
    var order = (from o in Session.Orders
                 where o.Id == number
                 select o).First();

    /*********************************************
     * Ici beaucoup trop de code permettant de calculer
     * le statut d'une commande.
     ********************************************/

     int result = resultatDesCalculsPrecedents;
     return result;
}
public enum OrderStatus
{
    Canceled,
    Pending,
    Paid,
    Delivered
}

public OrderStatus GetOrderStatus(string orderId)
{
    Order order = OrderRepository.GetOrderFromId(orderId);
    OrderStatus orderStatus = new OrderStatusSpecification(order).Execute();
    return orderStatus;
}

La différence de clarté entre ces deux codes est flagrante. Le code de qualité utilise des termes très précis pour expliciter son fonctionnement et sa finalité, là où l’autre reste très vague.

Même le type de retour est différent. Le mauvais code renvoie un simple nombre entier qui n’a de sens que celui que l’équipe aura bien voulu lui donner par convention, ce sens risquant d’évoluer pendant le cycle de développement de l’application, avec les conséquences qu’on imagine. Utiliser une énumération permet à peu de frais d’expliciter le sens du résultat de l’opération.

Par ailleurs, dans le code de qualité, les calculs potentiellement complexes sont isolés par un niveau d’indirection, alors que dans l’autre, tout est compressé dans un seul bloc.

S’attacher à rendre un programme plus clair ne permet pas seulement à l’équipe de travailler dans de meilleures conditions, cela permet aussi de rendre le code plus pérenne.

Parvenir à remplir au mieux cet objectif s’apprend beaucoup avec l’expérience. Toutefois je ne saurai trop vous conseiller cet excellent livre (en anglais) qui donne de nombreuses clefs pour apprendre à manipuler du code et à le rendre plus souple.

En tout état de cause, on devrait toujours penser aux autres développeurs lorsque l’on conçoit un programme; ceux qui sont susceptibles de travailler dessus aussi bien demain que dans un an.