(Оригинал текста на английском языке находится здесь. Перевод на русский язык — Александр Бельченко, 7 января 2005.)

Существует море информации о том, как нужно писать исходный код программ. В этом тексте вы найдете несколько советов о том, как его удалять.

Самый лучший способ удалять исходный код

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

Выделите участок кода в вашем редакторе, нажмите клавишу Backspace, и покончите с этим.

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

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

Таким разработчикам я скажу: "Use the source (control), Luke" [1]. Использование систем управления версиями (таких как CVS, Perforce, или Subversion), означает, что вам никогда не придется беспокоиться о том, что однажды сделанная работа может исчезнуть навсегда. Весь ваш старый код будет лежать в CVS, готовый к повторному использованию по первому же требованию.

Если у вас нет системы управления версиями (!?!?!) или у вас просто нет охоты копаться в старых ревизиях, то скопируйте кусок вашего кода в отдельный файл и сохраните его в отдельном месте. Но не оставляйте его там, где ему совсем не место — в вашем исходном тексте.

Почему это так важно?

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

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

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

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

Закомментированный код

Очень легко закомментировать одну или две строки кода (или даже двадцать строк!):

//  OldWayStepOne(fooey);
//  OldWayStepTwo(gooey);
    NewWay(fooey, gooey);

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

Будущие разработчики, посмотрев на этот код, увидят, что когда-то использовался старый вариант OldWay, также они увидят, что теперь работает новый вариант NewWay, но они не будут знать, почему старый вариант OldWay оставлен рядом:

  • Возможно, новый вариант NewWay всего лишь эксперимент? Если так, то чем он лучше старого? Как и когда должно быть принято окончательное решение: оставлять его или возвращаться к старому?
  • Возможно, старый вариант лучше, но вместе с ним что-то работает не так? Если так, то что именно не так? И причина этих непоняток кроется в самом коде OldWay, или в том, как этот код вызывается? Когда эти непонятки будут устранены?
  • Возможно, проект изменился, и старый вариант OldWay выполняет ненужную работу?

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

Не закрывайте комментариями куски кода, не сказав (в комментариях) зачем и почему.

Не лучше ли сделать так?:

//  OldWay работал лучше, но слишком неэффективно, и до тех пор, пока
//  не будет переработан MumbleFrabbitz, мы будем использовать
//  NewWay до этапа M4.
//    OldWayStepOne(fooey);
//    OldWayStepTwo(gooey);
    NewWay(fooey, gooey);

Кто может сказать сегодня, будет ли на самом деле переработан MumbleFrabbitz к этапу M4? Может быть и не будет. Это нормально; кто знает, что день грядущий нам готовит? По крайней мере, этот вариант поможет разработчикам понять, почему старый код оставлен рядом. Имея на руках информацию о том, почему внесены изменения, и почему старый код все еще оставлен здесь, разработчики смогут понять, когда они смогут окончательно перейти на новый вариант NewWay, или когда они смогут вернуться назад к более удачному решению.

Условная компиляция

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

#if 0
    OldWayStepOne(fooey);
    ...
    OldWayStepTwenty(hooey);
#endif

Для языка Python:

if 0:
    OldWayStepOne(fooey)
    ...
    OldWayStepTwenty(hooey)

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

Здесь применимо тоже правило, что и для комментирования кода:

Не отключайте код директивами условной компиляции, не объяснив почему.

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

В компании Lotus исходные тексты для программы Notes содержали много фрагментов кода, отключенного при помощи директивы "#ifdef LATER", исходя из (корректного) предположения, что символ препроцессора "LATER" нигде не определен. Этот вариант — очень слабая форма документирования; он показывает, что код пока еще не готов к компиляции, но будет готов позднее. Но когда? Среди разработчиков ходила шутка о том, что надо определить символ "LATER" и посмотреть, что из этого получится!

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

Невызываемый код

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

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

Оставляйте подсказки

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

//  (Здесь использовался другой алгоритм, который использовал хеширование
//   и работал быстрее, но он имел проблемы с синхронизацией. Если он
//   вам нужен, то он в ревизии 1.16 или ранее в файле ThingMap.java в CVS.)

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

Случайный мусор

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

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

Простое соглашение подобное этому:

//- OldWayImUnsureOf(zooey);

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

Вы также можете использовать подобный подход и для больших участков кода:

#if 0 //- Я думаю, что это не нужно, если использовать FooBar
    OldWayStepOne(fooey);
    ...
    OldWayStepTwenty(hooey);
#endif

Поддерживайте порядок

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

if (bDoThing) {
    OldWay();
}

Следует не только удалить строку с вызовом OldWay. Точно также следует удалить и пустой условный блок. Если флаг bDoThing проверяется только в этом месте, то удалите и его. Просмотрите код, который устанавливал этот флаг. Он уже устарел? Удаляйте и его. Будьте безжалостны. Поддерживайте порядок в коде. Убедитесь, что в вашем коде не осталось странных мест и тупиков, назначение которых невозможно понять, не зная, что здесь было раньше.

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

Don't worry, be happy

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

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

См. также

  • Erroneously empty code paths, об ошибках при программировании защитного кода.
  • Fix error handling first, о том, как важно, чтобы ваш обработчик ошибок всегда работал наилучшим образом.
  • Мой блог, в котором обсуждаются и другие похожие вопросы

Комментарии переводчика

  1. Use the source (control), Luke — смысл этой фразы состоит в том, что автор призывает обязательно пользоваться системами контроля версий (source control) в своей работе. Здесь используется игра слов, и видна явная параллель с известной фразой "Use the source, Luke" (UTSL), по смыслу аналогичной RTFM, только она относится к чтению исходников. Само же выражение "Use the source, Luke" произошло от "Use the force, Luke" ("Используй силу, Люк") — так в фильме "Звездные войны" Оби ван Кеноби поучал юного Люка Скайуокера.
  2. Don't worry, be happy — "Не волнуйся и будь счастлив", название широко известной жизнерадостной песни, автор Bobby McFerrin.

Comments

[gravatar]
ExplodeMan 9:54 AM on 2 Feb 2005

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

[gravatar]
Alexander Belchenko 10:32 AM on 3 Feb 2005

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

Add a comment:

name
email
Ignore this:
not displayed and no spam.
Leave this empty:
www
not searched.
 
Name and either email or www are required.
Don't put anything here:
Leave this empty:
URLs auto-link and some tags are allowed: <a><b><i><p><br><pre>.