Как стать автором
Обновить

Комментарии 44

их можно и нужно расставлять по коду как можно щедрее

Не согласен. assert выкидывает AssetionError, который сложно обрабатывать и пользователю ничего не скажет. AssetionError наследуется от Error, то есть не перехватывается catch(Exception exp) и все система упадет целиком без какой-то работы над ошибками.

Надо понимать, что assert это что-то вроде вся бизнес логика сломалось и ничего с системой сделать нельзя. Для реальной системе намного лучше использовать классическое:
if(условие не выполняется) {
throw new Подходящий_Exception(«Ваше сообщение об ошибке»);
}
Если пользователь увидит сообщение «Диск системы переполнен», он намного быстрее поймет что нужно сделать, чем непонятный AssertError.

assert хорош в unit-test'ах (но обычно у библиотек unit тестирования есть свои assert'ы вроде assertTrue, assertEquals и т, п.), но в реальном мало-мальски крупном приложении я бы assert использовать не стал.
Я не предлагал использовать assert в случае «Диск системы переполнен» (кстати, иронично, что в Java близкий аналог это OutOfMemoryError, которое тоже не Exception). Assert нужен в случае, когда, по вашим представлениям, условие должно выполняться абсолютно всегда, и если оно не выполняется, это означает только то, что ваши представления о системе не верны, а значит в ней есть баг. Тут, я считаю, действительно, нужно «падать» и искать баг, а не пытаться продолжить работу.

Если вы опасаетесь, что подсистема бажная и может кинуть AssertionError, при том, что для надсистемы она не критична (можно перезапустить подсистему / работать без нее), что же, заворачивайте вызовы подсистемы в try-catch с ловлей AssertionError, логгируйте ошибку и убивайте подсистему. Семантически ничего криминального в таком коде я не вижу, он отвечает требованиям и делает ровно то, что нужно. Хотя, вообще, это редкая ситуация.

Ну правильно, надо включать проверки в юнит-тестах. Но вы же не будете тянуть зависимость от JUnit в основной код.
Assert'ы имеют свои проблемы:
1) чрезмерное их использование приводит к захламлению рабочего кода, в то время как unit тесты и интеграционные тесты традиционно находятся в других пакетах модулях/режимах сборки. На мой взгляд мешать в рабочих классах ещё и методы тестирования (как описано в статье) скорее вредно. Одно дело редкая проверка с помощью assert'a в особо критичных случаях, другое дело вставка кусков кода только для «отладки»,

2) вместо assert'ов лучше использовать unit тесты, интеграционные тесты, системы непрерывного тестирования, которые не захламляют код, но при этом тестируют не менее надежно,

3) в относительно большой команде, тактика «чуть что все система падает» очень неудобна, так как будет мешать остальным разработчикам и тестерам работать с системой, вы сталкивались с ситуациями в большой команде, когда unit test'ы в системе непрерывного тестирования «шумят» (падают по непонятной причине)? Даже при этом, разработка всей команды становится не очень комфортной, потому что невозможно выкладывать изменения. Падение assert'ов потенциально может сделать недоступной разработку остальной команде на какое-то время. Даже полчаса -час простоя ВСЕЙ команды, может вылиться в потерю несколько человеко-дней,
Своя правда у вас есть.

1,2) На класс как в примере, действительно, можно было бы поддерживать referenceSet в коде тестов. В моем случае, есть довольно сложная система, которая не разбивается на такие простые компоненты. Функциональные тесты показывают, что ожидаемый результат отличается от реального, но ничего не падает. Как искать ошибку — не понятно. Все осдожняется тем, что система многопоточная, которые дебажить практически бесполезно. Проверочное состояние помогает определить, в каком месте какого потока состояние впервые отклоняется он ожидаемого — это зацепка для дебага.

