Bonnes pratiques de développement (guidelines)

Il est toujours difficile de formaliser ce qui est bon ou mauvais à faire dans un projet. Voici quelques guidelines qui pourront vous être utiles.

Jérémy 🤘
Jérémy 🤘

Il est toujours difficile de formaliser ce qui est bon ou mauvais à faire dans un projet. Voici quelques guidelines qui pourront vous être utiles.

Code Smells

Les code smells sont des mauvaises pratiques qui conduisent à l’apparition de défauts. Ceux-ci sont souvent issus de mauvais choix de conception et conduisent à une complexification du code source, de la maintenance et de l'évolutivité de celui-ci.

Il est donc important de toujours éviter ces mauvaises pratiques !

Duplicated Code

Le code dupliqué représente la même portion de code répétée à plusieurs endroits de l’application. La duplication de code peut se situer dans une même classe, au sein de méthodes différentes, ou dans des classes différentes.

Cette pratique entraîne une complexité de la maintenabilité et de l’évolutivité en cas de modification de comportement qu’il serait alors nécessaire d’impacter à plusieurs endroits dans l’application pour le même résultat.

Feature Envy

L’envie de fonctionnalité décrit un défaut d’encapsulation des données d’une classe. Le cas le plus concret est une méthode qui fait de nombreux appels à des méthodes d’autres classes.

Ces appels sont souvent effectués via des getters par besoin de données. Il s’agit du signe indiquant que la méthode se trouve sûrement dans la mauvaise classe.

BLOB

Aussi connu sous le nom de “God Class” ou “Winnebago”, l’anti-patron “BLOB” est une classe ayant trop de responsabilités au sein du logiciel.

Cela se manifeste par un trop grand nombre d’attributs et de dépendances aux classes data, ainsi qu’un nombre d’appels de ces méthodes par les classes extérieures très importantes.

La conséquence inévitable est le risque de rupture de compatibilité du code lors de modifications apportées à ce type de classes.

Long Parameter List

L’anti-patron “Long Parameter List” est une erreur héritée des débuts de la programmation, avant l’arrivée de l’orienté objet. Chaque fonction nécessitait une série de paramètres qu’il était préférable d’utiliser à la place des variables globales.

Aujourd’hui la situation a évolué et le surnombre de paramètres ne fait que nuire à la lisibilité et à la compréhension. Cela complique également l’utilisation et la refactorisation du code.

Long Method

L’implantation de longues méthodes est un problème récurrent. Il s’agit de rendre les méthodes inutilement longues et complexes quand il est possible de les décomposer.

Cette décomposition, en plus d’améliorer la lisibilité et la compréhension du code, permet de simplifier la refactorisation par la suite. On la caractérise souvent par l’utilisation d’un trop grand nombre de paramètres internes, de boucles ou conditions ainsi que de valeurs de retour. Il est préférable aussi de conserver une seule action métier par méthode.

Large Class

L’anti-patron “Large Class” décrit simplement le cas d’une classe trop grosse, possédant beaucoup de variables et de méthodes. Il s’agit souvent de classes un peu fourre-tout qui ont mal évolué niveau architecture (par exemple, les helpers). Ce genre de situation conduit le plus souvent vers de la duplication de code ou vers du “BLOB”.

Porter attention à ce genre de problème et ne pas tomber dans ce piège permet d’éviter le code spaghetti et les applications monolithiques qui sont très compliquées à maintenir et évoluer.

Variables nullables

Lors du test d’une variable “nullable”, il est préférable de tester si celle-ci est égale à un certain type ou de la classe recherchée plutôt que de tester si elle n’est pas simplement nulle.

Cela permet de mieux maîtriser les valeurs attendues et de pousser les comparaisons plus strictes au niveau du type.

Variables intermédiaires

Afin de garantir des performances optimales, il est préférable d’éviter de déclarer des variables intermédiaires lorsque cela n’est pas nécessaire.

Cela permet de réduire l’empreinte mémoire de l’application. En revanche, il reste préférable de déclarer une variable intermédiaire lorsque cela améliore la compréhension du code.

Else

Il est préférable d’éviter d’utiliser les conditions else. Il est plus approprié d’effectuer un return par défaut en bas de la fonction.

Cela permet d’améliorer le typage et d’harmoniser les retours des méthodes. Attention cependant aux méthodes qui ont trop de return : elles perdent en lisibilité et surtout sont plus difficiles à tester.

Tableaux associatifs

Il est primordial d’éviter d’utiliser les tableaux associatifs en PHP au lieu des classes. Il est préférable de définir et d’instancier la classe appropriée.

Cela permet de sortir des logiques procédurales et d’améliorer l’architecture de l’application et de faciliter les tests.

Principes d’architecture

SOLID

Single responsibility principle

Une classe doit avoir un rôle, un périmètre fonctionnel défini dans son DocBlock. Une classe doit avoir un nombre limité de méthodes (à partir de 10 ça commence à faire beaucoup). Une méthode doit avoir un nombre limité de lignes de code (100 est une limite haute).

Open/closed principle

Les schémas d’architecture doivent être décrits par des interfaces. Autant que nécessaire, des classes abstraites implémentent ces interfaces.

Liskov substitution principle

Si « Carré » est un sous-type de « Rectangle », alors tout objet de type « Rectangle » peut être remplacé par un objet de type « Carré » sans altérer les propriétés désirables du programme concerné.

Interface segregation principle

Une interface doit avoir un rôle et un périmètre défini dans son DocBlock. Ce périmètre doit être limité. Par exemple, il est préférable d'éviter d’avoir une interface PaymentProcessorInterface car tous les systèmes de paiements (carte bancaire, virement bancaire…) ne gèrent pas les mêmes actions.

Il est donc préférable d’avoir plusieurs interfaces CardPaymentProcessorInterface, TransferPaymentProcessorInterace...

Dependency inversion principle

Autant que possible, il est préférable d’injecter des interfaces de services, et non pas des services directement.

Corollaire : autant que possible, on définit des interfaces pour les services qu’on injecte. C’est particulièrement vrai lorsque l’on définit un service réutilisable à travers un package Composer : il doit exposer des interfaces.

DRY

Il s’agit d’un principe de programmation visant à exercer les développeurs à reconnaître des duplications, puis de trouver le moyen de les supprimer.

Celles-ci peuvent se produire évidemment dans le code, mais aussi à tout niveau de l’application. Par exemple, l'architecture, les tests unitaires ou les processus de déploiement peuvent aussi être impactés. DRY est donc un principe plutôt général comparé à de la simple duplication de code.

KISS

Keep it simple, stupid (ne complique pas les choses). Ligne directrice de conception qui préconise la simplicité dans la conception et que toute complexité non indispensable devrait être évitée dans toute la mesure du possible.