Le code comme produit de qualité
Introduction
Dans le métier de développeur, fournir un code qui « marche » ne suffit plus. Les nouvelles applications sont de plus en plus gourmandes en ressources, et les exigences des utilisateurs sont plus que jamais changeantes. Ainsi, les boîtes de développement se rendent compte que la qualité du code importe énormément, puisque cela affecte directement la qualité de l’application et sa durée de vie.
Le « Software Craftsmanship » s’est développé récemment pour contrer l’approche de développement « quick & dirty » trop focalisée sur les délais de développement. Cette dernière a maintes fois montré ses faiblesses puisque le temps gagné en développement est souvent largement rattrapé par le temps perdu en maintenance, entre bugs imprévisibles et listes interminables de dettes techniques.
Le Software Craftsmanship est un état d’esprit, celui de vouloir créer du bon code, et de le faire proprement. En pratique, cela consiste en une boite à outils de méthodologies de développement à la disposition des développeurs pour améliorer la qualité de leur code. Cet article présente quelques-uns des concepts du Software Craftsmanship, entre Unit Testing, TDD, BDD et les principes SOLID.
Unit Testing
Qu’est ce que c’est ?
Le « Unit Testing » est la pratique de diviser le code en «unités» individuelles et de tester leur comportement séparément.
Un « test unitaire » est un simple morceau de code exécuté automatiquement qui teste le comportement d’une de ces unités de code.
Ecrire du code pour tester le code peut décourager certains programmeurs qui doutent de pouvoir respecter les délais si le temps de programmation est doublé. Ce n’est pas tout à fait vrai, pour de simples raisons :
- Comme chaque programmeur le sait, nous passons beaucoup plus de temps à détecter des bugs stupides qu’à écrire du code.
- Les tests unitaires doivent être de simples morceaux de code. Si cela devient trop compliqué, vous le faites probablement mal et vous n’écrivez pas du tout de tests unitaires.
Les tests unitaires ne doivent surtout pas être confondus avec les tests d’intégration, dans lesquels des unités individuelles d’un programme qui interagissent sont combinées et testées en tant que groupe.
C’est pour qui ?
Tous ceux qui écrivent du code. Les programmeurs ne peuvent pas compter sur les testeurs pour détecter leurs erreurs, c’est la responsabilité du programmeur de fournir un logiciel sans bugs.
Quelle utilité ?
Cela contribue à améliorer la qualité et la robustesse de votre code et à détecter les bugs tôt dans le processus de développement. Vous pouvez le considérer comme un filet de sécurité, cela vous donne la certitude que le fait de modifier votre code ne rompt pas le comportement souhaité.
TDD & BDD
Le TDD et le BDD sont des méthodes de développement de logiciels Agiles largement reconnues comme étant de bonnes pratiques pour compléter le concept de « unit testing ».
Test driven Development
Le TDD, ou développements pilotés par les tests, consiste en la répétition d’un cycle de développement court où les tests sont écrits avant le code. Les étapes à suivre dans le cycle TDD sont :
- Commencez par écrire un test
- Exécutez le test et tous les autres tests. À ce stade, le test que vous venez d’ajouter devrait échouer. S’il n’échoue pas ici, il est possible que le test ne soit pas correct et qu’il comporte donc un bug.
- Écrivez la quantité minimale de code nécessaire pour réussir le test
- Exécutez les tests pour vérifier les nouveaux tests.
- Vous pouvez éventuellement faire du « refactoring » de votre code, en vous assurant que votre test reste vert.
- Répétez à partir de 1

Le principal avantage de TDD est qu’il en découle une très grande couverture de tests (pourcentage du code testé automatiquement), ce qui vous donne plus de confiance en votre code, et résulte en beaucoup moins de bugs.
Behaviour Driven Development (BDD)
Le BDD, ou développements pilotés par le comportement, stipule que les tests unitaires doivent impérativement tester le comportement du code, et non son implémentation. En d’autres termes, lors de la conception des tests, vous devez vous concentrer sur ce que la fonction doit faire, sans vous soucier de la manière dont elle le fait.
L’avantage principal de la méthodologie BDD est de rendre les tests plus faciles à maintenir : si vous décidez de modifier l’implémentation de votre code, vous n’aurez plus à vous soucier de modifier vos tests.
Principes SOLID
Tous les codes sont techniquement testables, mais certains codes sont structurellement très difficiles à tester. Ils auront donc besoin d’un « refactoring » parfois lourd et coûteux pour pouvoir écrire des tests unitaires utiles.
Pour s’assurer que le code soit facilement testable et qu’il se prête bien aux changements, il existe plusieurs règles de bonnes pratiques qu’un programmeur peut suivre et appliquer.
Les cinq principes de base, connus et reconnus sous l’acronyme S.O.L.I.D., font également partie du développement logiciel Agile ou adaptatif. Ces principes, lorsqu’ils sont combinés, permettent aux programmeurs de développer facilement des logiciels faciles à maintenir et à étendre, d’éviter les « code smells » et de refactorer facilement le code.

Single Responsibility
Ce principe stipule qu’une classe ne devrait avoir qu’une seule responsabilité, donc une seule raison de changer. Cela signifie que si une classe grandit et comporte de nombreuses dépendances (comme ce couteau suisse multifonctions), vous enfreignez probablement cette règle et vous devriez diviser cette classe en de plus petites classes.

Open-Closed
Selon ce principe, une classe doit être ouverte pour extension, mais fermée pour modification. En d’autres termes, si vous vous trouvez en train de modifier l’implémentation la plus profonde d’une classe à chaque nouvelle exigence (comme si vous aviez besoin d’une intervention chirurgicale à cœur ouvert pour enfiler un manteau), vous devriez probablement repenser votre architecture.

Liskov Substitution
Suivant ce principe, les objets d’un programme doivent pouvoir être remplacés par des occurrences de leurs sous-types sans altérer l’exactitude de ce programme. Autrement dit, si vous avez une classe dérivée qui étend la classe de base et rompt son comportement souhaité (par exemple, en supposant qu’un canard en jouet dérive d’un canard réel), vous violez ce principe et devez repenser les hiérarchies d’héritage de vos classes.

Interface Segregation
Ce principe est simple : de nombreuses interfaces spécifiques au client sont préférables à une interface à usage général. Cela revient à dire que si vous avez une interface multifonctions (comme cet appareil à multi-prises) dont les classes qui l’implémentent n’utilisent que quelques fonctions, vous devez décomposer cette interface en des parties plus petites.

Dependency Inversion
Ce principe stipule qu’il faut dépendre d’abstractions et non de concrétions. En d’autres termes, si vous avez une classe fortement couplée à l’implémentation d’une autre classe (comme cette lampe fortement couplée au mur), vous devez dissocier les dépendances en masquant les implémentations derrière des interfaces.

Conclusion
En bref, les méthodologies Agiles présentées dans cet article, si elles sont bien appliquées et non abusées, aident le développeur à la création d’un code de bonne qualité, sans nécessairement affecter négativement les délais de livraison. La rédaction de « test unitaires » automatiques améliore considérablement la robustesse du code en agissant comme un filet de sécurité. La TDD vous dit quand vous écrivez ces tests, la BDD vous dit comment vous les écrivez ; ils sont complémentaires et doivent donc absolument être utilisés ensemble pour la rédaction de bons tests unitaires. Les principes SOLID vous permettent de produire un code facile à tester, facile à maintenir et adaptif au changement. Toute cette panoplie harmonieuse de bonnes pratiques, si judicieusement combinées, produit un effet positif sur la qualité de code, ce qui doit forcément se refléter sur le produit final.