Чому DRY важливий?


81

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

Мені навряд чи доведеться скоро редагувати це знову.

Це схоже на набагато менше роботи, аби просто піти ...

function doStuff1(){/*.a.*/}
function doStuff2(){/*.b.*/}
function doStuff3(){/*.c.*/}

І якщо мені коли-небудь потрібно щось додати ...

function doStuff4(){/*.d.*/}

І якщо мені потрібно його зняти, я його видаляю.

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

Чому БУДУТЬ, коли це виглядає як швидке вирізання + паста буде набагато меншою роботою?


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

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

14
Я думаю, що ви можете це значно підсумувати: Єдину точку зміни легше підтримувати.
Сокіл

17
Якщо ви не можете відповісти на це самостійно, вам потрібно отримати трохи більше реального досвіду розвитку та підтримки.
Девід Геффернан

15
@Wayne Я відчував велике занепокоєння у джерелі, ніби мільйони програмістів раптом закричали від терору.
інкогніто

Відповіді:


121

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

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

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

Враховуючи цю пораду, це звучить як у вашому випадку

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

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

Чому БУДУТЬ, коли це виглядає як швидке вирізання + паста буде набагато меншою роботою?

Відомі останні слова. Ви пошкодуєте, подумавши, що коли молодший інженер налаштовує / виправляє / рефактори, то один doStuff і навіть не усвідомлює, що інші існують. Настає веселість. В основному не виникає печія. Кожен рядок коду коштує дорожче. Скільки кодових шляхів потрібно випробувати з такою кількістю повторюваних функцій? Якщо одна функція, вам просто потрібно протестувати один основний шлях з кількома модифікаціями поведінки. Якщо вставлено копію, вам доведеться протестувати кожен doStuff окремо. Швидше за все, ви пропустите одного, і у клієнта може з’явитися непотрібна помилка, і у вас можуть з’явитися небажані електронні листи у вашій скриньці.


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

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

16
Я підкреслив би одну легку підводку DRY: подібний код злився. Якщо у вас є два випадки використання, які функціонально не пов'язані, але мають дуже схожий код, їх легко об'єднати, оскільки DRY - це добре . На жаль, коли вам потрібно розвиватися, ви часто опиняєтесь перед неприємним завданням знову розбити функцію, а потім перейти через усі сайти викликів і уважно розглянути, який з них слід викликати ... Приклад: Структурне введення LLVM (всі подібні типи об'єднані в один) робить неможливим відображення ІК назад до вихідного коду.
Матьє М.

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

1
@MatthieuM це трохи несправедливий приклад. LLVM застосовує структурну типізацію як оптимізацію ; тобто LLVM люди вирішили заплатити ціну важко зрозумілого ІР за користь від продуктивності. DRY, як правило, є проблемою ремонту, але в цьому випадку явно було навмисним рішенням зменшити ремонтопридатність.
Бенджамін Ходжсон

47

Тому що DRY пізніше буде працювати менше.


СУХА: (не повторюй себе)

Одна функція, яка бере аргумент.

def log(arg):
    print(arg)

C&P: (Копіювати та вставляти)

26 gazillion функцій роблять по суті те ж саме, але з різницею в 2 char.

def logA():
    print('a')

def logB():
    print('b')

...ad infinitum...

Як щодо того, як ми оновлюємо нашу друк, щоб уточнити, що саме є друком?

СУХА:

def log(arg):
    print(arg + "Printed from process foo")

Зроблено.

C&P:

Ви повинні повернутися назад і змінити кожну функцію .


Як ви вважаєте, що було б простіше налагодити?


10
Крім того, вам потрібно написати стільки подібних наборів тестів, скільки у вас є дублюючі функції.
9000

Ви адекватно проілюстрували цю концепцію, але на практиці ніхто не зробив би те, що ви описали, з функціями gazillion, не так.
Роберт Харві

@ Роберт, я сподіваюся, що ні! Я вибрав дуже просте завдання, щоб спробувати краще проілюструвати концепцію і чому це може бути хорошою справою.
Іван

11
@Robert - чи читав ти будь-яку статтю на thedailywtf.com ;) - є деякі, хто зробив би саме це
HorusKol

1
@ 9000 Ні, якщо у вас немає тестових наборів: p (що насправді часто трапляється у деяких проектах ... на жаль ...)
Svish

16

Тому що , застосовано до вашого прикладу:

  • + читабельність

    Менше коду часто означає менший шум . (не завжди...)

  • + гнучкість

    Якщо вам коли-небудь довелося змінити поведінку doStuffX, ви захочете вбити себе або того, хто це написав,

  • + розширюваність

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

  • + економічність

    менший код тут означає:

    • => менша розробка => знижена вартість
    • => менша ймовірність помилок => менший час підтримки => знижена вартість
  • + (можлива) керована оптимізація

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

  • + тестування та якість

    Тестування простіше: doStuffпотрібно тестування, і все. Ну не точно, але це охоплює вже більше . Тільки його очікування на IO варіюються і потребують тестування в різних умовах, але все-таки набагато простіше тестувати та більш рентабельно, ніж усі варіанти doStuffX.

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


