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

57

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

API агентства является наиболее полным, поскольку он имеет все функциональные возможности ... затем немного меньше Home API, а затем мобильный API.

Здесь архитекторы создали общий уровень (многоканальные EJB-сервисы, используемые всеми API). Но тогда API-интерфейсы разные.

Между API нет большой разницы. Большая команда начинала с канала агентства, и сейчас мы адаптируем ее для домашнего канала. Мы просто обогащаем объекты специально для нашего домашнего приложения. В противном случае код на 95% похож между API. API построен на основе Spring MVC и имеет (контроллеры, модели и некоторые утилиты).

В основном контроллеры выполняют сопоставление BO с ChannelObject (мне кажется, это не подходящее место), а также некоторые дополнительные утилиты и сериализаторы. На данный момент все дублировано. Они говорят, что причина дублирования в том, что они хотят, чтобы API были независимыми. «Если завтра мы хотим другого поведения для дома, чем агентство или мобильный, мы не будем бороться !!»

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

Мохамед Амин Мрад
источник
22
И если в будущем наступит три завтрашних дня, они решат, что им нужен постоянный доступ к данным и представление между всеми API-интерфейсами ... ну ... "Борьба!"
Becuzz
26
Дублирующий код не обязательно плохая вещь. Поговорка «СУХОЙ - враг разъединения» не может быть подчеркнута достаточно. Хавинг сказал, что проектирование для будущего, а не для настоящего, действительно очень плохая вещь. Это будущее почти никогда не сбывается. Вместо этого, разработайте решение с высокой степенью развязки, покрытое хорошими автоматизированными тестами того, что нужно сейчас. Тогда, в будущем, если потребуется что-то другое, это будет легче изменить.
Давид Арно
2
Я думаю, что два случая, когда я никогда не сожалел о дублировании кода, это (а) когда дублированный код является очень маленькой и не очень важной частью общего количества, и (б) когда я копирую код из системы, которая уже умирает в новую систему, предназначенную для долголетия. Есть много других случаев, когда я плакал горькими слезами после разветвления кода.
Майкл Кей,
14
Там, где я работал, часто отмечалось, что нужно (часто) дублировать один раз, а в третий раз абстрагироваться от общности. Это устраняет дух времени для ранней, возможно, неуместной абстракции, которая увеличивает связь вместо сплоченности. Когда будущие требования действительно хорошо поняты, конечно, могут быть сделаны исключения.
Питер Гиркенс
3
Один тривиальный случай, когда повторяющийся код может быть приемлемым, это если он генерируется автоматически
samgak

Ответы:

70

Дублирование может быть правильным, но не по этой причине.

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

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

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

Килиан Фот
источник
1
Если две вещи ведут себя одинаково, это дублирование. Хотя, если они не ведут себя одинаково по причине, они не должны быть объединены. Можно ли извлечь какую-то общую часть реализаций? Иногда есть строительные блоки, еще не абстрагированные, кто знает.
Дедупликатор
32
В качестве примера, у нас был кусок кода, используемый тремя частями нашего приложения, и он был довольно ужасно написан с множеством небольших условных веток повсюду, чтобы покрыть исключения для каждой из этих трех. Но , и это был важный момент, он интенсивно использовался в течение двух лет без каких-либо значительных сообщений об ошибках. Поэтому, когда четвертой части приложения нужно было что-то с ней сделать, но опять-таки немного по-другому, было принято решение просто не касаться некорректного кода, который работал безупречно, а просто скопировать его и создать лучше написанную, гибкую базу для будущее.
KRyan
2
Дублирование - это то, что нужно делать, когда затраты на читаемость возрастают слишком высоко по сравнению с затратами на обслуживание, которые в конечном итоге связаны друг с другом. Я не думаю, что это применимо вообще в этом сценарии, и часто наблюдается в меньшем масштабе в проекте, а не что-то подобное. Даже тогда очень редко вы попадаете в ситуацию, в которой это когда-либо имеет место, это произойдет, если у вас будет какое-то вложенное нишевое дублирование, которое заставит вас использовать шаблонный метод шаблона или тому подобное, но в небольших местах. Это обычно приводит к запутыванию кода.
опа
Пример , где дублирование полезно (и «удаление его yould быть в целом более дорогостоящим предприятием ») вводится valdation в веб - приложениях: Мы используем первый (возможно упрощенную) проверку на клиенте , так что пользователь получает немедленную обратную связь о проблемах; и затем мы делаем ту же (или более тщательную) проверку на сервере, потому что клиентам нельзя доверять.
Хаген фон
3
@HagenvonEitzen Но это не обязательно должно быть дублирование, в зависимости от стека технологий. Например, у вас может быть вход для проверки JavaScript в браузере, а затем проверка на Java на сервере, поэтому вы дублируете функциональность. Но если бы вы запускали Node.js на сервере, вы могли бы использовать одну и ту же проверку JavaScript в браузере и на сервере, исключая дублирование. Вы по-прежнему хотите, чтобы код выполнялся в нескольких местах (в доверенной и недоверенной среде), но код не обязательно должен дублироваться.
Джошуа Тейлор
87

У Сэнди Метц, известного разработчика программного обеспечения и автора экосистемы Ruby, есть отличное сообщение в блоге и доклад, в котором она также рассказывает о связи между дублированием и абстракцией. Она приходит к следующему выводу

дублирование намного дешевле, чем неправильная абстракция

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

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

larsbe
источник
23
Ах, да, если вы не можете вывести обобщенные правила, попытка абстрагировать их может только провалиться. И если корреспонденция случайна, она может быть недолгой.
Дедупликатор
5
Изменение абстракции может быть дорогостоящим, когда оно будет на месте, но избавиться от дублирования, как только оно будет на месте, может быть еще больше проблем. Конечно, это во многом зависит от языка и т. Д. - современные системы со строгим статическим типом могут помочь вам получить даже крупномасштабные изменения в правильной абстракции. Синхронизация дублированных функций, однако, не является чем-то, с чем система типов может вам сильно помочь (потому что дубликаты для системы типов просто разные). Но я полагаю, что в динамических языках типа утка все наоборот; так что это может иметь смысл для Руби.
оставлено около
34

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

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

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

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

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

Док Браун
источник
3
Еще больший предупреждающий знак, чем «если завтра» для меня - «Это никогда не изменится»
abuzittin gillifirca
@abuzittingillifirca: а какое это имеет отношение к вопросу или моему ответу?
Док Браун
1
Я оспариваю ваш первый абзац.
abuzittin gillifirca
2
@abuzittingillifirca: хорошо, прочитайте вопрос еще раз: речь идет о рассуждении с аргументом «если завтра» для обоснования решения о дублировании, которое трудно отменить , поэтому сделать программное обеспечение на самом деле труднее изменить в определенных случаях. Это может быть немного нелогично, но лучший способ сохранить изменчивость программного обеспечения в будущем - это не делать какие-либо (возможно, ошибочные) предположения о будущем, а сохранять программное обеспечение как можно более компактным и твердым.
Док Браун
13

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

Таким образом, вы платите цену дублированного кода, чтобы получить автономию и независимость.

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