Почему СУХОЙ важно?


81

Очень просто, зачем мне писать код, который работает для всех случаев и масштабируемых данных, когда все, что мне нужно сделать, это повторить один и тот же процесс несколько раз с небольшими изменениями?

Мне вряд ли понадобится редактировать это снова в ближайшее время.

Похоже, гораздо меньше работы, чтобы просто пойти ...

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

И если мне когда-нибудь понадобится что-то добавить ...

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

И если мне нужно удалить это, я удаляю это.

Труднее понять, как превратить все это в один простой шаблон, в который я могу просто подать данные и разобраться со всеми делами, и внести кучу изменений, которые, как мне кажется, никогда не произойдут сделать.

Зачем быть СУХИМ, если похоже, что быстрое нарезание + паста будет намного менее трудоемким?


11
потому что сухой все еще быстрее, когда вы делаете это правильно, а также, что если вы допустили ошибку в. это влияет на всех остальных
Даниэль Литтл

97
«Мне вряд ли понадобится редактировать это снова в ближайшее время» - вы можете надеяться, но, скорее всего, вы здесь ошибаетесь. И если вы снова поработаете над этим кодом, но не так скоро, это только ухудшит ситуацию; Вы забудете, где находятся дубликаты, и дубликаты вырастут тонкими, но коварными несоответствиями. «Пишите так, как будто человек, который будет поддерживать ваш код, - опасный маньяк, который знает, где вы живете», - цитирует классика.
9000

14
Я думаю, что вы можете в значительной степени подвести итог: единую точку изменений легче поддерживать.
Сокол

17
Если вы не можете ответить на этот вопрос самостоятельно, вам нужно получить более реальный опыт разработки и сопровождения.
Дэвид Хеффернан

15
@ Уэйн Я почувствовал большое беспокойство в источнике, как будто миллионы программистов внезапно закричали от ужаса.
Инкогнито

Ответы:


121

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

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

Я всегда ошибаюсь в сторону СУХОГО, в редком случае повторяюсь, когда думаю, что преимущества в удобочитаемости стоят риска того, что кто-то забудет исправить ошибку в нескольких местах.

Принимая во внимание этот совет, это звучит как в вашем случае

повторите тот же процесс несколько раз с небольшими изменениями

Я бы определенно работал, чтобы не повторить себя в вашем случае. Предполагая минимальные «настройки» - они могут обрабатываться с различными параметрами, которые влияют на поведение, или, возможно, вводятся в зависимости для выполнения различных подзадач.

Зачем быть СУХИМ, если похоже, что быстрое нарезание + паста будет намного менее трудоемким?

Знаменитые последние слова. Вы будете сожалеть, думая, что, когда младший инженер настраивает / исправляет / реорганизует один doStuff и даже не осознает, что другие существуют. Веселье наступает. В основном нет изжоги. Каждая строка кода стоит дороже. Сколько путей кода вы должны протестировать с таким количеством повторяющихся функций? Если одна функция, вам просто нужно протестировать один основной путь с несколькими изменениями поведения. Если вы вставили копию, вы должны проверить каждый doStuff отдельно. Скорее всего, вы пропустите один, и у клиента может появиться нежелательная ошибка, и у вас могут появиться нежелательные электронные письма в вашем почтовом ящике.


2
Э-э, просто, чтобы быть ясным, я не говорю, что сухое - это плохо, этот вопрос больше защищает дьяволов. Я действительно ищу логичный ответ, который я могу связать с людьми, которые думают, что вырезать + вставить + настроить код - это хорошо.
Инкогнито

2
При этом мне больше всего нравится ваш ответ, так как он охватывает как сбои в СУХОЙ: не беспокоить и идти за борт, так и объяснять последствия. - Что касается того, что нужно жертвовать читабельностью ради ошибок, я бы сказал, что повторяющийся код менее читабелен по той же причине, на которую вы указали, когда легко потерять след.
Инкогнито

16
Я хотел бы подчеркнуть одну легкую ловушку СУХОГО: подобный код объединен. Если у вас есть два варианта использования, которые функционально не связаны, но имеют очень похожий код, их легко объединить, потому что DRY хорош . К сожалению, когда нужно эволюционировать, вы часто сталкиваетесь с неприятной задачей - снова разделить функцию, а затем пройтись по всем сайтам вызовов и тщательно продумать, какой из них следует вызывать здесь ... Пример: структурная типизация LLVM (все похожие типы объединены в один) почти невозможно отобразить IR обратно в исходный код.
Матье М.

