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

Любая действительная причина дублирования кода?

В настоящее время я просматриваю очень старый проект на С++ и вижу там много дубликатов кода.

Например, существует класс с 5 обработчиками сообщений MFC, каждый из которых содержит 10 одинаковых строк кода. Или есть 5-строчный фрагмент для очень конкретного преобразования строк каждый здесь и там. Сокращение дублирования кода не является проблемой в этих случаях вообще.

Но у меня странное чувство, что я могу что-то недопонимать и что изначально была причина для этого дублирования.

Что может быть веской причиной дублирования кода?

4b9b3361

Ответ 1

Когда я впервые начал программировать, я написал приложение, в котором у меня была куча аналогичной функциональности, которую я завернул в аккуратную небольшую функцию 20-30... Я очень гордился собой за то, что написал такую ​​элегантную часть код.

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

Через год, когда меня попросили сделать что-то очень похожее, я сознательно решил игнорировать СУХОЙ. Я собрал основной процесс и сгенерировал все дубликаты кода. Дублированный код был задокументирован, и я сохранил шаблон, используемый для генерации кода. Когда клиент запросил конкретные условные изменения (например, если x == y ^ z + b, то 1 + 2 == 3.42), это был кусок пирога. Это было невероятно легко поддерживать и изменять.

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

Ответ 2

Хорошим прочтением этого является крупномасштабный дизайн программного обеспечения С++ от Джона Лакоса.

У него много хороших примеров дублирования кода, где это может помочь или помешать проекту.

Самый важный момент заключается в том, чтобы решить, как удалить дубликат или дублировать код:

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

В конце концов, методы содержат (бизнес) логику, а иногда вы хотите изменить логику для каждого вызывающего, иногда нет. Зависит от обстоятельств.

В конце концов, все дело в обслуживании, а не о хорошем источнике.

Ответ 3

Лень, это единственная причина, о которой я могу думать.

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

Все еще оставляет плохой вкус во рту.

Ответ 4

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

Нет времени для правильного рефакторинга

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

Обобщение кода невозможно/не "довольно" из-за языковых ограничений

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

Вы не уверены, что вообще будет обобщение

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

Я добавлю больше, если вспомню что-то еще.


Добавлено позже...

Развертка Loop

За время, прошедшее до того, как компиляторы были умны, поскольку вместе с Эйнштейном и Хокингом, вам приходилось разворачивать циклы или встроенный код быстрее. Развертка Loop заставит ваш код дублироваться и, вероятно, быстрее на несколько процентов, его компилятор в любом случае не сделал этого для вас.

Ответ 5

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

Do_A_Policy()
{
  printf("%d",1);
  printf("%d",2);
}

Do_B_Policy()
{
  printf("%d",1);
  printf("%d",2);
}

Теперь вы можете предотвратить "дублирование кода" с такой функцией:

first_policy()
{
printf("%d",1);
printf("%d",2);
}

Do_A_Policy()
{
first_policy()
}

Do_B_Policy()
{
first_policy()
}

Однако существует риск того, что какой-нибудь другой программист захочет изменить Do_A_Policy() и сделает это, изменив first_policy() и вызовет побочный эффект изменения Do_B_Policy(), побочного эффекта, о котором может не знать программист. поэтому такой "дублирование кода" может служить механизмом безопасности в отношении таких будущих изменений в программе.

Ответ 6

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

Ответ 7

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

Пример (псевдокод):

procedure setPropertyStart(adress, mode, value)
begin
  d:=getObject(adress)
  case mode do
  begin
    single: 
       d.setStart(SingleMode, value);
    delta:
       //do some calculations
       d.setStart(DeltaSingle, calculatedValue);
   ...
end;

procedure setPropertyStop(adress, mode, value)
begin
  d:=getObject(adress)
  case mode do
  begin
    single: 
       d.setStop(SingleMode, value);
    delta:
       //do some calculations
       d.setStop(DeltaSingle, calculatedValue);
   ...
end;

Вы могли бы как-то реорганизовать вызов метода (setXXX), но в зависимости от языка это может быть сложно (особенно с наследованием). Это дублирование кода, так как большая часть тела одинакова для каждого свойства, но может быть сложно реорганизовать общие части.

Короче говоря, если рефакторированный метод является более сложным фактором, я бы пошел с дублированием кода, хотя он "злой" (и останется злым).

Ответ 8

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

Это, конечно, когда пришло время отделить этот общий сегмент кода от новой функциональности.

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

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

Ответ 9

Для такого рода дублирования кода (много строк повторяется много раз), я бы сказал:

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

Возможно, первое решение, однако, из того, что я обычно видел: - (

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

Разделение кода на несколько функций, повторное использование кода правильным способом и все, что часто приходит с опытом - или вы не наняли правильных людей; -)

Ответ 10

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

Однако в этом случае я не думаю, почему они это делали, хе.

Ответ 11

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

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

Ответ 12

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

Ответ 13

Похоже, что оригинальный автор был неопытным и/или был сильно нажат вовремя. Большинство опытных программистов объединяют вещи, которые используются повторно, потому что позже будет меньше обслуживания - форма лени.

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

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

Ответ 14

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

Откидывается до лени или плохой практики обзора.

ИЗМЕНИТЬ:

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

Вы просмотрели историю изменений в файле?

Ответ 15

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

Ответ 16

У меня нет проблем с дублированным кодом, когда он создается генератором исходного кода.

Ответ 17

Что-то, что мы обнаружили, что вынудило дублировать код, было нашим кодом манипуляции с пикселями. Мы работаем с ОЧЕНЬ большими изображениями, а накладные расходы на функции выходили из порядка 30% нашего времени на пиксель.

Дублирование кода манипуляции с пикселями дало нам на 20% быстрее обход изображения за счет сложности кода.

Это, очевидно, очень редкий случай, и, в конце концов, он сильно раздул наш источник (300-строчная функция теперь составляет 1200 строк).

Ответ 18

Нет причин для дублирования кода.

См. шаблон Refactor безжалостно.

Оригинальный программист либо спешил встретить крайний срок, либо ленив. Не стесняйтесь рефакторировать и улучшать код.

Ответ 19

по моему скромному мнению нет места для дублирования кода. посмотрите, например, на эту статью в википедии

или, позвольте сослаться на цитату Ларри Уолла:

"Мы будем поощрять вас развивать три великих достоинства программиста: лень, нетерпение и высокомерие".

довольно ясно, что дублирование кода не имеет ничего общего с "лень". ха;)

Ответ 20

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