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


125

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

На ум приходят две идеи.

  1. «Просто» используйте дедукцию, основанную на том, должен ли код выглядеть так, как будто он должен выполняться. Однако иногда это может быть сложной, трудоемкой работой, слегка рискованной (ваша оценка подвержена ошибкам) ​​без существенной отдачи от бизнеса.

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

Есть ли лучшие идеи или что-то вроде канонического подхода?


55
Может быть полезно взглянуть на историю контроля версий: когда был создан «мертвый код»? Выглядело ли оно мертвым, когда оно было создано? Был ли проверен другой код (который с тех пор был изменен или удален), который его использовал, в то же время, когда он был создан?
ChrisW

9
Компилятору нельзя доверять, если в игре используется какая-либо форма метапрограммирования, например рефлексия. Надлежащий grep базового каталога является важной практикой. Также распространено использование нескольких приложений, совместно использующих код, поэтому обязательно выполняйте поиск на нужном уровне каталогов.
Адам Кэвнесс

16
Я бы спросил - «Зачем его удалять?». Если он используется в каком-то крайнем случае, который вызывается один раз в голубой луне, вы сломали вещи. Если он никогда не используется, и вы оставляете его там, ущерб состоит в том, что исполняемый файл немного больше. Разве это не для какого-то встроенного устройства, это большое дело? Добавьте комментарий и перейдите к продуктивному использованию своего времени.
mickeyf

40
@mickeyf Ущерб в том, что кто-то должен поддерживать этот код. Это означает, что разработчик должен понимать, что он делает. Разработчик должен изменить его, если что-то изменится, и код вокруг него теперь должен сделать что-то другое. Поверьте мне, когда вы оставляете бездельник лежать без дела, это большая головная боль для любого, кто пытается разобраться в этом позже.
jpmc26

9
@MichaelJ. Я хочу сказать, что этого не должно было быть в первую очередь. И если я оставлю это, ситуация будет еще хуже: теперь какой-то другой разработчик в дальнейшем должен это расследовать. Чем дольше он остается, тем больше времени уходит на его понимание. Это стоимость лишнего кода.
jpmc26

Ответы:


112

В моем идеальном фэнтезийном мире, где у меня 100% покрытие модульных тестов, я просто удаляю его, запускаю свои модульные тесты, и когда ни один тест не становится красным, я фиксирую его.

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

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

249
Наблюдая за состоянием крупных программных проектов, в которых инженеры в течение десяти-двенадцати лет в основном придерживались подхода «не стоит» к удалению вероятного лишнего кода, я не могу рекомендовать этот подход.
njuffa

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

8
По моему опыту, состояние таких проектов никогда не связано с «не стоящим» подходом к исправлению кода после факта, это всегда из-за плохого кода, написанного в первую очередь. Ошибочно писать плохой код, но также ошибочно (более сложная ошибка) думать, что очистка кода всегда того стоит.
Вейланд Ютани

42
@Weyland Yutani Это совсем не соответствует моему опыту. Большая часть возможного излишнего кода, который я видел, была достаточно хорошо написана и совершенно разумна с учетом спецификаций программного обеспечения, аппаратных платформ или версий операционных систем, существовавших десять лет назад, необходимых для обхода ошибок или ограничений в цепочке инструментов или доступном ранее оборудовании и т. Д. .
njuffa

20
Ответ пропускает одно из самых важных и важных преимуществ продолжения и внесения изменений: обучение чему-либо. Изучив его, вы можете добавить структуру (комментарии, тесты), чтобы помочь разработчикам в дальнейшем. Выбор не менять что-то, потому что вы не знаете последствий, является программированием культа груза, даже если этот выбор не состоит в том, чтобы удалить что-то.
Кодзиро

84

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

Многие ответы здесь имеют отличные решения для первой половины. Такие инструменты, как статические анализаторы, отлично подходят для выявления мертвого кода. grepможет быть вашим другом в некоторых случаях. Один из необычных шагов, которые я часто предпринимаю, состоит в том, чтобы попытаться определить первоначальную цель кода. Намного легче утверждать, что «X больше не является функцией нашего продукта, а сегмент кода Y был разработан для поддержки функции X», чем сказать «я не вижу никакой цели для сегмента кода Y».

