Question

Le couplage lâche est, à certains développeurs, le Saint-Graal du logiciel bien conçu. Il est certainement une bonne chose quand il rend le code plus souple face aux changements qui doivent se produire vraisemblablement dans un avenir prévisible, ou évite la duplication de code.

D'autre part, les efforts de composants vaguement quelques augmenter la quantité de indirection dans un programme, ce qui augmente sa complexité, souvent le rendant plus difficile à comprendre et qui rend souvent moins efficace.

Considérez-vous l'accent sur le couplage lâche sans cas d'utilisation pour le couplage lâche (par exemple en évitant la duplication ou la planification du code des changements qui doivent se produire vraisemblablement dans un avenir prévisible) d'être un anti-modèle? Peut perdre le couplage tombent sous le parapluie de YAGNI?

Était-ce utile?

La solution

Un peu.

Parfois, couplage lâche qui vient sans trop d'effort est très bien, même si vous ne disposez pas d'exigences spécifiques exigeant que certains modules découpler. Le fruit à faible pendaison, pour ainsi dire.

Par contre, pour des montants ridicules overengineering de changement sera beaucoup de complexité inutile et d'efforts. YAGNI, comme vous le dites, il frappe sur la tête.

Autres conseils

est la pratique de la programmation X bon ou mauvais? De toute évidence, la réponse est toujours "ça dépend".

Si vous cherchez votre code, se demandant ce que « modèles » vous pouvez injecter, alors vous le faites mal.

Si vous construisez votre logiciel afin que les objets non liés ne pas autour du violon les uns avec les autres, alors vous le faites à droite.

Si vous êtes « ingénierie » votre solution pour qu'il puisse être infiniment étendu et changé, alors vous êtes en train de le rendre plus compliqué.

Je pense à la fin de la journée, vous vous retrouvez avec la vérité simple: est-il plus ou moins compliqué d'avoir les objets découplés? Si elle est moins compliqué de les coupler, alors c'est la bonne solution. Si elle est moins compliqué de les découpler, alors c'est la bonne solution.