13

Оскільки всі інші зробили чудову роботу з пояснення проблем ремонту з дублюючим кодом, я просто скажу це:

Багато програми вимагає від вас думати про майбутнє, а не лише про безпосереднє сьогодення. Ви маєте рацію, що скопіювати та вставити зараз простіше, але твердження, що мені навряд чи доведеться скоро редагувати це знову " показує, що ви не думаєте правильно. Так, ви можете придбати собі трохи часу за допомогою швидка та брудна копія / вставка, але, тим самим, ви показуєте, що не можете визивати за межі своєї негайної проблеми і думати про завтрашній день. Ви впевнені, що вам ніколи не потрібно буде переглянути цей код? Чи знаєте ви напевно, що є Немає помилок в ньому? Чи можете ви на 100% гарантувати, що вам не потрібно буде переглядати його, коли потрібно буде впровадити наступний набір функцій? Це питання завтра, і їх потрібно враховувати, коли ви розробляєте сьогодні.

Звичайно, бувають випадки, коли потрібно буде скопіювати / вставити. Як розробник інтерфейсу, я виявив випадки, коли мені доводиться порушувати принцип DRY. Це смокче, я скучаю щоразу, коли це трапляється, і, на щастя, це рідко. Але це дійсно станеться.

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

Не сприймайте це неправильно: я не намагаюся побити вас чи карати, а скоріше намагаюся змусити вас побачити, де ваш менталітет неправильний. Програмісти вкладають гроші в майбутню лінь; DRY - це спосіб досягти цього. Робота, яку ви виконуєте сьогодні над вирішенням складної проблеми дизайну, завтра окупиться.


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

1
@Incognito, я намагався бути трохи іронічним :)
bedwyr

7

Мені навряд чи доведеться скоро редагувати це знову.

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

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


Хороша відповідь, але навіть якщо я можу піти з нею, як бути з бідним соком, який отримує, щоб підтримувати його після мене? ;).
інкогніто

Дивіться: "частіше за все ви будете працювати над кодом, який потрібно підтримувати" :)
Алекс

Навіть тоді це лише випадок, якщо те, що ви копіюєте та вставляєте, - це 100% бездоганна помилка. І це не так, і перестаньте думати, що це може бути.
Dan Ray

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

6

Як я вже заявив у відповіді на інше питання, мій підхід такий:

  1. Перший раз, коли я вирішую певну проблему, я просто виконую її.
  2. Вдруге (тобто коли я вирішую подібну проблему) я думаю: гм, можливо, я повторююсь, але зараз перейду на швидке копіювання та вставлення.
  3. Третій раз думаю: гм, повторюю себе -> зробіть це загальним!

Тобто до 2, інший принцип (YAGNI) перемагає DRY. Але починаючи з 3 (або 4, якщо я дійсно лінивий!), Здається, мені це знадобиться, і тому я слідую СУХО.

Оновлення

Деякі подальші ідеї з мого недавнього досвіду. Мені довелося адаптувати / інтегрувати два компоненти A і B, розроблені іншою командою, у наш продукт. По-перше: два компоненти A іb B дуже схожі між собою, тому мене вже тривожило те, що вони мали дещо іншу архітектуру. По-друге: мені довелося їх адаптувати, щоб я був радий використовувати підкласи і лише переосмислити те, що мені справді потрібно.

Тож я почав рефакторинг цих двох компонентів (кожен з яких складається з приблизно 8 класів C ++): я хотів мати спільну архітектуру як для A, так і для B, а потім додати необхідні нам функції, визначивши підкласи. Таким чином, наші два нових компоненти A 'і B' були б отримані з існуючих.

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

Гаразд, так і бути: я зробив масивну копію та перейменував класи з A і B і почав адаптувати копію коду. Я змусив його працювати ще два тижні (все ще роблю виправлення помилок зараз).

Переваги: ​​функціональність майже завершена, і коли ми виправили всі помилки, ми закінчили. Ми зберегли все рефакторинг та тестування A і B.

Недоліки: два тижні тому інша команда змінила інший компонент C, який використовується A і B. Вони адаптували A і B, але A 'і B' також були зламані, і ми повинні були самі їх змінити. Це ввело нову помилку, яку нам довелося виправити. Ця додаткова робота, ймовірно, була б непотрібною, якби A 'і B' ділили більшість свого коду з A і B.

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


