Какова обратная сторона условных атрибутов по сравнению с #if/#endif?
В моей базе кода много #if DEBUG/#endif
заявления, которые в основном имеют логику типа утверждения, что я недостаточно смел, чтобы работать в производстве.
[Conditional("DEBUG")]
public void CheckFontSizeMath()
{
//This check must not block SellSnakeOil() in production, even if it fails.
if(perferredSize+increment!=increment+preferredSize)
throw new WeAreInAnUnexpectedParallelUniverseException();
}
Буду ли я сожалеть, что изменил все это на новый способ ведения дел?
ОБНОВЛЕНИЕ: я ищу разницу между характеристиками двух похожих, но разных синтаксических стилей для выполнения утверждений. Я понимаю, что существует множество других способов демонстрации работы приложений, и я тоже этим занимаюсь. Я не готов отказаться от утверждений в целом.
Также я обновил имя метода для реалистичного сценария только для отладки.
4 ответа
Там нет проблем сделать это. Более современный подход заключается в использовании кодовых контрактов.
Пишите тесты! Тогда вам не нужно бояться, что ваш код делает то, чего вы не ожидаете, когда начинаете вносить эти изменения.
После того, как вы протестируете свой код, вы сможете рефакторинг для вашего сердца.
Код без тестов, даже написанный вчера, является устаревшим кодом... Получите копию книги " Эффективная работа с устаревшим кодом", это удивительная книга для управления устаревшим кодом; 32 отзыва с 5 звездами.
Другие варианты, которые у вас есть, это либо использовать кодовые контракты в соответствии с предложением Ханса, либо использовать методы утверждения в System.Diagnostics.Debug
пространство имен, например
Debug.Assert(1 + 1 == 2, "Math went wrong!");
Эта проверка автоматически удаляется при сборке версии выпуска.
Недостатки:
Это не так надежно, как жесткие проверки и исключения, которые работают независимо от конфигурации сборки. Это хорошая идея, чтобы принять во внимание тот факт, что большая часть кода должна обрабатывать ошибки в режиме выпуска.
Поведение может различаться в разных конфигурациях. Если вы неосторожны, вы можете в конечном итоге поместить не относящуюся к отладке логику в условный метод или добавить побочные эффекты, чтобы ваш производственный код не работал правильно (в основном то же самое, что случайный вызов методов внутри макросов ASSERT() в C++; side эффекты отстой!) Самое главное здесь исключения. Условные методы не позволяют вам возвращать значения по любой причине, чтобы исключить одну потенциальную ошибку. Тем не менее, они позволяют генерировать исключения, которые могут резко изменить путь, по которому происходит ошибка. Это усложняет понимание и поддержание вещей.
На сайте вызова не очевидно, что вызываются условные методы. Вы просто видите "DoSomething();". Я предпочитаю называть свои условные методы через соглашение, где я знаю, что это условно; например, DEBUG_SanityCheckBufferContents().
Если вы не извлечете тело метода, ваш отладочный код все еще будет существовать, и его можно будет осмотреть / вызвать посредством отражения среди прочего. IL метода все еще излучается, а сайты вызовов - нет.
Это делает модульное тестирование очень сложным, поскольку поведение отличается в разных конфигурациях. Это то же самое, что и пункт 2, но я добавил его в качестве отдельного пункта, потому что это действительно отстойно с точки зрения тестирования. Большинство разработчиков запускают тесты в режиме отладки или выпуска до проверки, но не в обоих случаях. Наш CI запускает оба набора тестов, так что очень просто проверить что-то после прохождения всех тестов, только чтобы убедиться, что вы нарушили конфигурацию отладки, но тесты пройдены, потому что вы выполнили сборку релиза (или наоборот).
Короче говоря, мои правила:
- Предпочитаю жесткие проверки и исключения с юнит-тестами. Используйте условные методы там, где это невозможно (например, критические проверки производительности)
- Назовите условные методы четко
- Прагма # если код в теле метода
- Будьте очень осторожны с изменением потока управления программой в условных методах (лично я предпочитаю Debug.Assert вместо исключения при использовании условных методов, но я видел множество других программистов, использующих исключения, так что это, вероятно, обсуждается)