1
Бинго. Если два или более фрагментов кода будут изменены, и изменения всегда будут одинаковыми для всех фрагментов, то их следует объединить. Любая часть, которая должна измениться не так, как другие, не должна объединяться. Если код никогда не изменится, не имеет большого значения, будет ли он объединен или нет. Вопрос о том, должны ли изменения быть заблокированы или отключены, гораздо важнее, чем размер рассматриваемого кода.
суперкат

1
@MatthieuM это немного несправедливый пример. LLVM применяет структурную типизацию в качестве оптимизации ; то есть ребята из LLVM решили заплатить цену сложного для понимания IR за преимущества в производительности. СУХОЙ обычно является проблемой ремонтопригодности, но в этом случае это было явно преднамеренное решение по снижению ремонтопригодности
Бенджамин Ходжсон

47

Потому что СУХОЙ будет меньше работы позже.


СУХОЙ: (Не повторяй себя)

Одна функция, принимающая аргумент.

def log(arg):
    print(arg)

C & P: (Копировать и Вставить)

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

def logA():
    print('a')

def logB():
    print('b')

...ad infinitum...

Как насчет того, чтобы обновить нашу печать, чтобы указать, что именно печатает?

DRY:

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

Готово.

С & Р:

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


Как вы думаете, что было бы легче отлаживать?


10
Кроме того, вам нужно написать столько же похожих наборов тестов, сколько у вас дублирующих функций.
9000

Вы адекватно проиллюстрировали эту концепцию, но на практике никто не сделал бы то, что вы описали с функциями gazillion, в любом случае, не так.
Роберт Харви

@ Роберт, надеюсь, нет! Я выбрал очень простое задание, чтобы попытаться лучше проиллюстрировать концепцию и почему она может быть полезной.
Джон

11
@Robert - вы читали какие-либо статьи на thedailywtf.com ;) - есть некоторые, кто сделает именно это
HorusKol

1
@ 9000 Нет, если у вас нет тестовых наборов: p (что на самом деле часто бывает в некоторых проектах ... к сожалению ...)
Свиш

16

Потому что применительно к вашему примеру:

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

    Меньше кода часто приводит к меньшему шуму . (не всегда...)

  • + гибкость

    Если вам когда-либо приходилось менять поведение doStuffX, вы захотите убить себя или того, кто это написал,

  • + расширяемость

    Если вы извлекли отдельные части в выбранную вами структуру данных, а затем просто перебрали ее, вызвав универсальный тип doStuff, вы также можете добавить одну строку в структуру данных, где вы хотите новую запись, или удалить ее, и изменение поведения будет означать редактирование doStuff. Проще поддерживать .

  • + экономическая эффективность

    меньше кода здесь означает:

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

    В зависимости от языка, компилятор / интерпретатор может иметь больше шансов определить, что generic- doStuffкод всегда выполняет почти идентичные вещи, часто один за другим, и может встроить его или попытаться оптимизировать . Вероятно, не для X вариаций doStuffX.

  • + тестирование и качество

    Тестировать проще: doStuffнужно тестирование, и все. Ну, не совсем, но это уже больше . Только его ожидания ввода-вывода варьируются и должны быть проверены в различных условиях, но это все же намного проще для тестирования и более ремонтопригодны, чем все варианты doStuffX.

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


13

Поскольку все остальные проделали огромную работу по объяснению проблем сопровождения дублирующегося кода, я просто скажу следующее:

Большая часть программирования требует от вас думать о будущем, а не только о настоящем. Вы правы, что копировать и вставлять теперь проще, но утверждение, что мне вряд ли понадобится редактировать это снова в ближайшее время ", показывает, что вы не правильно думаете. Да, вы могли бы купить себе немного времени с быстрое и грязное копирование / вставка, но при этом вы показываете, что не можете выйти за пределы своей непосредственной проблемы и думать о завтрашнем дне. Уверены ли вы, что вам никогда не понадобится пересматривать этот код? Вы точно знаете, что есть в нем нет ошибок? Можете ли вы на 100% гарантировать, что вам не нужно будет пересматривать его, когда будет реализован ваш следующий набор функций? Это проблемы завтрашнего дня, которые необходимо учитывать при разработке сегодня.

Конечно, бывают случаи, когда необходимо копировать / вставлять. Как разработчик пользовательского интерфейса, я обнаружил, что бывают случаи, когда мне приходится нарушать принцип DRY. Это отстой, я съеживаюсь каждый раз, когда это происходит, и, к счастью, это редко. Но это действительно произойдет.

