В моей команде мы убирали много старых вещей в большом монолитном проекте (целые классы, методы и т. Д.).
Во время этих задач по очистке мне было интересно, есть ли какая-нибудь аннотация или библиотека более привлекательная, чем обычно @Deprecated
. Это @FancyDeprecated
должно помешать успешной сборке проекта, если вы не очистили старый неиспользуемый код после истечения определенной даты.
Я искал в Интернете и не нашел ничего, что имеет описанные ниже возможности:
- должна быть аннотация или что-то подобное для размещения в коде, который вы собираетесь удалить до определенной даты
- до этой даты код скомпилируется и все будет работать нормально
- после этой даты код не будет скомпилирован, и он сообщит вам о проблеме
Я думаю, что я ищу единорога ... Есть ли подобная технология для какого-либо языка программирования?
В качестве плана BI я думаю о возможности создания магии с помощью некоторых модульных тестов кода, который должен быть удален и который начинает проваливаться в «крайний срок». Что Вы думаете об этом? Есть идея получше?
Ответы:
Я не думаю, что это будет полезной функцией, когда она действительно запрещает компиляцию. Когда в 01/06/2018 большие части кода, которые были скомпилированы днем ранее, не будут компилироваться, ваша команда снова быстро удалит эту аннотацию, очищенный код или нет.
Тем не менее, вы можете добавить некоторые пользовательские аннотации к коду, как
и создайте небольшой инструмент для сканирования этих аннотаций. (Простой вкладыш в grep сделает это, если вы не хотите использовать отражение). На других языках, кроме Java, можно использовать стандартизированный комментарий, подходящий для «grepping», или определение препроцессора.
Затем запустите этот инструмент незадолго до или после определенной даты, и, если он все еще обнаружит эту аннотацию, напомните команде о необходимости срочно очистить эти части кода.
источник
Это будет особенность, известная как бомба замедленного действия . НЕ СОЗДАЙТЕ ВРЕМЕННЫЕ БОМБЫ.
Код, независимо от того , насколько хорошо вы структурировать и документировать его, не превратится в плохо понимал почти мифический черный ящик , если он живет за пределами определенного возраста. Последнее, что кому-то понадобится в будущем, - это еще один странный режим отказа, который застает их врасплох, в самое неподходящее время и без очевидных средств защиты. Нет абсолютно никакого оправдания для преднамеренного создания такой проблемы.
Посмотрите на это следующим образом: если вы организованы и в курсе вашего кода достаточно базы , что вы заботитесь о устаревания и следовать по нему, то вам не нужен механизм в коде , чтобы напомнить вам. Если вы этого не сделаете, есть вероятность, что вы также не в курсе других аспектов кодовой базы и, вероятно, не сможете своевременно и правильно реагировать на сигнал тревоги. Другими словами, бомбы замедленного действия никому не нужны. Просто сказать нет!
источник
В C # вы должны использовать
ObsoleteAttribute
следующий способ:Идея здесь состоит в том, чтобы сделать как можно более безболезненное изменение для затронутых пользователей и гарантировать, что они могут продолжать использовать эту функцию по крайней мере для одной версии библиотеки.
источник
libfoo.so.2
иlibfoo.so.3
могут прекрасно сосуществовать друг с другом, ваш нисходящий поток может продолжать использовать старую библиотеку, пока они не переключатся.Вы неправильно поняли, что значит «устарел». Устаревший означает:
Оксфордские словари
По определению устаревшая функция все равно будет компилироваться.
Вы хотите удалить функцию на определенную дату. Все в порядке. То, как вы делаете это, вы удаляете это в тот же день .
До тех пор, пометьте как устаревший, устаревший, или как его называет ваш язык программирования. В сообщении укажите дату, когда оно будет удалено, и то, что его заменяет. Это будет генерировать предупреждения, указывающие, что другие разработчики должны избегать нового использования и должны заменять старое использование везде, где это возможно. Эти разработчики будут либо соблюдать, либо игнорировать его, и кому-то придется иметь дело с последствиями этого, когда он будет удален. (В зависимости от ситуации это может быть вы или разработчики, использующие его.)
источник
Не забывайте, что вам необходимо сохранить возможность создавать и отлаживать более старые версии кода, чтобы поддерживать уже выпущенные версии программного обеспечения. Саботаж сборки после определенной даты означает, что вы также рискуете помешать себе в будущем выполнять законные работы по обслуживанию и поддержке.
Кроме того, это кажется тривиальным обходным решением - вернуть часы моей машины за год или два до компиляции.
Помните, что «не рекомендуется» - это предупреждение о том, что что-то исчезнет в будущем. Если вы хотите принудительно запретить людям использовать этот API, просто удалите связанный код . Нет смысла оставлять код в базе кода, если какой-то механизм делает его непригодным для использования. Удаление кода дает вам проверки во время компиляции, которые вы ищете, и не имеет тривиального обходного пути.
Редактировать: я вижу, вы ссылаетесь на "старый неиспользуемый код" в вашем вопросе. Если код на самом деле не используется , нет смысла его оскорблять. Просто удали это.
источник
Я никогда раньше не видел такой возможности - аннотацию, которая начинает действовать после определенной даты.
Однако этого
@Deprecated
может быть достаточно. Поймать предупреждения в CI и заставить его отказаться от принятия сборки, если таковые имеются. Это переносит ответственность с компилятора на ваш конвейер сборки, но имеет то преимущество, что вы можете (полу) легко изменять конвейер сборки, добавляя дополнительные шаги.Обратите внимание, что этот ответ не полностью решает вашу проблему (например, локальные сборки на машинах разработчиков все равно будут успешными, хотя и с предупреждениями) и предполагают, что у вас настроен и запущен конвейер CI.
источник
Вы ищете календари или списки дел .
Другой альтернативой является использование пользовательских предупреждений компилятора или сообщений компилятора, если вам удастся иметь мало предупреждений в вашей кодовой базе. Если у вас слишком много предупреждений, вам придется потратить дополнительные усилия (около 15 минут?) И собрать предупреждение компилятора в отчете о сборке, который ваша непрерывная интеграция предоставляет для каждой сборки.
Напоминания о том, что код должен быть исправлен, хороши и необходимы. Иногда эти напоминания имеют строгие крайние сроки в реальном мире, поэтому может понадобиться поставить их на таймер.
Цель состоит в том, чтобы постоянно напоминать людям, что проблема существует и должна быть решена в течение определенного периода времени - функция, которая просто нарушает сборку в определенное время, не только не делает этого, но сама эта функция является проблемой, которая должна быть исправлено в течение определенного периода времени.
источник
Один из способов думать об этом - то, что вы подразумеваете под временем / датой ? Компьютеры не знают, что это за понятия: они должны быть каким-то образом запрограммированы. Распространено представлять время в формате UNIX «секунд с начала эпохи», и обычно вводить определенное значение в программу с помощью вызовов ОС. Однако, независимо от того, насколько распространено это использование, важно помнить, что это не «фактическое» время: это просто логическое представление.
Как уже отмечали другие, если вы установили «крайний срок», используя этот механизм, тривиально кормить в другое время и нарушать этот «крайний срок». То же самое касается более сложных механизмов, таких как запрос NTP-сервера (даже через «безопасное» соединение, поскольку мы можем заменять наши собственные сертификаты, центры сертификации или даже исправлять криптографические библиотеки). Сначала может показаться, что такие люди виноваты в работе вокруг вашего механизма, но может случиться так, что это делается автоматически и по уважительным причинам . Например, неплохо иметь воспроизводимые сборки , и инструменты, которые могут помочь в этом, могут автоматически сбрасывать / перехватывать такие недетерминированные системные вызовы. libfaketime делает именно это,устанавливает временные метки всех файлов, функция записи / воспроизведения
1970-01-01 00:00:01
Qemu подделывает все аппаратное взаимодействие и т. д.Это похоже на закон Гудхарта : если вы заставляете поведение программы зависеть от логического времени, то логическое время перестает быть хорошей мерой «фактического» времени. Другими словами, люди обычно не будут связываться с системными часами, но они будут, если вы дадите им причину.
Существуют и другие логические представления времени: одним из них является версия программного обеспечения (либо ваше приложение, либо некоторая зависимость). Это более желательное представление для «крайнего срока», чем, например, для времени UNIX, так как оно более специфично для того, что вас волнует (изменение наборов функций / API), и, следовательно, с меньшей вероятностью нарушит ортогональные задачи (например, возиться со временем UNIX до работа в установленные сроки может привести к повреждению файлов журналов, заданий cron, кешей и т. д.).
Как уже говорили другие, если вы управляете библиотекой и хотите «подтолкнуть» это изменение, вы можете нажать новую версию, которая устарела, и вызвать новые предупреждения, чтобы помочь пользователям найти и обновить их использование), а затем другую новую версию, которая удаляет Особенности полностью. Вы можете опубликовать их сразу после друг друга, если хотите, поскольку (опять же) версии являются просто логическим представлением времени, они не должны быть связаны с «фактическим» временем. Семантическая версия может помочь здесь.
Альтернативная модель - «вытянуть» изменения. Это похоже на ваш «план Б»: добавьте тест в приложение-потребитель, которое проверяет, что версия этой зависимости, по крайней мере, является новым значением. Как обычно, красный / зеленый / рефакторинг для распространения этого изменения через кодовую базу. Это может быть более подходящим, если функциональность не является «плохой» или «неправильной», а просто «плохо подходит для этого варианта использования».
Важный вопрос с подходом «pull» заключается в том, считается ли версия зависимости «единицей» ( функциональности ) и, следовательно, заслуживает тестирования; или это просто «частная» деталь реализации, которая должна выполняться только как часть реальных модульных ( функциональных ) тестов. Я бы сказал: если различие между версиями зависимости действительно считается особенностью вашего приложения, тогда проведите тест (например, проверяя, что версия Python>> 3.x). Если нет, то недобавить тест (поскольку он будет хрупким, неинформативным и чрезмерно ограничительным); если вы управляете библиотекой, тогда идите по «push» маршруту. Если вы не управляете библиотекой, просто используйте ту версию, которая вам предоставлена: если ваши тесты пройдут, ограничивать себя не стоит; если они не пройдут, значит, это ваш «крайний срок»!
Существует другой подход, если вы хотите препятствовать определенному использованию функций зависимостей (например, вызывать определенные функции, которые плохо работают с остальным кодом), особенно если вы не контролируете зависимость: запретите свои стандарты кодирования / не поощряйте использование этих функций и добавляйте проверки для их линтера.
Каждый из них будет применим в разных обстоятельствах.
источник
Вы управляете этим на уровне пакета или библиотеки. Вы контролируете пакет и контролируете его видимость. Вы можете отказаться от видимости. Я видел это внутри крупных компаний, и это имеет смысл только в культурах, которые уважают владение пакетами, даже если пакеты имеют открытый исходный код или бесплатны для использования.
Это всегда грязно, потому что команды клиентов просто не хотят ничего менять, поэтому вам часто нужно несколько раундов только для белого списка, когда вы работаете с конкретными клиентами, чтобы договориться о крайнем сроке миграции, возможно, предлагая им поддержку.
источник
Одним из требований является введение понятия времени в сборку. В C, C ++ или других языках систем , которые используют C-подобный препроцессор / построить 1 , можно было бы ввести метку времени через определяет для препроцессора во время сборки:
CPPFLAGS=-DTIMESTAMP()=$(date '+%s')
. Это может произойти в make-файле.В коде можно сравнить этот токен и вызвать ошибку, если время истекло. Обратите внимание, что при использовании макроса функции обнаруживается случай, который кто-то не определил
TIMESTAMP
.В качестве альтернативы можно просто «определить» рассматриваемый код, когда придет время. Это позволило бы программе компилироваться при условии, что никто ее не использует. Скажем, у нас есть заголовок, определяющий api, "api.h", и мы не разрешаем звонить
old()
через определенное время:Подобная конструкция, вероятно, исключит
old()
тело функции из некоторого исходного файла.Конечно, это не доказательство глупости; можно просто определить старый
TIMESTAMP
в случае аварийной сборки в пятницу вечером, упомянутой в другом месте. Но это, я думаю, довольно выгодно.Это, очевидно, работает только тогда, когда библиотека перекомпилируется - после этого устаревший код просто больше не существует в библиотеке. Это не помешало бы ссылкам клиентского кода на устаревшие двоичные файлы.
1 C # поддерживает только простое определение символов препроцессора, а не числовые значения, что делает эту стратегию нежизнеспособной.
источник
TIMESTAMP
перекомпилироваться при каждой сборке. Это также выведет из строя инструменты, такие какccache
. Это означает, что типичное время компиляции для инкрементных сборок значительно увеличится в зависимости от того, насколько сильно на кодовую базу влияют функции, которые устарели таким образом.TIMESTAMP
значения, скажем, на 86400, чтобы получить ежедневную детализацию и, следовательно, меньшее количество перекомпиляций.В Visual Studio вы можете настроить сценарий предварительной сборки, который выдает ошибку после определенной даты. Это предотвратит компиляцию. Вот сценарий, который выдает ошибку 12 марта 2018 года или после этой даты ( взято отсюда ):
Обязательно прочитайте другие ответы на этой странице, прежде чем использовать этот скрипт.
источник
Я понимаю цель того, что вы пытаетесь сделать. Но, как уже упоминали другие, сборочная система / компилятор, вероятно, не подходящее место для реализации этого. Я бы предложил более естественный уровень для реализации этой политики - это либо переменные SCM, либо переменные среды.
Если вы сделаете последнее, в основном добавьте флаг функции, который помечает прогон предварительного устаревания. Каждый раз, когда вы создаете устаревший класс или вызываете устаревший метод, проверяйте флаг функции. Просто определите одну статическую функцию
assertPreDeprecated()
и добавьте ее к каждому устаревшему пути кода. Если он установлен, игнорировать вызовы assert. Если это не бросить в исключение. Как только дата пройдет мимо, снимите флажок функции в среде выполнения. Любые устаревшие вызовы кода будут отображаться в журналах выполнения.Для решения на основе SCM я предполагаю, что вы используете git и git-flow. (Если нет, логика легко адаптируется к другим VCS's). Создать новую ветку
postDeprecated
. В этой ветке удалите весь устаревший код и начните работу по удалению любых ссылок, пока он не скомпилируется. Любые нормальные изменения продолжают вносить вmaster
ветку. Продолжайте объединять любые изменения кода, не осуждаемые как устаревшие,master
обратно,postDeprecated
чтобы минимизировать проблемы интеграции.После окончания срока действия устаревшей создайте новую
preDeprecated
ветку изmaster
. ЗатемpostDeprecated
вернитесь вmaster
. Предполагая, что ваш выпуск выходит изmaster
ветки, теперь вы должны использовать пост-устаревшую ветку после даты. Если возникла чрезвычайная ситуация или вы не можете доставить результаты вовремя, вы всегда можете выполнить откатpreDeprecated
и внести необходимые изменения в эту ветку.источник