Эффект последней строки, или К чему приводит копипаст

Рассказывает автор блога HOW NOT TO CODE


Я повидал много ошибок, связанных с методом «Копировать-вставить», и из всех них извлек один вывод: в большинстве случаев ошибка допускается в последнем копипастном фрагменте. Я ни разу не видел описания этого феномена в книгах и поэтому дал ему название сам — «эффект последней строки».

Введение

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

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

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

Эффект последней строчки

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

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

Вот простой пример:

Обратите внимания на строчку z += other.y;. Программист забыл исправить y на z.

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

Где-то я слышал, что альпинисты часто срываются на последних десятках метров своего восхождения. Не потому, что они устали: они просто слишком обрадованы тем, что вершина почти достигнута — они уже чувствуют сладкий вкус победы, теряют концентрацию и совершают фатальную ошибку. Я думаю, что с программистами случается примерно то же самое.

Вот еще примеры.

Пролистывая свою базу багов, я нашел 84 фрагмента кода, ошибки в которых вызваны многострадальным копипастом. Из них в 41 фрагменте ошибки содержатся где-то в середине блока скопированных и вставленных строк:

Длина строки "THREADS=" равна 8, а не 6.

В остальных 43 случаях ошибки находились в последней строке.

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

Допустим, что длина нашего однородного блока равна 5. Получается, что в первых четырех блоках будет 41 ошибка — в среднем по 10 на блок. И только на один последний блок придется 43 ошибки!

Итак, какую закономерность мы вывели:

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

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

Примеры

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

Source Engine SDK

В конце должна была быть вызвана функция SetW().

Chromium

Последний блок идентичен предпоследнему.

Multi Theft Auto

Последняя строка была вставлена чисто механически — в этом блоке должно было быть только 3 строчки.

Source Engine SDK

Программист забыл в конце заменить BackgroundColor.y на BackgroundColor.z.

Trans-Proteomic Pipeline

В последнем условии программист забыл заменить prob > max6 на prob > max7.

SeqAn

ReactOS

Переменная mjstride окажется всегда равной 1. Вот как должна была выглядеть последняя строчка:

Mozilla Firefox

Строка с ftp в конце лишняя — она уже повторялась выше.

Quake-III-Arena

В последней строке должно быть dir[2].

Clang

В самом конце блока выражение SM.getExpansionColumnNumber(ContainerREnd) сравнивается с самим собой.

Выводы

Из этой статьи вы узнали, в чем опасность метода копипаста — ошибка чаще всего совершается в самом конце. Я думаю, причина этого кроется в человеческой психологии, а не профессиональных навыках. То, что вы увидели выше, написали не новички, а высокопрофессиональные разработчики проектов вроде Clang или Qt.

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

Источник: блог How Not To Code