Подтвердить что ты не робот

Является ли нарушение принципа DRY всегда плохим?

Я обсуждал принцип DRY (не повторяю себя), также известный как DIE (Duplication Is Evil), и есть голоса, что любое простое повторение кода всегда зло. Я хотел бы услышать ваше мнение о следующих моментах:

  • Неопределенное будущее. Скажем, что у нас одинаковый код в двух местах. Ключ в том, что эти два места имеют только случайную коннотацию. Есть вероятность, что они будут меняться в будущем, потому что их контекст и семантика различны. Создание абстракции из этих мест не является дешевым, и если одно из этих мест изменится, разворот от абстракции будет еще более дорогим.
  • читаемость. Существует сложное вычисление, которое включает несколько переменных или шагов. В другом месте кода есть еще один, который имеет некоторые части идентичные. Проблема в том, что если мы выберем общие части, читаемость расчета уменьшится, а созданная абстракция будет очень сложной, чтобы дать ей описательное имя. Хуже того, если какая-то часть алгоритма изменится в будущем, как в пункте 1.

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

4b9b3361

Ответ 1

Это полностью обоснованные причины нарушения DRY. Я должен добавить третью: производительность. Это редко бывает большой проблемой, но это может изменить ситуацию, и абстракция может замедлить работу.

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

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

Ответ 2

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

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

Короче говоря: старайтесь избегать дублирования; если дублирование, как известно, трудно учесть и во время написания безвредности, просто оставьте комментарий в качестве напоминания.


См. также 97 вещей, которые должен знать каждый программист:

р. 14. Остерегайтесь Share by Udi Dahan

Тот факт, что две совершенно разные части системы выполняли некоторую логику таким же образом означало меньше, чем я думал. До тех пор, пока я не вытащил эти библиотеки общего кода, эти части не зависели друг от друга. каждый может развиваться самостоятельно. Каждый может изменить свою логику в соответствии с потребностями систем, изменяющих бизнес-среду. Эти четыре строки аналогичного кода были случайно - временная аномалия, совпадение.

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

Ответ 3

Попробуем понять, почему DRY важен, и тогда мы можем понять, где нарушение правила разумно:

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

Представьте, что в вашей программе есть такая строка:

cost = price + price*0.10 // account for sales tax

и где-то еще в вашей программе, у вас есть аналогичная строка:

x = base_price*1.1; // account for sales tax

Если налог с продаж изменится, вам нужно будет изменить обе эти линии. Здесь почти нет повторного кода, но тот факт, что если вы вносите изменения в одно место, это требует изменения в другом месте, что делает код не сухим. Что еще, может быть очень сложно понять, что вы должны внести изменения в два места. Возможно, ваши юнит-тесты поймают его, но, возможно, нет, поэтому важно избавиться от дублирования. Возможно, вы будете учитывать стоимость налога с продаж в отдельной константе, которая может использоваться в нескольких местах:

cost = price + price*sales_tax;
x = base_price*(1.0+sales_tax);

или, возможно, создать функцию, чтобы абстрагировать ее еще больше:

cost = costWithTax(price);
x = costWithTax(base_price);

В любом случае, это, скорее всего, будет стоить того.

Кроме того, у вас может быть код, который выглядит очень похожим, но не нарушает DRY:

x = base_price * 1.1; // add 10% markup for premium service

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

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

a0 = f(0);
a1 = f(1);

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

Есть много веских причин сделать ваш код СУХОЙ, но есть много веских причин, чтобы не делать этого.

Ответ 4

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

Ответ 5

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

Ответ 6

За отличным ответом на этот вопрос, пожалуйста, обратитесь к "Прагматическому программисту" Томаса, Хант (это был Дейв Томас, который вначале придумал термин "Сухой" )

Короче говоря, нет простого ответа, почти всегда лучше оставаться сухим, но если он улучшает читаемость, тогда вы должны использовать свое лучшее суждение, это ваш звонок!

Ответ 7

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

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

Я также считаю, что абстракция к композиции почти всегда является лучшей идеей в этом отношении, чем абстрагирование к наследованию, которое может легко привести вас к ложным уравнениям и LSP и ISP.

Ответ 8

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