3) Ну если падает конкретный тест/сценарий использования, можно с остальными работать. Если падает просто все, на худой конец можно пописать новые фичи, пока суть да дело :)
1,2) тогда да, assert имеет смысл, хотя другой вариант сделать примерно так
if(logger.isDebug() && условие) {
logger.debug(" Assert error ....");
}
С последующим ручным или автоматическим анализом логов. Плюс в том, что в отличии от assert'ов никто не мешает включать logger debug на продакшене для поиска особо сложным проблем. Но это все-таки редкая ситуация, когда используются хитрые способы.

3) Да, если тест/сценарий не выполняется при загрузке и т.п. вещах. Можно пописать новые фичи, но достаточно неприятное чувство когда человек 50 разработчиков хочет тебе лично попинать ногами за то что они не могут сделать свою срочную работу, а должны программировать в уме.
Такое логгирование ничем не лучше по производительности, потому что надо поддерживать то же самое проверлчное состояние и делать те же проверки, за исключением того, что оно не будет падать, хотя, по-хорошему, должно.
Такое логгирование ничем не лучше по производительности, потому что надо поддерживать то же самое проверлчное состояние и делать те же проверки

Кто мешает убрать все проверки сразу после отладки из реального кода?

за исключением того, что оно не будет падать, хотя, по-хорошему, должно

Кому должно падать? Я работал с системами, запуск, которых занимал до часа. Работал с системами, настолько большими. что физически не были способны работать иначе чем на сверхдорогом сервере, где сидела вся команда из пары десятков разработчиков. Отладка падениями обошлась бы там очень дорого.

Ещё раз assert'ы плохи тем что:
1) У QA и в системах непрерывного тестирования настройки могут быть как на продакшене, а значит никаких assert'ов работать не будет, если log.error легко поймать в логах автоматическими средствами, то assert'ы нет,

2) Если у QA или в системах непрерывного тестирования assert'ы включены, то с большим шансом тестирование может прерваться и QA заведут блокер с наивысшим приоритетом и не смогут тестировать релиз вообще. В результате даже пустячная проблема с assert'ов потребует сверх срочного решения. Ошибка в логах, приведет к созданию обычного тикета, который можно будет сделать в рабочем порядке.

3) Assert'ы мешают другим разработчикам,

4) Assert'ы нарушают разделение рабочего кода и кода тестирования, часто усложняя понимание кода
5) Не всякая система позволяет себя ронять и поднимать, иногда это будет обходится очень дорого (см. выше),

6) Логирования подозрительных кусков кода можно использовать на продакшене и на QA серверах, в отличии от assert'ов.

7) В современных IDE, вроде IDEA, достаточно способов отладки без всяких assert'ов, используя точки остановки c условиями. Причем в отличии от assert'ов, можно анализировать состояние реальных классов и переменных в живую, а не одного стек трейса.

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

9) В результате, правильное логирование, отладка и все возможные тесты и так покрывают большинство случаев где нужен assert,

10) В отличии от assert'ов логирование покажет сразу ВСЕ ошибки. Если в системе провалится несколько проверок, то логирование покажет их все, а assert потребует отладки каждой по отдельности. Ещё хуже если ошибки взаимосвязанные, есть большой шанс, что будешь разбираться со следствием, вместо причины, потому что тот assert сработал первым.
после отладки
А потом, когда вылезет новый баг, обратно весь код добавлять?

1) что мешает включить их у QA и в CI? Вы так пишете, как будто эти настройки даны свыше и изменению не подлежат.

2) Ну если баг вроде как есть, но пустячный (вроде неправильный формат вывода в лог), QA может отключить проверки в одном соответствующем классе и тестировать дальше. В чем проблема?

3) Аргументированно.

4) Напротив, проверки позволяют не держать все инварианты и предусловия в уме, а читать их. Упрощает вникание в сложные системы.

5) Принимается.

6) Почему нельзя проверки на QA?

7) Ок, ну чтобы поставить остановку с условием, проверочное состояние все равно надо обновлять. По сути, я, не зная о такой возможности, добивался того же эффекта, ставя остановку на бросание AssertionError. И потом дебаг в Идее со всеми плюшками

8, 9) Опять голословно в стиле «assert — корень всех зол».

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

Чисто субъективно: я стал тратить меньше времени на отладку подобных ошибок (и в принципе практически их не допускаю).