Вторая половина - это ключевой шаг к преодолению тупика, связанного с тем, следует ли удалять код. Вы должны понять, что означает неправильный ответ. Если люди умрут, если вы неправильно ответите, обратите внимание! Может быть, это хорошее время, чтобы признать, что с течением времени происходит развитие кода, и вместо этого попытаться не писать больше кода самостоятельно. Если люди не умрут, спросите себя, как простить своих пользователей. Можете ли вы отправить им исправление, если вы что-то сломали и поддерживаете отношения с клиентами? У вас есть команда Q & A, которой платят, чтобы найти такие проблемы? Эти вопросы важны для понимания того, насколько вы должны быть уверены, прежде чем нажать клавишу удаления.

В комментариях rmun указал на отличную формулировку концепции понимания первоначального назначения кода перед его удалением. Цитата теперь известна как Забор Честертона . Хотя он слишком велик, чтобы его можно было цитировать непосредственно в комментарии, я думаю, что он заслуживает того, чтобы его правильно процитировать здесь:

В отношении реформирования вещей, в отличие от деформации, существует один простой и простой принцип; принцип, который, вероятно, будет называться парадоксом. В таком случае существует определенный институт или закон; скажем, ради простоты, забор или ворота, установленные через дорогу. Более современный тип реформатора радостно подходит к этому и говорит: «Я не вижу смысла в этом; давайте очистим его ». На что более умный тип реформатора преуспеет, чтобы ответить:« Если вы не видите его использования, я, конечно, не позволю вам очистить его. Уходи и думай. Затем, когда вы сможете вернуться и сказать мне, что вы видите его использование, я могу позволить вам уничтожить его.


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

15
@kojiro Это очень верно. Мне нравится думать, что с Честертоном все будет в порядке, если бы я, как «современный реформатор», пришел и сказал: «Я не знаю, почему этот забор здесь, я признаю это. Но я бы хотел покрасить его в красный цвет, чтобы увидеть, это дает мне любую новую информацию, "Честертон, вероятно, был бы счастлив с этим.
Корт Аммон

41
Метод декодирования часов режима ядра ОС VMS SYS $ ASCTIM содержит строку кода, которая помогает исправить сидерический дрейф весеннего равноденствия. Ни один из модульных тестов DEC не выполняет этот код. Он работал один раз - правильно - 2000-02-28 в 23: 59: 59: 999. Он не будет работать до 2400 года. Пожалуйста, не удаляйте его.
А.И. Бревелери,

13
@AIBreveleri Я надеюсь, что в самом коде есть комментарий, объясняющий это, а не только здесь, на StackExchange: D
Кайл Странд,

11
@KyleStrand О чем ты говоришь? Это является документация. Можете ли вы придумать лучшее место для размещения важной информации, чтобы ее могли найти другие люди, чем StackExchange? ;-)
Cort Ammon

43

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


11
Я не downvoter, но что, если секция кода, которую вы подозреваете, никогда не запускается, является не полной функцией или классом, а секцией метода / функции?
Тулаинс Кордова

9
В зависимости от языка это не всегда может быть надежно - некоторые языки позволяют динамически выполнять вызовы методов. Например, php:$object->$variableMethod($arg1, $arg2);
Dezza

9
@ TulainsCórdova Тогда, вероятно, это не очень хорошее решение. Что касается каждого потенциального решения, используйте его, если оно имеет смысл в данном контексте. Но, может быть, grepнапример. Функция, охватывающая раздел кода, может дать подсказки относительно того, как используется функция и, следовательно, ее содержание?
Piwi

7
«например, если имя упоминается в комментарии, в файле документации или в скрипте» - или если кто-то использует отражение для вызова метода (если используется язык высокого уровня / OO). Хотя все еще не обязательно на 100% точный, поскольку некоторые языки поддерживают некоторые очень тупые способы поиска и вызова методов.
Аромат

Это полезно, если у вас есть доступ ко всему возможному коду, который может использовать функцию. Однако, если код является частью библиотеки, как вы узнаете, что что-то еще, что вы не можете найти, не сломается?
Кевин Ши

