Table des matières
Principes
Niveau unique d'abstraction
Le respect d'un niveau d'abstraction favorise la lisibilité.
Mutabilité | |
---|---|
Correction | |
Efficacité de la production | |
Amélioration continue | |
Développeur unique |
Une ligne de code peut se situer à différents niveaux d'abstraction. L'affectation d'une valeur à une variable se situe à un niveau d'abstraction inférieur à celui d'un appel de méthode, par exemple. Enfin, il peut y avoir beaucoup plus de logique derrière l'appel de méthode que dans l'affectation d'une variable. Même les appels de méthode peuvent se situer à différents niveaux d'abstraction. L'appel à une méthode d'un framework se situe à un autre niveau que l'appel à une méthode de l'application.
Pour que le code soit facile à lire et à comprendre, un seul niveau d'abstraction devrait être utilisé dans une méthode. Dans le cas contraire, le lecteur aura du mal à distinguer l'essentiel des détails. Si des bits sont nécessaires, ils ne doivent pas être mélangés avec l'appel de méthodes.
Pour faire une analogie, il est utile de regarder les articles des quotidiens : le plus important y figure en premier lieu, le titre. Il devrait indiquer dans les grandes lignes de quoi l'article traite. La première phrase de l'article le décrit à un niveau d'abstraction élevé. Plus on avance dans l'article, plus les détails apparaissent. Nous pouvons également structurer notre code de cette manière. Le nom de la classe est le titre. Viennent ensuite les méthodes publiques de haut niveau d'abstraction. Celles-ci peuvent éventuellement appeler des méthodes de niveau inférieur, jusqu'à ce qu'il ne reste plus que les "méthodes de bitpays". Grâce à cette répartition, je peux, en tant que lecteur de la classe, décider du niveau de détail que je souhaite consulter. Si je ne suis intéressé que par le fonctionnement de la classe, je n'ai besoin de regarder que les méthodes publiques. La fonctionnalité y est résolue à un niveau d'abstraction élevé. Si je suis intéressé par des détails supplémentaires, je peux aller plus loin et consulter les méthodes privées.
Sources bibliographiques : Clean Code, page 36 et suivantes.
Principe de responsabilité unique (SRP)
La concentration facilite la compréhension. Une classe avec exactement une tâche est plus compréhensible qu'un magasin général.
Mutabilité | |
---|---|
Correction | |
Efficacité de la production | |
Amélioration continue | |
Développeur unique |
Le principe de responsabilité unique (SRP) est l'un des SOLID principes. Il est le suivant : une classe ne doit un responsabilité.
Le principe de responsabilité unique repose sur l'idée que les modifications ou les extensions des fonctionnalités d'une application doivent se limiter à quelques classes. Plus le nombre de classes à adapter est élevé, plus le risque est grand que les modifications nécessaires entraînent des problèmes à des endroits qui n'ont rien à voir avec l'extension. Une violation du principe de responsabilité unique entraîne un couplage et donc une complexité accrue, il devient plus difficile de comprendre le code.
Séparation des préoccupations (SoC)
Si une unité de code n'a pas de tâche claire, il est difficile de la comprendre, de l'appliquer et, le cas échéant, de la corriger ou de l'étendre.
Mutabilité | |
---|---|
Correction | |
Efficacité de la production | |
Amélioration continue | |
Équipe |
Traduit par séparation des intérêts, ce principe signifie qu'il ne faut pas regrouper plusieurs intérêts dans une même classe. Que sont les intérêts ? Les intérêts sont des objectifs "complètement différents". On dit aussi que les intérêts sont orthogonaux entre eux et surtout orthogonaux à la fonctionnalité principale d'une unité fonctionnelle. Voici quelques exemples de préoccupations typiques : Tracing, Logging, Transactionnalité, Caching. Ces intérêts doivent être transférés dans des unités fonctionnelles spécialisées selon le principe de la séparation des intérêts (Separation of Concerns).
Le principe de la séparation des préoccupations est étroitement lié au principe de la responsabilité unique. Les Concerns sont un surplus de Responsibilities. Dans l'idéal, chaque Responsibility se compose d'un seul Concern, à savoir sa fonctionnalité principale. Mais souvent, une Responsibility contient plusieurs Concerns mélangées. Comme cela ne peut généralement pas être évité, le principe ne veut pas dire qu'une Responsibility ne doit comporter qu'un seul Conern, mais que les Conerns doivent être séparés. Au sein d'une méthode, il devrait par exemple être clairement reconnaissable qu'il existe plusieurs conerns. En outre, les noyaux ne devraient pas être dispersés dans la méthode, mais regroupés de manière à ce que l'on sache clairement ce qui appartient à un noyau.
Dans le Domain Driven Design, on essaie par exemple de séparer strictement le domaine commercial de l'infrastructure. Ainsi, une classe du domaine commercial ne doit contenir aucune infrastructure, par exemple pour l'accès aux bases de données, mais doit représenter exclusivement la logique commerciale. La persistance est un "Concern" qui n'a rien à voir avec la logique commerciale. La séparation des préoccupations conduit à un couplage lâche et à une forte cohésion. Les différents composants se concentrent chacun sur une tâche, un Concern, et sont donc faciles à comprendre. Toutes les parties qui composent le composant sont orientées vers cette tâche unique, ce qui rend les parties étroitement liées (forte cohésion). La séparation des préoccupations permet en outre d'obtenir des composants faciles à tester. En effet, si l'objectif d'une unité de code est focalisé, il y a moins de tests à effectuer. Par rapport à l'unité de code à tester, il y a moins de combinaisons de paramètres de test à vérifier. Si la séparation des intérêts doit être pratiquée de manière conséquente, l'orientation objet doit être complétée par le concept de programmation orientée aspect (AOP). Il est ainsi possible d'extraire complètement d'une méthode des aspects tels que la transactionnalité, le traçage ou la mise en cache.
Conventions de code source
Le code est plus souvent lu qu'écrit. C'est pourquoi il est important de disposer de conventions qui favorisent une lecture et une saisie rapides du code.
Mutabilité | |
---|---|
Correction | |
Efficacité de la production | |
Amélioration continue | |
Équipe |
Nous considérons que les aspects suivants sont importants :
- Règles de nommage
- Commenter correctement
Nous ne voulons pas dire par là que les autres conventions ne sont pas importantes, nous voulons juste commencer par ces deux-là, car elles nous semblent élémentaires. En effet, pour toutes les conventions de code, une chose est très importante à nos yeux : il s'agit moins de la forme concrète que du respect systématique de la convention. Et il s'agit de prendre conscience de la nécessité des conventions.
Règles de nommage
Sans règles de nommage, il faut s'adapter encore et encore au style de certains développeurs.
Les règles de nommage doivent aider le lecteur du code à comprendre le code. Comme il est par exemple utile de distinguer les champs des variables locales, une règle d'appellation pourrait aider à le faire. La forme d'une telle convention dans un cas particulier est une question de goût. Certains préfèrent "this.xyz", d'autres "_xyz". La variante choisie n'est pas importante pour nous. Ce qui nous importe, c'est que la convention soit respectée de manière conséquente. La nécessité d'une règle de nommage pour les champs, par exemple, dépend également du contexte. Dans une classe de 400 lignes, une règle d'appellation qui met en évidence les champs par rapport aux variables serait très importante pour nous, alors que dans les classes de petite taille, elle passe plutôt au second plan. À l'aide de l'analyse de la cause racine, Clean Code Developer s'intéresse à la cause réelle de la nécessité d'une règle de nommage.
Commenter correctement
Les commentaires inutiles, voire erronés, ralentissent la lecture. Le code doit être suffisamment clair pour se passer autant que possible de commentaires.
En termes simples, un commentaire dans le code est une indication que le code peut encore être amélioré. Les cas typiques de ce genre sont les 3 lignes de code qui sont écrasées par un commentaire. À ce stade, il est probablement utile d'extraire les trois lignes en tant que méthode (Refactoring : Extract Method) et d'utiliser le commentaire comme nom de la méthode. De manière générale, le besoin de commentaires peut être réduit en utilisant de bons noms pour les variables, les méthodes, les classes, etc.
Au lieu de
int longueur ; // en mm
mieux
int longueurInMM ;
Au lieu de
public double Preis() {) // calcule le prix brut ... }
mieux
public Money Prix brut() { ... }
Il ne faut pas commenter ce que l'on fait, mais plutôt, si on le fait, pourquoi on le fait.
Pratiques
Suivi des problèmes
Seul ce que l'on écrit ne s'oublie pas et peut être délégué et suivi efficacement.
Mutabilité | |
---|---|
Correction | |
Efficacité de la production | |
Amélioration continue | |
Équipe |
Une gestion structurée de tous les "issues" est nécessaire, ne serait-ce que pour ne rien perdre. Et ce n'est que lorsqu'il est possible d'avoir une vue d'ensemble de tous les points ouverts qu'il est possible de les classer par ordre de priorité et de les hiérarchiser. Pour cela, il n'est pas nécessaire d'utiliser des outils sophistiqués, un tableau avec des cartes en carton peut également faire l'affaire. Surtout, ce n'est pas l'outil qui doit être mis en avant ici, mais l'activité.
Voir aussi sous Outils.
Tests d'intégration automatisés
Les tests d'intégration garantissent que le code fait ce qu'il doit faire. Ne pas automatiser cette activité récurrente serait une perte de temps.
Mutabilité | |
---|---|
Correction | |
Efficacité de la production | |
Amélioration continue | |
Développeur unique |
Nous avons déjà décrit la condition fondamentale pour toute modification du code dans le degré rouge grâce à l'utilisation d'un système de contrôle de version. Nous pouvons sans souci apporter des modifications au code, supprimer des fichiers et des répertoires entiers, grâce au système de contrôle de version, tout est à nouveau accessible.
Si nous apportons des modifications au code, nous devons être sûrs de ne rien casser. Et cette sécurité ne peut être obtenue que si nous testons après la modification si l'application se comporte toujours comme avant. Effectuer ces tests à la main après chaque modification ne serait pas pratique, nous devons les automatiser. L'un des grands maux du développement de logiciels est la peur d'oublier quelque chose lors de modifications du code, de ne pas tenir compte d'un détail et de provoquer ainsi une erreur dans un code qui fonctionnait auparavant. En général, il n'est même pas important de savoir si les modifications ont pour but d'améliorer le code (refactorisation) ou de répondre à des exigences supplémentaires. Tant que nous ne sommes pas sûrs, après avoir effectué une modification, que tout fonctionne comme avant, la peur demeure. Celle-ci nous pousse à laisser le code tel quel en cas de doute, car il fonctionne. Les refactorisations nécessaires ne sont pas effectuées par peur de faire des erreurs.
Pour que nous puissions nous engager dans des projets déjà en cours (appelés Brownfield projets, contrairement à Greenfield "sur le terrain"), nous avons besoin de procédures qui peuvent être appliquées au code existant. Les tests d'intégration automatisés conviennent à cet effet. Soit ils commencent tout en haut de l'interface utilisateur et testent l'application à travers toutes les couches, soit ils commencent plus bas. Dans tous les cas, plusieurs unités fonctionnelles sont testées en interaction.
Ainsi, avant d'apporter des modifications ou des extensions au code, nous réalisons des tests d'intégration pour les zones de code concernées. Pour ce faire, nous pouvons utiliser des outils et des techniques comme WatiN, UI Automation, etc. Il est bien sûr également souhaitable de procéder à des tests unitaires qui testent les différentes unités fonctionnelles de manière isolée. Pour cela, le code doit toutefois remplir des conditions qui ne sont probablement pas toujours remplies : le code doit déjà contenir le Principe de responsabilité unique doivent être prises en compte. Dans le cas contraire, les dépendances entre les unités fonctionnelles (composants, classes ou méthodes) sont si importantes qu'elles ne peuvent pas être testées de manière isolée. L'objectif à long terme est bien sûr d'avoir une base de code où les tests unitaires sont possibles. Plus encore : à l'avenir, nous créerons les tests avant l'implémentation (Test first). Mais pour y arriver par des refactorisations, il faut d'abord des tests d'intégration pour s'assurer que l'application se comporte toujours comme avant la refactorisation.
Voir aussi sous Outils.
Lire, Lire, Lire
La lecture forme !
Mutabilité | |
---|---|
Correction | |
Efficacité de la production | |
Amélioration continue | |
Développeur unique |
La lecture forme - nous sommes en tout cas fermement convaincus que cela vaut également pour les développeurs de logiciels. La technologie logicielle continue d'évoluer. Outre les grandes étapes de développement telles que la programmation procédurale, la programmation orientée objet, la programmation fonctionnelle, la programmation orientée aspect, etc., il y a constamment des évolutions à petite échelle auxquelles un développeur de logiciels professionnel doit faire face. Il y a d'une part des techniques telles que Injection de dépendances ou Mappeur relationnel d'objets. Mais même au sein de ces techniques, il existe des étapes de développement telles que Langages spécifiques au domaine (DSL) pour la configuration vs. configuration basée sur XML. Outre les aspects techniques du développement de logiciels, le processus est lui aussi en constante évolution. Ainsi, la reconnaissance que les modèles en cascade ne fonctionnent pas s'est imposée, différents processus agiles sont développés. Le développeur Clean Code doit garder tout cela à l'esprit.
Nous proposons donc de lire au moins six livres spécialisés par an. En outre, il convient de lire régulièrement des périodiques, et nous entendons par là non seulement les revues spécialisées, mais aussi les blogs.
Vous trouverez des suggestions dans la Bibliographie.
Critiques
Quatre yeux voient plus que deux. Lorsqu'un développeur explique son code à un autre, des détails qui n'avaient pas été pris en compte jusqu'alors apparaissent généralement.
Mutabilité | |
---|---|
Correction | |
Efficacité de la production | |
Amélioration continue | |
Équipe |
Les revues se présentent, pour simplifier, sous deux formes : en tant que processus continu dans le cas de la programmation en binôme et en tant qu'étape indépendante dans le cas de la revue de code. Dans les deux cas, l'objectif est le même : le code doit être examiné par un deuxième développeur. Cela permet d'éviter l'"aveuglement". Le simple fait qu'un développeur présente et décrive son code à un autre développeur suffit à susciter des réactions.
En règle générale, ce n'est qu'en discutant avec d'autres développeurs que l'on peut voir où se situent les points forts et les points faibles d'une base de code. C'est justement le processus d'amélioration continue qui nécessite de se confronter au point de vue d'autres développeurs.
Bien entendu, le code source n'est pas la seule base appropriée pour les revues. Elles offrent une possibilité avantageuse de vérifier les résultats de toute activité de développement, pour autant qu'ils aboutissent à un résultat "lisible". Outre les revues purement informelles, comme la programmation en binôme ou l'évaluation par une deuxième personne, il existe également la revue formelle avec un processus de revue ainsi que des rôles correspondants. D'autres types de revues connus sont par exemple le walkthrough, la revue technique, la revue par les pairs et l'inspection.
Les revues complètent les tests dynamiques, comme le test unitaire automatique ou le test d'intégration automatique du degré jaune respectivement degré orange. Contrairement à ces tests, les revues sont également très bien adaptées pour trouver des erreurs dans les exigences. Ils peuvent également être utilisés très tôt dans le processus de développement et les erreurs peuvent ainsi être détectées très tôt. Et plus les erreurs sont détectées tôt, plus leur élimination est avantageuse.
Sources
Source | Auteur | Brève description |
---|---|---|
Connaissances de base sur les tests de logiciels, formation et formation continue sur les tests de logiciels. | T. Linz et A. Spillner | Le manuel d'apprentissage pour le Certified Tester Foundation Level selon ISTQB |
Testeur certifié Foundation Level selon la norme ISTQB |
Le degré orange est suivi du degré degré jaune à.