Qu’est-ce qui fait un bon état d’esprit de conception de logiciels? – Meilleure programmation

Online Coding Courses for Kids

Un ensemble de principes que chaque ingénieur logiciel doit bien comprendre a été promu par le légendaire Robert C. Martin (Oncle Bob) dans son article de 2000 «Principes de conception et modèles de conception. “

Principe de responsabilité unique (PRS)

“Une classe ou un module doit avoir une, et une seule, raison de changer.”

Mélanger les responsabilités en une seule classe / module est l’état de faible cohésion (décrit ci-dessus). Par exemple, une classe qui implémente la logique métier tout en ayant une logique persistante (par exemple, récupérer / stocker des données dans la base de données) viole évidemment SRP, car la modification de la logique de la base de données crée éventuellement des effets secondaires pour la logique métier, ce qui est une mauvaise conception.

Classes polyvalentes, en particulier objet dieu, sont également difficiles à écrire pour les tests unitaires, à réutiliser ou à composer.

Principe ouvert-fermé

«Les entités logicielles (classes, modules, fonctions, etc.) doivent être ouvertes pour extension, mais fermées pour modification.»

L’extension du système avec plus de fonctionnalités nécessite de modifier les fonctionnalités existantes et est horrible pour toute équipe de développement.

L’idée est que, lorsque de nouvelles exigences sont ajoutées, nous ne devons pas modifier le code existant mais l’étendre en utilisant la technique la plus courante: concevoir des abstractions / interfaces avec différentes implémentations à des fins différentes qui peuvent être commutées au moment de l’exécution. C’est ce qu’on appelle le modèle de stratégie.

Voyons un autre cas d’utilisation. Nous exécutons l’application sous des cas de test automatisés qui sont intégrés dans notre système CI pour garantir que la fonctionnalité fonctionne après chaque validation. Mais lors des tests, nous n’avons pas besoin de vérifier la fonctionnalité de chargement d’image qui consomme des données réseau et ralentit les tests tout en réduisant l’efficacité de notre serveur CI. Nous devons donc ajuster le code de production pour ajouter une logique de test, comme if "underTest" then "do not load image"? Non, la solution devrait être de définir une interface comme ImageLoader et fournir une implémentation nommée OptOutImageLoader, qui ne fait rien pour les tests utilisant le injection de dépendance technique.

Ainsi, le respect du principe ouvert-fermé est très important pour rendre le système hautement extensible à faible risque.

Principe de substitution de Liskov (LSP)

“Les sous-classes / classes dérivées doivent être substituables à leur classe de base / parent.”

Dans la programmation orientée objet, si une classe enfant viole le contrat ou modifie le comportement de sa classe parent, alors elle n’est pas substituable à la classe parent. Cela introduit une odeur de code – des problèmes profonds dans le système qui ne sont pas clairement visibles au début mais qui apparaissent plus tard dans la phase de maintenance.

Par exemple, nous définissons une abstraction de Bird (classe abstraite) qui peut fly (méthode abstraite). Tous les cours pour enfants de l’oiseau, comme Pigeon, Eagle, etc., implémentez fly méthode car ils peuvent voler à leur manière différemment. Une exception est Penguin, qui jette un Exception indiquant qu’il ne peut pas voler. Quelque part dans la base de code, nous exécutons fly() méthode sur une liste d’oiseaux. Si la liste ne contient pas Penguin, l’application peut fonctionner sans aucun problème. Mais si un jour on ajoute Penguin dans la liste, il plantera. Nous devons essayer de saisir l’exception qui introduit le couplage à la mise en œuvre concrète de Penguin classe ou viole le principe ouvert-fermé ci-dessus.

Un exemple de violation du LSP

Nous avons probablement la mauvaise abstraction de Bird car toutes les races d’oiseaux ne peuvent pas voler. Donc fly ne doit pas être une méthode abstraite Bird mais pourrait être dans le Flyable interface.

Cette violation de contrat est souvent introduite lorsque nous étendons ou modifions un système existant dont l’abstraction n’était pas bien conçue. LSP nous rappelle donc que la conception d’abstraction est importante.

Principe de ségrégation des interfaces

«Les clients ne devraient pas être obligés de mettre en œuvre des méthodes qu’ils n’utilisent pas.»

Nous ne voyons pas vraiment un gros problème si une classe implémente une interface avec une méthode vide contenant uniquement //do nothing commentaire.

Mais le vrai problème est que quelque chose ne va pas dans nos abstractions. La conception d’abstraction est plus un art que le codage. Concevoir des abstractions correctes est un défi pour tous les domaines. Il est extrêmement important de poursuivre l’extension et la maintenance du système.

Ce principe suggère que nous devrions diviser les interfaces qui sont très grandes en interfaces plus petites et plus spécifiques afin que les clients n’aient qu’à connaître les méthodes qui les intéressent, les rendant ainsi plus cohérentes et solides.

Principe d’inversion de dépendance (DIP)

«Les modules de haut niveau ne devraient pas dépendre de modules de bas niveau. Les deux devraient dépendre d’abstractions (par exemple des interfaces). »

«Les abstractions ne devraient pas dépendre des détails. Les détails (implémentations concrètes) devraient dépendre des abstractions. »

L’inversion de contrôle (IoC), ou programmation basée sur interface (également connue sous le nom d’architecture basée sur interface), qui incarne DIP est une approche bien connue pour aider les ingénieurs logiciels à concevoir des systèmes complexes axés sur l’abstraction de haut niveau des entreprises et des fonctionnalités sans se soucier de la mise en œuvre concrète au stade de la conception.

La clé est que lors de la construction d’interfaces, nous ne devons pas penser à la façon dont leurs méthodes seront implémentées. Par exemple, nous avons une interface de référentiel ayant getAllUsers(): Listméthodes. Nous avons besoin de cette interface car elle sert notre logique métier. Mais lors de la conception de notre couche de domaine, nous ne nous soucions pas de la façon dont les données utilisateur sont stockées, que ce soit dans un SGBD relationnel ou dans un serveur NoSql; nous allons bien tant qu’il peut obtenir une liste de tous les utilisateurs.

Ce principe aide également à réduire le couplage étroit entre les composants / modules en créant des dépendances basées sur des abstractions tandis que toute mise en œuvre détaillée est définitivement cachée de la vue d’ensemble du système.

Close Menu