30
  • Определите код, который выглядит мертвым (статический анализ и т. Д.).
  • Добавьте сообщение журнала для каждого вызова предположительно мертвого кода. Это легко с функциями / методами; со статическими членами, такими как константы, это сложнее. Иногда вы можете просто пометить код как устаревший, и среда выполнения автоматически запишет вам сообщение. Оставьте код без изменений.
    • Записывайте сообщение, когда загруженный мертвый модуль загружен: большинство языков имеют способ выполнить статическую инициализацию во время загрузки, которая может быть поддержана.
    • Убедитесь, что ваше лог-сообщение содержит разумную трассировку стека, чтобы вы понимали, что называется предположительно мертвым кодом.
  • Запустите измененный код через все ваши тестовые наборы. Ваши тестовые наборы должны также проверять на особые времена, такие как пересечение полуночи, поворот четверти, поворот года и т. Д. Посмотрите журналы, обновите ваше понимание того, что мертво. Обратите внимание, что модульные тесты могут специально проверять мертвый код, в то время как другие модульные тесты и интеграционные тесты не касаются его.
  • Запустите измененный код на производстве в течение нескольких недель. Убедитесь, что все периодические процессы, такие как раз в месяц задания ETL cron, выполняются в течение этого периода.
  • Посмотри логи. Все, что было зарегистрировано, на самом деле не мертво. Транзитивное замыкание графа вызовов над остальной частью мертвого кода также потенциально не является мертвым, даже если оно не было вызвано. Проанализируйте это. Может быть, некоторые ветви благополучно мертвы (например, работают с API ныне не существующей службы), а некоторые еще нет. Может быть, целый модуль / класс загружается только для определенной в нем константы, и вы можете легко ее использовать.
  • Все, что осталось, благополучно умерло и может быть удалено.

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

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

1
@ 9000 Я согласен в теории, но унаследованные системы пронизаны скрытыми зависимостями, которые могут помешать этому виду тестирования. Чтобы ваш пример тестирования работал, вам нужно знать, что существует какая-то временная связь. Если временная связь является внешней по отношению к коду, который вы тестируете, вы не увидите его в коде и знаете, что временная связь является фактором. Например, код силоса А установлен в GAC . Несколько лет назад бункер B попросил бункер A добавить путь к коду для отчета, который им нужен для обработки данных бункера A. прод.
Эрик

1
@ 9000 продолжение Теперь код бункера B имеет временную связь с «мертвым» путем кода в коде бункера A, который не очевиден, если просто взглянуть на код бункера A. Как бы вы проверили модульный тест для этой временной связи, поскольку временная связь есть только в коде бункера B, не зная, что говорить с бункером B? Даже тогда время не является фактором в вашем коде (бункер A), так как будет выглядеть временный тест?
Эрик

2
Кто-нибудь помнит панику Y2k ? Некоторый код был правильным в 2000 году, потому что он был неправильным для 2100! У нас была потенциальная проблема, которая могла возникнуть один раз в 100 лет или даже один раз в 400 лет.
Стив Барнс

16

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

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

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


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

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

7

Многие люди полагают, что «безопасная» вещь - это оставить код, если вы не можете доказать, что он не используется.

Но код не является активом, это обязательство.

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

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


Шаг 1: Удалить весь код. Шаг 2: вернуть то, что нужно. Шаг 3: повторите.

1
@Adrian Могу я обратить ваше внимание на Knight Capital? en.wikipedia.org/wiki/… - на тот случай, если вы захотите подкрепить свою точку зрения ссылкой на нее. Они в основном взорвались, потому что какой-то старый код вернулся к жизни и любезно потерял для них почти 500 миллионов долларов. Последующее расследование было сосредоточено на процедурах их выпуска, но основная проблема заключалась в том, что «мертвая функциональность не была удалена».
SusanW

6

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

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

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

Подробнее о переключателях читайте здесь: https://martinfowler.com/articles/feature-toggles.html.


6

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

Просто измените имя метода (например, измените DoSomethingна DoSomethingX) и затем запустите сборку.

Если ваша сборка прошла успешно, метод, очевидно, ничем не используется. Безопасно удалить.

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

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


8
Это хороший совет для языков программирования, которые не имеют полной динамической / поздней привязки . Тем не менее, для тех, кто имеет, это сложнее. И, конечно же, код может использовать метод, даже если он никогда не использовался в производстве.
эйс

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

