Чи є ароматизатори OOP, де деякі або всі принципи SOLID є антитетичними для чистого коду?


26

Нещодавно я обговорив з моїм другом про OOP у розробці відеоігор.

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

Його стурбованість полягала в тому, що велика кількість класів перетвориться на кошмар технічного обслуговування. Моя думка полягала в тому, що це матиме прямо протилежний ефект. Ми продовжували обговорювати це так, як здавалося, століттями, згодом погодившись не погодитись, сказавши, що, можливо, були випадки, коли принципи SOLID та належний OOP насправді не змішувались добре.

Навіть запис у Вікіпедії про принципи SOLID зазначає, що вони є вказівками, які допомагають писати коди, що підтримуються, і що вони є частиною загальної стратегії спритного та адаптивного програмування.

Отже, моє питання:

Чи є випадки в OOP, коли деякі або всі принципи SOLID не піддаються очищенню коду?

Я можу собі уявити, що Принцип заміни Ліскова, можливо, може суперечити іншому аромату безпечної спадщини. Тобто, якщо хтось придумав іншу корисну модель, реалізовану за допомогою спадкування, цілком можливо, що LSP може бути в прямому конфлікті з нею.

Є інші? Можливо, певні типи проектів чи певні цільові платформи краще працюють із менш підходом SOLID?

Редагувати:

Я просто хотів би зазначити, що я не запитую, як поліпшити свій код;) Єдина причина, про яку я згадував проект у цьому питанні, - це дати трохи контексту. Моє запитання про ООП та принципи дизайну взагалі .

Якщо вам цікаво мій проект, дивіться це .

Редагувати 2:

Я уявляв, що на це запитання дадуть відповідь одним із трьох способів:

  1. Так, існують принципи проектування OOP, які частково суперечать SOLID
  2. Так, існують принципи проектування OOP, які повністю суперечать SOLID
  3. Ні, SOLID - це коліна бджіл, і ООП назавжди стане кращим з цим. Але, як і все, це не панацея. Пийте відповідально.

Варіанти 1 та 2, ймовірно, отримали б довгі та цікаві відповіді. Варіант 3, з іншого боку, був би короткою, нецікавою, але загальною заспокійливою відповіддю.

Ми, здається, сходимося на варіант 3.


Як ви визначаєте "чистий код"?
GrandmasterB

Чистий код в рамках цього питання - це структура коду таким чином, що відповідає цілям OOP та набору обраних принципів проектування. Отже, я знайомий з чистим кодом з точки зору цілей, поставлених OOP + SOLID. Мені цікаво, чи існує інший набір принципів дизайну, які працюють з OOP, але повністю або частково несумісні з SOLID.
MetaFight

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

1
Ця гра по суті є експериментом. Я випробовую різні підходи до розробки, а також намагаюся зрозуміти, чи може код підприємства-y працювати під час написання гри. Я начебто очікую, що виступ стане проблемою, але це ще не стало. Якщо / коли це станеться, то наступне, з чим я буду експериментувати, - як адаптувати свій код до коду виконавця. Стільки навчання!
MetaFight

1
Загрожуючи деякими потоками, я хотів би повернутися до питання "чому": OOP в розробці ігор . У зв'язку з характером розвитку гри, «традиційний» ООП , здається, падає з моди на користь різних смаків сутностей / компонент системи, цікавий варіант тут , наприклад. Це швидше змушує мене думати, що питання не має бути "SOLID + OOP", а "OOP + Game Development". Якщо ви подивитеся на графік взаємодії об'єктів для ігрового розробника. порівняно скажімо, N-рівень рівня, відмінності можуть означати, що нова парадигма є хорошою.
J Trana

Відповіді:


20

Чи є випадки в OOP, коли деякі або всі принципи SOLID не піддаються очищенню коду?

Загалом, ні. Історія показала, що принципи SOLID в значній мірі сприяють збільшенню роз'єднаності, що, в свою чергу, показало, що збільшує гнучкість коду, а отже, і вашу здатність до пристосування змін, а також полегшує розгляд коду, перевірку, повторне використання. коротше кажучи, зробіть свій код чистішим.