Но честно — я не знаю насколько сложна и запутанна система у Вас, и применим ли этот совет для нее.
Ни разу не встречал мнения «написал многопоточную систему, отлаживать было очень просто» :)

Да JMM тут вообще не причем, баги же не в стиле «не поставил volatile и изменения оказались не видны на другом ядре». По моему опыту, основные проблемы дебага многопоточности в том, что

1) при дебаге невозможно воспроизвести реальную динамику. Потому что дебаг останавливает все потоки, что в реальности не происходит.

2) При дебаге сложно следить за состоянием системы, чтобы понять, что уже что-то пошло не так. Допустим, остановились в какой-то точке какого-то потока, а другой поток замер в каком-то неинтересном месте (на локе, например). Хотя если бы он остановился в «нужном» месте, уже стало бы понятно, что то, что он видит, отличается от ожидаемого.

2) Просто суть багов, которые можно допустить в многопоточном приложении, более сложная и они трудноотлавливаемее.
А зачем человека минусуют. Такой способ мышления действительно имеет место быть. Важно хорошо представлять что и как взаимодействует и стараться критически важный код вдумчиво писать. И отлаживать так тоже удается. В голове!
Assert нужен в случае, когда, по вашим представлениям, условие должно выполняться абсолютно всегда

Но ведь проверка через assert работает только в отладочном режиме. И если ошибка проявится в production, вы об этом не узнаете, а программа окажется в непредусмотренном состоянии, а результаты её работы будут, в общем, случайными.
Обычная проверка с IllegalStateExceprion например, такой проблеме не подвержена.
1) Можно включить проверки для какого-то класса и на продакшене. 2) Если хотите IllegalStateException вместо AssertionError (хотя большой разницы нет, потому что IllegalStateException вы тоже наверняка никогда не ловите), делайте условие и IllegalStateException, никто не запрещает же. Но вы же вряд ли хотите, чтобы на продакшене помимо MyCoolSet еще в фоне поддерживался referenceSet, потому что тогда теряется вообще смысл делать MyCoolSet.
Все Exception обычно ловятся на границе исполняемого контейнера. Например, на веб сервере любой Exception внутри обработчика запроса будет перехвачен сервером, а пользователь получит сообщение об ошибке. При этом сервер продолжит работу.
А AssertionError, как Error, вырубит весь сервер, скорее всего.
Нет. Не вырубит. Вы б проверили перед тем как писать.
Не согласен. assert выкидывает AssetionError, который сложно обрабатывать и пользователю ничего не скажет. AssetionError наследуется от Error, то есть не перехватывается catch(Exception exp) и все система упадет целиком без какой-то работы над ошибками.
Не ясен смысл возражения. AssertionError не предназначен для обработки внутри приложения и создан именно для того, что бы приложение упало. Для ловли ошибок есть куча других exceptions.
С assert'ами есть ряд проблем при достаточно большой команде. Так как при включенных assert система падает, может сложиться ситуация при очень «щедром» использовании assert'ов, система упадет у товарищей по команде, так что они не смогут вообще работать с системой. Если assert'ы включаются у QA команде может быть ещё хуже ситуация, когда QA вообще не сможет ничего тестировать из-за падения assert'a в начале тестов.
Падение кода — это прекрасно. Это значит, что баг не привел к тихому неправильному поведению, деньги/заказы в интернет магазине/заявки не потеряли и т. д.

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

может сложиться ситуация при очень «щедром» использовании assert'ов, система упадет у товарищей по команде,
Щедрость проверок не должна ни на что влиять, потому что они никогда не должны падать. Если падает, при этом вы считаете, что система без проверок-то рабочая, вы неправильно используете проверки.
Падение кода — это прекрасно. Это значит, что баг не привел к тихому неправильному поведению, деньги/заказы в интернет магазине/заявки не потеряли и т. д.