1
Хм ... Я заинтригован, я не думаю, что последнее, что вы говорите, правда. Это не для ванильного javascript (не скомпилированного), ruby, python или smalltalk, например, верно? Если вы ссылаетесь на вещи, которые не существуют, эти ошибки только во время выполнения.
эйс

Возможно, мы не согласны с тем, что подразумевается под «связыванием», что для меня указывает на разрешение логического представления для физического представления, например символа для адреса. Функции Javascript хранятся в виде пар тегов / значений в содержащем объекте, поэтому любое понятие привязки кажется несостоятельным.
Джон Ву

1
Да, мы действительно не согласны. Термин имеет другое значение для языков, которые не имеют полной поздней привязки (как я объяснил в первом комментарии). Когда вы связываете методы во время выполнения - на языках, которые могут добавлять и удалять методы во время выполнения, на лету - вы используете позднее связывание так, как я понимаю, это должно быть сделано. Это верно для языков в стиле ruby ​​/ python / smalltalk, и там у вас нет отдельных файлов карт. Поскольку особенно широко используются ruby ​​и python, я не согласен с вашим представлением о том, что это «обычно» означает.
эйс

4
  • Я бы начал использовать анализатор кода, чтобы проверить, является ли это мертвым кодом
  • Я бы начал проверять свои тесты и пытаться добраться до кода. Если я не могу получить код в тестовом случае, это может быть мертвый код
  • Я бы удалил код и выкинул бы исключение вместо этого. Для одного выпуска исключение активируется, а во втором выпуске исключение может быть удалено. Чтобы быть в безопасности, установите аварийный флаг (в Java, системное свойство), чтобы иметь возможность активировать исходный код, когда клиент замечает исключение. Таким образом, исключение можно отключить, а исходный код можно активировать в производственной среде.

6
-1. Совершенно не рекомендуется вносить эти изменения в производительный код, флаг безопасности или нет. Только когда вы уверены, что рассматриваемый код не используется, он может быть удален в производительном коде. Такого рода возиться, именно поэтому всегда должны быть разные производительные и тестовые среды.
Йоханнес Хан

3
Это будет работать в фантазиях, когда охват тестами составляет почти 90%, но что если нет, и у вас есть проект с 100 000 строк кода. Вот почему я описал попытку тестирования кода, и если ни один тест не может достичь кода ... он может быть мертвым.
Маркус Лозберг

ИМХО Если вы не уверены, что не можете полностью удалить код - вы не должны создавать исключений в производственной среде - протоколирование, предложенное ФП, является гораздо лучшей альтернативой, обеспечивает то же самое, и вы можете получить диагностику вместо того, чтобы полагаться на жалобы клиентов.
Себи

@JohannesHahn Я думаю, что вы имеете в виду «производственный код», то есть код, работающий в производственной среде.
jpmc26

@ jpmc26 Да, конечно.
Йоханнес Хан

3

Удаление недоступного кода

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

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

Если вы используете динамический язык или язык с достаточно сильным отражением, что потенциально возможный доступ к фрагменту кода может быть получен во время выполнения посредством отражения, то вы не можете полагаться на компилятор. К таким языкам относятся Python, Ruby или Java.

Если вы используете язык с беспринципной перегрузкой, то простое удаление перегрузки может просто переключить разрешение перегрузки на другую перегрузку без вывода сообщений . Некоторые такие языки позволяют программировать предупреждение / ошибку во время компиляции, связанную с использованием кода, в противном случае вы не можете полагаться на компилятор. К таким языкам относятся Java (использование @Deprecated) или C ++ (использование [[deprecated]]или = delete).

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

Подсказка в следующем разделе ...


Удаление потенциально неиспользуемого кода

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

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

В прошлом я успешно использовал трехэтапный подход к удалению такого кода:

  1. На каждой ветке, которая, как подозревается, НЕ должна быть взята, регистрируйте предупреждение.
  2. После одного цикла выведите исключение / верните ошибку при вводе определенного фрагмента кода.
  3. После другого цикла удалите код.

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

Надеемся, что большинство приложений имеют более короткие циклы.

Я советую размещать комментарий TODO с указанием даты и указывать, когда следует перейти к следующему шагу. И напоминание в вашем календаре.