5

Просто для уточнення, оскільки я не знаходжу цього в жодній з інших відповідей:

DRY - це принцип розробки програмного забезпечення, спрямований на зменшення повторення інформації різного роду .

Кожна частина знань повинна мати єдине, однозначне, авторитетне представлення в системі.

Принцип DRY, про який згадували Енді Хант та Дейв Томас, не обмежується дублюванням коду. Він також виступає за генерацію коду та будь-які процеси автоматизації. Як не дивно, результати генерування коду можуть бути навіть дублюючим кодом ...

Причина, чому це вже докладно пояснено в інших відповідях, але коментар Falcon підсумовує це досить добре IMHO:

Єдину точку зміни легше підтримувати.


О, о, я подумав, що в тезі є деякі дані. Я покладу туди трохи інформації.
інкогніто

3

Є така річ, як занадто багато СУХОГО. Коли це станеться, дві концепції, які в якийсь момент виявляються досить схожими на код факторингу (1), можуть згодом виявитися досить різними, що заслуговують на окремі реалізації.

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

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

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

Зрозуміло, що якість коду часто знижується в міру розвитку коду, але я бачив випадки, коли багатопараметрична функція зі спагетті if-then-else в тілі була результатом цілеспрямованого, але погано проведеного рефакторингу.

(1) Я використовую слово "код", але це стосується і дизайну.


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

@Incognito: я відредагував свою відповідь. Ніякого конкретного прикладу, але, сподіваюся, те, що я мав на увазі, є досить зрозумілим.
Джон

2

Я маю зазначити проблеми з DRY у світі реляційних баз даних. Бази даних призначені для швидкої та ефективної роботи з використанням заданої логіки та за допомогою запитуваних запитів. Принципи DRY часто змушують розробника писати неаргабельні запити або використовувати логіку Row-by-agonging-Row для використання існуючого коду в декількох ситуаціях. Сухості та оптимізація продуктивності часто розходяться, а у світі баз даних продуктивність, як правило, набагато важливіша, ніж ремонтопридатність. Це не означає, що ви взагалі не повинні використовувати принципи DRY, просто ви повинні знати, як це вплине на загальну зручність використання бази даних. Розробники додатків річ DRY по-перше, а продуктивність по-друге, розробники баз даних вважають цілісність даних по-перше, продуктивність по-друге, безпека даних третьою (продуктивність і безпека можуть поміняти місця в деяких системах).

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

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

Приклади того, про що я говорю. Вам потрібно здійснювати імпорт даних мільйона записів раз на місяць. Записи вже можна вручну додавати через користувальницький інтерфейс, викликаючи збережену програму. Цей процес, оскільки він був розроблений для імпорту одного запису, додає лише один запис за один раз. Використовуючи DRY, щоб уникнути наявності коду вставки в двох місцях, ви пишете курсор для повторного виклику протоколу, а не записування необхідного імпорту на основі встановлених даних. Час імпорту йде від 30 хвилин, які знадобляться на основі заданої логіки до 18 годин. Тепер правильним способом дотримуватися DRY у цьому випадку було б виправити процедуру для обробки імпорту записів з декількома помилками. На жаль, часто неможливо або дуже складно надіслати масив до протоколу (залежно від заднього кінця db) і, змінивши proc, ви в кінцевому підсумку зламаєте додаток.

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

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


1

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


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

1

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

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

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

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


1

Так, не турбуйтеся про DRY, якщо ви пишете Throwaway Code .

Але DRY важливо, звичайно, якщо ви плануєте зберегти код.


1

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

Якщо програма повинна обробляти віджети, кожен з яких має три вузоли, і це багато циклів форми

for (i=0; i<3; i++)
  thisWidget.processWoozle(i);

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

#define WOOZLES_PER_WIDGET 3

і кожну петлю переписували

for (i=0; i<WOOZLES_PER_WIDGET; i++) ...

така конструкція може полегшити зміну кількості шнурів на віджет.

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

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


0

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

Я хотів би додати дебатів невеликий голос, що не відповідає.

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

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

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

2
Ваша друга точка кулі цілком правильна.
Джим Г.

1
@Ozz, гордість за ваше ремесло важлива навіть для хорошого програміста, але, можливо, "точка зору програмістів" повинна включати в себе стурбованість для "задоволення клієнтів".
Джеймс Андерсон

0

<tl;dr>

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