Разница в том, что при нарушении режима «СУХОЙ» у вас должна быть очень веская причина, и утверждение «Сложнее понять, как превратить все это в одну прямую модель, на самом деле не является одним из них». Если вы не испытываете значительных временных трудностей и не хотите, чтобы ваш босс кричал, чтобы получить что-то в течение следующих нескольких часов, или вы потеряете свою работу, я не думаю, что это обоснованное обоснование.

Не поймите это неправильно: я не пытаюсь вас ругать или наказывать, а скорее пытаюсь заставить вас понять, в чем ваш менталитет. Программисты вкладывают в будущую лень; СУХОЙ - это способ достижения этого. Работа, которую вы выполняете сегодня, решая сложную задачу проектирования, окупится завтра.


Я не уверен, что согласен с боссом, который говорит вам: «сделай это, или ты уволен» - отличная причина нарушить СУХОЙ. Технический долг, когда у вас есть время, чтобы сделать это правильно, действительно ли это экономит время и т. Д.?
Инкогнито

1
@ Инкогнито, я пытался быть немного ироничным :)
суетник

7

Мне вряд ли понадобится редактировать это снова в ближайшее время.

Если это действительно так, то вам, возможно, удастся сойти с рук, но чаще всего вы будете работать над кодом, который необходимо поддерживать. Это означает расширение функциональности, исправление ошибок и другие улучшения. Если у вас есть небольшие вариации одного и того же кода в 10 разных местах, и однажды вы возвращаетесь к этому коду и хотите внести изменения, теперь у вас есть склонная к ошибкам задача внесения одного и того же изменения в 10 разных местах (извините, было 11 мест, вы забыли одно и теперь у вас есть ошибка).

Если вы можете обобщить, какую проблему вы пытаетесь решить, вы можете облегчить расширение и исправление кода, если появятся ошибки.


Классный ответ, но даже если мне это сойдет с рук, как насчет бедного сока, который поддерживает его после меня? ;).
Инкогнито

Смотрите: «чаще всего вы будете работать над кодом, который нужно поддерживать» :)
Алекс

Даже тогда это только в том случае, если то, что вы копируете и вставляете, на 100% безошибочно. И это не так, и перестаньте думать, что это может быть.
Дэн Рэй

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

6

Как я уже говорил в ответе на другой вопрос, мой подход заключается в следующем:

  1. В первый раз, когда я решаю определенную проблему, я просто делаю это.
  2. Во второй раз (то есть, когда я решаю подобную проблему), я думаю: хм, может быть, я повторяюсь, но сейчас я пойду на быстрое копирование и вставку.
  3. В третий раз я думаю: хм, я повторяюсь -> сделай это вообще!

Т.е. до 2 другой принцип (YAGNI) выигрывает у DRY. Но, начиная с 3 (или 4, если я действительно ленив!), Мне кажется, что Я нуждаюсь в этом, и поэтому я следую за DRY.

Обновить

Некоторые дальнейшие идеи из моего недавнего опыта. Мне пришлось адаптировать / интегрировать два компонента A и B, разработанные другой командой, в наш продукт. Во-первых: два компонента A и 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 - это принцип разработки программного обеспечения, направленный на сокращение повторения информации всех видов .

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

Принцип СУХОГО, как упоминали Энди Хант и Дейв Томас, не ограничивается предотвращением дублирования кода. Это также защищает генерацию кода и любые процессы автоматизации. По иронии судьбы, результаты генерации кода могут даже дублировать код ...

Причина, по которой это уже было подробно объяснено в других ответах, но комментарий Фалькона достаточно хорошо резюмирует ИМХО:

Единую точку изменений легче поддерживать.


Ого, я думал, что в теге есть некоторые данные. Я положу немного информации там.
Инкогнито

3

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

Другими словами, СУХОЕ и слабая связь иногда конфликтуют. Если вы ожидаете, что doStuff1 и друзья будут расходиться с каждым новым выпуском программного обеспечения, можно дублировать их код.

По моему опыту, может быть трудно судить о том, куда движется ваше программное обеспечение в будущем, и по этой причине DRY часто является безопасным выбором.

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

Понятно, что качество кода часто ухудшается по мере развития кода, но я видел случаи, когда многопараметрическая функция со спагетти if-then-else в теле была результатом благонамеренного, но плохо проведенного процесса рефакторинга.

(1) Я использую слово «код», но это относится и к дизайну.


Было бы полезно привести пример «слишком много сухого», так как это менее видимый конец спектра.
Инкогнито

@Incognito: я отредактировал свой ответ. Нет конкретного примера, но, надеюсь, то, что я имел в виду, достаточно ясно.
Joh