1
На самом деле, в C ++ вы можете пометить вашу подозрительную перегрузку, [[deprecated]]чтобы идентифицировать сайты, которые вызывают эту версию; затем вы можете проверить их, чтобы увидеть, изменится ли их поведение. В качестве альтернативы, определите вашу перегрузку как = delete- в этом случае вам нужно будет явно привести аргументы, чтобы использовать одну из других версий.
Тоби Спейт

@TobySpeight: Это правда, и хорошая альтернатива тоже. Позвольте мне отредактировать это в.
Матье М.

«Доктор, мне больно, когда я так поступаю». «Ну , не делай этого! » Не используйте подходы, которые делают код неуправляемым.

2

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

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

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

PS: Чтобы уточнить в ответ на комментарий .. Оригинальный вопрос «Как вы можете безопасно удалить ..», конечно, контроль версий предполагается в моем ответе. Так же, как копаться в мусоре, чтобы найти ценное, предполагается. Ни один орган, не имеющий смысла выбрасывать код и контроль версий, не должен быть частью строгости каждого разработчика.

Проблема в коде, который может быть лишним. Мы никогда не узнаем, что фрагмент кода является излишним, если мы не можем гарантировать, что 100% путей выполнения не достигают его. И предполагается, что это достаточно большой программный продукт, и эта гарантия практически невозможна. И если я не прочитал вопрос неправильно, единственное время, когда весь этот поток разговоров имеет отношение к делу, - это случаи, когда удаленный код может вызываться, и, следовательно, возникает проблема времени выполнения / производства. Контроль версий не спасает никого из-за производственных сбоев, поэтому комментарий о «Контроль версий» не имеет отношения к вопросу или моей первоначальной точке зрения, то есть к надлежащему устареванию в течение очень длительного периода времени, если вам действительно это нужно, иначе

ИМХО, комментарий излишен и является кандидатом на удаление.


12
Если бы у меня был эквивалент контроля версий , возражения моей жены будут легко отменены. То же самое и с удалением кода: это не убийственное преступление. Хранилище никогда не выбрасывается.
JDługosz

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

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

1

Может быть, компилятор это замечает, он просто не суетится.

Запустите сборку с полной оптимизацией компилятора, ориентированной на размер. Затем удалите подозрительный код и снова запустите сборку.

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

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


1
Не все языки скомпилированы, не все компиляторы имеют оптимизацию, и не все оптимизации одинаковы, многие не удаляют непроверенный код только в том случае, если этот код существует по причине. Если код находится в общей библиотеке / DLL, он не будет удален.
Стив Барнс

1
@SteveBarnes Ну, да, если вы не делаете LTO и статически связываете все, вас ждет некоторая боль. Это дано.
Навин

1

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

PHP:

public function deleteFoo()
{
    error_log("In deleteFoo()", 3, "/path/to/log");
}

Оказывается, код был использован! Некоторые AJAX-методы вызывают «method: delete, elem = Foo», который затем объединяется и вызывается с помощью call_user_func_array () .

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


Существуют библиотеки для PHP и Perl, называемые Tombstone (php: github.com/scheb/tombstone ), которые могут быть полезны здесь.
Алистер

0

Используйте grepили какие-либо инструменты, которые у вас есть в первую очередь, вы можете найти ссылки на код. (Первоначально не моя инструкция / совет.)

Затем решите, хотите ли вы рискнуть удалить код или мое предложение может пригодиться:

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

