Вы нашли некоторый код, который выглядит излишним, а компилятор этого не замечает. Что вы делаете, чтобы быть уверенным (или настолько близким, насколько можете), что удаление этого кода не вызовет регрессии.
На ум приходят две идеи.
«Просто» используйте дедукцию, основанную на том, должен ли код выглядеть так, как будто он должен выполняться. Однако иногда это может быть сложной, трудоемкой работой, слегка рискованной (ваша оценка подвержена ошибкам) без существенной отдачи от бизнеса.
Разместите логи в этом разделе кода и посмотрите, как часто они вводятся на практике. После достаточного количества выполнений у вас должна быть разумная уверенность, что удаление кода безопасно.
Есть ли лучшие идеи или что-то вроде канонического подхода?
clean-code
Брэд Томас
источник
источник
Ответы:
В моем идеальном фэнтезийном мире, где у меня 100% покрытие модульных тестов, я просто удаляю его, запускаю свои модульные тесты, и когда ни один тест не становится красным, я фиксирую его.
Но, к сожалению, мне приходится просыпаться каждое утро и сталкиваться с суровой реальностью, когда у большого количества кода либо нет модульных тестов, либо когда они есть, нельзя доверять, чтобы действительно охватить все возможные крайние случаи. Поэтому я рассмотрел бы риск / вознаграждение и пришел к выводу, что это просто не стоит:
источник
Есть две половины этого процесса. Первое подтверждает, что код действительно мертв. Во-вторых, это понимание затрат, связанных с ошибками, и обеспечение их надлежащего снижения.
Многие ответы здесь имеют отличные решения для первой половины. Такие инструменты, как статические анализаторы, отлично подходят для выявления мертвого кода.
grep
может быть вашим другом в некоторых случаях. Один из необычных шагов, которые я часто предпринимаю, состоит в том, чтобы попытаться определить первоначальную цель кода. Намного легче утверждать, что «X больше не является функцией нашего продукта, а сегмент кода Y был разработан для поддержки функции X», чем сказать «я не вижу никакой цели для сегмента кода Y».Вторая половина - это ключевой шаг к преодолению тупика, связанного с тем, следует ли удалять код. Вы должны понять, что означает неправильный ответ. Если люди умрут, если вы неправильно ответите, обратите внимание! Может быть, это хорошее время, чтобы признать, что с течением времени происходит развитие кода, и вместо этого попытаться не писать больше кода самостоятельно. Если люди не умрут, спросите себя, как простить своих пользователей. Можете ли вы отправить им исправление, если вы что-то сломали и поддерживаете отношения с клиентами? У вас есть команда Q & A, которой платят, чтобы найти такие проблемы? Эти вопросы важны для понимания того, насколько вы должны быть уверены, прежде чем нажать клавишу удаления.
В комментариях rmun указал на отличную формулировку концепции понимания первоначального назначения кода перед его удалением. Цитата теперь известна как Забор Честертона . Хотя он слишком велик, чтобы его можно было цитировать непосредственно в комментарии, я думаю, что он заслуживает того, чтобы его правильно процитировать здесь:
источник
Я также склоняюсь к
grep
имени функции / класса в коде, что может дать некоторые дополнительные преимущества, которых не может иметь анализатор кода, например, если имя упоминается в комментарии, в файле документации или в скрипте, например. Я запускаю grep для файлов в дереве исходного кода и сохраняю результат в файле; обычно результат дает сжатую информацию: имя файла / путь, номер строки и строку, где встречается имя, что может дать подсказки, где функция / класс вызывается или упоминается без какого-либо семантического значения (в отличие от анализатора кода ) и независимо от расширений файлов. Определенно не окончательное решение, но хорошее дополнение к анализу.источник
$object->$variableMethod($arg1, $arg2);
grep
например. Функция, охватывающая раздел кода, может дать подсказки относительно того, как используется функция и, следовательно, ее содержание?источник
В дополнение к уже упомянутым существующим ответам вы также можете итеративно удалить код из нескольких версий.
В начальной версии вы могли бы сделать предупреждение об устаревании с блоком кода, все еще работающим. В версии после этого вы можете удалить блок кода, но оставить сообщение об ошибке, позволяющее пользователям использовать эту функцию как устаревшую и больше не доступную. В окончательной версии вы удалите блок кода и все сообщения.
Это может помочь выявить непредвиденные функциональные возможности без предупреждения для конечных пользователей. В лучшем случае код действительно ничего не делает, и все, что происходит, это то, что ненужный код хранится в нескольких версиях перед удалением.
источник
Многие люди полагают, что «безопасная» вещь - это оставить код, если вы не можете доказать, что он не используется.
Но код не является активом, это обязательство.
Если вы не можете объяснить, почему это важно, и указать на его тесты, «более безопасной» альтернативой может быть удаление.
Если вы все еще не уверены, то, по крайней мере, добавьте тесты для проверки кода зомби.
источник
Вы можете использовать функциональные переключатели, чтобы изменить путь выполнения вашего программного обеспечения, чтобы полностью игнорировать рассматриваемый код.
Таким образом, вы можете безопасно развернуть изменения с неиспользуемым кодом и отключить их. Если вы заметили некоторые серьезные ошибки, связанные с кодом, включите тумблер и исследуйте возможный путь к нему.
Такой подход должен дать вам уверенность, если вы не видите проблем в течение длительного периода времени, а также возможность включить его в режиме реального времени без развертывания. Однако еще лучшим способом было бы также применить дополнительную регистрацию и тестовое покрытие вокруг рассматриваемой области, которая предоставит больше доказательств того, используется ли она или нет.
Подробнее о переключателях читайте здесь: https://martinfowler.com/articles/feature-toggles.html.
источник
Статический анализ, конечно ... и что приятно, вам не нужны новые инструменты; Ваш компилятор имеет все необходимые инструменты статического анализа.
Просто измените имя метода (например, измените
DoSomething
наDoSomethingX
) и затем запустите сборку.Если ваша сборка прошла успешно, метод, очевидно, ничем не используется. Безопасно удалить.
Если ваша сборка не удалась, выделите строку кода, которая ее вызывает, и проверьте, какие
if
операторы окружают вызов, чтобы определить, как его инициировать. Если вы не можете найти ни одного возможного варианта использования данных, который его инициирует, вы можете безопасно удалить его.Если вы действительно беспокоитесь об его удалении, подумайте о том, чтобы сохранить код, но пометив его ObsoleteAttribute (или его эквивалентом на вашем языке). Отпустите его так же для одной версии, затем удалите код, если в дикой природе проблем не обнаружено.
источник
источник
Удаление недоступного кода
В принципиально статически типизированном языке вы всегда должны знать, доступен ли код на самом деле или нет: удалите его, скомпилируйте, если нет ошибки, он не был доступен.
К сожалению, не все языки статически типизированы, и не все статически типизированные языки являются принципиальными. Вещи, которые могут пойти не так, как следует (1) отражение и (2) беспринципная перегрузка.
Если вы используете динамический язык или язык с достаточно сильным отражением, что потенциально возможный доступ к фрагменту кода может быть получен во время выполнения посредством отражения, то вы не можете полагаться на компилятор. К таким языкам относятся Python, Ruby или Java.
Если вы используете язык с беспринципной перегрузкой, то простое удаление перегрузки может просто переключить разрешение перегрузки на другую перегрузку без вывода сообщений . Некоторые такие языки позволяют программировать предупреждение / ошибку во время компиляции, связанную с использованием кода, в противном случае вы не можете полагаться на компилятор. К таким языкам относятся Java (использование
@Deprecated
) или C ++ (использование[[deprecated]]
или= delete
).Так что, если вам не очень повезло работать со строгими языками (Rust приходит на ум), вы, возможно, действительно стреляете себе в ногу, доверяя компилятору. И, к сожалению, тестовые наборы, как правило, неполные, поэтому они не слишком помогают.
Подсказка в следующем разделе ...
Удаление потенциально неиспользуемого кода
Скорее всего, на код действительно ссылаются, однако вы подозреваете, что на практике ветки кода, которые ссылаются на него, никогда не используются.
В этом случае, независимо от языка, код может быть наглядно доступен, и могут использоваться только инструменты времени выполнения.
В прошлом я успешно использовал трехэтапный подход к удалению такого кода:
Что такое цикл? Это цикл использования кода. Например, для финансового приложения я бы ожидал короткий месячный цикл (с выплатой зарплаты в конце месяца) и длинный годовой цикл. В этом случае вам придется подождать не менее года, чтобы убедиться, что для инвентаризации на конец года не было получено ни одного предупреждения, поскольку в нем могут использоваться пути кода, которые в противном случае никогда не используются.
Надеемся, что большинство приложений имеют более короткие циклы.
Я советую размещать комментарий TODO с указанием даты и указывать, когда следует перейти к следующему шагу. И напоминание в вашем календаре.
источник
[[deprecated]]
чтобы идентифицировать сайты, которые вызывают эту версию; затем вы можете проверить их, чтобы увидеть, изменится ли их поведение. В качестве альтернативы, определите вашу перегрузку как= delete
- в этом случае вам нужно будет явно привести аргументы, чтобы использовать одну из других версий.Удаление кода из производства похоже на уборку дома. В тот момент, когда вы выбросите предмет с чердака, ваша жена убьет вас на следующий день за то, что вы выбросили подарок на родину третьего племянника своей прабабушки от своего соседа, который умер в 1923 году.
Серьезно, после поверхностного анализа с использованием различных инструментов, о которых все уже упоминали, и после использования уже упомянутого подхода поэтапной амортизации, имейте в виду, что вы можете уйти из компании, когда произойдет фактическое удаление. Позволить коду остаться и зарегистрировать его выполнение и убедиться, что любые оповещения о его выполнении обязательно сообщаются вам (или вашим преемникам и назначенным лицам).
Если вы не будете придерживаться этого подхода, ваша жена может быть убита вами. Если вы сохраняете код (как и любой подарок на память), то вы можете успокоить свою совесть в том, что закон Мура вам на помощь, а стоимость ненужного дискового пространства, используемого кодом, который выглядит как «камень в моей обуви», уменьшает каждый год, и вы не рискуете стать центром множества слухов о кулере для воды и странных взглядов в коридорах.
PS: Чтобы уточнить в ответ на комментарий .. Оригинальный вопрос «Как вы можете безопасно удалить ..», конечно, контроль версий предполагается в моем ответе. Так же, как копаться в мусоре, чтобы найти ценное, предполагается. Ни один орган, не имеющий смысла выбрасывать код и контроль версий, не должен быть частью строгости каждого разработчика.
Проблема в коде, который может быть лишним. Мы никогда не узнаем, что фрагмент кода является излишним, если мы не можем гарантировать, что 100% путей выполнения не достигают его. И предполагается, что это достаточно большой программный продукт, и эта гарантия практически невозможна. И если я не прочитал вопрос неправильно, единственное время, когда весь этот поток разговоров имеет отношение к делу, - это случаи, когда удаленный код может вызываться, и, следовательно, возникает проблема времени выполнения / производства. Контроль версий не спасает никого из-за производственных сбоев, поэтому комментарий о «Контроль версий» не имеет отношения к вопросу или моей первоначальной точке зрения, то есть к надлежащему устареванию в течение очень длительного периода времени, если вам действительно это нужно, иначе
ИМХО, комментарий излишен и является кандидатом на удаление.
источник
Может быть, компилятор это замечает, он просто не суетится.
Запустите сборку с полной оптимизацией компилятора, ориентированной на размер. Затем удалите подозрительный код и снова запустите сборку.
Сравните двоичные файлы. Если они идентичны, то компилятор заметил и тихо удалил код. Вы можете удалить его из источника безопасно.
Если бинарные файлы разные ... тогда это неокончательно. Это может быть какое-то другое изменение. Некоторые компиляторы даже включают дату и время компиляции в двоичном коде (и, возможно, его можно отключить!)
источник
Я на самом деле недавно столкнулся с этой точной ситуацией с помощью метода, называемого "deleteFoo". Нигде во всей кодовой базе не было найдено этой строки, кроме объявления метода, но я мудро написал строку журнала в верхней части метода.
PHP:
Оказывается, код был использован! Некоторые AJAX-методы вызывают «method: delete, elem = Foo», который затем объединяется и вызывается с помощью call_user_func_array () .
Если есть сомнения, войдите! Если вы провели достаточно времени, не увидев заполненный журнал, подумайте об удалении кода. Но даже если вы удалите код, оставьте журнал на месте и комментарий с датой, чтобы упростить поиск комита в Git парню, который должен его поддерживать!
источник
Используйте
grep
или какие-либо инструменты, которые у вас есть в первую очередь, вы можете найти ссылки на код. (Первоначально не моя инструкция / совет.)Затем решите, хотите ли вы рискнуть удалить код или мое предложение может пригодиться:
Вы можете изменить функцию / блок кода, чтобы записать, что он был использован в файле журнала. Если в файле журнала нет таких сообщений, которые вы когда-либо записывали, вы, вероятно, можете удалить код регистрации.
Две проблемы:
Получение журнала от других пользователей. Возможно, вы можете установить глобальный флаг, который будет вызывать сбой программы при выходе и просить пользователя отправить вам журнал ошибок.
Отслеживание звонящего. В некоторых языках высокого уровня (например, Python) вы можете легко получить трассировку. Но на скомпилированных языках вам нужно сохранить адрес возврата в журнале и принудительно создать дамп ядра при выходе (пункт 1).
В C это должно быть довольно просто: используйте условный блок (например, #ifdef ... #endif), чтобы использовать его только тогда, когда вы знаете, что он будет работать (и проверили, что он работает), и просто прочитайте адрес возврата из стека (может требовать или не требовать встроенного языка ассемблера).
Сохранение аргументов в файле журнала может или не может быть полезным.
источник
Если вы знаете, что делает код, окружающий его, проверьте, не сломался ли он. Это самый простой и экономически эффективный способ рефакторинга фрагмента кода, над которым вы работаете, и его следует использовать в любом случае, как и для разработки любых изменений в коде, над которым вы работаете.
Если, с другой стороны, вы реорганизуете фрагмент кода, в котором вы не знаете, что он делает, не удаляйте его . Сначала поймите это, а затем проведите рефакторинг, если вы решите, что это безопасно (и только если вы можете определить, что рефакторинг будет правильным использованием вашего времени).
Теперь могут быть некоторые обстоятельства (я знаю, что сам столкнулся с этим), когда «мертвый» код на самом деле не связан ни с чем . Например, библиотеки кода, разработанные подрядчиком, которые фактически нигде не были реализованы, потому что они устарели сразу после того, как приложение было доставлено (почему да, у меня есть конкретный пример, как вы узнали?).
Лично я действительно удалил весь этот код, но это огромный риск, который я не рекомендую воспринимать легкомысленно - в зависимости от того, на сколько кода это изменение может потенциально повлиять (потому что всегда есть вероятность, что вы что-то упустили) следует быть чрезвычайно осторожным и запускать агрессивные модульные тесты, чтобы определить, не нарушит ли удаление этого древнего унаследованного кода ваше приложение.
Теперь, несмотря на все сказанное, вероятно , не стоит тратить ваше время или здравомыслие на то, чтобы попытаться удалить подобный код. Нет, если это не становится серьезной проблемой с вашим приложением (например, неспособность завершить сканирование безопасности из-за раздувания приложения ... почему да, я ДЕЙСТВИТЕЛЬНО все еще имею в виду пример), поэтому я бы не рекомендовал его, если вы не достигнете такая ситуация, когда код действительно начал гнить.
Короче говоря - если вы знаете, что делает код, сначала проверьте его. Если вы этого не сделаете, вы, вероятно, можете оставить это в покое. Если вы знаете, что не можете оставить это в покое, посвятите свое время агрессивной проверке изменений перед их внедрением.
источник
Мой подход, который я всегда считал отраслевым стандартом в этом случае, странно до сих пор не упоминался:
Получить вторую пару глаз.
Существуют различные виды «неиспользуемого кода», и в некоторых случаях удаление целесообразно, в других случаях вам следует его реорганизовать, а в других случаях вы убегаете так далеко, как можете, и никогда не оглядываетесь назад. Вам нужно выяснить, какой это, и для этого вам лучше всего соединиться со вторым - опытным! - разработчик, тот, кто очень хорошо знаком с базой кода. Это значительно снижает риск ненужной ошибки и позволяет вносить необходимые улучшения, чтобы поддерживать базу кода в поддерживаемом состоянии. И если вы этого не сделаете, в какой-то момент у вас закончатся разработчики, которые очень хорошо знакомы с базой кода.
Я также видел подход к ведению журнала - точнее, я видел код ведения журнала: еще больше мертвого кода, который оставался там в течение 10 лет. Подход журналирования вполне приличный, если вы говорите об удалении целых функций, но не если вы просто удаляете небольшой кусочек мертвого кода.
источник
Простой ответ на ваш вопрос заключается в том, что вы не можете безопасно удалить код, который вы не понимаете, в том числе не понимая, как он вызывается. Там будет некоторый риск.
Вы должны будете решить, как лучше смягчить этот неизбежный риск. Другие упоминали ведение журнала. Регистрация может, конечно, доказать, что она используется, но не может доказать, что это не так. Поскольку основная проблема с мертвым кодом заключается в том, что он поддерживается, вы можете с легкостью добавить комментарий о том, что это подозреваемый мертвый код, и не поддерживать его.
Если код находится под контролем исходного кода, вы всегда можете узнать, когда он был добавлен, и определить, как он был вызван.
В конечном счете, вы либо понимаете это, оставляете это в покое, либо рискуете.
источник
В случае, если разработчик рассматриваемого кода все еще доступен, просмотрите удаление кода с ним . Также читайте комментарии в коде .
Вы получите правильное объяснение, почему этот код был добавлен и для какой функции он служит. Это может быть просто поддержка для конкретного случая использования, или у вас даже может не хватить опыта, чтобы судить, действительно ли это не требуется. В крайнем случае можно удалить все свободные операторы из программы на C и не заметить ничего неправильного (может потребоваться несколько минут, чтобы нехватить памяти).
Это действительно плохая культура, когда автор кода сидит рядом с вами, но вы не видите причин для разговора, потому что вы уверены, что он просто пишет плохой код, а у вас все так прекрасно. И, конечно же, он просто пишет случайные слова в комментариях, не нужно тратить время на чтение.
Одна из наиболее важных причин написания комментариев в коде - объяснить, ПОЧЕМУ он был реализован таким образом. Вы можете не согласиться с решением, но вам нужно принять во внимание проблему.
Обсуждение с автором может также выявить, что код является историческим остатком того, что было удалено или никогда не было завершено, поэтому его можно безопасно удалить.
источник
Я полностью согласен с первым пунктом Маркуса Лозберга: код должен определенно анализироваться с помощью инструментов. Мозгам обезьян нельзя доверять с такой задачей !!
Большинство стандартных языков программирования могут использоваться в IDE, и каждая IDE, которую стоит назвать, имеет функцию «найти для всех», которая является именно тем инструментом, который подходит для такой ситуации. (Например, Ctrl + Shift + G в Eclipse)
Конечно, инструменты статического анализатора не идеальны. Необходимо помнить о более сложных ситуациях, когда решение о вызове рассматриваемого метода происходит только во время выполнения и не раньше (вызовы через Reflection, вызовы «eval» -функций в языках сценариев и т. Д.).
источник
Две возможности:
источник