1) Assert'ы не предназначены для продакшена,
2) Совсем не обязательно ронять всю систему, если можно выкинуть checked exception, правильно его обработать, откатить транзакцию и сообщить клиенту что именно эта функция, не работает,
3) Как раз. уронив систему до записи заявки, её легко потерять,
1) Согласен, о чем разговор?
2) Как я писал выше, правильно можно обработать и AssertionError.
3) Откатите вы транзакцию или упадете — результат-то один, и пользователь поймет, что произошла ошибка. Это допустимо.
2) Можно, но вы считаете что хорошая идея захламлять рабочий код обработкой случаев возможных только для отладки у разработчика?
3) Не всегда, error это фатальная ошибка которая не обещает сохранения данных. Но проблема assert'ов не в этом, а в том что падение assert'ов в отличии от остальных тестом в том что они мешают остальным разработчикам в команде, в отличии от unit, интеграционных и модульных тестов и в том что чрезмерное их использование увеличивают сложность «рабочего» кода (особенно при создании дополнительных методов проверки), в отличии от всех других методов тестирования,
2) я не вижу вариантов лучше, в случае, который я описал выше
3) Что error «не обещает»?) Процесс бросания и обработки error и exception ничем не отличаются
2) Вы описали странный случай, когда у вас две дублирующие логики в одном классе для проверки своего хранилища. Если вам так уж нужно было это отладить, ну добавили вы этот код, повесили точку останова на
private void checkSize() {
if(referenceSet.size() != size()) {
// точка остановки отладки
}
запустили отладку, а после того как нашли проблему убрали лишний код. Зачем тут assert'ы и лишний код, который никогда не будет работать в реальном приложении? В отличии от assert'а, в Idea можно будет анализировать код всех переменных и вызывать любые выражения, что позволит найти проблему намного быстрее. Вывод: совершенно непонятно, чем тут assert лучше обычного отладочного кода. Совершенно непонятно зачем в рабочем коде проекта отладочный мусор, да ещё и обработка AssertError'ов.

3) По умолчанию error'ы вообще не должны по-хорошему обрабатываться и выбрасываться. «An Error is a subclass of Throwable that indicates serious problems that a reasonable application should not try to catch. Most such errors are abnormal conditions.»
Да, кстати в IDEA есть возможность устанавливать условия срабатывания Breakpoint'ов. Поэтому вместо checkSize можно установить breakpoint с условием referenceSet.size() != size() и никаких assert'ов с разборами непонятных стек трейсов.
Так в том-то и дело, что корректно написанная программа не должна падать даже при включённых assertions. И если произошло падение, значит что-то не было учтено и мы нашли баг, что однозначное благо.
В байт-коде ассерт выглядит примерно так. Если в классе есть хоть один ассерт, то компилятор создаёт статическое финальное поле типа $assertionsEnabled и инициализирует значением desiredAssertionStatus для данного класса. Затем каждый ассерт оборачивается в if($assertionsEnabled) {...}. В принципе, насколько я понимаю, если вы напишете нечто подобное вручную, то вы получите аналогичный по скорости код. Поэтому я бы не стал заниматься misuse и написал бы что-то в духе:

class MyClass {
private static final boolean ADVANCED_VERIFICATION = 
             Boolean.parseBoolean(System.getProperty("myapp.MyClass.ADVANCED_VERIFICATION"));

...
  if(ADVANCED_VERIFICATION) {
    initReferenceSet();
  }
...
}


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

Для того и писал пост, кстати, — чтобы узнать что-то новое в комментариях ;)
Это навряд ли. Совсем другое дело, что JIT-компилятор assert-секции пропустит, потому что final boolean поле уже инициализировано и условие после подстановки превращается в if(false) {...}, что позволяет со спокойной совестью его выкинуть. Но точно такую же подстановку JIT-компилятор сделает и с вашей собственной final boolean переменной.
Смотрю на ваш код и удивляюсь. Перед тем, как превращать код в нечитаемое месиво плясками вокруг ассертов, лучше посмотреть сначала в сторону контрактного программирования.
Похоже на месиво, потому что вся логика опущена. 15 строк проверок и 15 строк «логики». В реальности — 15 строк проверок скорее на 150 строк логики, что не так страшно.

