Gardez à l'esprit la métrique de stabilité de Martin et ce qu'il entend par «stabilité»:
Instability = Ce / (Ca+Ce)
Ou:
Instability = Outgoing / (Incoming+Outgoing)
Autrement dit, un package est considéré comme complètement instable si toutes ses dépendances sont sortantes: il utilise d'autres choses, mais rien ne l'utilise. Dans ce cas, il est logique que cette chose soit concrète. Ce sera également le type de code le plus facile à modifier car rien d'autre ne l'utilise, et donc rien d'autre ne peut se casser si ce code est modifié.
Pendant ce temps, lorsque vous avez le scénario opposé de "stabilité" complète avec un package utilisé par une ou plusieurs choses, mais qu'il n'utilise rien seul, comme un package central utilisé par le logiciel, c'est à ce moment que Martin dit que cette chose devrait être abstrait. Cela est également renforcé par la partie DIP de SOLI (D), le principe d'inversion des dépendances, qui stipule essentiellement que les dépendances doivent circuler uniformément vers les abstractions pour le code de bas et de haut niveau.
C'est-à-dire que les dépendances devraient se diriger uniformément vers la "stabilité", et plus précisément, les dépendances devraient se diriger vers les packages avec plus de dépendances entrantes que les dépendances sortantes et, en outre, les dépendances devraient se diriger vers les abstractions. L'essentiel de la raison derrière cela est que les abstractions offrent une marge de manœuvre pour substituer un sous-type à un autre, offrant ce degré de flexibilité pour que les parties concrètes implémentant l'interface changent sans casser les dépendances entrantes à cette interface abstraite.
Y a-t-il des inconvénients importants à dépendre des abstractions?
Eh bien, je suis en fait en désaccord avec Martin ici pour mon domaine au moins, et ici je dois introduire une nouvelle définition de "stabilité" comme dans "manque de raisons de changer". Dans ce cas, je dirais que les dépendances devraient se diriger vers la stabilité, mais les interfaces abstraites n'aident pas si les interfaces abstraites sont instables (par ma définition de "instable", comme sujettes à être modifiées à plusieurs reprises, pas Martin). Si les développeurs ne parviennent pas à obtenir les abstractions correctes et que les clients changent d'avis à plusieurs reprises de manière à rendre les tentatives abstraites de modélisation du logiciel incomplètes ou inefficaces, alors nous ne bénéficions plus de la flexibilité améliorée des interfaces abstraites pour protéger le système contre les changements en cascade qui brisent les dépendances . Dans mon cas personnel, j'ai trouvé des moteurs ECS, tels que ceux trouvés dans les jeux AAA,le plus concret : vers les données brutes, mais ces données sont très stables (comme dans "peu susceptibles de devoir être modifiées"). J'ai souvent trouvé la probabilité que quelque chose nécessitant des changements futurs soit une mesure plus utile que le rapport des couplages efférents au total pour guider les décisions SE.
Donc, je modifierais un peu DIP et je dirais simplement que "les dépendances devraient se diriger vers les composants qui ont la plus faible probabilité de nécessiter d'autres modifications", que ces composants soient des interfaces abstraites ou des données brutes. Tout ce qui m'importe, c'est la probabilité qu'elles nécessitent des changements directs de conception. Les abstractions ne sont utiles dans ce contexte de stabilité que si quelque chose, en étant abstrait, réduit cette probabilité.
Dans de nombreux contextes, ce pourrait être le cas avec des ingénieurs et des clients décents qui anticipent les besoins du logiciel à l'avance et conçoivent des abstractions stables (comme dans, immuables), tandis que ces abstractions leur offrent toute la marge de manœuvre dont elles ont besoin pour échanger des implémentations concrètes. Mais dans certains domaines, les abstractions peuvent être instables et sujettes à être inadéquates, tandis que les données requises du moteur peuvent être beaucoup plus faciles à anticiper et à stabiliser à l'avance. Dans ces cas, il peut donc être plus avantageux du point de vue de la maintenabilité (la facilité de changer et d'étendre le système) que les dépendances se dirigent vers les données plutôt que vers les abstractions. Dans un ECS, les parties les plus instables (comme dans les pièces les plus fréquemment modifiées) sont généralement les fonctionnalités résidant dans les systèmes (PhysicsSystem
, par exemple), tandis que les parties les plus stables (comme celles qui sont le moins susceptibles d'être modifiées) sont les composants qui ne sont constitués que de données brutes ( MotionComponent
, par exemple) que tous les systèmes utilisent.