Зараз можуть бути випадки, коли принципи SOLID стикаються з DRY (не повторюйте себе), KISS (тримайте це просто нерозумно) або іншими принципами гарного дизайну OO. І звичайно, вони можуть стикатися з реальністю вимог, обмеженнями людей, обмеженнями наших мов програмування, іншими перешкодами.

Коротше кажучи, принципи SOLID завжди піддаватимуться очищенню коду, але в деяких сценаріях вони піддаються менше, ніж конфліктні альтернативи. Вони завжди хороші, але іноді інші речі є більш хорошими.


14
Мені подобається, але іноді інші речі корисніші . У ньому є почуття "Ферми тварин". ;)
FrustratedWithFormsDesigner

12
+1 Коли я просто переглянув принципи SOLID, я бачу 5 "приємно мати". Але жоден з них не сушить СУХОТИ, ПОСЛУГИТИ, і "уточнюйте свої наміри". Використовуйте SOLID, але проявляйте деяку обережність та скептицизм.
user949300

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

Що щодо інтеграційної сегрегації проти ефективної конструкції агрегатів? Якщо базовий інтерфейс "послідовності" [наприклад, IEnumerable] включає такі методи як Countі asImmutableта властивості на зразок getAbilities[повернення якого вказуватиме на те, чи Countбудуть такі речі, як "ефективні"], тоді може бути статичний метод, який бере декілька послідовностей і агрегує їх, щоб вони буду поводитись як одна довша послідовність. Якщо такі здібності присутні в базовому типі послідовностей, навіть якщо вони прив'язуються до виконання за замовчуванням, то сукупність зможе розкрити ці здібності ...
supercat

... і ефективно їх реалізовувати, використовуючи базові класи, які можуть це зробити. Якщо один агрегує десятимільйонний список елементів, який знає його кількість, і п'ять списків елементів, який може лише послідовно отримувати елементи, запит на 10 000,003-й запис повинен прочитати підрахунок з першого списку, а потім прочитати три елементи з другого . Інтерфейси кухонної мийки можуть порушувати провайдер, але вони можуть значно покращити ефективність деяких сценаріїв композиції / агрегації.
supercat

13

Я думаю, що я маю незвичну перспективу в тому, що працював і в фінансах, і в іграх.

Багато програмістів, з якими я зустрічався в іграх, були жахливими в програмуванні інженерів програмного забезпечення - але вони не мали потреби в таких практиках, як SOLID. Традиційно вони складають свою гру в коробку - тоді вони закінчені.

У галузі фінансів я виявив, що розробники можуть бути дуже неохайними і недисциплінованими, оскільки їм не потрібна продуктивність, яку ви робите в іграх.

Обидва вищезазначені твердження, звичайно, є надмірними узагальненнями, але насправді в обох випадках чистий код є критичним. Для оптимізації важливий чіткий і зрозумілий код. Заради ремонту ви хочете те саме.

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

Ви, напевно, могли переглянути два фрагменти коду та сказати, який із них найкраще відповідає SOLID. Але поодиноко немає об'єктивного способу перетворення коду на ПОЛІТИЧНИЙ. Це, безумовно, до тлумачення розробника.

Слід сказати, що "велика кількість занять може призвести до кошмару технічного обслуговування". Однак, якщо SRP не буде правильно трактовано, ви можете легко вирішити цю проблему.

Я бачив код з багатьма шарами, як правило, ніякої відповідальності. Класи, які не мають нічого, крім стану переходу від одного класу до іншого. Класична проблема занадто багато шарів непрямості.

SRP при зловживанні може призвести до відсутності згуртованості у вашому коді. Про це можна сказати, намагаючись додати функцію. Якщо вам завжди доведеться змінювати декілька місць одночасно, то вашому коду не вистачає згуртованості.

Відкрите-закрите не обходиться без своїх критиків. Наприклад, див. Огляд принципу « Відкрите закрите», що відбувся у Йона Скіта . Я не буду відтворювати його аргументи тут.

Ваш аргумент щодо LSP здається досить гіпотетичним, і я насправді не розумію, що ви маєте на увазі під іншою формою безпечного успадкування?

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

DIP може призвести до непридатного коду. Я бачив класи з масовою кількістю параметрів в імені DIP. Ці класи звичайно "додавали б" свої складові частини, але я називаю тест-здатність, ми ніколи більше не повинні використовувати нове ключове слово.

