Кодове з'єднання вводиться DRY та OOD


14

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

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

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

Як можна досягти оптимального балансу між DRY та небажаним зчепленням коду?


1
Завжди добре не сліпо виконувати правила, а спочатку залучати мозок.
gnasher729

досить справедливо - значить, вказівки, а не правила.
користувач2549686

Ви читали сторінку Вікі на DRY (або OAOO, як це називали)? wiki.c2.com/?OnceAndOnlyOnce Ось тут відбулося багато початкових дискусій з цього приводу. (Насправді, Уорд винайшов Wiki спеціально для дискусій про патерни та практики.)
Йорг У Міттаг

Дуже пов’язані відповіді, навіть якщо питання не зовсім схоже на дублікат: softwareengineering.stackexchange.com/questions/300043/…
Халк

Відповіді:


8

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

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

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

Спадщина змушує вас до великих перебудов, коли у вас є концептуальна зміна, як та, яку ви описуєте.

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

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

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


1
+1 за вказівку на те, що спадщина - це проблема, а не СУХА. Найпростішим способом повторного використання коду є видалення зайвих залежностей, і надто часто люди пропускають той факт, що батьківський клас (і це нащадки) - це всі залежності, коли використовують успадкування. Тільки коли ви зменшуєте чи усуваєте залежності, ви фактично отримуєте код багаторазового використання.
Грег Бургхардт

3
" Чи є отримана конструкція OOP, відкрита для обговорення ". Все відкрито для дебатів. Питання, яке потрібно задати, чи відкрите це для розумної, раціональної дискусії? Відповідь - ні. Я думаю, ваш останній абзац погіршує інакше дуже гарну відповідь.
Девід Арно

@davidarno дійсно не слідкую за тобою, я читаю OOD в заголовку як об’єктно-орієнтований дизайн? тож я вирішуючи це питання, не пробиваючись через дискусію
Еван

1
@Ewan: Я тут з Девідом Арно. Я думаю, що більше 2-х десятиліть добре відомо, що віра "якщо спадщини немає, значить, це не ООП" є помилкою.
Док Браун

jeeze - це саме та дискусія, яку я намагався уникати. є погляди в обидві сторони, остаточної відповіді немає
Юван

3

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

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

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

То як ви можете вирішити цю ситуацію, якщо ви не готові відмовитися від принципу DRY? Ну, є кілька добре відомих тактик підходу до цього:

  1. Або зберігайте A, B і L як частину одного продукту, з одним загальним номером версії, загальним процесом збирання, випуску та розгортання з високим ступенем автоматизації

  2. або зробити L продуктом самостійно, з незначними номерами версій (без несумісних змін) та основними номерами версій (можливо, містять неполадки), і дозвольте А та В дозволити кожному посилатися на інший рядок версії L.

  3. Зробіть L якомога більш твердим та дбайте про зворотну сумісність. Чим більше модулів у L можна повторно використовувати без модифікацій (OCP), тим менше ймовірність порушення змін. І інші принципи в "SOLID" допомагають підтримати цю мету.

  4. Використовуйте автоматичні тести, особливо для L, а також для A і B.

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

Зауважте, коли A і B розробляються, підтримуються та розвиваються різними непов'язаними командами, принцип DRY стає зовсім менш важливим - DRY - це ремонтопридатність та еволюціонічність, але дозволяти двом різним командам надавати індивідуальні зусилля з обслуговування може бути часом ефективнішим, ніж пов’язання їх продуктів разом через трохи повторного використання.

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


1

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

Любіть своїх близнюків. Вбийте клонів.

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

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

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

Скажімо, ви працюєте в компанії ABC. Їм керують три виконавці компанії, A, B і C. Всі вони хочуть, щоб ви створили програмний продукт, але кожен з них має свої відділи. Всі вони хочуть, щоб ви почали з малого. Просто виведіть просте повідомлення зараз. Отже, ви пишете «Hello World».

А ненавидить це, хоче, щоб ви там помістили назву компанії.

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

C просто хоче калькулятор і подумав, що повідомлення є лише способом для початку роботи.

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

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

A, B і C - це різні майстри, яким повинен слугувати ваш код. Жоден рядок коду не може довго служити більш ніж одному майстру.


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