Очень просто, зачем мне писать код, который работает для всех случаев и масштабируемых данных, когда все, что мне нужно сделать, это повторить один и тот же процесс несколько раз с небольшими изменениями?
Мне вряд ли понадобится редактировать это снова в ближайшее время.
Похоже, гораздо меньше работы, чтобы просто пойти ...
function doStuff1(){/*.a.*/}
function doStuff2(){/*.b.*/}
function doStuff3(){/*.c.*/}
И если мне когда-нибудь понадобится что-то добавить ...
function doStuff4(){/*.d.*/}
И если мне нужно удалить это, я удаляю это.
Труднее понять, как превратить все это в один простой шаблон, в который я могу просто подать данные и разобраться со всеми делами, и внести кучу изменений, которые, как мне кажется, никогда не произойдут сделать.
Зачем быть СУХИМ, если похоже, что быстрое нарезание + паста будет намного менее трудоемким?
code-quality
dry
Инкогнито
источник
источник
Ответы:
Если вы повторитесь, вы можете создать проблемы с ремонтопригодностью. Если все doStuff1-3 имеют схожий структурированный код и вы решаете проблему в одном, вы можете легко забыть исправить проблему в других местах. Кроме того, если вам нужно добавить новый регистр для обработки, вы можете просто передать различные параметры в одну функцию, а не вставлять копию повсеместно.
Однако умные программисты часто доводят DRY до крайности. Иногда, чтобы не повторяться, вы должны создавать абстракции, настолько тупые, что ваши товарищи по команде не могут следовать за ними. Иногда структура двух вещей только смутно похожа, но достаточно различна. Если doStuff1-4 отличаются настолько, что рефакторинг их, чтобы они не повторялись, заставляет вас писать неестественный код или делать умные откаты кодирования, которые заставят вашу команду смотреть на вас, тогда, возможно, будет хорошо повторить себя. Я наклонился назад, чтобы не повторяться пару раз неестественным образом, и пожалел о конечном продукте.
Я всегда ошибаюсь в сторону СУХОГО, в редком случае повторяюсь, когда думаю, что преимущества в удобочитаемости стоят риска того, что кто-то забудет исправить ошибку в нескольких местах.
Принимая во внимание этот совет, это звучит как в вашем случае
Я бы определенно работал, чтобы не повторить себя в вашем случае. Предполагая минимальные «настройки» - они могут обрабатываться с различными параметрами, которые влияют на поведение, или, возможно, вводятся в зависимости для выполнения различных подзадач.
Знаменитые последние слова. Вы будете сожалеть, думая, что, когда младший инженер настраивает / исправляет / реорганизует один doStuff и даже не осознает, что другие существуют. Веселье наступает. В основном нет изжоги. Каждая строка кода стоит дороже. Сколько путей кода вы должны протестировать с таким количеством повторяющихся функций? Если одна функция, вам просто нужно протестировать один основной путь с несколькими изменениями поведения. Если вы вставили копию, вы должны проверить каждый doStuff отдельно. Скорее всего, вы пропустите один, и у клиента может появиться нежелательная ошибка, и у вас могут появиться нежелательные электронные письма в вашем почтовом ящике.
источник
Потому что СУХОЙ будет меньше работы позже.
СУХОЙ: (Не повторяй себя)
Одна функция, принимающая аргумент.
C & P: (Копировать и Вставить)
26 функций gazillion делают по сути то же самое, но с разницей в 2 символа.
Как насчет того, чтобы обновить нашу печать, чтобы указать, что именно печатает?
DRY:
Готово.
С & Р:
Вы должны вернуться и изменить каждую функцию .
Как вы думаете, что было бы легче отлаживать?
источник
Потому что применительно к вашему примеру:
+ читабельность
Меньше кода часто приводит к меньшему шуму . (не всегда...)
+ гибкость
Если вам когда-либо приходилось менять поведение
doStuffX
, вы захотите убить себя или того, кто это написал,+ расширяемость
Если вы извлекли отдельные части в выбранную вами структуру данных, а затем просто перебрали ее, вызвав универсальный тип
doStuff
, вы также можете добавить одну строку в структуру данных, где вы хотите новую запись, или удалить ее, и изменение поведения будет означать редактированиеdoStuff
. Проще поддерживать .+ экономическая эффективность
меньше кода здесь означает:
+ (возможно) управляемая оптимизация
В зависимости от языка, компилятор / интерпретатор может иметь больше шансов определить, что generic-
doStuff
код всегда выполняет почти идентичные вещи, часто один за другим, и может встроить его или попытаться оптимизировать . Вероятно, не для X вариацийdoStuffX
.+ тестирование и качество
Тестировать проще:
doStuff
нужно тестирование, и все. Ну, не совсем, но это уже больше . Только его ожидания ввода-вывода варьируются и должны быть проверены в различных условиях, но это все же намного проще для тестирования и более ремонтопригодны, чем все вариантыdoStuffX
.В целом это составляет более обслуживаемого код и повышения эффективности разработки для вашей команды, и это одна из многих хороших практик , чтобы помочь вам производить более надежное и надежное программное обеспечение.
источник
Поскольку все остальные проделали огромную работу по объяснению проблем сопровождения дублирующегося кода, я просто скажу следующее:
Большая часть программирования требует от вас думать о будущем, а не только о настоящем. Вы правы, что копировать и вставлять теперь проще, но утверждение, что мне вряд ли понадобится редактировать это снова в ближайшее время ", показывает, что вы не правильно думаете. Да, вы могли бы купить себе немного времени с быстрое и грязное копирование / вставка, но при этом вы показываете, что не можете выйти за пределы своей непосредственной проблемы и думать о завтрашнем дне. Уверены ли вы, что вам никогда не понадобится пересматривать этот код? Вы точно знаете, что есть в нем нет ошибок? Можете ли вы на 100% гарантировать, что вам не нужно будет пересматривать его, когда будет реализован ваш следующий набор функций? Это проблемы завтрашнего дня, которые необходимо учитывать при разработке сегодня.
Конечно, бывают случаи, когда необходимо копировать / вставлять. Как разработчик пользовательского интерфейса, я обнаружил, что бывают случаи, когда мне приходится нарушать принцип DRY. Это отстой, я съеживаюсь каждый раз, когда это происходит, и, к счастью, это редко. Но это действительно произойдет.
Разница в том, что при нарушении режима «СУХОЙ» у вас должна быть очень веская причина, и утверждение «Сложнее понять, как превратить все это в одну прямую модель, на самом деле не является одним из них». Если вы не испытываете значительных временных трудностей и не хотите, чтобы ваш босс кричал, чтобы получить что-то в течение следующих нескольких часов, или вы потеряете свою работу, я не думаю, что это обоснованное обоснование.
Не поймите это неправильно: я не пытаюсь вас ругать или наказывать, а скорее пытаюсь заставить вас понять, в чем ваш менталитет. Программисты вкладывают в будущую лень; СУХОЙ - это способ достижения этого. Работа, которую вы выполняете сегодня, решая сложную задачу проектирования, окупится завтра.
источник
Если это действительно так, то вам, возможно, удастся сойти с рук, но чаще всего вы будете работать над кодом, который необходимо поддерживать. Это означает расширение функциональности, исправление ошибок и другие улучшения. Если у вас есть небольшие вариации одного и того же кода в 10 разных местах, и однажды вы возвращаетесь к этому коду и хотите внести изменения, теперь у вас есть склонная к ошибкам задача внесения одного и того же изменения в 10 разных местах (извините, было 11 мест, вы забыли одно и теперь у вас есть ошибка).
Если вы можете обобщить, какую проблему вы пытаетесь решить, вы можете облегчить расширение и исправление кода, если появятся ошибки.
источник
Как я уже говорил в ответе на другой вопрос, мой подход заключается в следующем:
Т.е. до 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.
Итак: дублирование кода всегда опасно. Я думаю, что это всегда вопрос поиска компромиссов, и часто это не так просто.
источник
Просто чтобы уточнить, поскольку я не нахожу это ни в одном из других ответов:
Принцип СУХОГО, как упоминали Энди Хант и Дейв Томас, не ограничивается предотвращением дублирования кода. Это также защищает генерацию кода и любые процессы автоматизации. По иронии судьбы, результаты генерации кода могут даже дублировать код ...
Причина, по которой это уже было подробно объяснено в других ответах, но комментарий Фалькона достаточно хорошо резюмирует ИМХО:
источник
Существует такая вещь, как слишком много СУХОГО. Когда это происходит, две концепции, которые кажутся в какой-то момент достаточно похожими, чтобы оправдать код факторинга (1), могут позже оказаться настолько разными, что они заслуживают отдельных реализаций.
Другими словами, СУХОЕ и слабая связь иногда конфликтуют. Если вы ожидаете, что doStuff1 и друзья будут расходиться с каждым новым выпуском программного обеспечения, можно дублировать их код.
По моему опыту, может быть трудно судить о том, куда движется ваше программное обеспечение в будущем, и по этой причине DRY часто является безопасным выбором.
Код, который был чрезмерно «высушен», обычно имеет сложный поток управления и слишком много параметров. То, что изначально было простой функцией, позже было расширено для поддержки новой функциональности, управляемой дополнительным параметром. После двух или трех итераций функция перестает обслуживаться. Исправьте ошибку, возникающую в настройке, и вы вносите новые ошибки в другие настройки.
Понятно, что качество кода часто ухудшается по мере развития кода, но я видел случаи, когда многопараметрическая функция со спагетти if-then-else в теле была результатом благонамеренного, но плохо проведенного процесса рефакторинга.
(1) Я использую слово «код», но это относится и к дизайну.
источник
Я должен упомянуть проблемы с DRY в мире реляционных баз данных. Базы данных предназначены для быстрой и качественной работы с использованием основанной на множестве логики и посредством запросов sargable. Принципы СУХОГО часто заставляют разработчика писать запросы без Sargable или использовать логику Row-by-agonizing-Row для использования существующего кода в различных ситуациях. СУХОЙ и оптимизации производительности часто противоречат друг другу, и в мире баз данных, производительность, как правило, гораздо более критична, чем поддержка. Это не означает, что вам вообще не следует использовать принципы DRY, просто вы должны знать, как это повлияет на общее удобство использования базы данных. Разработчики приложений считают «СУХОЙ» в первую очередь, а производительность - во-вторых, разработчики баз данных - в первую очередь «целостность данных», «второе - производительность», «третья безопасность данных» (в некоторых системах производительность и безопасность могут меняться местами).
В целом я заметил, что чем больше уровней абстракции вы помещаете в запросы к базе данных, тем медленнее они становятся. Я не говорю, что не хотел, чтобы люди, разрабатывающие сами программы баз данных, не делали работу, позволяющую разработчикам использовать DRY, не влияя на производительность базы данных, но я не занимаюсь разработкой программного обеспечения для баз данных на этом уровне. поэтому, возможно, конфликт между абстракцией и производительностью в базе данных сложнее исправить, чем я полагаю. Тем не менее, мы должны работать с системами, как они в настоящее время построены. Мы можем просить о лучшем внедрении принципов DRY в будущих выпусках, которые также не снижают производительность (и с годами она стала лучше, но все еще проблематична), но в то же время мы должны рассмотреть, является ли DRY правильным решением для этой базы данных. в это время.
Но часто именно те функции, которые вы хотите использовать для обеспечения соблюдения принципа СУХОЙ, вызывают огромные проблемы для базы данных. Я не говорю, никогда не используйте СУХОЙ, но не переусердствуйте с этим.
Примеры того, о чем я говорю. Вам необходимо выполнять импорт данных из миллиона записей раз в месяц. Записи уже могут быть добавлены вручную через пользовательский интерфейс, вызывая сохраненный процесс. Этот процесс, поскольку он был разработан для импорта отдельных записей, добавляет только одну запись за раз. Используя DRY, чтобы избежать вставки кода в двух местах, вы пишете курсор для многократного вызова proc, а не для записи необходимого импорта на основе набора. Время на импорт идет от 30 минут, которые потребуются при использовании логики на основе набора, до 18 часов. Теперь правильным способом придерживаться DRY в этом случае было бы исправление proc для обработки импорта нескольких записей. К сожалению, часто невозможно или очень трудно отправить массив в процесс (в зависимости от серверной части базы данных), и, изменяя процесс, вы в конечном итоге нарушаете работу приложения.
Скалярные функции и табличные функции также используются для реализации принципов DRY, и они также могут серьезно повлиять на производительность, особенно если вам нужно использовать их таким образом, чтобы индексы не были полезными.
Представления также хороши для реализации DRY. Однако, если вы реализуете DRY с помощью представлений, которые вызывают представления, которые вызывают другие представления, вы быстро достигнете точки, в которой запросы будут задерживаться при загрузке. На самом деле вам может понадобиться сгенерировать наборы данных из миллионов записей, когда вам нужно только три в конце. Таким образом, одноуровневое представление сложного набора объединений для реализации DRY может быть превосходным (у меня есть одно, которое мы используем, чтобы убедиться, что вся финансовая отчетность использует один и тот же базовый набор таблиц и вычислений определенных вещей), более двух уровней и вам нужно подумать, если вы создаете беспорядок производительности.
источник
Я не вижу ключевых моментов моего ответа выше, так что здесь идет. Не смотрите на СУХОЙ как правило противделать что-то. Это можно сформулировать так, но на самом деле это может служить совершенно другой и позитивной цели. Это сигнал остановиться, подумать и найти лучший ответ. Это заставляет меня искать возможности для разработки лучшего решения. Это хорошая сторона неприятного запаха в моем коде, которая побуждает меня переосмыслить свой дизайн и заставляет меня делать это намного лучше. DRY - это не просто небольшое нарушение синтаксиса. Это бросает мне вызов модульности. Это бросает мне вызов, чтобы компонентировать. Это сигнал повторения, который напоминает мне подумать об использовании шаблонов и генерации кода вместо грубой силы и невежества. Это помогает мне понять, что я должен найти время для автоматизации своей автоматизации. Это приводит вас к скупому образу жизни! Это помогает вам тратить больше времени на создание более крутых новых вещей, а не придирчивых старых скучных деталей. И это дает вам хорошие манеры, хорошее дыхание и здоровый образ жизни! Ну, может быть, я немного сбился с пути ...
источник
У меня есть старый устаревший проект, где некоторые из бывших разработчиков вообще не заботились о DRY. Таким образом, вся кодовая база была загромождена вспомогательными методами, такими как GetSystemTimeAsString (), LogToFile () и множеством других вещей. Некоторые методы были слегка адаптированы к особым потребностям, но большинство было просто копировать и вставлять.
К сожалению, некоторые методы имели небольшие ошибки, такие как char массив, в некоторых случаях недостаточно длинные, используя небезопасные вещи, такие как strcpy () и т. Д.
Так что это была настоящая PITA, чтобы найти все фрагменты кода, согласовать их и исправить ошибки. И мы все еще гармонизируем и исправляем вещи.
Вы никогда не узнаете, допустили ли вы ошибку в первом методе, а затем должны были исправить ее несколько раз, потому что вы просто скопировали ее. И если вы хотите использовать некоторые методы позже, как вы узнаете, какой из 5 методов в кодовой базе является подходящим для вашего случая сейчас? Итак, вы просто копируете один, настраиваете его, и вот оно начинается снова ...
источник
Да, не беспокойтесь о DRY, если вы пишете Throwaway Code .
Но DRY важен, конечно, если вы планируете сохранить код.
источник
Фраза «не повторяйся» немного упрощена. Что важно, так это «избегайте инкапсулирования одной части потенциально изменяемой информации в двух независимых местах».
Если программа должна обрабатывать виджеты, каждый из которых имеет три woozles, и имеет много циклов вида
тогда ожидание того, что виджеты будут содержать три woozles, будет инкапсулировано в каждом из этих циклов, и обновление кода для размещения любого другого количества woozles на виджет может быть затруднено. Для сравнения
и каждый цикл был переписан
Такой дизайн может очень легко изменить количество woozles для виджета.
Тем не менее, важно отметить, что, хотя желательно объединить информацию, такую как количество вузлов на виджет, в одну точку, это не всегда практично. Иногда может быть необходимо жестко закодировать логику, которая будет работать, только если вещи определенного размера. Например, если у каждого woozle есть значение, и кто-то хочет найти медиану, связанную с конкретным виджетом, может быть возможно отсортировать значения и выбрать средний, и такой подход будет работать с любым количеством woozles, но логика который написан от руки специально, чтобы найти медиану из трех пунктов, может быть значительно быстрее.
Хотя наличие константы WOOZLES_PER_WIDGET может сделать код более читабельным, его следует прокомментировать, чтобы было ясно, что его значение нельзя изменить без внесения других изменений в логику программы. В этом случае логика, жестко закодированная для трех элементов, и константа WOOZLES_PER_WIDGET будут дублировать информацию «каждый виджет имеет три woozles», но преимущества такого дублирования (более высокая скорость выполнения) могут перевесить стоимость.
источник
Хотя я на самом деле согласен с другими авторами комментариев о ремонтопригодности и т. Д., Все они действительны.
Я хотел бы добавить небольшой несогласный голос к дискуссии.
источник
<tl;dr>
Я не мог прочитать все повторяющиеся ответы, поэтому я, возможно, что-то пропустил (и я сам повторю это <= посмотри, что я здесь сделал?).
Вот список вещей, которые удивительны в отношении предотвращения дублирования кода!
doFoo1(a, b)
, существует большая вероятность, что многие из ее назойливых ошибок и крайних случаев будут обнаружены и устранены. Если все копируют код и создаютdoFoo2(specialA)
...doFuu2^n(a, b, c)
тогда они дублируют проблемыdoFoo1
и конкретно создают намного больше работы.</tl;dr>
Длинная версия:
Проблема с дублированием кода заключается в том, что он «растет в геометрической прогрессии» (другими словами, он быстро расширяется), потому что, когда вы дублируете код, вы неосознанно предоставляете другим разрешение (например, вы больше не можете судить их) и вы поощряете их делать то же самое. Вы также усложняете задачу, потому что трудно найти и повторно использовать полезный код, когда в источнике много запутанных избыточных повторений. Особенно, если код еще не извлечен в метко названную функцию. Так что, если вы столкнулись с общей проблемой, которую легко решить, вы, вероятно, сами напишете фрагмент кода, который решит ее ... И вам, вероятно, не удастся проверить несколько крайних случаев, добавив еще больше глючного непроверенного кода.
Другое дело, что для новичка это может звучать как проблема, которая затронет только крупные компании, но я обнаружил, что она очень сильно поражает крошечные стартапы (как в 10 000 строк дублированного кода на стороне сервера). Это состояние души. Вы должны не только овладеть СУХОЙ, но и стремиться побуждать других делать то же самое; потому что в противном случае вы обрекаете себя на дублирование кода. Когда средства СУХОЙ находятся под рукой и применяются, их гораздо легче применять. При наличии большого количества дублированного кода гораздо проще применять решения копирования-вставки.
Вещи, которые я считаю вредными при дублировании кода:
Последние замечания о предотвращении дублирования кода и подведении итогов:
Это также было сказано ранее, но иногда избегание дублирования заставляет вас «наклоняться назад» и делать вещи, которые слишком сложны (или не важны), чтобы другие могли их понять. Написание нечитаемого кода (или, как мы в шутку называем его «код, сохраняющий работу») само по себе является проблемой, даже если не требуется предотвращение дублирования кода. Тем не менее, я обнаружил, что если с самого начала внедрять правильную инфраструктуру и лучшие практики, намного проще предотвратить дублирование кода, и люди часто могут избегать неинтуитивных действий, чтобы предотвратить будущие ненужные и нечитаемые кучи работы, выполненные для предотвращения дублирования кода, если вы делаете все правильно с самого начала.
Что делает все правильно? Что ж, на этот вопрос сложно ответить, но одно - определить, какие методы необходимы для проекта, посмотреть, что уже было реализовано другими (вне и внутри) внутри компании, и использовать это, когда это возможно; документирование всего, что вы добавляете в кодовую базу, и попытка сделать его на одну ступеньку более общим, чем должно быть, но это все. Не переусердствуйте с шаблонами проектирования, просто чтобы сделать код гибким там, где он не должен быть.
источник