SOLID самостійно недостатньо для написання чистого коду. Я бачив книгу Роберта К. Мартіна " Чистий код: Підручник з гнучкої майстерності програмного забезпечення ". Найбільша проблема в ньому полягає в тому, що цю книгу легко читати та інтерпретувати як правила. Якщо ви це зробите, ви пропускаєте суть. Він містить великий список запахів, евристики та принципів - набагато більше, ніж лише п’ять від SOLID. Усі ці «принципи» - це насправді не принципи, а настанови. Дядько Боб розглядає їх сам як «кубисті дірки» для понять. Вони - балансуючий акт; сліпо дотримуватися будь-яких настанов спричинить проблеми.


1
Якщо у вас є велика кількість параметрів конструктора, це говорить про те, що ви порушили SRP. Однак контейнер DI все одно усуває біль, пов’язану з великою кількістю параметрів конструктора, тому я не згоден з вашими твердженнями про DIP.
Стівен

Усі ці «принципи» - це насправді не принципи, а настанови. Вони - балансуючий акт; як я вже говорив у своїй посаді після СРП, занадто екстремальність сама по собі може бути проблематичною.
Дейв Хілліє

Гарна відповідь, +1. Я хотів би додати одне: я читав рецензію Скіта більше критиків щодо стандартного визначення підручників OCP, а не до основних ідей OCP. Наскільки я розумію, ідея захищеної варіації - це те, що OCP повинен був бути з першого місця.
Док Браун

5

Ось моя думка:

Незважаючи на те, що принципи SOLID спрямовані на не надлишкову та гнучку базу коду, це може бути компромісом у читанні та обслуговуванні, якщо занадто багато класів і шарів.

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

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


3
+1 За визначенням, майже гнучка система повинна бути менш ретельною, ніж та, яка менш гнучка. Гнучкість виникає за рахунок додаткової складності, яку вона приносить.
Енді

@Andy не обов'язково. на моїй теперішній роботі багато найгірших частин коду безладно, тому що його просто зібрали, "зробивши щось просте, просто зламайте його разом і змусьте його працювати, щоб він не став таким складним". В результаті багато частин системи на 100% жорсткі. Ви взагалі не можете їх змінити, не переписавши великі частини. Це справді важко підтримувати. Ремонтопридатність виходить з високої згуртованості та низької зв'язку, а не від того, наскільки гнучка система.
сара

3

У перші дні, що розвиваються, я почав писати розбійницьку мову на C ++. Оскільки я хотів застосувати хорошу об'єктно-орієнтовану методологію, яку я засвоїв у своїй освіті, я одразу побачив ігрові предмети як об'єкти C ++. Potion, Swords, Food, Axe, І Javelinsт.д. все походить від базового основного Itemкоду, обробки імені, значка, вага, що таких речей.

Потім я зашифрував логіку сумки і зіткнувся з проблемою. Я можу покласти Itemsв сумку, але тоді, якщо я вибираю його, то як я можу знати, чи це Potionчи Sword? Я подивився в Інтернеті, як знищувати предмети. Я зламав параметри компілятора, щоб увімкнути інформацію про час виконання, щоб я знав, що таке мої абстраговані Itemістинні типи, і почав перемикати логіку на типи, щоб знати, які операції я б дозволяв (наприклад, уникайте пиття Swordsі не ставте на Potionsноги)

Це по суті перетворило код у велику кулю напівкопійованого бруду. Коли проект продовжувався, я почав розуміти, що таке провал дизайну. Що сталося, це те, що я намагався використовувати класи для представлення значень. Моя ієрархія класу не була змістовною абстракцією. Що я повинен був зробити це робить Itemреалізувати набір функцій, таких , як Equip (), Apply (), і Throw (), і зробити кожен поводяться на основі значень. Використання переліків для представлення обладнаних слотів. Використання переліків для представлення різних видів зброї. Використовуючи більше значень та менше класифікуючи, оскільки мій підкласифікація не мала іншої мети, ніж заповнення цих кінцевих значень.

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


