Pull to refresh

Comments 61

Хуже «мертвого» кода может быть только простыня из закомментированного кода
Ну она хотя бы сразу в глаза бросается и не прикидывается чем-то реально работающим

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

А кто сказал, что к моменту использования комментированного кода его тесты будут актуальны?

Разумеется, речь шла о мёртвом, но незакоментированном коде, иначе тесты не имеют смысла. Моё мнение насчёт закоментированного кода: его быть не должно. Системы контроля версий всегда помогут восстановить удалённый код, а закомментированный код хуже, чем удалённый, по указанным выше причинам — к тому же, он занимает драгоценное место в исходниках, мозоля глаз.

Здравствуйте.
Целиком и полностью поддерживаю озвученную Вами позицию относительно удаления закоментированного кода. Однако, я сталкивался с тем, что некоторые разработчики считают, что это код там очень нужен, и если он мне мешает, я могу удалить его в своей локальной копии, а в репозитории пусть лежит всё целиком. Я вижу оправдание этому только в случае, если такой закоментированный код, во-первых, не содержит сложной логики, например, представляет собой какой-то отладочный вывод, который лениво набивать вновь, либо содержит наброски решения с соответствующим комментарием, т.е., фактически, является псевдокодом, и, во-вторых, будет в результате удалён сразу после того, как какая-либо необходимость в нём отпадёт.
UFO just landed and posted this here
О да.
У меня на работе хоть и есть git, но старый код почему-то не удаляется.
Типа, а вдруг потом потребуется. :)
UFO just landed and posted this here

Есть термин "code smell", а smell code выглядит как указание к действию

В компилируемых языках вполне можно #define`ами отрезать ненужные для конкретного случая куски кода.
Выжигать надо только то, что уже ТОЧНО не нужно.
Про #define в статье упоминалось
возможно, тот, кто вносит изменения не считает, что код должен исчезнуть навсегда и комментирует его или добавляет условную компиляцию.

