Является ли копирование и вставка кодированием когда-либо приемлемым?

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

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

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

Ответы

Ответ 1

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

Ответ 2

Задайте этот вопрос о своих функциях

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

Ответ 3

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

Средний случай - использовать макрос, если у вас есть такой доступный.

Ответ 4

Да, и это точно так же, как вы говорите; незначительные, но жесткие вариации. Не жуйте себя, если это действительно то, что требует ситуация.

Ответ 5

Re Допустимо ли разрезание и прошлое:

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

Отрезки, похожие на похожие, но не совсем похожие:

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

Например, если у вас есть сегмент кода, который отличается в двух сегментах - diff # 1 и diff # 2. И в diff # 1 вы можете иметь diff1A или diff1B, а для diff # 2 вы можете иметь diff2A и diff2B.

Если diff1A и diff2A всегда вместе, а diff1B и diff2B всегда вместе, то diff1A и diff2A могут содержаться в одном командном классе или в одной абстрактной реализации шаблона, а diff1B и diff2B - в другом.

Однако, если есть несколько комбинаций (то есть diff1A и diff2A, diff1A и diff2B, diff1B и diff2A, diff1B и diff2B), тогда вы можете переосмыслить свою функцию, потому что она может пытаться самостоятельно выполнять слишком много обязанностей.

Операторы Re SQL:

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

Например:

private static final String EMPLOYEE_COLUMNS = " id, fName, lName, status";

private static final String EMPLOYEE_TABLE = " employee";

private static final String EMPLOYEE_HAS_ACTIVE_STATUS = " employee";

private static final String GET_EMPLOYEE_BY_STATUS =
  " select" + EMPLOYEE_COLUMNS + " from" + EMPLOYEE_TABLE + " where" + EMPLOYEE_HAS_ACTIVE_STATUS;

private static final String GET_EMPLOYEE_BY_SOMETHING_ELSE =
  " select" + EMPLOYEE_COLUMNS + " from" + EMPLOYEE_TABLE + " where" + SOMETHING_ELSE;

Ответ 6

В моей базе кода компании у нас есть около 10 или около того больших волосатых операторов SQL, которые имеют высокую степень общности. Все утверждения имеют общее ядро ​​или, по крайней мере, ядро, которое отличается только словом или двумя. Затем вы можете сгруппировать 10 операторов в 3 или 4 группы, которые добавляют общие придатки к ядру, опять же с одним или двумя словами, разными в каждом придатке. Во всяком случае, подумайте о 10 операторах SQL как наборов на диаграмме Венна со значительным перекрытием.

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

Код умный, поскольку ни один из SQL не повторяется. Если вам когда-либо понадобится изменить предложение в SQL, вы измените его только в одном месте, и все 10 SQL-операторов будут соответствующим образом изменены.

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

С момента написания этого вопроса, я часто задавался вопросом, было бы лучше, если бы просто вырезать и вставлять SQL-запрос 10 раз. Конечно, если бы мы это сделали, любые изменения в SQL могли возникнуть в 10 местах, но комментарии могли бы помочь нам указать на 10 мест для обновления.

Преимущество того, что SQL понятно и все в одном месте, вероятно, перевешивает недостатки вырезания и вставки SQL.

Ответ 7

Как предполагает Мартин Фаулер,

сделайте это один раз, отлично.

сделать это дважды, начинает пахнуть.

Сделайте это три раза, время refactor.


РЕДАКТИРОВАТЬ: в ответ на комментарий, происхождение совета - Дон Робертс:

Три удара и рефакторинг.

Мартин Фаулер описывает это в главе Рефакторинг главы 2, "Правило трех" (стр. 58).

Ответ 8

АБСОЛЮТНО NEEEVER..

:)

Вы можете опубликовать этот код и посмотреть, что это проще, чем то, что выглядит как

Ответ 9

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

Недавно у меня была функция add() и функция edit() в PHP script. Они оба сделали практически то же самое, но функция edit() выполнила запрос UPDATE вместо запроса INSERT. Я просто сделал что-то вроде

function add($title, $content, $edit = false)
{
    # ...
    $sql = edit ? "UPDATE ..." : "INSERT ...";
    mysql_unbuffered_query($sql);
}

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

Ответ 10

  • Хороший код - код многократного использования.
  • Не изобретайте велосипед.
  • Примеры существуют по какой-то причине: чтобы помочь вам учиться и в идеале лучше кода.

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

Это из лени? "Бла-бла, я сделал это раньше... Я только меняю несколько имен переменных.. сделал".

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

Это потому, что вы не понимаете? "Черт.. Я не понимаю, как работает эта функция, но мне интересно, будет ли она работать в моем коде.." Это может быть! Это может сэкономить ваше время в тот момент, когда вы подчеркнули, что у вас установлен крайний срок в 9 часов утра, и вы смотрите на красные глаза на часы около 4 утра.

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

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

Ответ 11

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

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

#define RETPOS(E) do { if ((E) > 0) then return; } while(0)

но это требование является необходимостью. Я часто использую препроцессор C, несмотря на его недостатки, потому что он не добавляет еще один элемент в toolchain и поэтому не требует изменения процесса сборки или Make файлов.

Ответ 12

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

Ответ 13

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

Ответ 14

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