Dernière mise à jour:

Le principe de responsabilité unique

Cédric Gérard
Cédric Gérard Code

Le principe SOLID de responsabilité unique (Single Responsibility principle ou SRP) est un principe fondamental en programmation orientée objet (POO) qui stipule qu’une unité de code (UdC) ne devrait avoir qu’une seule responsabilité.

Dit comme ça, ce principe semble simple à comprendre. Mais d’expérience, c’est certainement un des plus mal compris et maîtrisé. Par exemple, si je vous demande ce qu’on entend par “responsabilité”, qu’est-ce qui vous vient à l’esprit ?

Régulièrement, on va dire que notre UdC ne doit être en charge que d’un seul traitement. Cette définition est tout aussi vague que la précédente. Une définition plus technique consiste à dire qu’une UdC ne doit avoir qu’une seule raison de changer. La encore, ce n’est pas évident de comprendre ce qu’on entend par la notion de changement. Est-ce qu’il s’agit seulement de l’ajout d’une fonctionnalité ? Un refactoring est-il considéré comme un changement ? Qu’en est-il de la monté de version d’un lib ?

Pour mieux cerner ce principe, il faut comprendre que SRP est un principe qui concerne la répartition de la logique du code dans une application. En POO, on pourrait simplifier ça par le fait de savoir où mettre tel code dans telle classe ou module.

En fait, et c’est Bob Martin qui le dit lui-même, la meilleure question à se poser à ce sujet, c’est “A QUI?”. À qui est dédiée cette fonctionnalité ? Lorsqu’on est capable de répondre à cette question, si une UdC est en charge de répondre aux demandes de plus d’un profil d’utilisateur alors elle ne respect par le principe de responsabilité unique. Elle a donc autant de raison de changer qu’il y a de profils concernés par son utilisation.

Prenons un exemple concret:

no srp Ruby code
Code qui ne respecte pas SRP

Le classe ci-dessus présente quatre méthodes, chacune d’elles a un rôle bien défini. Il y en a une pour calculer la paie d’un salarié, une pour afficher le résultat, une pour récupérer le nombre d’heures travaillées par le salarié et enfin une pour sauvegarder le salarié en base de données.

Ici, chacune des méthodes est liée à un profil d’utilisateur différent. Le calcul de la paie est lié à la finance, l’affichage de la paie est de la responsabilité des ressources humaines, le reporting du temps de travail est le rôle des manager et enfin la sauvegarde en DB est de la responsabilité de l’équipe technique.

Si on se réfère à notre définition, quelques lignes plus haut, cette implémentation ne respect pas le principe de responsabilité unique. En effet, cette classe va changer selon l’évolution des besoins de ce quatre utilisateurs. Il y a donc bien quatre origines possibles à l’évolution de cette classe et elle à finalement plusieurs raisons de changer.

Pourtant, à première vue, cette classe semble tout à fait correcte. Alors comment faire si on souhaite respecter ce principe. Voici un exemple de code qui peut vous aider à y voir plus clair :

srp Ruby code
Classe pour représenter un employé

Ici, on réduit la classe Employee à un simple value object sans logique. La logique va être déplacée dans d’autres classes, chacune sera dédiée à une responsabilité. Voici un exemple de découpage :

srp Ruby code
Classes en charge de gérer la paie

Vous remarquerez ici qu’on fournit deux classes pour calculer la paye. Ces classes, qui implémentent le même contrat (PayCalculator) permettent de remplacer le if de la fonction de calcul de la version précédente.

srp Ruby code
Classes pour la persistence et le reporting
srp Ruby code
Classe pour l'affichage en console de la paye

Voici les trois dernières responsabilités qui ont été sortie. Un repository est en charge de la persistance des employés, un reporter se charge de calculer le temps de travail effectif en fonction du planning et enfin une classe qui permet d’afficher une paye en console.

Premier constat, on a plus de fichiers au bout du compte. Chaque fichier reste simple correspond à une intention bien particulière qu’il est facile de comprendre. Ici, chaque fichier est à mettre en face d’un profil d’utilisateur et n’a donc qu’une seule raison de changer.

D’un point vu technique, il est plus facile de faire évoluer le code de la deuxième version, car un changement dans l’une des classes ne pourra pas avoir d’impact sur les autres. On peut facilement remplacer une classe par une autre si on veut faire évoluer notre besoin. C’est le cas pour le calcul de la paye, mais on pourrait faire de même avec le pointer pour imprimer une fiche de paie ou envoyer le résultat par email par exemple.

Voici un petit exemple d’un calcul de paie qui s’appuie sur le découpage de nos responsabilités :

srp Payroll

En conclusion, SRP, est un principe qui permet de garantir que le code est correctement reparti dans des UdC qui facilitent la lecture, le test et les modifications à venir. En revanche, on se retrouve avec beaucoup plus de fichiers par rapport à une approche traditionnelle basée sur les concepts réels (e.g. Employee).

Je vous invite à avoir ce principe en tête lorsque vous codez. Le gain apporté par son utilisation en termes de maintenance et d’évolution en vaut vraiment le coup.

Cédric Gérard

Cédric Gérard

Je suis dans l'informatique depuis tout jeune. D'abord intéressé par le hardward (montage, overcloking), j'ai mis du temps à trouver ma voie. Je suis tombé dans le développement en 2007, je n'ai jamais arrêté depuis..

Aujourd'hui, je suis développeur web avec une plus grande appétence pour le backend. J’accorde beaucoup d’attention à la valeur apportée aux utilisateurs finaux. On ne réalise pas d'application que pour se faire plaisir, après tout.

Je mets aussi un point d'honneur à livrer du code de qualité en m'appuyant sur les bonnes pratiques du développement logiciel et je défends les valeurs du software craftmanship.

L'agilité est également un élément essentiel pour un travail fiable et efficace. Je ne parle pas de méthode, mais de l'état d'esprit prôné par l'agilité.

J'aime partager mes compétences et j'ai une appétence particulière pour l'encadrement des développeurs juniors.

Je suis également en quête de sens, aucune technologie étant une fin en elle-même, j'ai besoin de savoir pourquoi je travaille et qu'elle est la valeur produite.

Articles en relation

Le principe d'injection de dépendance

Le principe de ségrégation des interfaces

Le principe de substitution de Liskov