2

Я должен упомянуть проблемы с DRY в мире реляционных баз данных. Базы данных предназначены для быстрой и качественной работы с использованием основанной на множестве логики и посредством запросов sargable. Принципы СУХОГО часто заставляют разработчика писать запросы без Sargable или использовать логику Row-by-agonizing-Row для использования существующего кода в различных ситуациях. СУХОЙ и оптимизации производительности часто противоречат друг другу, и в мире баз данных, производительность, как правило, гораздо более критична, чем поддержка. Это не означает, что вам вообще не следует использовать принципы DRY, просто вы должны знать, как это повлияет на общее удобство использования базы данных. Разработчики приложений считают «СУХОЙ» в первую очередь, а производительность - во-вторых, разработчики баз данных - в первую очередь «целостность данных», «второе - производительность», «третья безопасность данных» (в некоторых системах производительность и безопасность могут меняться местами).

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

Но часто именно те функции, которые вы хотите использовать для обеспечения соблюдения принципа СУХОЙ, вызывают огромные проблемы для базы данных. Я не говорю, никогда не используйте СУХОЙ, но не переусердствуйте с этим.

Примеры того, о чем я говорю. Вам необходимо выполнять импорт данных из миллиона записей раз в месяц. Записи уже могут быть добавлены вручную через пользовательский интерфейс, вызывая сохраненный процесс. Этот процесс, поскольку он был разработан для импорта отдельных записей, добавляет только одну запись за раз. Используя DRY, чтобы избежать вставки кода в двух местах, вы пишете курсор для многократного вызова proc, а не для записи необходимого импорта на основе набора. Время на импорт идет от 30 минут, которые потребуются при использовании логики на основе набора, до 18 часов. Теперь правильным способом придерживаться DRY в этом случае было бы исправление proc для обработки импорта нескольких записей. К сожалению, часто невозможно или очень трудно отправить массив в процесс (в зависимости от серверной части базы данных), и, изменяя процесс, вы в конечном итоге нарушаете работу приложения.

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

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


1

Я не вижу ключевых моментов моего ответа выше, так что здесь идет. Не смотрите на СУХОЙ как правило противделать что-то. Это можно сформулировать так, но на самом деле это может служить совершенно другой и позитивной цели. Это сигнал остановиться, подумать и найти лучший ответ. Это заставляет меня искать возможности для разработки лучшего решения. Это хорошая сторона неприятного запаха в моем коде, которая побуждает меня переосмыслить свой дизайн и заставляет меня делать это намного лучше. DRY - это не просто небольшое нарушение синтаксиса. Это бросает мне вызов модульности. Это бросает мне вызов, чтобы компонентировать. Это сигнал повторения, который напоминает мне подумать об использовании шаблонов и генерации кода вместо грубой силы и невежества. Это помогает мне понять, что я должен найти время для автоматизации своей автоматизации. Это приводит вас к скупому образу жизни! Это помогает вам тратить больше времени на создание более крутых новых вещей, а не придирчивых старых скучных деталей. И это дает вам хорошие манеры, хорошее дыхание и здоровый образ жизни! Ну, может быть, я немного сбился с пути ...


DRY влияет на меня совсем по-другому, однако, если это влияет на вас, мне скорее нравится философия «быть сигналом к ​​остановке, думать и найти лучший ответ» и бросать вызов.
n611x007

1

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

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

Так что это была настоящая PITA, чтобы найти все фрагменты кода, согласовать их и исправить ошибки. И мы все еще гармонизируем и исправляем вещи.

Вы никогда не узнаете, допустили ли вы ошибку в первом методе, а затем должны были исправить ее несколько раз, потому что вы просто скопировали ее. И если вы хотите использовать некоторые методы позже, как вы узнаете, какой из 5 методов в кодовой базе является подходящим для вашего случая сейчас? Итак, вы просто копируете один, настраиваете его, и вот оно начинается снова ...


1

Да, не беспокойтесь о DRY, если вы пишете Throwaway Code .

Но DRY важен, конечно, если вы планируете сохранить код.


1

Фраза «не повторяйся» немного упрощена. Что важно, так это «избегайте инкапсулирования одной части потенциально изменяемой информации в двух независимых местах».

Если программа должна обрабатывать виджеты, каждый из которых имеет три woozles, и имеет много циклов вида

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

тогда ожидание того, что виджеты будут содержать три woozles, будет инкапсулировано в каждом из этих циклов, и обновление кода для размещения любого другого количества woozles на виджет может быть затруднено. Для сравнения