(Je travaille actuellement dans une assez petite codebase qui fait un travail simple, d'une manière très compliquée, et une partie de ce qui le rend si compliqué est le manque de compréhension des termes « couplage » et la « cohésion » de la part des développeurs originaux.)

Je pense que ce que vous obtenez ici est le concept de cohésion . Est-ce que ce code ont une bonne fin? Puis-je internaliser cette fin et comprendre la « grande image » de ce qui se passe?

Il pourrait conduire à coder en dur à suivre, non seulement parce qu'il ya beaucoup plus de fichiers sources (ce sont des classes en supposant séparées), mais parce qu'aucune classe unique semble avoir un but.

Du point de vue agile, je pourrais suggérer que ce couplage lâche serait un anti-modèle. Sans la cohésion, voire des cas d'utilisation pour cela, vous ne pouvez pas écrire des tests unitaires sensibles, et ne peut pas vérifier l'objet du code. Maintenant, le code agile peut conduire à perdre de couplage, par exemple lorsque le développement piloté par les tests est utilisé. Mais si les bons tests ont été créés, dans l'ordre, il est probable qu'il y ait à la fois une bonne cohésion et le couplage lâche. Et vous parlez seulement les cas lorsqu'aucun la cohésion est clairement là.

Encore une fois du point de vue agile, vous ne voulez pas ce niveau artificiel de indirection, car il est un gaspillage d'efforts sur quelque chose qui ne sera probablement pas nécessaire de toute façon. Il est beaucoup plus facile de refactoring lorsque le besoin est réel.

Dans l'ensemble, vous voulez haut couplage au sein de vos modules, et le couplage lâche entre eux. Sans le haut de couplage, vous ne probablement pas la cohésion.

Pour la majorité des questions comme celle-ci, la réponse est « ça dépend ». Dans l'ensemble, si je peux faire un dessin couplé logiquement vaguement de manière logique, sans grand frais généraux à le faire, je le ferai. Éviter le couplage inutile dans le code est, à mon avis, un objectif de conception tout à fait utile.

Une fois qu'il vient à une situation où il semble que les composants doivent être étroitement logiquement, je chercherai un argument convaincant avant de commencer à les briser.

Je suppose que le travail de principe I avec la plupart de ces types de pratique est l'une d'inertie. J'ai une idée de la façon dont je voudrais que mon code pour le travail et si je peux le faire de cette façon sans rendre la vie plus dur alors je le ferai. Si vous le faites va rendre le développement plus difficile, mais l'entretien et le futur travail plus facile, je vais essayer de trouver un deviner si ce sera plus de travail sur la durée de vie du code et l'utiliser comme mon guide. Sinon, il aurait besoin d'être un point de conception délibéré pour être la peine d'aller avec.

La réponse est simple couplage lâche est bon quand il est fait correctement.

Si le principe d'une fonction, un but est suivi alors il devrait être assez facile de suivre ce qui se passe. En outre, le code couple lâche suit comme une question de cours sans aucun effort.

Règles de conception simple: 1. ne construisent pas la connaissance de plusieurs éléments en un seul point (comme l'a fait partout, dépend), à moins que vous construisez une interface de façade. 2. une fonction - un but (cet effet peut être comme dans une façade à multiples facettes) 3. un module - un ensemble clair de fonctions interdépendantes - un objectif clair 4. Si vous ne pouvez pas simplement test unitaire alors il ne dispose pas d'un simple but

Tous ces commentaires au sujet plus facile à refactor sont plus tard une charge de morues. Une fois que la connaissance se construit dans de nombreux endroits, en particulier dans les systèmes distribués, le coût de refactoring, la synchronisation de déploiement, et à peu près tous les autres coups de coûts jusqu'à présent de considération que dans la plupart des cas, les extrémités du système jusqu'à être saccagé à cause de cela.

La chose triste sur le développement de logiciels ces jours-ci est de 90% des personnes de développer de nouveaux systèmes et n'ont pas la capacité de comprendre les anciens systèmes, et ne sont jamais là quand le système a obtenu un tel mauvais état de santé en raison de refactoring continue de bits et pièces.

Peu importe la façon dont étroitement couplée à une chose est autre si cette autre chose ne change jamais. Je l'ai trouvé en général plus productif au cours des années à se concentrer sur la recherche de moins de raisons que les choses changent, pour rechercher la stabilité, que de les rendre plus faciles à changer en essayant d'obtenir la forme de couplage lâche possible. Découplage J'ai trouvé très utile, au point où je préfère parfois la duplication de code modeste paquets DECOUPLE. A titre d'exemple de base, j'avais le choix d'utiliser ma bibliothèque de mathématiques pour mettre en œuvre une bibliothèque d'images. Je ne l'ai pas et juste quelques fonctions de double emploi mathématiques de base qui étaient trivial à copier.

Maintenant, ma bibliothèque d'images est complètement indépendant de la bibliothèque de mathématiques d'une manière où, peu importe quel genre de changements que je fais mes calculs lib, il ne sera pas affecter la bibliothèque d'images. C'est de mettre avant tout la stabilité. La bibliothèque d'images est plus stable maintenant, comme ayant des raisons radicalement moins au changement, car il est découplé de toute autre bibliothèque qui pourrait changer (en plus de la bibliothèque standard C qui nous l'espérons ne devrait jamais de changement). En prime, il est aussi facile à déployer quand il est juste une bibliothèque autonome qui ne nécessite pas tirer dans un tas d'autres libs pour le construire et l'utiliser.

La stabilité est très utile pour moi. Je aime construire une collection de code bien testé qui a de moins en moins de raisons de changer jamais dans l'avenir. Ce n'est pas un rêve de pipe; Je code C Je l'ai utilisé et en utilisant à nouveau depuis les fin des années 80 qui n'a pas changé depuis lors. Certes, il est des choses de faible niveau du code orienté pixel et lié à géométrie alors que beaucoup de mes affaires de niveau supérieur est devenu obsolète, mais il est quelque chose qui aide encore beaucoup à avoir autour. Cela signifie presque toujours une bibliothèque qui repose sur de moins en moins de choses, si rien du tout extérieur. Fiabilité monte et place si votre logiciel dépend de plus en plus sur des bases stables qui trouvent peu ou pas de raisons de changer. Moins de pièces mobiles est vraiment agréable, même si, dans la pratique, les pièces mobiles sont beaucoup plus nombreuses que les parties stables. Il aide encore ma santé mentale beaucoup de savoir que l'ensemble d'une base de code ne se compose pas de pièces mobiles.

Le couplage lâche est dans la même veine, mais je trouve souvent que le couplage lâche est beaucoup moins stable que pas de couplage. À moins que vous travaillez dans une équipe avec des designers d'interface bien supérieurs et les clients qui ne changent pas leur esprit que j'ai jamais travaillé avec, même interfaces pures trouvent souvent des raisons de changer d'une manière qui provoque encore en cascade tout au long du code casses. Cette idée que la stabilité peut être obtenue en orientant les dépendances vers l'abstrait plutôt que le béton est utile que si la conception de l'interface est plus facile d'obtenir dès la première fois que la mise en œuvre. Je trouve souvent inversée où un développeur aurait pu créer un très bon, sinon merveilleux, la mise en œuvre compte tenu des exigences de conception qu'ils pensaient qu'ils doivent remplir, pour trouver à l'avenir que les exigences de conception changent complètement. Le design est beaucoup plus difficile d'obtenir le droit que la mise en œuvre si vous me demandez avec de grandes bases de code à grande échelle en essayant de satisfaire toujours l'évolution des besoins, et dans ce cas, la séparation des conceptions abstraites des mises en œuvre concrètes ne aide beaucoup si la conception abstraite est la chose qui est le plus sujettes à modifier.

Je aime favoriser la stabilité et le découplage complet pour que je puisse au moins dire avec confiance: « Cette petite bibliothèque isolée qui a été utilisé pendant des années et garanti par des tests approfondis n'a pratiquement aucune chance d'exiger des changements, peu importe ce qui se passe dans la chaotique monde extérieur. » Il me donne une petite tranche de bon sens, peu importe quel genre de changements de conception sont appelés à l'extérieur.

Le couplage et la stabilité, Exemple ECS

J'aime aussi les systèmes composants entité et ils introduisent beaucoup de couplage serré parce que le système de dépendances composant tous les accès logements et manipuler des données brutes directement, comme suit:

Toutes les dépendances ici sont assez serrés car les composants exposent simplement des données brutes. Les dépendances ne sont pas des abstractions se dirigeant vers, ils se dirigeant vers données brutes ce qui signifie que chaque système a le montant maximum de connaissances possibles sur chaque type de composant leur demande d'accès. Les composants ont aucune fonctionnalité avec tous les systèmes accès et falsification des données brutes. Cependant, il est très facile de raisonner sur un système comme celui-ci, car il est si plat. Si une texture sort çela, alors vous savez avec ce système immédiatement que seuls les éléments de texture accès au système de rendu et la peinture, et vous pouvez probablement écarter rapidement le système de rendu, car il ne lit que de textures sur le plan conceptuel.

En attendant une alternative à couplage lâche peut-être ceci:

... avec toutes les dépendances se dirigeant vers des fonctions abstraites, pas de données, et chaque chose dans ce diagramme exposant une interface publique et la fonctionnalité de ses propres. Ici, toutes les dépendances peuvent être très lâche. Les objets pourraient même ne pas dépendre directement de l'autre et interagissent les uns avec les autres via des interfaces pures. Néanmoins, il est très difficile de raisonner sur ce système, surtout si quelque chose va mal, compte tenu de l'enchevêtrement complexe d'interactions. Il y aura aussi plus d'interactions (plus de couplage, quoique plus souple) que l'ECS parce que les entités doivent connaître les composants qu'ils agrègent, même si elles ne connaissent l'autre interface publique abstraite.

Aussi, s'il y a des changements de conception à quoi que ce soit, vous obtenez casses plus en cascade, que l'ECS, et il sera généralement plus de raisons et de tentations pour les changements de conception car chaque chose tente de fournir une interface orientée objet agréable et l'abstraction. Cela vient immédiatement à l'idée que essayera chaque petite chose simple à imposer des contraintes et des limites à la conception, et les contraintes sont souvent ce qui justifie les changements de conception. La fonctionnalité est beaucoup plus limitée et doit faire tant d'hypothèses plus de conception que les données brutes.

Je l'ai trouvé dans la pratique du type ci-dessus « plat » système ECS être tellement plus facile de raisonner sur que même les systèmes les plus faiblement couplés avec une toile d'araignée complexe de dépendances en vrac et, surtout pour moi, je trouve donc peu de raisons pour la version ECS à jamais nécessaire de modifier les composants existants puisque les composants dont ils dépendaient ont aucune responsabilité, sauf pour fournir les données appropriées nécessaires aux systèmes de fonctionner. Comparez la difficulté de concevoir une interface pure IMotion et objet de mouvement concret mise en œuvre de cette interface qui fournit des fonctionnalités sophistiquées tout en essayant de maintenir invariants par rapport aux données privées par rapport à une composante de mouvement qui n'a besoin que de fournir des données brutes pertinentes pour résoudre le problème et ne prend pas la peine avec fonctionnalité.

La fonctionnalité est beaucoup plus difficile d'obtenir le droit que les données, ce qui explique pourquoi je pense qu'il est souvent préférable de diriger le flux de données vers les dépendances. Après tout, combien de bibliothèques vecteur / matrice sont là-bas? Combien d'entre eux utilisent exactement la même représentation des données et ne diffèrent subtilement fonctionnalité? Un nombre incalculable, et pourtant nous avons encore tant malgré des représentations de données identiques parce que nous voulons des différences subtiles dans la fonctionnalité. Combien de bibliothèques images sont là-bas? Combien d'entre eux représentent des pixels d'une manière différente et unique? Presque aucun, et montre encore une fois que la fonctionnalité est beaucoup plus instable et enclin à la conceptionles changements que les données dans de nombreux scénarios. Bien sûr, à un moment donné nous avons besoin de fonctionnalités, mais vous pouvez concevoir des systèmes où la majeure partie des dépendances flux vers les données, et non pas vers des abstractions ou des fonctionnalités en général. Tel serait donner la priorité la stabilité au-dessus de couplage.

Les la plupart des fonctions stables que j'ai jamais écrit (le genre que je me sers et la réutilisation depuis les fin des années 80 sans avoir à les changer du tout) ont été tous ceux qui comptaient sur les données brutes, comme une fonction de la géométrie qui vient d'accepter un réseau de flotteurs et des nombres entiers, et non pas celles qui dépendent d'une interface d'objet de Mesh complexe ou IMesh ou multiplication vecteur / matrice qui dépend seulement float[] ou double[], pas celle qui dépendait de FancyMatrixObjectWhichWillRequireDesignChangesNextYearAndDeprecateWhatWeUse.

Licencié sous: CC-BY-SA avec attribution
scroll top