Bien programmer, des règles et principes généraux
Bien programmer n’est donné à tout le monde. S’il est assez facile de débuter dans le métier avec de nombreux exemples et formations en ligne, sans règles le résultat n’est pas forcément à la hauteur. De mon point de vue un bon code doit respecter certains principes et des règles de bon sens. Une bonne programmation rend le code :
- maintenable : intervenir dans un programme même après des années ne doit pas être un calvaire
- évolutif : un bon programme est pensé évolutif et non totalement hermétique à son évolution
- lisible et documenté : vous devez, ou un autre développeur, pouvoir intervenir dans le code sans vous arracher les cheveux pour le comprendre !
Les principes et règles suivants sont génériques et applicables à tout type de projet. Courants dans la profession, ce sont des gages de qualité de vos livraisons.
Les « nombres magiques »
Ce sont des valeurs testées sans aucune explication et dont la valeur est définie directement dans une condition, une affectation, … On les appelle ainsi car ce sont des valeurs qui apparaissent sans être connues, comme par magie. Ce procédé doit être tout simplement interdit dans le code réalisé. On parle de « nombre » magique mais cela peut être tout type de valeur.
Les bonnes pratiques consistent en la définition d’une constante, ou autre procédé. Programmer une constante permet de comprendre la valeur et de la modifier sans devoir parcourir tout le code.
Il est toutefois toléré d’utiliser une valeur utilisée de manière unique si celle-ci est expliquée par un commentaire clair et sans équivoque.
Programmer sans affectations dans une condition
Pour que le code soit clair et lisible, il est impératif de ne pas effectuer d’affectation dans une condition de test, ou autre forme de bloc. Ce genre de pratique peut facilement induire en erreur. Ce type de programmation se confond avec une erreur courante d’oubli de doublage d’un égal dans une condition if en PHP, ou en langage C / C++ par exemple…
Les blocs de code sans délimiteurs
Il faut clairement s’interdire, par respect des normes de codages choisies (PSR pour PHP par exemple), d’omettre les délimiteurs de bloc sous prétexte que cela est admis par le langage en cas d’unique instruction.
La raison de cette interdiction est la facilité de lecture du code produit. La délimitation des blocs de code dans les conditions et autres éléments du code est un gage de bonne lisibilité.
Les commentaires
Il est primordial de convenablement documenter son code afin de pouvoir :
- Générer automatiquement une documentation développeur
- Comprendre ce qui est fait
- Permettre de reprendre facilement et rapidement des éléments de code lors d’un patch ou d’une évolution
On documentera donc :
- Chaque fonction ou méthode par un entête explicitant la finalité du traitement, ses paramètres d’entrée, de sortie, ses valeurs et types de retours, …
- Chaque classe pour les langages objets
- Les variables intermédiaires lorsque cela est nécessaire à la bonne compréhension du traitement
- Les étapes des traitements
- Les éventuels pièges à éviter
- Les choix faits s’ils ne sont pas évidents
Toutefois, on ne commentera pas :
- Les codes javascripts livrés aux clients (mais les originaux commentés le seront dans les sources sous Git)
- Les fichiers de code CSS livrés aux clients (mais les originaux commentés le seront dans les sources sous Git)
- Les trames HTML livrés aux clients (mais les originaux commentés le seront dans les sources sous Git)
- D’une manière générale un code en clair livré à un client n’aura pas forcément vocation à être commenté, mais une version commentée devra impérativement exister pour permettre l’évolution du code, sa maintenance, …
Les commentaires doivent être précis et clairs pour une bonne compréhension. Ils doivent être relatif au code, pas aux critiques de choix des précédents développeurs.
Le format préconisé est celui inspiré des « java docs ». Ce choix est à adapter en fonction du ou des outils de génération de documentation développeur.
Les entêtes précisant le copyright, auteur, … doivent être standardisés si existants.
Attention, certains langages ou certaines normes limitent les commentaires comme dans le cas de Symfony pour PHP qui préconise un jeu de règles via CS Fixer omettant un certain nombre de commentaires.
La redondance de code
Les redondances de code sont à proscrire sauf si une raison valable explique cette duplication ; l’urgence de livraison n’en étant pas une.
Programmer c’est aussi réfléchir et analyser.
Le fait d’avoir des redondances va augmenter le code inutile de l’application et donc sa consommation en ressources. Mais le point négatif le plus impactant est le fort risque de programmer des bugs lorsqu’une modification est nécessaire dans un traitement.
En effet en cas de duplication de code, la plupart du temps le programmeur oublie de répercuter les modifications dans l’une des copies. Cela revient à avoir des comportements différents suivant les appels dans l’application.
Il convient donc de vérifier qu’une fonctionnalité ou une portion de code n’existe pas déjà avant de se lancer tête baissée dans le codage.
Le détournement d’utilisation
Il est strictement interdit de détourner une variable, un champ de base de données ou tout autre élément de sa vocation première. Il ne faut pas perturber la compréhension du code et donc les futures interventions.
Pour illustrer ce propos, admettons qu’une table utilisateurs contiennent un champ commentaire non utilisé jusqu’à présent.
Lors du développement en s’apercevant que cette table d’utilisateurs ne contient pas de champs pour stocker le prénom, le développeur est tenté pour limiter ses modifications d’utiliser ce champs commentaire…
Cette pratique est mauvaise et prohibée dans notre service. Le danger est que la lecture du code induise le prochain intervenant dans le code en erreur. Imaginez que ce dernier doive implémenter l’ajout d’un commentaire… en voyant qu’un champ existe, il y a fort à parier qu’il va utiliser ce champ ce qui aura pour résultat de « casser » le bon fonctionnement de la gestion du prénom. (Exemple simpliste mais malheureusement courant).
Le nommage des éléments
Le nommage des éléments du code (variables, fonctions, classes, méthodes, constantes, …) doit être clair et en une unique langue. Le Camel case est souvent de rigueur dans une équipe de développement. Certaines règles viennent en fonction du langage compléter cette règle globale et générique. On préfèrera dans la mesure du possible des noms assez courts mais toujours compréhensibles.
Programmer sans Code mort
Le code mort est à éviter dans les applications (hors code d’un Framework par exemple). Lors de la création d’élément il sera porté une attention particulière à ne pas laisser de code non utilisé.
Dans le cas de modifications, il convient avant de programmer un traitement, de s’assurer qu’un traitement similaire n’existe pas déjà. Si un traitement existe mais ne correspond pas tout à fait au besoin, il doit être envisagé de faire évoluer le traitement existant et d’en adapter les appels déjà en place.
Anatomie d’un bon traitement
Définir et programmer une méthode, fonction ou traitement devrait suivre la logique suivante, même si elle apparaît un peu scolaire au premier abord :
- Déclaration des variables locales
- Initialisation des variables
- Utilisation / Traitements
- Libération des éléments
- Retours
Bibliothèques et ressources tierces
Sauf si imposé dans le cadre d’un projet par un client, toute bibliothèque ou ressource utilisée doit être soigneusement choisie et vérifiée. Il convient de vérifier, de manière non exhaustive que :
- La ressource est suffisamment suivie et ne risque pas d’être abandonnée rapidement
- Son contenu et son utilisation sont suffisamment robustes (on évitera par exemple les ressources de source plus ou moins connue téléchargée 3 fois depuis sa création)
- La licence permet une utilisation légale de la ressource.
- La ressource est suffisamment documentée ou maîtrisée (dans ce cas le documenter)
- Aucun conflit n’existe entre la ressource et le projet et est adaptée à celui-ci
- La ressource ne fait pas doublon avec une autre ressource du projet. Dans ce cas envisager l’utilisation de la ressource déjà existante, ou la remplacer par celle souhaitée (en justifiant son choix).
- Préférer les ressources utilisables via gestionnaires de paquets tels que Composer, npm, … (en fonction du langage ou technologies utilisés)
Programmer une gestion des erreurs
La gestion des erreurs n’est pas une option, mais une obligation. Elle garanti un bon fonctionnement général des applications et permet la détection d’anomalies et leurs traitement. C’est un gage de qualité.
Suivant le langage et les traitements, il sera mis en place gestion d’erreurs et gestion d ‘exceptions.
Toutes les erreurs doivent faire l’objet d’une entrée dans un fichier de log (ou équivalent), avec un maximum d’informations sur le contexte afin de faciliter le support.
Parmi les bonnes pratiques :
- Le retour des fonctions et méthodes doivent être exploités,
- La manipulation d’une variable, d’un tableau, d’un objet doit se faire en ayant préalablement testé son existence,
- Les types des données doivent au besoin être vérifiés
- Les saisies des utilisateurs et les entrées externes de données doivent impérativement être contrôlées,
- …
Bases de données et requêtes
Quand disponible dans un projet, il faut utiliser l’ORM et son éventuel QueryBuilder. On évitera au maximum de créer des requêtes spécifiques à un type de base de données. Toutefois quand cela s’avère nécessaire, un commentaire devra à minima en expliquer les raisons.
Les applications développées doivent respecter quand cela est possible le pattern MVC. Les accès aux données devront donc se placer dans les Modèles des Applications.
Il est communément admis d’interdire d’utiliser dans une application un accès en tant qu’administrateur de base de données ou un utilisateur dont les privilèges dépassent ceux nécessaires à l’application et son contexte.
La manipulation directe de données en base de données devrait être prohibée pour conserver la cohérence des applications. Les manipulations doivent être réalisées à travers les applications. La sécurité et la cohérence des applications et données est en jeu à ce niveau. Par ailleurs les accès direct aux données peuvent être préjudiciables vis-à-vis des législations en vigueur comme le RGPD.
Les accès « manuels » en, base de données, que ce soit en ligne de commande ou via une interface graphique telle que PgAdmin ou PhpMyAdmin doivent être ponctuelles, réfléchies et supervisées.
Toute procédure stockée, trigger, ou autre élément en base doit disposer de ses sources et de commentaires adaptés. La production de MCD est vivement encouragée. Ce document devrait être rédigé avant de programmer !
Dans le cas d’une application s’appuyant sur un ORM où la base de données est automatiquement générée (comme avec Symfony et Doctrine), il ne doit pas être réalisé d’opérations manuelles sur la structure de la base de données, cela risquerait de provoquer des effets de bord dans les applications.
En cas de ressources / données partagées entre plusieurs applications, la mise en place d’API, de DBlink ou autres est souvent un choix judicieux. Cela évitera la duplication des informations et facilitera votre maintenance.
Les noms des champs et tables (et autres éléments) ne doivent pas être identiques à des mots « réservés » courant dans les bases de données et ce afin d’éviter toute ambiguïté de compréhension et tout effet de bord.
Le requêtage doit se faire de manière protégée, notamment lorsque des données externes sont utilisées. On privilégiera donc les requêtes préparées, avec attachement de données typées. Ce mode est d’autant plus privilégié lorsqu’une requête est régulièrement utilisée (plus d’une fois), ou utilisée dans une boucle, afin d’optimiser la gestion du cache de requêtes de la base de données.
Il est impératif de se détacher au maximum des contraintes liées à l’utilisation d’une version d’un type de base de données et ce afin de se prémunir contre tout problème lors d’une mise à jour de serveurs de bases de données.