Pamiętaj o metodzie stabilności Martina i o tym, co rozumie przez „stabilność”:
Instability = Ce / (Ca+Ce)
Lub:
Instability = Outgoing / (Incoming+Outgoing)
Oznacza to, że pakiet jest uważany za całkowicie niestabilny, jeśli wszystkie jego zależności są wychodzące: używa innych rzeczy, ale nic go nie używa. W takim przypadku sensowne jest, aby ta rzecz była konkretna. Będzie to również najłatwiejszy rodzaj kodu do zmiany, ponieważ nic innego go nie używa, a zatem nic innego nie może się zepsuć, jeśli ten kod zostanie zmodyfikowany.
W międzyczasie, gdy masz odwrotny scenariusz pełnej „stabilności” z pakietem używanym przez jedną lub więcej rzeczy, ale nie używa on niczego samodzielnie, jak pakiet centralny używany przez oprogramowanie, wtedy Martin mówi, że to powinno być abstrakcyjny. Potwierdza to również część DIP SOLI (D), Zasada Inwersji Zależności, która zasadniczo stwierdza, że zależności powinny jednolicie płynąć w kierunku abstrakcji zarówno dla kodu niskiego, jak i wysokiego poziomu.
Oznacza to, że zależności powinny równomiernie płynąć w kierunku „stabilności”, a dokładniej, zależności powinny płynąć w kierunku pakietów z większą liczbą zależności przychodzących niż zależności wychodzące, a ponadto zależności powinny płynąć w kierunku abstrakcji. Istotą tego uzasadnienia jest to, że abstrakcje zapewniają oddech, aby zastąpić jeden podtyp innym, oferując taki stopień elastyczności, aby konkretne części wdrażające interfejs mogły się zmieniać bez przerywania nadchodzących zależności od tego abstrakcyjnego interfejsu.
Czy są jakieś istotne wady uzależnienia od abstrakcji?
Cóż, właściwie nie zgadzam się z Martinem tutaj przynajmniej dla mojej domeny i tutaj muszę wprowadzić nową definicję „stabilności” jak w „braku powodów do zmiany”. W takim przypadku powiedziałbym, że zależności powinny płynąć w kierunku stabilności, ale abstrakcyjne interfejsy nie pomagają, jeśli abstrakcyjne interfejsy są niestabilne (z mojej definicji „niestabilny”, ponieważ podatny na wielokrotne zmiany, a nie Martina). Jeśli programiści nie mogą uzyskać poprawnych abstrakcji, a klienci wielokrotnie zmieniają zdanie w taki sposób, że abstrakcyjne próby modelowania oprogramowania są niekompletne lub nieskuteczne, nie czerpiemy już korzyści ze zwiększonej elastyczności abstrakcyjnych interfejsów w celu ochrony systemu przed kaskadowymi zmianami przerywającymi zależności . W moim osobistym przypadku znalazłem silniki ECS, takie jak te w grach AAA,najbardziej konkretny : w kierunku surowych danych, ale takie dane są wysoce stabilne (jak w „mało prawdopodobne, by kiedykolwiek trzeba je zmienić”). Często zdarza mi się, że prawdopodobieństwo czegoś, co wymaga przyszłych zmian, jest bardziej użyteczną miarą niż stosunek efektorowego do łącznego sprzężenia przy podejmowaniu decyzji dotyczących SE.
Chciałbym więc trochę zmienić DIP i powiedzieć: „zależności powinny przepływać w kierunku komponentów, które mają najniższe prawdopodobieństwo wymagania dalszych zmian”, niezależnie od tego, czy są to abstrakcyjne interfejsy czy surowe dane. Liczy się dla mnie tylko prawdopodobieństwo, że mogą wymagać bezpośrednich zmian przełomowych. Abstrakcje są użyteczne w tym kontekście stabilności tylko wtedy, gdy coś, będąc abstrakcją, zmniejsza to prawdopodobieństwo.
W wielu kontekstach może tak być w przypadku porządnych inżynierów i klientów, którzy z góry przewidują potrzeby oprogramowania i projektują stabilne (jak w niezmienionych) abstrakcjach, podczas gdy abstrakcje te zapewniają im całą swobodę, której potrzebują, aby zamienić konkretne wdrożenia. Ale w niektórych domenach abstrakcje mogą być niestabilne i podatne na nieodpowiednie, podczas gdy dane wymagane od silnika mogą być znacznie łatwiejsze do przewidzenia i stabilne z góry. Tak więc w takich przypadkach może być bardziej korzystne z punktu widzenia łatwości konserwacji (łatwość zmiany i rozszerzenia systemu), aby zależności płynęły w kierunku danych, a nie abstrakcji. W ECS najbardziej niestabilnymi częściami (jak w częściach najczęściej wymienianych) są zazwyczaj funkcje rezydujące w systemach (PhysicsSystem
, np.), podczas gdy najbardziej stabilne części (jak najmniej prawdopodobne, że zostaną zmienione) to komponenty, które składają się z surowych danych ( MotionComponent
np.), z których korzystają wszystkie systemy.