#define WOOZLES_PER_WIDGET 3

и каждый цикл был переписан

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

Такой дизайн может очень легко изменить количество woozles для виджета.

Тем не менее, важно отметить, что, хотя желательно объединить информацию, такую ​​как количество вузлов на виджет, в одну точку, это не всегда практично. Иногда может быть необходимо жестко закодировать логику, которая будет работать, только если вещи определенного размера. Например, если у каждого woozle есть значение, и кто-то хочет найти медиану, связанную с конкретным виджетом, может быть возможно отсортировать значения и выбрать средний, и такой подход будет работать с любым количеством woozles, но логика который написан от руки специально, чтобы найти медиану из трех пунктов, может быть значительно быстрее.

Хотя наличие константы WOOZLES_PER_WIDGET может сделать код более читабельным, его следует прокомментировать, чтобы было ясно, что его значение нельзя изменить без внесения других изменений в логику программы. В этом случае логика, жестко закодированная для трех элементов, и константа WOOZLES_PER_WIDGET будут дублировать информацию «каждый виджет имеет три woozles», но преимущества такого дублирования (более высокая скорость выполнения) могут перевесить стоимость.


0

Хотя я на самом деле согласен с другими авторами комментариев о ремонтопригодности и т. Д., Все они действительны.

Я хотел бы добавить небольшой несогласный голос к дискуссии.

  • Это важно только для программистов. Людям, которые платят вашу зарплату, наплевать, пока программное обеспечение проходит UAT.
  • С точки зрения важности он занимает гораздо более низкое место, чем получение правильных требований, выслушивание спонсоров проекта и своевременная доставка.

так как этот сайт предназначен для «программистов», я думаю, можно с уверенностью сказать, что вопрос направлен на «точку зрения программистов». Ваши заявления о плательщиках заработной платы, UAT и степени важности, конечно, верны, но не имеют отношения к этому конкретному вопросу.
Оз

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, чтобы улучшить качество жизни? По моему опыту, нет, часто люди считают что-то более актуальное, пока оно не выходит из-под контроля.
  5. Дублирование кода труднее читать, потому что оно делает код многословным там, где его не нужно, в местах, где многословие не добавляет информации о предполагаемой функциональности: например, вызовы универсальных методов, которые используются [снова и снова] для установить основу для нескольких видов предполагаемой функциональности, усложнит для этой фактической функциональности раскрыться.
  6. Это было упомянуто много. Если код неправильный, какой-то бедный парень или парень должен будет искать и изменять каждое использование этого кода. Например, если кто-то использовал небезопасный инъекционный вызов SQL для mysql_query в очень немногих местах организованного класса, где это необходимо, было бы легко исправить это и использовать вместо этого PHP PDO, но если бы он использовал его в более чем тысяче мест, копируя вызов и, наконец, для его исправления потребуется аутсорсинг, а иногда и более опасный код необходимо будет переписать с нуля.
  7. Дублирование кода - плохая привычка. Если вы практикуете что-то, это постепенно становится второй натурой и влияет на окружающих вас людей. Младшие разработчики видят, как ты это делаешь и так же. Вы должны практиковать то, что проповедуете, и приобретать привычку поступать правильно. Вы узнаете больше. Написание недублируемого кода сложнее и сложнее. Это полезная привычка.

Последние замечания о предотвращении дублирования кода и подведении итогов:

Это также было сказано ранее, но иногда избегание дублирования заставляет вас «наклоняться назад» и делать вещи, которые слишком сложны (или не важны), чтобы другие могли их понять. Написание нечитаемого кода (или, как мы в шутку называем его «код, сохраняющий работу») само по себе является проблемой, даже если не требуется предотвращение дублирования кода. Тем не менее, я обнаружил, что если с самого начала внедрять правильную инфраструктуру и лучшие практики, намного проще предотвратить дублирование кода, и люди часто могут избегать неинтуитивных действий, чтобы предотвратить будущие ненужные и нечитаемые кучи работы, выполненные для предотвращения дублирования кода, если вы делаете все правильно с самого начала.

Что делает все правильно? Что ж, на этот вопрос сложно ответить, но одно - определить, какие методы необходимы для проекта, посмотреть, что уже было реализовано другими (вне и внутри) внутри компании, и использовать это, когда это возможно; документирование всего, что вы добавляете в кодовую базу, и попытка сделать его на одну ступеньку более общим, чем должно быть, но это все. Не переусердствуйте с шаблонами проектирования, просто чтобы сделать код гибким там, где он не должен быть.

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.