Только если какой то код вообще не нужен, то нет смысла его оставлять. Вся проблема в том чтобы найти такой код.
Код бывает разный. Например, код программируемого микроконтроллера. На базе одного микроконтроллера строится несколько устройств отличающихся рядом функций. Большая часть кода универсальна. В таком случае для компиляции прошивки под конкретный девайс define`ами отрезается лишний функционал.
Если вы знаете, что этот код точно для чего то нужен и этот #define может когда-то выполняться, то выходит, что код не мертвый.
Ну и эти рассуждения о мертвом коде наверное в меньшей степени полезны для компилируемых языков. Да и автор оригинала рассуждает в контексте python'a
Это абсолютно нормальная практика для языка типа С, это не мертвый код, он ведь работает у вас, просто в специфичных случаях.
>Мертвый код, то есть код, который никогда не выполняется в вашей программе — это реальная помеха для поддержки вашей кодовой базы.

Утверждение неверно.

Некоторый код может включатся / выключатся конфигами, когда нужно.
И это должно быть явно видно в самом коде.
UFO just landed and posted this here
Если код может включаться, то он уже и не мертвый. Тут главное не «выжечь» его по ошибке
Страшнее это мертвый код в проекте, который в одном единственном файле на 300кб. Вот это реальный экстрим.
В таком случае должны возникнуть претензии к разработчику(архитектору). Я, кстати, видел такой файл. Причём это был один класс. Было мучительно больно его приводить к виду «более-менее можно понять что оно делает».
да там уже не мертвого кода бояться надо.

Вот уж точно. На одной прошлой работе я помогал портировать на iOS игру на C++, в ней вся логика и отрисовка были заключены в одном методе на ~3500 строк. Самой большой проблемой было понять, что, чёрт возьми, в нём вообще происходит. О рефакторинге и удалении мёртвого кода я даже не заикался, т.к. там всё было построено на анти-функциональной парадигме: туча глобальных переменных, всё усыпано состояниями, как булка — маком, классы как имена для пачек процедур. В таком проекте нет понятия "мётрвый код", т.к. всё сыпется от малейшего чиха.

Как показывает практика в таких случаях лучшее, что можно сделать — написать всё с нуля.
Я вот сейчас на новой работе столкнулся с функцией на 4300+ строк. В ней прописана какая-то аццки непонятная вещь по инициализации системы. Интересно, что в том же файле определяются еще 20+ вспомогательных функций. И самое крутое — ни одного комментария. Вообще. Оно просто работает и я понятия не имею как :)
Явно мертвый код надо хоронить, иногда с почестями, иногда не прощаясь.

А сомнительный мертвый код я стараюсь убирать в два прохода.
Сначала код комментится, потом удаляется. Причем между первой и второй итерациями код должен пройти хотя бы тестовую среду.
Поэтому если я встречаю код, закомментированный по причине, которую я сходу не помню — в топку без разговоров.
Используем похожий подход для сомнительного кода, который вроде и мёртвый, но просто грохнуть страшно.
В первом проходе прячем в коммент с меткой TODO и планируемой датой для удаления — например через неделю после следующего мажорного апдейта.
После дня икс, увидев такую тудушку можно удалять с чистой совестью: программа живёт и чувствует себя хорошо без него на всех окружениях, спустя целую итерацию.

Явно неиспользуемый и откровенно старый выжигаем без сожаления.
Боле точно это рассмотрено у Фаулера http://martinfowler.com/bliki/SacrificialArchitecture.html
Не рассмотрен случай когда, «мёртвый код» написан тобой. (Здесь я имею ввиду код зависящий от настроек которые никогда не будут выставлены) Сам наступал на эти грабли (тащил старый код).
А я сознательно не удаляю мёртвый код, если он реализует какую-нибудь необычную вещь, которую нельзя будет в будущем воспроизвести прямо из головы с первой попытки. Вот, например, я сначала сделал что-то одним способом. Затем придумал способ получше. Старую реализацию я оставляю прямо там, где она была, если она представляет какой-то интерес. Может в будущем пригодится в другом проекте. Вместо того, чтобы поддерживать библиотеку сниппетов с детальными описаниями, я храню интересный код прямо там, где он изначально появился. Так мне гораздо проще его находить. Когда нужно повторно реализовать что-то такое, что ты уже раньше делал, намного проще вспомнить то, в каком проекте и с какой целью ты это раньше делал, чем искать какой-то абстрактный сниппет среди сотен других. Память устроена ассоциативно.
Мне кажется так можно быстро захламить проект, лучше уж использовать систему контроля версий для альтернативных реализаций каких-то фич
Пока мне не удавалось ничего захламить. А система контроля версий для этого подходит ещё хуже, чем специализированная база сниппетов с описаниями.
Как правильно говорят — система контроля версий помогает. В крайнем случае можно создать отдельный проект или просто текстовый файл для хранения подобных конструкций, само-собой с подробным описанием, чтоб даже через год открыть и вспомнить что этот код делает.
Мне не помогает. Проблема отдельного проекта или текстового файла в том, что там отсутствует контекст, из которого понятно, как это лучше использовать.
Ну так в контроле версий и контекст сохраняется и описание к коммитам можно писать
Но дело хозяйское, главное чтобы удобно было
Зато в контроле версий нет удобного поиска. Нужно более-менее точно помнить время, когда ещё была старая реализация. В принципе, мой способ сочетает в себе всё необходимое и лишён недостатков. Во-первых, старая реализация сохраняется вместе с контекстом её использования. Во-вторых, её всегда можно быстро найти, поскольку она есть в самой последней версии кода проекта. В любых других способах нет либо того, либо другого. Хотя, я признаю, что другие способы более правильные с методологической точки зрения. И если отсутствие методологической чистоты считать недостатком, то недостатки у моего способа всё-таки есть. Просто я быдло… и методологическая чистота не находится в числе моих приоритетов :)
проблема в таком случае возникает, если этот код открывает другой разработчик, да даже сам через год работы в других проектах забываешь где рабочий код, а где «на память»
Нет, другие разработчики этого мёртвого кода, естественно, не видят. В основную ветку я сливаю только то, что реально используется. Такой мёртвый код живёт только в моих собственных репозиториях. (Похоже я забыл сказать самое главное :)
UFO just landed and posted this here
Вижу здесь необходимость указывать конкретный файл и регулярные выражения. Каждая из этих вещей по отдельности мешает счесть такой поиск удобным.
UFO just landed and posted this here
Ассоциативно. По памяти. Я всегда помню, в каком проекте я уже что-то подобное делал. И приблизительно знаю, в каком файле это может быть.
UFO just landed and posted this here
Часто я не знаю, что конкретно нужно искать. Нужно открыть какие-то файлы проекта, посмотреть на них глазами, и тогда становится понятно, куда ещё можно заглянуть или что конкретно следует искать.

Давайте предположим… просто ради смеха, что grep — не самый лучший инструмент для поиска кода. Вам когда-нибудь удавалось найти с его помощью хоть что-то в коде, если это был не print() с сообщением об ошибке? Не предложить кому-нибудь сделать это, а реально найти что-нибудь самому…
UFO just landed and posted this here
Вам везёт. А я уже стар и не могу рассчитывать на то, что память надёжно сохранит мелкие подробности.
Вам когда-нибудь удавалось найти с его помощью хоть что-то в коде, если это был не print() с сообщением об ошибке?

Пользуюсь grep, знакомство с чужим проектом практически всегда начинается с него. Да, сижу в vim, а не в IDE. Нет, потребности не ощущаю. Да, работал в IDE, вкус устриц знаю.

Отлаживаетесь, наверное, в чистом gdb…
UFO just landed and posted this here
Я разочарован. Думал, вы вообще не отлаживаетесь, поскольку пишете код сразу без ошибок.
Все логично, код должен работать, периодически устраиваю проходы по коду вычищая всякую дрянь, сразу становится опрятнее, чище и понятнее. В случае если что-то может пригодится (то есть почти никогда) всегда можно вытащить историю из системы контроля версий.
Чем хороши Delphi и C# тем что в режиме отладчика там видны методы, которые никем не вызываются и их можно удалить

И что, методы вызываемые через reflection по имени на базе пользовательского ввода тоже подсветит как используемые?

Не в курсе, как в Delphi и C#, а в Java такие методы разработчики обычно аннотируют:


@SuppressWarnings("unused")
public void doSomething()
...

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

Вы, наверное, также аннотирует весь public API, если пишите библиотеку, да?

Не стоит так обижаться на сарказм.

Вы преувеличиваете мои возможности (см. профиль), к тому же, я не испытываю боли ниже поясницы из-за комментариев в интернете, на которые я даже не отвечал. Каждый имеет право высказаться.
Мне тоже доставляет удовольствие удалять код на питоне)
За последний код, осознал, что мне больше нравиться коммитить удаления строк и файлов, чем добавлять их.
Просто физическое удовольствие, когда git status выводит жирный список deleted, от предвкушения предстоящего коммита =)
Идея. В continuous integration прикрутить систему ачивок для стимуляции хороших практик:
«уборщик кода» — больше всех удалил кода
«нинзя» — не сломал ни одного теста
и т. д )
Главное заранее хорошо все продумать.
«уборщик кода» может до добра не довести :)
Sign up to leave a comment.

Articles