Что я должен увидеть в стороне контрактного программирования? Как бы вы решили проблему, описанную в комментарии habrahabr.ru/post/247253/#comment_8208091?
За джаву не отвечаю, ибо дотнетчик, но, судя по виденному мной, для джавы есть всё то же самое и больше. Соответственно, исхожу из этого.

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

У вас в коде понатыканы ненужные переменные, ненужные возвращаемые значения и т.п. Это мусор что при 15 строках, что при 150.
Все то же самое я прочел в статье на Википедии и так и не понял, как именно это решит мою проблему. Куча красивых слов. Почему в моем примере «понатыкано от балды»? Вы чисто физически корректность реализации множества по-другому не проверите. Все равно надо поддерживать параллельную заведомо корректную реализацию и сравнивать их. А как это будет оформлено — вот так на коленке, или с помощью супер-пупер красивого контрактного фреймворка, я разницы не вижу. Задачу ловли багов они решают одинаково.

Не знаю, считается ли Checkers framework контрактным программированием в Java, и если да, я представляю, о какой статической валидации идет речь, но это работает только в тривиальных случаях. Никакую ошибку в реализации множества он статически не выловит, пока не изобретут ИИ умнее человека.
Корректность реализации множества можно проверить обычными юнит-тестами.

Контрактное программирование и обычное функциональное/юнит тестирование позволяют избежать излишнего кода. Видимо, Вы не чувствуете (именно слово 'чувствуете') в этом проблему. Когда Ваш код вырастет на сотни тысяч строк кода, обзаведется огромным количеством внутренних связей, сложной и запутанной доменной моделью, Вы поймете, что лишние 10-20% кода увеличивают время для прочтения и понимания, что происходит в коде, на порядок. Что в свою очередь замедляет разработку, а в какой-то момент просто ее парализует (наблюдал такое, когда ядро самописного фреймворка все боялись трогать — и ставили костыли в коде для обхода его багов).

А после того когда Вы выкините весь этот тестовый код из продакшн-кода, Вы почувствуете прилив свежего воздуха.
Множества — да, но выше я уже писал, что пример упрощен. Невозможно проверить юнит-тестами относительно монолитную многопоточную систему.

лишние 10-20% кода увеличивают время для прочтения и понимания, что происходит в коде

Проверки явно декларируют то, что без них разработчик вынужден держать в голове, при дебаге «методом пристального взгляда» или обычном. Поэтому я не согласен.
Предусловия еще куда ни шло (и то их можно опускать, если не пишешь библиотеку с апи или методы не обрабатывают внешние данные).
Но тот откровенно тестовый код как в Вашем примере — однозначно захламляет кодовую базу.
В целом ваш пример действительно выглядит очень искусственно. По идее надо из MyCoolSet выкинуть весь тестовый функционал и создать отдельный класс типа ValidatingSet, например, который в конструкторе получает любой другой Set и делегирует к нему все вызовы, параллельно поддерживая HashSet и сравнивая результаты. Если MyCoolSet всегда создаётся через какой-нибудь фабричный метод, то в режиме тестирования вы будете создавать new ValidatingSet(new MyCoolSet()) вместо просто new MyCoolSet(). Тогда у вас будет полное разделение кода функционала и кода верификации, плюс код верификации будет абстрагирован от кода функционала и его можно будет переиспользовать для других реализаций Set. Ну и в продакшне вы не потеряете даже память на null-ссылку referenceSet, раз уж вы беспокоитесь насчёт производительности.
Я уже писал несколько раз, что пример упрощен, естественно, есть тысяча более правильных способов проверить корректность реализации множества, начиная с использования guava-testlib.
Ну вот по упрощённому примеру в данном случае совсем непонятно, как должен выглядеть неупрощённый пример, в котором ваш подход оправдан. Возможно, вы упростили чрезмерно :-)
Коллеги, по самой статье есть ряд замечаний и фактических ошибок.

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

По примеру кода полно фактических ошибок использования assert:

1.
assert initReferenceSet();

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