2
Проблема полягала в плутанні типів з класами значень (зауважте: я не використовую слово class для позначення поняття OOP / C ++ про клас.) Існує більше ніж один спосіб представити точку в декартовій площині (прямокутні координати, полярні координати), але всі вони є одним і тим же типом. Однак основні мови OOP природно не підтримують класифікацію значень. Найближче до цього - об'єднання C / C ++, але вам потрібно додати додаткове поле, щоб знати, який чорт ви помістили туди.
Доваль

4
Ваш досвід може бути використаний як анти-приклад. Не використовуючи SOLID чи будь-яку методологію моделювання, ви створили нездійсненний і незрозумілий код.
Ейфорія

1
@Euphoric Я дуже старався. У мене була об'єктно-орієнтована методологія. Існує різниця між методологією та успішною її реалізацією, хоча :)
Артур Гавлічек

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

1
У вашому базовому класі ITEM повинно було бути кілька булевих методів "canXXXX", усі за замовчуванням - FALSE. Потім ви можете встановити "canThrow ()", щоб повернути істину в класі Javelin, а canEat () повернути істину для вашого класу Postion.
Джеймс Андерсон

3

Його стурбованість полягала в тому, що велика кількість класів перетвориться на кошмар технічного обслуговування. Моя думка полягала в тому, що це матиме прямо протилежний ефект.

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

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

У нас було декілька абстрактних (і чистих) інтерфейсів, реалізованих навантаженнями підтипів, як це було зроблено (зроблено цю діаграму в контексті розмови про переваги ECS, ігноруйте коментар внизу зліва):

введіть тут опис зображення

Там, де інтерфейс руху або інтерфейс вузла сцени можуть бути реалізовані сотнями підтипів: світильниками, камерами, сітками, фізичними вирішувачами, шейдерами, текстурами, кістками, примітивними формами, кривими тощо тощо (а часто було декілька типів кожного ). І головна проблема полягала в тому, що ці конструкції не були настільки стійкими. У нас були вимоги, що змінюються, і іноді самі інтерфейси доводилося змінювати, і коли ви хочете змінити абстрактний інтерфейс, реалізований 200 підтипами, це надзвичайно дорога зміна. Ми почали пом'якшувати, що, використовуючи абстрактні базові класи, між якими знижувались витрати на такі зміни дизайну, але вони все ще були дорогими.

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

введіть тут опис зображення

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

Крім того, оскільки суб'єкти в ECS використовують склад замість спадкування, їм фактично не потрібно містити функціональність. Вони є лише аналогічним «контейнером компонентів». Це зробило так, що аналогічні 200 підтипів, які реалізували інтерфейс руху, перетворюються на 200 екземплярів сутності (а не окремі типи з окремим кодом), які просто зберігають компонент руху (що є не що інше, як дані, пов'язані з рухом). A PointLightбільше не є окремим класом / підтипом. Це зовсім не клас. Це екземпляр сутності, який просто поєднує деякі компоненти (дані), пов’язані з тим, де він знаходиться в просторі (рух) та специфічними властивостями точкових вогнів. Єдиний функціонал, пов'язаний з ними, знаходиться всередині систем, як-отRenderSystem, який шукає легких компонентів у сцені, щоб визначити, як відобразити сцену.

Із зміною вимог підходу до ECS часто виникала потреба лише змінити одну або дві системи, що працюють на цих даних, або просто запровадити нову систему на стороні, або ввести новий компонент, якщо потрібні нові дані.

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

введіть тут опис зображення

Чи є випадки в OOP, коли деякі або всі принципи SOLID не піддаються очищенню коду?

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

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

  1. Так, існують принципи проектування OOP, які частково суперечать SOLID
  2. Так, існують принципи проектування OOP, які повністю суперечать SOLID.

Я не впевнений, чи справді ECS є ароматом OOP. Деякі люди визначають це таким чином, але я вважаю це дуже різним, що пов'язано з характеристиками зв'язку та відокремленням даних (компонентів) від функціональності (системи) та відсутністю інкапсуляції даних. Якщо це вважати формою ООП, я вважаю, що це дуже суперечить SOLID (принаймні, найсуворіші ідеї SRP, відкриті / закриті, заміни лисков і DIP). Але я сподіваюсь, що це розумний приклад одного випадку та сфери, де найбільш фундаментальні аспекти SOLID, принаймні, як люди взагалі інтерпретують їх у більш розпізнаваному контексті OOP, можуть бути не так застосовні.

