Conception Orientée Objet
Vue d'ensemble
Ce pack contient des règles de conception pour les codebases écrites dans un style orienté objet, et non des conseils universels. Les conventions écrites d'un projet priment sur ce pack. Suivez l'idiome du module que vous modifiez. Cette compétence dimensionne la tâche et nomme la compétence appropriée.
Chargez la compétence que cet index nomme avant de répondre : ses règles et ses exemples s'y trouvent, pas ici.
Quelle quantité de conception une tâche nécessite
| Tâche | Utiliser | Ignorer |
|---|---|---|
| Une réponse utilisée une fois, puis jetée | Rien | Tout |
| Une méthode dans une classe existante | Son nom et son contrat | Remodelage |
| Une fonctionnalité au sein d'un flux existant | L'idiome que ce flux utilise | Nouvelles limites |
| Une nouvelle classe ou un nouveau module | La boucle de conception | Rien |
| Un nouveau contexte | La boucle, puis ses limites | Rien |
| Un nouveau système à partir de rien | La boucle, les contextes, puis la structure | Rien |
Avant de concevoir
Avant de concevoir, énoncez la porte : une règle que le logiciel doit suivre, avec un exemple qu'elle accepte et un qu'elle rejette. Par exemple, "Un créneau peut contenir au plus un rendez-vous." Elle accepte la réservation d'un deuxième patient dans un créneau différent et rejette la réservation d'un deuxième patient dans le même créneau. Si vous pouvez écrire la règle, commencez. Si vous ne le pouvez pas, ce qui manque n'est pas de la conception, et ce pack ne peut pas le fournir.
La boucle de conception
- Dites ce que le logiciel doit faire dans les mots du domaine (parler le langage du domaine), et trouvez l'objet qui sait ce dont chaque comportement a besoin (assigner les responsabilités).
- Trouvez la limite de cohérence : ce qui doit être vrai ensemble en une seule transaction (concevoir les agrégats).
- Décidez où chaque règle vit : une entité, un objet-valeur ou un service du domaine (placer la logique métier).
- Concevez les messages auxquels chaque objet répond (encapsuler l'état et le comportement), et rendez les états impossibles à construire (rendre les états impossibles impossibles à construire).
- Inversez les dépendances pour que le domaine ne sache rien de la base de données ou du framework (inverser les dépendances, superposer le système).
- Nommez les choses dans les mots du domaine, et commentez uniquement ce que le code ne peut pas dire (nommer les classes et les méthodes, commenter ce que le code ne peut pas dire).
- Vérifiez le résultat par rapport aux signaux d'alarme ci-dessous (réviser la conception objet).
À quel point une règle est stricte
Chaque règle fondamentale de ce pack porte l'une des trois étiquettes suivantes, et l'étiquette indique son degré de rigueur.
- Règle. Enfreindre cette règle est un défaut. Aucun framework ne l'excuse.
- Défaut. Faites ceci sauf si une condition énoncée s'applique. La condition est sa propre phrase, jamais une clause subordonnée.
- Jugement. Deux réponses sont défendables. La compétence indique ce qui fait pencher la balance.
Symptômes vers les compétences
Les symptômes pointent vers la compétence qui les traite, et ce tableau s'agrandit au fur et à mesure que les compétences arrivent.
| Symptôme | Compétence |
|---|---|
| Quelle classe devrait faire ceci ? | Assigner les responsabilités |
| Cette classe fait trop de choses | Assigner les responsabilités |
| Un changement se répercute sur de nombreuses classes | Diagnostiquer le couplage |
| À quel point ces deux parties sont-elles liées ? | Diagnostiquer le couplage |
| Est-ce un objet ou juste des données ? | Décider objet ou données |
| Notre modèle de domaine est anémique | Décider objet ou données |
| D'autres code décident pour cet objet | Encapsuler l'état et le comportement |
| Les setters permettent à cet objet d'enfreindre ses règles | Encapsuler l'état et le comportement |
| Cet objet peut exister à moitié construit | Construire des objets valides |
| Ce constructeur prend trop d'arguments | Construire des objets valides |
| Chaque nouveau cas signifie modifier du code qui fonctionne | Encapsuler ce qui varie |
| Quelle flexibilité cela devrait-il avoir ? | Encapsuler ce qui varie |
| Est-ce une valeur ou une entité ? | Modéliser les valeurs et les entités |
| Les chaînes brutes et les nombres portent des règles métier | Modéliser les valeurs et les entités |
| Cette classe devrait-elle étendre cette classe ou la contenir ? | Choisir la composition plutôt que l'héritage |
| Changer une classe de base casse ses sous-classes | Choisir la composition plutôt que l'héritage |
| Une sous-classe viole ce que promet son parent | Respecter la substituabilité |
| Le code vérifie quel sous-type il contient | Respecter la substituabilité |
| Le même switch sur un type revient sans cesse | Remplacer les conditionnels par le polymorphisme |
| Sous-classes ou filtrage par motif ? | Remplacer les conditionnels par le polymorphisme |
| Le code traverse une chaîne d'objets | Limiter ce qu'un objet sait |
| Cette classe ne fait que transmettre des appels | Limiter ce qu'un objet sait |
| Comment cette classe ou cette méthode devrait-elle être nommée ? | Nommer les classes et les méthodes |
| Des noms comme Manager, Helper ou Util | Nommer les classes et les méthodes |
| Les appelants dépendent de méthodes d'interface qu'ils n'utilisent jamais | Concevoir les interfaces |
| Interface ou classe de base abstraite ? | Concevoir les interfaces |
| Le code du domaine dépend d'une base de données ou d'un framework | Inverser les dépendances |
| Où les objets sont-ils créés et câblés ensemble ? | Inverser les dépendances |
| Les appelants savent comment une autre classe stocke ou formate les données | Cacher l'implémentation |
| Une classe divulgue ses erreurs ou étapes internes | Cacher l'implémentation |
| Les drapeaux ou les champs optionnels permettent des combinaisons impossibles | Rendre les états impossibles impossibles à construire |
| Un type admet des valeurs que le domaine n'a jamais | Rendre les états impossibles impossibles à construire |
| Les mots du code diffèrent de ceux du personnel | Parler le langage du domaine |
| Un mot signifie des choses différentes pour deux équipes | Parler le langage du domaine |
| Quels objets doivent changer ensemble ? | Concevoir les agrégats |
| Les sauvegardes entrent en collision ou un chargement en tire trop | Concevoir les agrégats |
| Quels changements d'état sont autorisés ? | Modéliser les cycles de vie |
| Un objet annulé ou fermé change à nouveau | Modéliser les cycles de vie |
| Comment les objets du domaine doivent-ils être stockés et trouvés ? | Concevoir les dépôts |
| Le dépôt a une méthode find par écran | Concevoir les dépôts |
| Les cas d'utilisation répètent la même vérification métier | Placer la logique métier |
| Service du domaine, méthode d'entité ou service applicatif ? | Placer la logique métier |
| D'autres parties doivent réagir après qu'un changement soit enregistré | Publier des événements du domaine |
| Un message a été envoyé pour un changement qui a été annulé | Publier des événements du domaine |
| Où le modèle d'une équipe se termine-t-il et celui d'une autre commence-t-il ? | Délimiter les contextes |
| Quelles parties sont essentielles, et lesquelles pouvons-nous acheter ? | Délimiter les contextes |
| Dans quel sens les couches doivent-elles dépendre ? | Superposer le système |
| Un écran ou une tâche ne peut pas être testé sans son framework | Superposer le système |
| Les modules dépendent les uns des autres dans un cycle | Organiser les modules |
| Monolithe modulaire ou services séparés ? | Organiser les modules |
| Un changement dans notre API casse les applications qui l'appellent | Franchir les frontières système |
| Comment versionner cette API ou ce message ? | Franchir les frontières système |
| L'outil de mapping façonne nos classes du domaine | Maîtriser la persistance |
| Une liste exécute une requête par ligne | Maîtriser la persistance |
| Les écrans ont besoin de données façonnées différemment du modèle | Séparer les lectures des écritures |
| Modèle de lecture, projection ou event sourcing ? | Séparer les lectures des écritures |
| MVC, MVP ou MVVM pour cet écran ? | Séparer la présentation du domaine |
| Un écran édite directement des objets du domaine | Séparer la présentation du domaine |
| Quel patron de conception correspond à ce problème ? | Choisir un patron |
| Un patron a été ajouté avant son problème | Choisir un patron |
| Ces classes de patron pourraient être une fonction | Patrons que le langage fournit |
| Visiteur, ou un ensemble fermé avec filtrage ? | Patrons que le langage fournit |
| Une méthode retourne null quand elle ne trouve rien | Concevoir le comportement en cas d'échec |
| Les refus reviennent sous forme de codes que les appelants ignorent | Concevoir le comportement en cas d'échec |
| Les threads partagent un objet et perdent ou mélangent ses modifications | Gérer l'état partagé |
| Un verrou ou un propriétaire unique pour cet état ? | Gérer l'état partagé |
| Un appel à un autre système se bloque ou échoue à mi-chemin | Rendre le travail fiable |
| Une nouvelle tentative a effectué le travail deux fois | Rendre le travail fiable |
| Nous ne pouvons pas expliquer un incident à partir de nos enregistrements | Concevoir ce qu'il faut enregistrer |
| Que devons-nous journaliser, compter ou auditer ? | Concevoir ce qu'il faut enregistrer |
| Un examen a trouvé une classe god ou un lava flow | Reconnaître les antipatrons |
| Quel antipatron devrions-nous corriger en premier ? | Reconnaître les antipatrons |
| Les tests cassent bien que le comportement n'ait pas changé | Tester le code orienté objet |
| Mock, stub ou faux pour ce collaborateur ? | Tester le code orienté objet |
| Les tests dépendent de l'heure ou de valeurs aléatoires | Concevoir pour la testabilité |
| Le code est rendu public uniquement pour que les tests puissent l'atteindre | Concevoir pour la testabilité |
| Comment restructurer ce code en toute sécurité ? | Refactoriser vers la conception objet |
| Un refactoring est devenu trop gros pour être terminé | Refactoriser vers la conception objet |
| Nous devons modifier du code qui n'a pas de tests | Travailler avec du code legacy |
| Remplacer un ancien système pièce par pièce | Travailler avec du code legacy |
| Que doit vérifier cette revue ? | Réviser la conception objet |
| Quels résultats de revue bloquent une fusion ? | Réviser la conception objet |
| Personne ne se souvient pourquoi le code est façonné ainsi | Documenter les décisions de conception |
| Que devrions-nous dessiner, et à quel niveau ? | Documenter les décisions de conception |
| Les commentaires répètent le code ou le contredisent | Commenter ce que le code ne peut pas dire |
| Où expliquer pourquoi ce code semble étrange ? | Commenter ce que le code ne peut pas dire |
| Un hook ou un marqueur de framework contient une règle métier | Travailler au sein d'un framework |
| Jusqu'où devrions-nous suivre le framework ? | Travailler au sein d'un framework |
| Un calcul sauvegarde, envoie ou modifie également ses entrées | Appliquer des techniques fonctionnelles |
| Quelles techniques fonctionnelles conviennent au code objet ? | Appliquer des techniques fonctionnelles |
Compétences linguistiques
Une compétence linguistique conserve les règles fondamentales dans un langage et ne les remplace jamais. Une compétence linguistique de base est destinée au code sans framework.
oo-java, deobject-oriented-design-java: enregistrements, types scellés,equalsethashCode, exceptions vérifiées,Optional, et classes fermées à l'extension.oo-kotlin, deobject-oriented-design-kotlin: classes de données, types scellés, types nullables, délégation avecby, et fonctions d'extension.oo-typescript, deobject-oriented-design-typescript: identifiants marqués, état#private, classes abstraites, décorateurs, unions discriminées, et racine de composition.oo-javascript, deobject-oriented-design-javascript: classes, fermetures, délégation par mixins, modules ES, et fonctions comme objets de première classe.
Licence
Cette compétence est fournie dans l'espoir qu'elle sera utile, mais SANS AUCUNE GARANTIE, implicite ou explicite. Consultez le fichier LICENSE dans le dépôt d'origine pour plus de détails.