Две проблемы:

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

  2. Отслеживание звонящего. В некоторых языках высокого уровня (например, Python) вы можете легко получить трассировку. Но на скомпилированных языках вам нужно сохранить адрес возврата в журнале и принудительно создать дамп ядра при выходе (пункт 1).
    В C это должно быть довольно просто: используйте условный блок (например, #ifdef ... #endif), чтобы использовать его только тогда, когда вы знаете, что он будет работать (и проверили, что он работает), и просто прочитайте адрес возврата из стека (может требовать или не требовать встроенного языка ассемблера).

Сохранение аргументов в файле журнала может или не может быть полезным.


0

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

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

Теперь могут быть некоторые обстоятельства (я знаю, что сам столкнулся с этим), когда «мертвый» код на самом деле не связан ни с чем . Например, библиотеки кода, разработанные подрядчиком, которые фактически нигде не были реализованы, потому что они устарели сразу после того, как приложение было доставлено (почему да, у меня есть конкретный пример, как вы узнали?).

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

Теперь, несмотря на все сказанное, вероятно , не стоит тратить ваше время или здравомыслие на то, чтобы попытаться удалить подобный код. Нет, если это не становится серьезной проблемой с вашим приложением (например, неспособность завершить сканирование безопасности из-за раздувания приложения ... почему да, я ДЕЙСТВИТЕЛЬНО все еще имею в виду пример), поэтому я бы не рекомендовал его, если вы не достигнете такая ситуация, когда код действительно начал гнить.

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


0

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

Получить вторую пару глаз.

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

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


0

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

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

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

В конечном счете, вы либо понимаете это, оставляете это в покое, либо рискуете.


0

В случае, если разработчик рассматриваемого кода все еще доступен, просмотрите удаление кода с ним . Также читайте комментарии в коде .

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

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

Одна из наиболее важных причин написания комментариев в коде - объяснить, ПОЧЕМУ он был реализован таким образом. Вы можете не согласиться с решением, но вам нужно принять во внимание проблему.

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


-1

Я полностью согласен с первым пунктом Маркуса Лозберга: код должен определенно анализироваться с помощью инструментов. Мозгам обезьян нельзя доверять с такой задачей !!

Большинство стандартных языков программирования могут использоваться в IDE, и каждая IDE, которую стоит назвать, имеет функцию «найти для всех», которая является именно тем инструментом, который подходит для такой ситуации. (Например, Ctrl + Shift + G в Eclipse)

Конечно, инструменты статического анализатора не идеальны. Необходимо помнить о более сложных ситуациях, когда решение о вызове рассматриваемого метода происходит только во время выполнения и не раньше (вызовы через Reflection, вызовы «eval» -функций в языках сценариев и т. Д.).


5
Может быть, мозги обезьян не должны писать код? « Нетронутый человеческими руками » - это маркетинговая фраза. Я всегда думал, что руки гориллы делают эту работу.

3
(Обезьяны тоже писали инструменты) (Тссс! Ты

1
Я думаю, что вы оба упускаете мою точку зрения. Я четко сказал, что нет никакой гарантии, что статический анализ кода найдет каждый вызов метода или класса. Это, как говорится на банке, статический анализ. Нельзя и не следует ожидать, что динамические вызовы будут найдены с помощью рефлексии, eval () и т. Д. Моя точка зрения заключается в том, что статический анализ кода следует считать необходимой предпосылкой для удаления фрагмента кода. И чем больше проект, тем меньше вероятность того, что человеческий мозг даже способен выполнить этот анализ, не говоря уже о том, чтобы делать это правильно ...
Йоханнес Хан

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

1
Опять не хватает сути. Даже если инструменты не идеальны, потому что они написаны мозгами ape (и я даже не уверен, должен ли я это допустить! Вычисление статических иерархий вызовов не так уж сложно), они все равно намного превосходят ручное выполнение задач. Это не ситуация типа «все или ничего». Надежный инструмент на 99% все еще предпочтительнее, чем мозг, который может начинаться с 99%, но после первой тысячи строк кода быстро падает до гораздо более низких показателей.
Йоханнес Хан

-1

Две возможности:

  1. У вас 99% + тестовое покрытие : удалите код и покончите с этим.
  2. У вас нет заслуживающего доверия тестового покрытия. Тогда ответ состоит в том, чтобы добавить предупреждение об устаревании . То есть вы добавляете в это место некоторый код, который делает что-то вменяемое (например, записывает предупреждение в какое-то легко видимое место, которое не конфликтует с повседневным использованием вашего приложения). Тогда позвольте этому кипеть в течение нескольких месяцев / лет. Если вы никогда не встречали его, замените устаревание чем-то, что вызывает исключение. Позвольте этому стоять некоторое время. Наконец, удалите все полностью.

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

@gnat, ты прав. Когда я впервые отсканировал ответы, по какой-то причине мне показалось, что я видел несколько таких, которые наверху не так быстро и кратко добрались до этих двух пунктов. В середине ответов есть такие.
AnoE
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.