Заняття підлітками

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

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

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

Взаємодії

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

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

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

введіть тут опис зображення

... до цього лише ті системи, які мають функціональні можливості (сині компоненти тепер просто дані, а тепер це схема з’єднання):

введіть тут опис зображення

І з цього приводу виникають думки, і, можливо, спосіб створити деякі з цих переваг у більш відповідному контексті OOP, який є більш сумісним із SOLID, але я ще не зовсім знайшов конструкції та слова, і я вважаю важко, оскільки термінологія, якою я звик перекидати все, що стосується безпосередньо ООП. Я намагаюся зрозуміти це, читаючи відповіді людей тут, а також намагаюся сформулювати свої власні, але є деякі речі дуже цікаві щодо природи ECS, які я не зміг ідеально поставити палець на це може бути більш широко застосовно навіть до архітектур, які не використовують його. Я також сподіваюсь, що ця відповідь не прозвучить як акція ECS! Мені просто здається, що це дуже цікаво, оскільки проектування ECS дуже змінило мою думку,


Мені подобається відмінність між взаємодіями та сполученням. Хоча ваша перша діаграма взаємодії затуманена. Це плоский графік, тому не потрібно перетинати стрілки.
D Drmmr

2

Принципи SOLID хороші, але KISS та YAGNI мають пріоритет у випадку конфліктів. Призначення SOLID - управління складністю, але якщо застосування самого SOLID робить код складнішим, воно перемагає мету. Для прикладу, якщо у вас є невелика програма з лише кількома класами, застосування DI, сегрегація інтерфейсу тощо може дуже збільшити загальну складність програми.

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


Ваше обговорення OCP ігнорує можливість розширення поведінки класу за допомогою композиції (наприклад, використання об’єкта стратегії, щоб дозволити зміну алгоритму, використовуваного класом), що, як правило, вважається кращим способом дотримання принципу, ніж підкласифікація .
Жуль

1
Якщо KISS і YAGNI завжди мали пріоритет, вам все одно слід кодувати в "1" і "0". Асемблери - це просто щось інше, що може піти не так. Жодна компанія KISS та YAGNI не відзначають дві з багатьох витрат на проектні роботи. Ці витрати завжди повинні бути збалансовані у порівнянні з вигодою будь-яких дизайнерських робіт. SOLID має переваги, які в деяких випадках компенсують витрати. Немає простого способу сказати, коли ви перейшли лінію.
candied_orange

@CandiedOrange: Я не погоджуюся, що машинний код простіший за код на мові високого рівня. Машинний код в кінцевому підсумку містить безліч випадкових складностей через відсутність абстракції, тому КІСС точно не вирішує написати типову програму в машинному коді.
ЖакБ

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

1
@JacquesB - правда. І OCP по своїй суті протистоїть YAGNI; однак ви хочете досягти цього, вимагає від вас спроектувати точки розширення для подальшого вдосконалення. Пошук підходящої точки балансу між двома ідеалами є ... складним.
Жуль

1

З мого досвіду: -

Великі класи експоненціально складніше підтримувати, оскільки вони стають більшими.

Малі класи легше підтримувати, а складність збереження колекції малих класів арифметично збільшується до кількості занять.

Іноді великі класи неминучі. Велика проблема іноді потребує великого класу, але читати та розуміти їх набагато складніше. Для добре названих менших класів просто імені може бути достатньо для розуміння, вам навіть не потрібно дивитись на код, якщо не існує дуже специфічної проблеми з класом.


0

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

15 років тому я працював з розробниками Deplhi, які мали святий грааль, щоб провести класи, в яких містилося все. Таким чином, до іпотечного кредиту ви можете додати страхування та платежі, доходи та позики та інформацію про податки, і ви зможете нарахувати податки до сплати, сплати податку до вирахування, і він може серіалізуватися, зберігатися на диску тощо.

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

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

Крім того, що не завжди легко знайти хороші імена для занять, які займаються лише крихітною справою.

Тому я не впевнений, що "S" завжди є хорошою ідеєю.

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