Чи є суттєві недоліки залежно від абстракцій?


9

Я читав цю вікі за принципом стабільних абстракцій (SAP) .

SAP зазначає, що чим стабільніший пакет, тим абстрактнішим він повинен бути. Це означає, що якщо пакет менш стабільний (з більшою ймовірністю зміниться), він повинен бути більш конкретним. Те, що я насправді не розумію, це так. Напевно, у всіх випадках, незалежно від стабільності, ми повинні залежати від абстракцій та приховування конкретної реалізації?


Спробуйте використовувати компонент, який вам подобається, не використовуючи абстракції, які він надає, але роблячи все докладно на один рівень нижчий, ніж ви звикли. Це дасть вам гарне враження про переваги та недоліки абстракції.
Кіліан Фот

2
Чи читали ви пов’язану статтю та / або книгу, на якій базується стаття?
Йорг W Міттаг

1
+1 Добре запитання, тим більше, що я не думаю, що зв'язок між стабільністю та абстракцією є негайно інтуїтивним. Сторінка 11 цієї статті допомагає, її приклад абстрактного випадку має сенс, але, можливо, хтось може написати більш чіткий приклад конкретного випадку. Надіслати запит на зняття.
Майк

З якою проблемною сферою ви маєте справу з цими абстракціями? Як зазначається на С2: "При моделюванні реальних доменів - світу клієнтів, службовців, рахунків-фактур, рахунків матеріалів, продуктів, SKU, зарплат тощо", стабільні абстракції можуть бути важкими для пошуку. Обчислювальні домени - світ стеків, черг, функцій, дерева, процеси, нитки, графічні віджети, звіти, форми тощо - набагато більше шансів бути стабільними ". та "У деяких сферах стабільні абстракції важко підійти". Не знаючи, яку проблему ви намагаєтеся вирішити з SAP, важко дати вам хорошу відповідь.

@ JörgWMittag and Mike - Так, я читав статтю. Я просто відчуваю, що не вистачає пояснень, чому "нестабільні пакети повинні бути конкретними". На сторінці 13 цієї статті він показує графік, але насправді не надто детально пояснює, чому (1,1) на графіку слід уникати? Чи ідея, що в основному нестабільна означає менше аферентних залежностей, і для цього немає необхідності використовувати абстракцію? Якщо так ... то чи не корисна практика використовувати абстракцію в будь-якому випадку, на випадок, якщо стабільність зміниться з потребою зміни ...
SteveCallender

Відповіді:


7

Подумайте про ваших пакетах в якості API, щоб взяти приклад з паперу, візьміть визначення Readerз string Reader.Read()і Writerз в void Writer.Write(string)якості абстрактного API.

Потім ви можете створити клас Copyіз методом Copier.Copy(Reader, Writer)та реалізацією Writer.Write(Reader.Read())та, можливо, деякими перевірями здоровості.

Тепер, ви робите конкретні реалізації, наприклад FileReader, FileWriter, KeyboardReaderі DownloadThingsFromTheInternetReader.

Що робити, якщо ви хочете змінити свою реалізацію FileReader? Немає проблем, просто поміняйте клас та перекомпілюйте.

Що робити, якщо ви хочете змінити визначення своєї абстракції Reader? До жаль, ви не можете просто змінити, але ви також повинні змінити Copier, FileReader, KeyboardReaderі DownloadThingsFromTheInternetReader.

Це обґрунтування принципу стійкої абстракції: зробіть ваші конкретизації менш стійкими, ніж абстракції.


1
Я погоджуюся з усім, що ви говорите, але я вважаю, що визначення авторів стабільності і вашої різниці. Ви ставитесь до стабільності як до необхідності зміни, автор каже: "стабільність не є мірою ймовірності того, що модуль зміниться, скоріше це міра труднощів із зміною модуля". Тож моє запитання більше, чому вигідно, щоб пакунки, які легко змінюються, були більш конкретними, а не абстрактними?
SteveCallender

1
@SteveCallender Це тонка різниця: визначення автора "стабільність" - це те, що більшість людей називає "потреба в стабільності", тобто чим більше модулів залежить від модуля, тим більш "стабільним" повинен бути модуль.
Residuum

6

Через ЯГНІ .

Якщо у вас зараз є лише одна реалізація однієї речі , навіщо турбуватися із зайвим і марним шаром? Це призведе лише до зайвої складності. Ще гірше, іноді ви пропонуєте абстракційне мислення до того дня, коли настане друга реалізація ... а цього дня ніколи не буває. Яка марнотратна робота!

Я також думаю, що справжнє питання, яке потрібно задати собі, не є "чи потрібно залежати від абстракцій?" а швидше "Чи потрібна модульність?". І модульність не завжди потрібна, дивіться нижче.

У компанії, в якій я працюю, частина програмного забезпечення, яке я розробляю, сильно пов'язане з деяким апаратним пристроєм, з яким він повинен спілкуватися. Ці пристрої розроблені для виконання дуже конкретних цілей і є все, крім модульних. :-) Після того, як перший виготовлений пристрій вийде з фабрики і встановлений десь, і його прошивка, і апаратне забезпечення не можуть змінитися ніколи .

