Чи є нещільне з’єднання без використання шаф анти-візерунком?


22

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

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

Чи вважаєте ви зосередження уваги на сипучому з’єднанні без будь-яких випадків використання для сипучої муфти (наприклад, уникнення дублювання коду чи планування змін, які, можливо, відбудуться в осяжному майбутньому), як анти-шаблон? Чи може пухка муфта потрапити під парасольку YAGNI?


1
Більшість переваг приносять вартість. Використовуйте, якщо вигода переважає вартість.
LennyProgrammers

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

Відповіді:


13

Дещо.

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

З іншого боку, надмірне спостереження за смішні суми змін складе багато зайвих складностей та зусиль. ЯГНІ, як ви кажете, б'є по голові.


22

Добре чи погано практика програмування X ? Зрозуміло, що відповідь завжди "це залежить".

Якщо ви дивитесь на свій код, цікавитесь, які «шаблони» ви можете ввести, значить, ви робите це неправильно.

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

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

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

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


4
Я робив це лише днями: я думав, що мені знадобиться деяке опосередкування між двома класами «про всяк випадок». Тоді я поранив голову, намагаючись щось налагодити, вирвав непряму і був набагато щасливішим.
Френк Ширар

3

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

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

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

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

Загалом, ви хочете мати високу муфту в межах своїх модулів і нещільне з'єднання між ними. Без високоефективних зв'язків ви, мабуть, не маєте згуртованості.


1

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

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

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


1

Проста відповідь - нещільне з'єднання добре, коли це зроблено правильно.

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

Прості правила дизайну: 1. Не збирайте знання про декілька предметів в одну точку (як вказується скрізь, залежить), якщо ви не будуєте інтерфейс фасаду. 2. одна функція - одна мета (ця мета може бути багатогранною, наприклад, на фасаді) 3. один модуль - один чіткий набір взаємопов'язаних функцій - одна чітка мета 4. якщо ви не можете просто перевірити його тестування, то він не має проста мета

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

Сумна річ у розробці програмного забезпечення сьогодні: 90% людей розробляють нові системи і не мають можливості розуміти старі системи, і ніколи не бувають, коли система потрапила до такого поганого самопочуття через постійне рефакторинг шматочків і шматочків.


0

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

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

Стабільність мені дуже допомагає. Мені подобається створювати колекцію добре перевіреного коду, який має все менше і менше причин коли-небудь змінитись у майбутньому. Це не трубна мрія; У мене є код C, який я використовую і використовую знову з кінця 80-х, який з тих пір взагалі не змінився. Це, мабуть, низький рівень матеріалів, наприклад, орієнтований на пікселі та пов'язаний з геометрією код, в той час як багато моїх матеріалів вищого рівня застаріли, але це все-таки багато що допомагає. Це майже завжди означає бібліотеку, яка покладається на все менше і менше речей, якщо взагалі нічого зовнішнього. Надійність зростає і збільшується, якщо ваше програмне забезпечення все більше залежить від стабільних основ, які знаходять мало причин для зміни. Менше рухомих деталей справді приємно, навіть якщо на практиці рухомих деталей за кількістю набагато більше, ніж стійких деталей.

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

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

З'єднання та стабільність, приклад ECS

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

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

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

Тим часом нечітко поєднаною альтернативою може бути така:

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

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

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

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

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

Найбільш стабільні функції, які я коли-небудь писав (такі, які я використовував і використовував з кінця 80-х, не змінюючи їх взагалі), - це всі ті, які спиралися на необроблені дані, як функція геометрії, яка щойно прийняла масив плавці та цілі числа, а не ті, які залежать від складного Meshоб'єкта чи IMeshінтерфейсу, або множення вектора / матриці, що просто залежало від того, float[]чи double[]не залежало від цього FancyMatrixObjectWhichWillRequireDesignChangesNextYearAndDeprecateWhatWeUse.

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