Publié le 04/08/2022
Par Christophe MOMMER
Les principes SOLID font partie des principes "de base" de l'informatique qui permettent de faire du code propre, maintenable et évolutif. En effet, cet acronyme décrit 5 principes distincts, que nous allons analyser au fur et à mesure de 5 billets de blogs distincts.
Avant toute chose, il faut savoir que chacun de ces principes peut également être découvert en vidéo. La vidéo pour le premier principe se trouve ici : https://www.youtube.com/watch?v=9khqY9bdZrc
Maintenant, revenons à nos moutons !
S pour Single Responsibility
S signifie qu'une classe doit avoir une et une seule responsabilité, c'est-à-dire une seule raison de changer/d'être modifiée. Pour faire simple, si vous devez modifier une classe, ce doit être pour répondre à un seul but, qu'il soit technique ou business.
Prenons un exemple simple :
public class Article
{
public int Id { get; set; }
public string Title { get; set; }
public int Quantity { get; set; }
public async Task SaveToDatabase()
{
// code de sauvegarde en BDD
}
public void ShipToCustomer(Customer c)
{
// code permettant de déclencher l'envoi
}
}
Est-ce que ce code est conforme au premier principe ? Évidemment que non ! (sinon ce post n'aurait pas servi à grand-chose 😅)
En quoi est-ce que le principe n'est pas respecté ? Cette classe fait trop de choses ! Tout d'abord, nous avons une liste de propriétés, accessibles en lecture et en écriture. Puis, nous avons une méthode de sauvegarde en base de données (persistance) et finalement une méthode qui déclenche un process métier. La classe a donc 3 raisons d'être modifiée :
- On ajoute une nouvelle information au sujet des articles
- La sauvegarde en base de données doit être modifiée
- Le process métier d'envoi d'article doit être modifié
Étant donné que nous avons repéré ici 3 responsabilités, cela signifie qu'il faut donc 3 classes distinctes :
- La classe Article de base qui reste le DTO (Data Transfert Object), destinée à véhiculer l'information dans le système
- Une classe ArticleRepository qui s'occupe de gérer la persistance d'un article
- Une classe ArticleShippingService qui s'occupe de gérer le process métier d'envoi d'un article à un client
L'exemple est simple dans ce cas, et il peut parfois être plus compliqué d'arriver à distinguer un mélange de responsabilités. Pour le détecter, il suffit de faire preuve de vigilance sur le long terme : est-ce que je me retrouve à modifier cette classe pour plusieurs raisons ? Ou est-ce que je me retrouve à utiliser cette classe à plusieurs endroits pour différentes raisons ? Si la réponse est oui, il n'est pas impossible que la classe mixe plusieurs responsabilités !
Hum, OK, mais ça sert à quoi en fait ?
Définir qu'une classe possède une et une seule responsabilité n'est pas juste une histoire de se faire mousser et de dupliquer le nombre de classes dans son projet. En fait, si vous séparez bien les responsabilités, votre navigation dans le code et l'utilisation des objets seront simplifiés : vous savez qui fait quoi, et donc vous savez quoi utiliser ou quoi modifier en cas de besoin.
Pour faire un parallèle avec la vie réelle : vous allez chez votre boucher si vous avez besoin de viande et à la poste si vous devez envoyer un courrier, car vous savez que ce sont les services et les produits qu'ils offrent. Une enseigne qui fait les deux peut rendre service, mais si vous devez envoyer un colis, peut-être qu'elle ne l'acceptera pas ou le fera moins bien que la poste (encore que ça ...).
En bref : faite attention à ce que vos classes ne fassent pas trop de choses et qu'elles deviennent trop grosses, ingérable à maintenir et à faire évoluer !