Отже, я можу бути впевнений, що деякі частини програмного забезпечення ніколи не розвиватимуться. Ці частини не повинні залежати від абстракцій, оскільки існує лише одна реалізація, і ця ніколи не зміниться. Оголошення абстракцій на цих частинах коду лише заплутає всіх і забирає більше часу (не створюючи жодного значення).


1
Я схильний погоджуватися з YAGNI, але мені цікаво про ваш приклад. Ви ніколи не повторюєте жодного коду на різних пристроях? Мені важко повірити, що на пристроях однієї компанії немає якогось загального коду. Крім того, як клієнтам подобається, коли ви не виправляєте помилки у своїй прошивці? Ви говорите , що ніколи не є помилками, ніколи ? Якщо у вас є той самий код, який є помилковим у 4-х різних реалізаціях, вам доведеться виправити помилку 4 рази, якщо вона не знаходиться в загальному модулі.
Фурманатор

1
Загальний код @Fuhrmanator відрізняється від абстракцій. Загальний код може просто означати допоміжний метод або бібліотеку - абстракції не потрібні.
Ейлон

@Fuhrmanator Звичайно, у нас є загальний код у бібліотеках, але, як сказав Ейлон, не все залежить від абстракцій (однак, деякі частини все-таки є). Я ніколи не казав, що помилок ніколи не буває, я сказав, що їх не можна виправити (з причин, які не входять в рамки питання про ОП).
Виявлено

@Eilon мій коментар про модульність не завжди потрібна (не абстракції).
Фурманатор

@Spotted Немає проблем із тим, що не зможете виправити. Це просто досить конкретний приклад і не типовий для більшості програмного забезпечення.
Фурманатор

6

Я думаю, вас, можливо, бентежить слово стабільне, вибране Робертом Мартіном. Ось де я думаю, що починається плутанина:

Це означає, що якщо пакет менш стабільний (з більшою ймовірністю зміниться), він повинен бути більш конкретним.

Якщо ви прочитаєте оригінальну статтю , ви побачите (моє наголос):

Класичне визначення слова стабільність: "Не легко пересуватися". Це визначення, яке ми будемо використовувати в цій статті. Тобто стабільність не є мірою ймовірності зміни модуля; швидше це міра труднощів із зміною модуля .

Зрозуміло, що модулі, які складніше змінити, будуть менш мінливими. Чим важче змінити модуль, тобто чим він стійкіший, тим менш мінливим він буде.

Я завжди боровся з вибором автора слова стабільний , оскільки я (як і ви) схильний думати про "ймовірність" аспект стабільності, тобто навряд чи зміниться . Складність передбачає, що зміна цього модуля порушить безліч інших модулів, і над тим, щоб виправити код, буде багато роботи.

Мартін також використовує слова незалежні та відповідальні , які для мене передають набагато більше значення. На своєму навчальному семінарі він використав метафору про батьків дітей, які ростуть, і про те, як вони повинні бути "відповідальними", оскільки від них залежать їхні діти. Розлучення, безробіття, позбавлення волі тощо - чудові реальні приклади того негативного впливу, який зміни у батьків матимуть на дітей. Тому батьки повинні бути "стабільними" на благо своїх дітей. До речі, ця метафора дітей / батьків не обов’язково пов’язана зі спадщиною в ООП!

Отже, слідуючи духу "відповідальної", я придумав альтернативні значення, які важко змінити (або не повинні змінювати ):

  • Обов’язковий - тобто інші класи залежать від цього класу, тому він не повинен змінюватися.
  • Ось - там же.
  • Обмежений - зобов’язання цього класу обмежують його умову в зміні.

Отже, підключення цих визначень до заяви

чим стабільніший пакет, тим абстрактнішим він повинен бути

  • чим більше зобов'язаний пакет, тим абстрактнішим він повинен бути
  • тим більше зобов'язаним пакет більш абстрактним воно повинно бути
  • чим більш обмежений пакет, тим абстрактнішим він повинен бути

Приведемо принцип стійких абстракцій (SAP), підкресливши заплутані слова, стабільні / нестабільні:

Пакети, які є максимально стійкими, повинні бути максимально абстрактними. Нестабільні пакети повинні бути конкретними. Абстрактність пакету повинна бути пропорційною його стабільності .

Уточнюючи це без цих заплутаних слів:

Пакети, які максимально відносяться до інших частин системи, повинні бути максимально абстрактними. Пакети, які можна без проблем змінити, повинні бути конкретними. Абстрактність пакету повинна бути пропорційною тому, наскільки важко буде модифікувати .

TL; DR

Назва вашого запитання:

Чи є суттєві недоліки залежно від абстракцій?

Я думаю, якщо правильно створити абстракції (наприклад, вони існують, оскільки від них залежить багато коду), то значних недоліків немає.


0