2.
assert addToReferenceSet(e);
//....
assert removeFromReferenceSet(o);

Проблемs такие же, что и в пункте 1.
3.
assert referenceSet.size() == size() :
                "Cool size diverged from reference size";

А это вообще ворох проблем. К пункту 1 добавляется возможный невнятный NullPounter в режиме дебага, которого не будет на production.

Всё же, желательно, чтобы код с включенными assert и без них работал и работал одинаково.

Теперь о проблемах assert.
1. Народ правильно писал выше. На production они не нужны, т.к. не хорошо, когда приложение разваливается на некорректных данных. Обрабатывать эти assert не удобно. Об этом уже писали, не буду повторяться.
2. throw new IllegalStateException во всех отношениях лучше. Об этом тоже писали.
3. Они действительно захламляют код, и при определенной неаккуратности, его ещё и ломают.

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

Блин, ну вы бы внимательно прочитали сначала, зачем эти вызовы функций под проверками — именно для того, чтобы они НЕ были вызваны на продакшене.

Никакой NPE я не получу, потому что checkSize() вызывается, так или иначе, только из-под assert.

Как верно заметил lany, в принципе, в посте описан менее многословный способ делать какие-то верифицирующие проверки с состоянием: habrahabr.ru/post/247253/#comment_8207963

не хорошо, когда приложение разваливается на некорректных данных.

Как я уже писал раз пять, я не предлагаю делать assert на некорректных данных! Я предлагаю assert на некорректной программе.

Проверки захламляют код уж точно не больше, чем ISE. И «ломают» его точно так же, хотя, на самом деле, не ломают, а помогают вам — habrahabr.ru/post/247253/#comment_8208035
Да, извините, до последнего абзаца я не добрался. Видимо, выходные прошли хорошо :)
Зато глаза зацепились за явный антипатерн. Так как сделано в примере, лучше не делать.

Такое лучше через assert не реализовывать. Лучше правда такое делать так, как описано в #comment_8207963
Мне такой вариант нравится больше, чем assert. Хотя там над API нужно серьезно думать.
Но всё же, я больше склоняюсь к мысли, что всё это не нужно.

По мне лучше делать так:

1. Явные проверки закрыть UnitTest-ами.
2. Входные данные отбраковывать через throw new IllegalState или какими-нибудь чеками из guava (там их мало, мне пришлось дописывать свои, но в том же ключе).
3. И в тестовой среде, и production код должен работать одинаково.
4. Идти по пути максимальной понятности кода.

Таким образом, мы коду задаем жесткое API и уже заранее знаем что может произойти, и как это обработать. Если всё сделать правильно, то лишние assert не особо нужны. Действительно, зачем они нужны, если на любое некорректное поведение в системе мы получаем Runtime.

Кроме, того это замечательно ложится на EJB, в которых транзакции автоматом откатываются при Runtime.

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

Но возможная другая ситуация, вам дали поддерживать систему, в которой разработчик забил на хоть какую-то целостность входных данных. Это привело к тому, что любые не такие входные данные (а система то, сложная) приводят к NPE. Чтобы понять, что не так. нужно раз 10 воспроизвести этот NPE и подебажить часов 5-10 (я не шучу, так и было). Вот там-то да, я щедро раcставлял assert, т.к. ошибки были однотипные, что сильно экономило время их разбора.

Почитал ветку комментария #comment_8208035. Полностью согласен с вашими оппонентами. Особенно красноречив последний комментарий. Я тоже так делаю. Idea рулит!
У Google Guava есть набор методов в классе Preconditions которые прячут тот самый if (condition) throw Exception(message) при этом сохраняют удобство читаемости «assert ...» (в одну строку).
Это действительно уменьшает количество кода по сравнению с if'ами и становится понятно какие вариации недопустимы.
Одно «но»: Не все указывают эти предусловия в javadoc'ах и не все в общем-то их читают, но хорошо что в исходники заглядывают.
такое и у Spring есть: org.springframework.util.Assert
Зарегистрируйтесь на Хабре, чтобы оставить комментарий

Публикации