Ось перелік речей, які чудово запобігають дублюванню коду!

  1. Простіше тестувати: вам потрібно протестувати лише одну «копію» коду.
  2. Простіше виправити: помилку потрібно знайти лише в одній «копії» коду та виправити її.
  3. Легше оновити (те саме, що вище): потрібні зміни, часто можна впоратися, змінивши код в небагатьох місцях, тому що ви витратили час на правильне повторне використання коду і не скопіювали ті самі рядки в сотні чи тисячі різних місць у джерелі.
  4. Легше повторно використовувати: коли (не дублюється в декількох місцях) і зберігається в загальноприйнятих методах з назвою, їх легко знайти та використовувати замість того, щоб писати власні.
  5. Легше читати: дубльований код важко читати, оскільки він зайво багатослівний; він містить багато рядків, які не є частиною логіки та специфічної призначеної функціональності (наприклад, загальні команди, які використовуються для налаштування етапу для виконання дії, або загальні прості повторні завдання, які потрібні у багатьох місцях). Чистий код робить логіку та функціональність спливаючими, оскільки немає повторення, що засмічує кодовий простір.
  6. Простіше налагоджувати через (1) та (5).
  7. Економить ваш час та гроші та робити більше задоволень у майбутньому; спеціально створити кращий більш надійний код. Це підсумок, і це майже все вищезазначене. Якщо багато людей використовують одну і ту ж функцію doFoo1(a, b), є більша ймовірність, що багато її дратівливих несправностей і крайніх випадків будуть виявлені та усунені. Якщо всі копіюють код і створюють doFoo2(specialA)..., doFuu2^n(a, b, c)то вони дублювали проблеми doFoo1і конкретно створювали набагато більше роботи.

</tl;dr>

Довга версія:

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

Інша справа, що для початківців це може здатися проблемою, яка торкнеться лише великих компаній, але я виявив, що це загрожує крихітними стартапами просто погано (як у 10 000 рядків дублюваного коду на стороні сервера). Це стан душі. Вам слід не тільки опановувати ДУХУ, але й прагнути заохочувати інших робити те саме; тому що в іншому випадку ви будете прирікати себе в основному дублювати код. Коли засоби для боротьби із сухими руками знаходяться під рукою та застосовуються, застосувати їх набагато простіше. Коли багато дублюється коду, застосовувати рішення для копіювання пасти набагато простіше.

Речі, які я вважаю шкідливими при дублюванні коду:

  1. Чи корисна ця функція? Скажімо, ви знайдете функцію, яка виконує (або, здається, виконує те, що вам потрібно), як ви знаєте, чи вона навіть повинна працювати правильно або якщо це просто дублюючий чи відкинутий код.
  2. Надлишковий код. Іноді люди дублюють код, використовують його і забувають (вони завжди можуть повторити його в майбутньому). У якийсь момент хтось знімає виклики дублюваної функції в деяких місцях, намагаючись перетворити рефактор, але невикористана функція залишається, навіть якщо вона не використовується активно.
  3. Важко знайти те, що шукаєш. Дубльований код займає місце і робить пошук корисних і потрібних речей (за допомогою таких інструментів, як grep) важче завдання, ніж це повинно бути, оскільки ви отримуєте десятки чи тисячі результатів, де вам слід було отримати лише кілька.
  4. (Вище згадувалося): Важкий в обслуговуванні, але також важкий у використанні для підтримки та регресії. Якщо код тестування дублюється і не є належним чином вилучений у функції, інші повторять його. Хтось буде заважати писати простий у користуванні, простий для читання API, щоб зробити QoL кращим? На мій досвід, ні, люди часто вважають більш актуальним питання, поки це не виходить з рук.
  5. Дублювання коду важче читати, оскільки це робить код багатослівним там, де цього не повинно бути, в місцях, де багатослівність не додає інформації про призначений функціонал: наприклад, виклики загального методу, які використовуються [знову і знову] для створити підґрунтя для різних видів передбаченої функціональності, ускладнює виведення цієї фактичної функціональності.
  6. Про це вже багато говорилося. Якщо код невірний, якомусь бідному голові чи хлопцеві потрібно буде шукати та змінювати кожне використання цього коду. Наприклад, якщо хтось використовував небезпечний виклик SQL для ін'єкції mysql_query в дуже небагатьох місцях в організованому класі, де це потрібно, було б легко його виправити і використовувати PDO PDP PHP, але якби вони використовували його в більш ніж тисячі місць, копіюючи виклик і знову, виправляючи його, практично доведеться перенести назовні або іноді небезпечніше, код потрібно буде переписати з нуля.
  7. Копіювання коду - шкідлива звичка. Якщо ви практикуєте щось, це повільно стає другою природою, і це впливає на оточуючих вас людей. Молодші розробники бачать, що ти це робиш і робиш також. Ви повинні практикувати те, що ви проповідуєте, і звикати робити правильно. Ви дізнаєтесь більше. Введення коду, що не дублюється, складніше і складніше. Це корисна звичка.

Останні нотатки щодо запобігання надмірному копіюванню коду та підбиття підсумків:

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

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

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