Це означає, що якщо пакет менш стабільний (з більшою ймовірністю зміниться), він повинен бути більш конкретним. Те, що я насправді не розумію, це так.

Абстракції - це речі, які важко змінити в програмному забезпеченні, оскільки все залежить від них. Якщо ваш пакет буде змінюватися часто, і він надає абстракції, люди, які залежать від нього, будуть змушені переписати велику купу свого коду, коли ви щось зміните. Але якщо ваш нестабільний пакет пропонує деякі конкретні реалізації, після змін доведеться переписати набагато менший код.

Отже, якщо ваш пакет буде мінятися часто, він повинен краще містити конкременти, а не абстракції. Інакше ... хто, до біса, ним скористається? ;)


0

Майте на увазі метрику стабільності Мартіна і що він означає під "стабільністю":

Instability = Ce / (Ca+Ce)

Або:

Instability = Outgoing / (Incoming+Outgoing)

Тобто пакет вважається абсолютно нестабільним, якщо всі його залежності виходять: він використовує інші речі, але нічого не використовує. У цьому випадку має сенс бути конкретною. Це також буде найпростішим видом коду, який потрібно змінити, оскільки його більше нічого не використовує, а отже, нічого іншого не можна зламати, якщо цей код буде змінено.

Тим часом, коли у вас є протилежний сценарій повної "стабільності" з пакетом, який використовується однією або кількома речами, але він не використовує нічого самостійно, як центральний пакет, який використовується програмним забезпеченням, тобто, коли Мартін каже, що це повинно бути реферат. Це також підкріплюється принципом DIP SOLI (D), принципом інверсії залежності, який в основному стверджує, що залежності повинні рівномірно протікати до абстракцій як для коду низького, так і для високого рівня.

Тобто, залежності повинні рівномірно протікати до «стабільності», а точніше, залежності повинні протікати до пакетів з більшою кількістю вхідних залежностей, ніж вихідних, і, крім того, залежності повинні протікати до абстракцій. Суть обґрунтування цього полягає в тому, що абстракції надають приміщення для дихання для заміни одного підтипу іншим, пропонуючи таку ступінь гнучкості для конкретних частин, що реалізують інтерфейс, щоб змінити, не порушуючи вхідні залежності до цього абстрактного інтерфейсу.

Чи є суттєві недоліки залежно від абстракцій?

Ну, я фактично не погоджуюся з Мартіном тут, принаймні, для мого домену, і тут мені потрібно ввести нове визначення поняття "стабільність", як в "відсутність причин для зміни". У такому випадку я б сказав, що залежності повинні спрямовуватися на стабільність, але абстрактні інтерфейси не допомагають, якщо абстрактні інтерфейси нестабільні (за моїм визначенням "нестабільний", як це схильне до неодноразових змін, а не Мартіна). Якщо розробники не можуть виправити абстракції і клієнти неодноразово змінюють свою думку так, щоб зробити абстрактні спроби моделювання програмного забезпечення неповним або неефективним, тоді ми більше не отримаємо користі від розширеної гнучкості абстрактних інтерфейсів для захисту системи від каскадних змін, що залежать від залежності . В моєму особистому випадку я знайшов двигуни ECS, такі, які знайдені в іграх AAA,найбільш конкретно : щодо вихідних даних, але такі дані є досить стійкими (як, наприклад, "навряд чи колись потрібно буде змінювати"). Я часто знаходив, що ймовірність того, що щось вимагає, щоб майбутні зміни були кориснішою метрикою, ніж відношення еферентних до загальних з’єднань у керівних рішеннях SE.

Тож я б трохи змінив DIP і просто сказав: "Залежності повинні надходити до компонентів, які мають найменшу ймовірність вимагати подальших змін", незалежно від того, чи є ці компоненти абстрактними інтерфейсами чи необробленими даними. Для мене важливо лише ймовірність того, що вони можуть вимагати прямих змін у дизайні. Абстракції корисні лише в цьому контексті стабільності, якщо щось, будучи абстрактним, зменшує цю ймовірність.

У багатьох контекстах це може бути з пристойними інженерами та клієнтами, які передбачають потреби програмного забезпечення наперед та проектують стабільні (як у незмінні) абстракції, тоді як ці абстракції пропонують їм всю дихальну кімнату, необхідну для обміну конкретними реалізаціями. Але в деяких областях абстракції можуть бути нестабільними і схильними до неадекватності, тоді як дані, необхідні для двигуна, можуть бути набагато простіше передбачити та зробити їх стабільними заздалегідь. Тож у цих випадках фактично може бути корисніше з точки зору ремонтопридатності (простота зміни та розширення системи) залежність, що надходить до даних, а не до абстракцій. У системі ECS найбільш нестабільними частинами (як і частинами, що найбільш часто змінюються) є, як правило, функціональні можливості, що зберігаються в системах (PhysicsSystem, наприклад), тоді як найбільш стабільні частини (як, щонайменше, ймовірно, будуть змінені) - це компоненти, які просто складаються з необроблених даних ( MotionComponentнаприклад,), які використовують усі системи.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.