Я так понимаю, остальные цитаты вы решили проигнорировать?
не, меня просто эта зацепила сильно, и остальные надо смотреть в контексте, я их вот так в виде цитат не понял. (уже завтра, видимо, час ночи уже)
Нет. Когда вы пытаетесь прочитать байт следующий за последним.
тогда я не понимаю почему они говорят, что такое бывает часто? Это то, чего не должно происходить. Это то же самое, что попытаться получить 11-ый элемент массива, в котором 10 элементов. Это бывает не часто, а наоборот это то, чего никогда происходить не должно, и тут исключение уместно. Это не противоречит моим словам (путаница появляется только с тем, что они недопустимое поведение называют часто возникающим)
зачем эта фраза нужна, если «не только»? Это как сказать «ткань нужна для шиться одежды» и забыть сказать, что она используется ещё для 100 других целей.
Если бы там было сказано «для событий, которые не должны были произойти, используются исключения», то Ваше «не только» было бы вполне уместно, но когда там сказано «исключения используются для событий, которые не должны были произойти», то это описание назначения исключений. Это значит что для чего-то другого их использовать не нужно, они вот именно для этого.
В функцию валидации должны были или не должны были переданы невалидные данные?
это же функция валидации. Она предназначена для того, чтобы в неё невалидные данные попадали, иначе она не нужна вовсе, если бы там только валидные всегда были.
В метод, возвращающий значение из словаря, должен был, или не должен был быть передан несуществующий ключ?
не должен был. Если он был передан, то это произошло по ошибке
В http-клиент должен быть или не должен быть передан невозможный URI?
туда должен был попасть URI соответствующий стандарту, но при этом вполне может попасть несуществующий. При этом проверка на соответствие стандарту должна была произойти на этапе валидации, где несоответствие стандарту вполне ожидаемо (снова же, иначе функция валидации была бы не нужна). То есть тут всё вполне ожидаемо и предсказуемо :)
Нет. Нет никакой причины считать, что «any error condition» — это то, что «не должно было произойти».
ошибки и неожиданное поведение — это то, чему положено иногда происходить? Тогда почему это называется «ошибка» и «неожиданное поведение»? Мы заведомо пишем код с ошибками, и удивляемся событиям, которым положено периодически происходить? )
А что такое «ошибка в моем понимании»
в широком понимании, когда Вы под ошибкой понимаете не то, что какая-то часть системы сделала что-то не так, а то, что любой статус отличный от «успех» является ошибкой?
Может быть. Но это будет неверная (потому что бесполезная) интерпретация.
но Ваша интерпретация «ошибка — это то, что иногда происходит» как раз к этому и ведёт. Вы говорите, что ошибки — это часть стандартного поведения программы. Тогда поясните где грань между ошибкой и не ошибкой? Расшифруйте тут значение слова error короче :)
so that it reports the end by returning a special value; I won’t have it throw an exception
поясните идею, я что-то не понял. Они предлагают наоборот бросать эксепшин? То есть как только я читаю последний байт файла, то генерируется эксепшин, который мне надо ловить, иначе я не смогу продолжить выполнение своего кода? :) С потоковыми сокетами они также предлагают поступать, что когда я прочитал всё, что мне прислали, то не сокет должен изменить статус состояния, сообщив мне, что там пока пусто, а он должен мне эксепшин выдать?
P.S. Я полагаю они тут были неточны, и имели ввиду, что нужно бросать эксепшин в случае, если кто-то попытался продолжить чтение после того, как достиг конца файла — тут я вполне согласен. Просто тогда утверждение о том, что такое бывает редко, является неверным, если я могу как-то обнаружить тот факт, что прочитал файл до конца. Тогда получая порцию данных я просто буду смотреть осталось ли что-то ещё, и если осталось — продолжать чтение, а если нет — прекращу его. Если же я его по какой-то причине не прекратил, тогда эксепшин вполне уместен, почему бы и нет :)
Тут написано «только для вещей, которые не могут быть сделаны другими практиками». Это «другое», нежели ваше " только тогда, когда произошло что-то, чего не должно было произойти.".
В книге есть и та и другая фразы :) То есть наличие одной не отменяет наличие другой. Вот цитата из оригинала книги Exceptions are used in similar circumstances to assertions—for events that are not just infre quent, but that should never occur. Я где-то ранее в беседе уже приводил это на русском языке.
Вот понимаете ли, у вас свое понимание «контракта», не то, которым я и мои коллеги пользуемся.
хорошо, я не могу найти подходящего слова, чтобы заменить им слово «контракт» в своём утверждении, потому давайте уйдём от моего определения через «контракт» и обсудим само утверждение по факту: должно ли исключение бросаться ТОЛЬКО в ситуации, которая не должна была произойти, или НЕ ТОЛЬКО. Ведь важно это, потому что если я неправ, то никому уже не будет интересно правильное ли я слово подобрал или неправильное, если сама идея ошибочна. Если же я прав, то я всегда могу перефразировать это так, чтобы донести мысль до другого человека :)
«Лихко».
не увидел подтверждения Ваших слов. Там в тексте говорится «An exception is any error condition or unexpected behavior that is encountered by an executing program». То есть в явном виде сказано про ошибку или неожиданное поведение с которым столкнулась программа. Это то, о чём я и говорю «ТОЛЬКО то, что не должно было произойти».
Throw exceptions instead of returning an error code
Exceptions ensure that failures do not go unnoticed because calling code didn't check a return code.
обратите внимание на выражение error code (не status code, а именно error code). Я бы сказал, что тут речь про ошибки, которые не должны в программе возникать (а не ошибки валидации данных, например, которые скорее являются особым статусом данных, а не ошибкой), но вообще тут может иметься ввиду как одно, так и другое. Почему Вы считаете, что тут имеются ввиду именно ошибки в Вашем понимании? Просто я вижу это так, что если понимать ошибку в широком смысле, то любой отрицательный ответ может быть интерпретирован как ошибка и тогда это превращается в «не возвращайте false, возвращайте или true или бросайте исключение». Ну то есть в таком понимании ошибки утверждение приближается к абсурду.
Цитата оттуда же, которая явно говорит, что исключения — часть контракта
мы это с Вами обсуждали уже. Это как указание неустойки является частью договора, так и описание исключений является частью контракта. И я Вам уже ответил, что в такой значении я вполне с этим согласен, но я говорил подразумевая другое значение контракта — той части контракта, которая является его сутью, как в договоре сам объект договора. Вот когда договорённость в отношении самого объекта договора нарушается, тогда и обращаются к пункту с неустойками. Так и тут, когда нарушается сама суть контракта (кто кого и как должен вызвать и что должны сделать или вернуть), тогда и обращаемся к пункту с исключениями (как на это нарушение реагировать).
for conditions that cannot be addressed by other coding practices
где вы тут увидели «только для другого»? :) Вы копируете разные части фразы, объединяете в них отдельные слова и говорите, что их надо так понимать. Там говорится «только для этого», а потом «если это нельзя решить другим способом», а у Вас это как-то скомпилировалось в «только для другого».
«Не только» что?
не только в этих случаях исключения нужно бросать. Подтвердите, что уважаемые цитируемые источники это утверждают, потому что сейчас Вы это доказываете через свои догадки. Вы показываете реализацию, а потом начинаете рассуждать о чём думали авторы кода, когда его писали (что они знали что это нисколько не «по-настоящему исключительная» ситуация), хотя на самом деле они могли считать ровно обратное, и код часто приводящий к выбросу этого исключения считать никчёмным и непрофессиональным.
То есть факты:
1. их код бросает это исключение (верю, проверять не буду)
2. это исключение в реализациях возникает часто (верю)
Но дальше пошли догадки:
так и должно быть, и они это знали (не верю, предъявите доказательство… я не верю, что так и задумывалось)
процитируйте пожалуйста и выделите слово «другого» жирным, как я сделал для Вас, когда выделял слова «только», «по настоящему» и «не может».
Я утверждаю, что ситуация, в которой исключения используются в .NET BCL противоречит критериям, описанным в приведенной цитате.
хорошо, но я не могу этого проверить. Приведите тогда цитату из книги уровня «Совершенный код», где бы в явном виде говорилось, что вот НЕ ТОЛЬКО. Потому что Вы сейчас даёте конкретную реализацию, и мы начинаем гадать почему она такая. Вы говорите, что такое случается по 10 раз в день, а вдруг сами разработчики Вам ответят «так это неучи наш инструмент пользуют, и разумеется это не должно случаться в принципе, они просто на коленке код пишут» и в этом случае вся Ваша теория рассыпется, но мы этого проверить не можем, ведь смотрим на код и гадаем ))
всё, Вы начали отрицать факты. беседа потеряла смысл. Я Вам выделяю в тексте слово «только», а Вы отвечаете, что там нигде не сказано «только». И ладно когда Вы это сказали первый раз, и я подумал, что Вы просто пропустили, но когда я Вам его выделил, а Вы это повторили — значит Вы не пропустили, а просто игнорируете то, что противоречит Вашим убеждениям. Точно также Вы уже начали спорить не со мной, а с Макконнеллом на тему truly, при чём говорите, что спорите с моей интерпретацией его текста, но сами ставите под сомнение сам текст в явном виде.
Видимо время завершать беседу.
Throw an exception only for conditions that are truly exceptional. Exceptions should be reserved for conditions that are truly exceptional—in other words, for conditions that cannot be addressed by other coding practices.
ну да, совсем нет.
.NET BCL. Пример с ключом в словаре (в котором нет ничего исключительного) — он оттуда. И миллион других бросаемых ими исключений.
И он ничего не доказывает, потому что всего лишь означает, что позиция разработчиков в том, что не надо эту функцию дёргать не получив список существующих ключей. Я с этим инструментом не знаком, но могу предположить, что это что-то наподобие как попробовать запросить несуществующий ключ реестра или значение элемента массива с индексом больше максимального (выйдя за его пределы)
Возможно, кто-то использует (программные) исключения для описания исключений из правил. Но это точно не единственное их применение.
Тут снова же Ваши слова против текста профессиональной книги из топа. Вы всё ещё ссылаетесь лишь на своё мнение, что вот нисколько не аргумент, потому что я могу так же начать ссылаться исключительно на своё мнение и беседа превратится в тупое бодание двух упрямых баранов :) Потому давайте или подкреплять аргументами слова, или хотя бы ссылками на источники более достоверные, чем «потому что я так сказал».
Проблема в том, что вы устроили рекурсию. «Исключение предзначено для описания исключения», но вы не объясняете, что такое «исключение»
это не рекурсия, тут слово исключение имеет разные значения. Объект исключения (в коде) предназначен для описания исключительной ситуации (в логике программы). «Объект исключения» я думаю расшифровывать не нужно, а вот «исключительная ситуация» — это такая ситуация, которая не должна была произойти (возникновение которой исключается задачей, когда вам говорят «напишите программу сложения двух целых чисел», а на вход присылают «2.5 + 4.7» — вот это исключительная ситуация, которая по условия не должна возникать)
Так понятнее про игнорирование?
да. Но теперь Вы по сути сказали ровно то же самое, что и я: чтобы остановить выполнение кода, который не предназначен справляться с ситуацией и передать управление на тот уровень, где с ней умеют справляться. Просто выразили другими словами, а я Вас сразу не понял потому, что сказанное Вами звучит неоднозначно и может пониматься по-разному.
То есть суть в том, что Ваши слова в таком случае не противоречат сказанному мной
Каким образом какая-то функция валидации является примером того, что программист не может сам решать, каков у его кода контракт?
Перечитайте беседу, я это уже писал… дважды. В том числе в том комментарии, на который Вы этой фразой ответили
Объективен здесь только тот факт, что у МакКоннела написана такая фраза
Объективно то, что он излагает ту же идею: что исключение должно генерироваться только тогда, когда произошло что-то, чего не должно было произойти. И объективен тот факт, что эту книгу часто рекомендуют среди программистов к прочтению (она в топе рекомендаций). И потому у меня есть объективные причины полагать, что я прав (объективные потому, что писал книгу не я, и в топ выводил её не я, то есть это произошло без моего участия)
Да, они там нужны. Но не только там. Это важно, если что.
По Макконнеллу они нужны только там. Я считаю, что они нужны только там. Тысячи людей, которые читали эту книгу и рекомендуют её, считают, что в книге даются хорошие советы, значит они не увидели в ней ничего «еретического», значит считают эту идею как минимум неплохой. И только Вы сейчас настаиваете на том, что это не так. Предложите свой источник того же уровня, возможно другое мнение и правда существует в профессиональной среде, но пока у меня нет причин так считать.
А почему они находятся вне основной массы? По функционированию, не по предназначению?
по назначению. Они используются для описания исключений из правил. Просто вдумайтесь в название exception. ну и во фразу «it is exceptional situation» и «you should create an exception for it». Потому оно называется в английском «exception», а у нас «исключение», потому что именно для описания исключений предназначено, а не просто как часть функционального кода. То есть мы создаём объект исключения с описанием исключительной ситуации, которая произошла, а потом бросаем этот объект вверх, пока его кто-то не словит.
Предназначение исключения как программного инструмента — это создать сигнал, который вызывающий код не может случайно проигнорировать (только намеренно)
то есть для того, чтобы не обработать исключение, мне надо написать дополнительно код? Забавно, я думал мне приходится писать код для того, чтобы словить его и обработать где надо :) Получается я для каждого блока кода должен писать не список исключений, которые хочу ловить, а список исключений, которые ловить не хочу? Иначе я вполне могу забыть в вызывающем коде обработать этот сигнал, он поднимется на самый верх и заруинит программу. То есть этот сигнал может быть не обработан ни на одном уровне программы, при чём не специально, а просто по ошибке (забыли при написании кода добавить try...catch)
Да… и это не «неустойка взимается когда нарушен договор», а «неустойка взимается, чтобы соблюсти договор» :) Немного смешно прям.
Вы под контрактом понимаете расширительное понятие, в которое включаете все договорённости о действиях при его же нарушении. Это как прочитать в инструкции к устройству «если устройство зависнет — выключите и включите питание» и говорить, что одной из функций устройства является зависание, а одной из функций пользователя устройства — выключение и включение питания. Хотя на самом деле одно является ошибкой, а другое просто реакцией на ошибку… но для Вас если в инструкции что-то написано, значит это часть контракта.
Это не факт, это ваше мнение. Но не суть. Это не важно.
Странный у нас спор. Поверьте, это факт, я это слышал собственными ушами, а не придумал где-то у себя в голове и решил, что это так. Они иногда мне дают советы, которые не работают в конкретных ситуациях — это факт. Также фактом является то, что они не могут иногда указать критерий, по которому бы отделили те случаи, когда совет работает от этого нерабочего. Они просто говорят, что это исключение и обычно работает. Это всё факты, а не мои предположения. Моим предположением было бы, если бы я сказал «это значит, что они не смыслят в программировании» — вот это было бы уже мнение, а не факт, потому что данные события не доказывают их некомпетенстность.
Показательный пример чего?
Того, что программист далеко не всегда может сам решать каким будет контракт. Некоторые контракты являются просто бессмысленными и противоречивыми. Потому я и привёл в пример функцию валидации данных, которая при обнаружении невалидности данных генерирует исключение — тут контракт функции явно противоречит её сути, когда по контракту в функцию данные с ошибкой переданы быть не могут и это породит исключение, а сама суть функции в том, чтобы проверить переданы ли ей данные с ошибкой или без.
Объективная?
да, я её изложил. Объективная потому, что я не сам её выдумал, а сослался на источник, который находится вне меня (вне субъекта)
иии что?
это то же, о чём и я толкую. Что исключения нужны там, где произошло что-то, что никогда произойти не должно было.
Потому что есть другой механизм, который позволяет достичь того же поведения.
«исключительные» не значит «единственные». «исключительные» значит «те которые исключаются, находятся вне основной массы».
Вы понимаете, в чем предназначение исключений? Ну, по крайней мере, с точки зрения приведенной цитаты из МакКоннела?
Естественно. В том же, о чём писал я. Чтобы обработать в коде ситуацию, которая не должна была возникнуть и с которой этот код не предназначен справляться. Например когда при попытке сохранить изменения в БД рвётся соединение, тогда бросается исключение имеющее смысл «мне обещали, что предоставят ресурс для сохранения данных, но не предоставили — разбирайтесь кто из вас лажанул» (это так, простыми словами :)) )
P.S. Последнее Ваше сообщение похоже на троллинг. Давайте более содержательно, пожалуйста. Я же отвечал на Ваше сообщения и все эти «примера чего?» и «иии что?» содержали ответ в Вашем же сообщении, на которое я отвечал :)
«Если разработчик запрашивает в словаре несуществующий элемент, он получит исключение „несуществующий ключ“»
В таком виде да, ничего страшного нет. Так исключения в контрактах и описываются: как реакция на некоторые недопустимые действия (в Вашем примере меня предупреждают какие меня ждут последствия, если я запрошу несуществующий/неправильный ключ). Это значит, что я должен быть уверенным в существовании запрашиваемого ключа.
Описание исключений в контракте подобно описанию неустойки в договоре. Его там описывают не с расчётом на «неустойку описали, ну и хорошо, теперь можно нарушать пункты договора, всё предусмотрено», а с расчётом на «другая сторона может не выполнить свои ОБЯЗАТЕЛЬСТВА по договору и тогда мы поступим вот так». То есть неустойка хоть и является частью договора, но применяется тогда, когда его кто-то уже нарушает. Так и исключения, хоть и описываются в контракте, но применяются когда этот контракт уже нарушается.
Я же подумал с Ваших слов, что Вы предлагаете исключение сделать частью сути контракта, вида «функция генерирует число от 1 до 10, но если сгенерированное число больше 5, то функция сгенерирует исключение...», потому и сказал, что это гарантирует какую-то избыточность.
Приведите пример хорошего по Вашему мнению контракта предусматривающего исключение, и я Вам продемонстрирую чем это плохо. Пока могу только сказать то, что любой контракт, который предусматривает события, которые не должны произойти, является плохим контрактом (по меньшей мере избыточным). Представьте, что Вы с кем-то договариваетесь о встрече следующим образом: «давай встретимся завтра в кафе в час дня. Я обязательно буду. Но если не буду значит обязательно приди ко мне на похороны, потому что я умер. Но если потухнет Солнце — можешь не приходить...» ну и т.д. Вот зачем все эти исключения предусматривать по контракту, если достаточно сказать «я обязательно буду» что и будет контрактом, а вот все эти исключительные ситуации — это как раз реакция на нарушение контракта, которая очевидно в виде исключения и реализуется.
Ну то есть вы заведомо считаете себя лучше коллег. Кул.
Я лишь сообщил факт, Вы сейчас сами додумали остальное. Вообще утверждение «я лучше этого человека» звучит странно. Лучше в чём? :)
В том, что говорю только те вещи, в которых уверен, а если вдруг ошибаюсь, то признаю ошибки? — да, я крайне редко встречаю подобных людей и считаю это серьёзным преимуществом. Но ни о каком «я лучше» в общем понимании речи не идёт
Учитывая, что контракт в большей части случаев определяет разработчик кода, понятие «неуместного исключения» становится бессмысленным.
Это не совсем так. Показательный пример — функция валидации данных, которая в случае невалидности данных бросает исключение. А данном случае явное нарушение контракта, потому что сама функция теряет смысл и не должна была реализоваться, если ошибочность данных являлась недопустимой. Очень многие элементы контракта в коде устанавливаются не разработчиком, или устанавливаются им в неявном виде (как я привёл сейчас). Часто они продиктованы техзаданием, где описаны возможные события и состояния системы, а также описаны невозможные
Не «правильную», а «мне кажется, что правильную».
У меня есть объективная причина полагать, что я излагал правильную идею. Как минимум это подтверждается по меньшей мере одним уважаемым и рекомендуемым многими источником.
Отвратительный перевод
это не меняет сути. Ну и по контексту там понятно, что они называют утверждениями (несколькими пунктами выше про assert речь шла). А вот сутью тут является «for events that should never occur»
Из этого занятного вытекает, что как только у вас есть другой способ сообщать вызываемому коду об ошибке, чтобы он не мог ее проигнорировать (например, типизация), исключения перестают быть, гм, исключительными.
почему они перестают быть «исключительными»? Вы или в это слово вложили непонятный для меня смысл, или сказали что-то странное. И связь с типизацией я не понял. Если компилятор в момент компиляции обнаружит несоответствие типов, он вообще код не скомпилирует, а вот если он по какой-то причине не обнаружит этого (ну скажем типизация прикручена не на уровне компилятора, а где-то в рантайме), то когда код будет вызван с неправильными типами, он как раз таки исключение и будет бросать, потому что передача параметра неправильного типа — это нарушение контракта.
«То, чего никогда не может быть» — хорошо, перефразирую. «то, чего никогда не должно быть».
В более широком смысле исключение описывает ситуацию, в результате которой локальный кусок кода не может дальше выполняться
очень часто можно встретить выход в середине метода, потому что дальше он не может выполняться. Например когда происходит валидация массива значений, но сразу же обнаруживается, что там не массив, или когда был введён адрес АПИ к которому нужно было сделать запрос, но сам адрес оказался ошибочным и потому выполнение запроса невозможно и локальный код приходится завершать. Но если такие ситуации были предусмотрены по контракту, то тут нет причины бросать исключение и вполне логично вернуть код ошибки (которых там может быть 100 штук, начиная от недоступности АПИ и завершая ответом от АПИ, что пользователь неправильно ввёл пароль или указал недопустимый возраст).
В статье ни одного аргументированного довода против исключений не нашел
В статье указан основной недостаток — запутанность кода и нарушение инкапсуляции. Мы должны знать не только контракт вызова кода (функции), но и учитывать его внутренние особенности. Знать, что в каких-то вполне штатных ситуациях он может просто оборвать цепочку вызовов внешнего кода. Одно дело когда он обрывает цепочку вызовов потому, что его самого вызвали неправильно (передав неверные параметры или не позаботившись об окружении), а совсем другое дело, когда его и вызвали правильно, и всё в него правильно передали, а он БАЦ и исключение бросил.
А дальше вообще начинаются «Вредные советы»:
Пускай на верхнем уровне висит обработчик исключений и превращает все необработанные исключения в ошибки, сохраняет данные и деликатно завершает выполнение
Вырвали из контекста. Речь была про то, что любое исключение должно быть обработано. То есть исключения нужны не для того, чтобы ронять программу, а для того, чтобы правильно обрабатывать возникшие ошибки. Одним из аргументов того, что клиентский ввод не может обрабатываться как исключение, я видел в интернете утверждение типа, что нельзя ведь взять и прервать (уронить) выполнение программы просто потому, что человек опечатался. Так вот я и говорю, что обработка ситуации посредством порождения исключения не означает, что программу надо уронить. Как минимум на верхнем уровне всегда должен присутствовать обработчик всех необработанных ранее исключений, который будет логировать ошибки, показывать сообщения об ошибках пользователям и т.д. Это было к тому, что бросать исключения или не бросать никак не зависит от источника данных или чего либо ещё. И клиентский ввод может обрабатываться как исключение.
Если вы вернете из функции неизвестный код ошибки, ситуация будет еще опаснее.
Я не могу вернуть неизвестный код ошибки, потому что это будет нарушением контракта. Код точно знает какие ошибки он возвращает и внешний код должен точно знать, какими могут быть результаты выполнения вложенного кода (что он получает в ответ). Но когда код часть возвращаемых значений отдаёт не как возврат, а бросая исключение — это может стать серьёзной проблемой. Насколько я помню я саму статью писал под впечатлением от беседы на форуме, где человек рассказывал насколько круто он реализовал проброс ошибок валидации данных с помощью исключений сразу на несколько уровней и как это упростило его код. Потому я в статье уделял такое внимание именно случаем неуместного использования исключений (значительно больше, чем случаям их уместного использования). То есть человек вызывает функцию валидации для того, чтобы проверить верны ли данные, а в этой функции, обнаружив, что неверны, порождает исключение (как будто бы это что-то невообразимое, что потенциально ошибочные данные оказались ошибочными)
В работоспособности идей. Я вырабатываю универсальные правила, и если обнаруживается, что они не работают, то не пытаюсь закрыть дыры тоннами «особых случаев», а просто отказываюсь от того, что не работает. Вот коллеги этим нередко грешат, когда с уверенным лицом дают общий совет, а когда ты удивлённо озвучиваешь им конкретную ситуацию, из-за которой интересовался, то начинается «а, ну это исключение… тут иначе надо...» и оказывается что данный ранее совет можно просто в мусор выбросить сразу :)
Также я немного скорректировал ту идею, о которой писал в статье и продолжаю ею пользоваться годами: любой код должен вызываться по контракту, и если обнаруживается, что контракт был нарушен (ему передали неверные данные или не обеспечили заявленное окружение), то код должен бросить исключение, но ни в каких других случаях исключения не уместны. По сути исключение — это когда код говорит «я не знаю, что с этим делать, решайте это без меня»
Ни разу не видел код, который бы работал иначе и не порождал бы при этом лишних проблем.
Ну и Вы просили ссылки предоставить ранее. Вот например Макконнелл в «Совершенный код» говорит в пункте 8.4 то же самое (ну или как минимум очень близкое). Там у него тоже про «Исключения используются в
таких же обстоятельствах, как и утверждения: для событий, которые не просто редко
происходят, а которые никогда не должны случаться»
Учитывая, что идею я излагал достаточно правильную (может неточную в некоторых мелочах), очень удивлён, что её так задизлайкали. Видимо что-то я сделал не так и где-то в самом изложении проблема.
тут скорее вопрос в том, а нужно ли восстанавливаться после ошибки. Допустим можно вполне легко восстановиться после ошибки записи данных в БД, потому можно было бы в этом месте вернуть false в значении «не записалось попробуйте ещё» и пойти дальше обрабатывать ситуацию на верхних уровнях вида «например выдать сообщение о том, что надо попробовать обновить страничку». Но в силу того, что это лежит за пределами ответственности этого кода (например неверный пароль БД в конфиге, ошибка типа данных или что ещё, что коду было обещано, но не предоставлено), коду следует бросить исключение и прекратить работу, потому что сломалось что-то, за что он не ответственен. Меня тут в комментариях когда-то очень правильно поправили, что всё дело в предусмотренном к методу контракте. Если он предусматривает такую ситуацию, значит всё хорошо, а если не предусматривает (если это недопустимое состояние окружения, например), значит должно генерироваться исключение даже в тех случаях, когда гипотетически можно было просто вернуть статус провала операции и сделать вид, что всё ок. В каждом конкретном случае надо смотреть что находится в зоне ответственности, а что нет, и исходя из этого бросать исключения или возвращать статусы ошибок. Например если код валидирует данные и видит в них ошибку — то нужно возвращать статус ошибки (они по задумке могут быть невалидными), но если при попытке записать отвалидированные данные в БД выяснилось, что они невалидные — исключение (они по задумке обязаны быть валидными).
Ну то есть вы сам придумали определение, а теперь почему-то хотите, чтобы все остальные использовали механизм согласно этому определению. Найс.
Я рекомендую, а не пытаюсь кого-то заставить… описанный метод (и соответственно определения) я применяю в своей работе и он работает. Потому да, я предлагаю работающую схему (механизм) по которому у меня не возникает вопросов «вернуть ли код ошибки, false или бросить исключение». Задавая себе один простой вопрос я сразу принимаю решение о реакции на провал операции.
Как раз здравый смысл подсказывает, что, поскольку программа не контролирует свое окружение, никакую ситуацию нельзя исключать.
Если Вас поместить в стабильное окружение, где постоянно есть еда, вода и воздух в достаточных количествах, можете ли вы исключить ситуацию, что находясь в этом окружении задохнётесь от нехватки воздуха, умрёте от голода или жажды? Я вот исключил бы. То есть, я бы бросил исключение «наверх», если бы в какой-то момент почувствовал, что умираю от голода!
Это противоречит — вашей же — позиции «ваш код не должен ни о чем умалчивать». Отсутствие явной обработки исключения — это умолчание.
Он не умалчивает. Он всё ещё исключает возможность возникновения такого случая, так же, как это исключал код уровнем ниже. Позиция разработчика при написании такого кода приблизительно такая: «тот, кто вызовет этот код должен позаботиться о доступности папки на запись, её наличии и о работоспособности накопителя». То есть в этом коде всё ещё исключена невозможность записать файл! И если файл не записался, то исключение, которое бросил код уровнем ниже следует пропустить дальше по цепочке!
И… почему нельзя ошибку валидации представить в виде исключения?
Я не говорил что нельзя. Я говорил что в указанном контексте это плохо. Именно по причине того, что Вы написали далее
Эта функция может вернуть объект, если тот был удачно сохранён или ошибку валидации.
Или ошибку сохранения в БД. Или ошибку логирования. Или ошибку нехватки памяти. Вы себе представляете контракт такой функции?
У этой функции по факту есть 3 результата выполнения:
1. Объект удачно сохранён
2. Поля объекта не прошли валидацию (заполнены неверно)
3. Валидация или сохранение объекта невозможны (завершились ошибкой)
Таким образом у функции есть 2 штатных результата: сохранён/не сохранён. И нештатный результат: невозможно сохранить/проверить. Так зачем ШТАТНУЮ ситуацию представлять в виде исключения? Для меня вполне ожидаемо, что пользователь при регистрации допустит опечатку или не обратит внимания на заявленный шаблон заполнения поля.
В то же время я не ожидаю ситуации, что в момент записи в базу оборвётся соединение. А потому да, обрыв соединения — это исключение! Это значит, что произошло что-то такое, чего произойти в условиях моего кода не может! В момент работы было недопустимо изменено окружение, в котором код выполнялся.
Можете ли вы к каждому исключению дописать «но ведь это невозможно» или «но это же исключено»?
Ни к одному исключению это нельзя дописать, поэтому это мертворожденное правило — согласно нему любое исключение будет лишним.
Не любое… но многие из них! В моём коде иногда исключения присутствуют… очень часто я пропускаю исключения на самый верх и отдаю их пользователю в виде ошибки… вроде «недостаточно прав для сохранения файла, свяжитесь с администратором для решения проблемы»
Но на то они и исключения, что бы их было мало, а не весь код был ими напичкан по 3 штуки на функцию!
Я понимаю, что Вы можете быть со мной не согласны. Но как я писал ранее, это работающая схема, которая имеет полное право на жизнь. Я не пытался кого-то переубедить или что-то доказать. Как я и писал, эта статья — совет новичкам по позиционированию исключений как таковых… чем они являются и когда нужны. А учитывая, что это работает и работает неплохо, значит в согласии других не очень нуждается (грустно конечно, что многие оказались несогласны со мной, но всё же… суть статьи не в переубеждении)
По моему мнению такое определение лучше всего описывает саму суть исключений. Источника нет, как и у статьи в целом. Статья основана на опыте и ранее прочитанных и переваренных материалах
Вы так говорите, как будто тип и источник данных не определяются задачей.
Разумеется именно задачей и определяется. Но процитированная фраза была вырвана из контекста. А контекст был такой: источник получения данных не может сам по себе быть аргументом за или против порождения исключения
Если вас просят сохранить файл, уточните, возможна ли ситуация, что файл не сохранится. А если решили не уточнять, тогда не исключайте такую вероятность, а реализуйте реакцию на это событие. Ваш код не должен ни о чём умалчивать.
Такая ситуация, очевидно, возможна. А вот теперь вопрос — зачем обрабатывать ее на каждом уровне кода (ведь «код не должен ни о чем умалчивать»)?
Здравый смысл подсказывает, что при правильно работающем окружении программы такая ситуация во многих случаях исключена.
И не надо исключение на каждом уровне обрабатывать. Его надо породить на том уровне, где ситуация возникла, а обработать на том уровне, на котором эта ситуация была предусмотрена.
Что такое «отрицательный результат выполнения функции»?
Это, например, когда функция сохраняя данные в базу проводит их валидацию. Эта функция может вернуть объект, если тот был удачно сохранён или ошибку валидации. Ошибка валидации — отрицательный результат выполнения (объект не сохранён). Встречал случаи, когда эту ошибку передавали в виде исключения, хотя пользователь просто опечатался при вводе e-mail адреса или телефона :)
Как определить, является ли исключение лишним?
В статье есть ответ на этот вопрос
Можете ли вы к каждому исключению дописать «но ведь это невозможно» или «но это же исключено»?
к сожалению от этого потеряется категоричность утверждения. Ведь пользователь тоже «не должен» пытаться вводить имя там, где у него просят ввести возраст. Но это не повод для порождения исключения, потому как здравый смысл подсказывает, что он может это сделать (ведь ему никто не запретил)
тогда я не понимаю почему они говорят, что такое бывает часто? Это то, чего не должно происходить. Это то же самое, что попытаться получить 11-ый элемент массива, в котором 10 элементов. Это бывает не часто, а наоборот это то, чего никогда происходить не должно, и тут исключение уместно. Это не противоречит моим словам (путаница появляется только с тем, что они недопустимое поведение называют часто возникающим)
зачем эта фраза нужна, если «не только»? Это как сказать «ткань нужна для шиться одежды» и забыть сказать, что она используется ещё для 100 других целей.
Если бы там было сказано «для событий, которые не должны были произойти, используются исключения», то Ваше «не только» было бы вполне уместно, но когда там сказано «исключения используются для событий, которые не должны были произойти», то это описание назначения исключений. Это значит что для чего-то другого их использовать не нужно, они вот именно для этого.
это же функция валидации. Она предназначена для того, чтобы в неё невалидные данные попадали, иначе она не нужна вовсе, если бы там только валидные всегда были.
не должен был. Если он был передан, то это произошло по ошибке
туда должен был попасть URI соответствующий стандарту, но при этом вполне может попасть несуществующий. При этом проверка на соответствие стандарту должна была произойти на этапе валидации, где несоответствие стандарту вполне ожидаемо (снова же, иначе функция валидации была бы не нужна). То есть тут всё вполне ожидаемо и предсказуемо :)
ошибки и неожиданное поведение — это то, чему положено иногда происходить? Тогда почему это называется «ошибка» и «неожиданное поведение»? Мы заведомо пишем код с ошибками, и удивляемся событиям, которым положено периодически происходить? )
в широком понимании, когда Вы под ошибкой понимаете не то, что какая-то часть системы сделала что-то не так, а то, что любой статус отличный от «успех» является ошибкой?
но Ваша интерпретация «ошибка — это то, что иногда происходит» как раз к этому и ведёт. Вы говорите, что ошибки — это часть стандартного поведения программы. Тогда поясните где грань между ошибкой и не ошибкой? Расшифруйте тут значение слова error короче :)
P.S. Я полагаю они тут были неточны, и имели ввиду, что нужно бросать эксепшин в случае, если кто-то попытался продолжить чтение после того, как достиг конца файла — тут я вполне согласен. Просто тогда утверждение о том, что такое бывает редко, является неверным, если я могу как-то обнаружить тот факт, что прочитал файл до конца. Тогда получая порцию данных я просто буду смотреть осталось ли что-то ещё, и если осталось — продолжать чтение, а если нет — прекращу его. Если же я его по какой-то причине не прекратил, тогда эксепшин вполне уместен, почему бы и нет :)
хорошо, я не могу найти подходящего слова, чтобы заменить им слово «контракт» в своём утверждении, потому давайте уйдём от моего определения через «контракт» и обсудим само утверждение по факту: должно ли исключение бросаться ТОЛЬКО в ситуации, которая не должна была произойти, или НЕ ТОЛЬКО. Ведь важно это, потому что если я неправ, то никому уже не будет интересно правильное ли я слово подобрал или неправильное, если сама идея ошибочна. Если же я прав, то я всегда могу перефразировать это так, чтобы донести мысль до другого человека :)
не увидел подтверждения Ваших слов. Там в тексте говорится «An exception is any error condition or unexpected behavior that is encountered by an executing program». То есть в явном виде сказано про ошибку или неожиданное поведение с которым столкнулась программа. Это то, о чём я и говорю «ТОЛЬКО то, что не должно было произойти».
обратите внимание на выражение error code (не status code, а именно error code). Я бы сказал, что тут речь про ошибки, которые не должны в программе возникать (а не ошибки валидации данных, например, которые скорее являются особым статусом данных, а не ошибкой), но вообще тут может иметься ввиду как одно, так и другое. Почему Вы считаете, что тут имеются ввиду именно ошибки в Вашем понимании? Просто я вижу это так, что если понимать ошибку в широком смысле, то любой отрицательный ответ может быть интерпретирован как ошибка и тогда это превращается в «не возвращайте false, возвращайте или true или бросайте исключение». Ну то есть в таком понимании ошибки утверждение приближается к абсурду.
где вы тут увидели «только для другого»? :) Вы копируете разные части фразы, объединяете в них отдельные слова и говорите, что их надо так понимать. Там говорится «только для этого», а потом «если это нельзя решить другим способом», а у Вас это как-то скомпилировалось в «только для другого».
не только в этих случаях исключения нужно бросать. Подтвердите, что уважаемые цитируемые источники это утверждают, потому что сейчас Вы это доказываете через свои догадки. Вы показываете реализацию, а потом начинаете рассуждать о чём думали авторы кода, когда его писали (что они знали что это нисколько не «по-настоящему исключительная» ситуация), хотя на самом деле они могли считать ровно обратное, и код часто приводящий к выбросу этого исключения считать никчёмным и непрофессиональным.
То есть факты:
1. их код бросает это исключение (верю, проверять не буду)
2. это исключение в реализациях возникает часто (верю)
Но дальше пошли догадки:
так и должно быть, и они это знали (не верю, предъявите доказательство… я не верю, что так и задумывалось)
хорошо, но я не могу этого проверить. Приведите тогда цитату из книги уровня «Совершенный код», где бы в явном виде говорилось, что вот НЕ ТОЛЬКО. Потому что Вы сейчас даёте конкретную реализацию, и мы начинаем гадать почему она такая. Вы говорите, что такое случается по 10 раз в день, а вдруг сами разработчики Вам ответят «так это неучи наш инструмент пользуют, и разумеется это не должно случаться в принципе, они просто на коленке код пишут» и в этом случае вся Ваша теория рассыпется, но мы этого проверить не можем, ведь смотрим на код и гадаем ))
Видимо время завершать беседу.
ну да, совсем нет.
И он ничего не доказывает, потому что всего лишь означает, что позиция разработчиков в том, что не надо эту функцию дёргать не получив список существующих ключей. Я с этим инструментом не знаком, но могу предположить, что это что-то наподобие как попробовать запросить несуществующий ключ реестра или значение элемента массива с индексом больше максимального (выйдя за его пределы)
Тут снова же Ваши слова против текста профессиональной книги из топа. Вы всё ещё ссылаетесь лишь на своё мнение, что вот нисколько не аргумент, потому что я могу так же начать ссылаться исключительно на своё мнение и беседа превратится в тупое бодание двух упрямых баранов :) Потому давайте или подкреплять аргументами слова, или хотя бы ссылками на источники более достоверные, чем «потому что я так сказал».
это не рекурсия, тут слово исключение имеет разные значения. Объект исключения (в коде) предназначен для описания исключительной ситуации (в логике программы). «Объект исключения» я думаю расшифровывать не нужно, а вот «исключительная ситуация» — это такая ситуация, которая не должна была произойти (возникновение которой исключается задачей, когда вам говорят «напишите программу сложения двух целых чисел», а на вход присылают «2.5 + 4.7» — вот это исключительная ситуация, которая по условия не должна возникать)
да. Но теперь Вы по сути сказали ровно то же самое, что и я: чтобы остановить выполнение кода, который не предназначен справляться с ситуацией и передать управление на тот уровень, где с ней умеют справляться. Просто выразили другими словами, а я Вас сразу не понял потому, что сказанное Вами звучит неоднозначно и может пониматься по-разному.
То есть суть в том, что Ваши слова в таком случае не противоречат сказанному мной
Объективно то, что он излагает ту же идею: что исключение должно генерироваться только тогда, когда произошло что-то, чего не должно было произойти. И объективен тот факт, что эту книгу часто рекомендуют среди программистов к прочтению (она в топе рекомендаций). И потому у меня есть объективные причины полагать, что я прав (объективные потому, что писал книгу не я, и в топ выводил её не я, то есть это произошло без моего участия)
По Макконнеллу они нужны только там. Я считаю, что они нужны только там. Тысячи людей, которые читали эту книгу и рекомендуют её, считают, что в книге даются хорошие советы, значит они не увидели в ней ничего «еретического», значит считают эту идею как минимум неплохой. И только Вы сейчас настаиваете на том, что это не так. Предложите свой источник того же уровня, возможно другое мнение и правда существует в профессиональной среде, но пока у меня нет причин так считать.
по назначению. Они используются для описания исключений из правил. Просто вдумайтесь в название exception. ну и во фразу «it is exceptional situation» и «you should create an exception for it». Потому оно называется в английском «exception», а у нас «исключение», потому что именно для описания исключений предназначено, а не просто как часть функционального кода. То есть мы создаём объект исключения с описанием исключительной ситуации, которая произошла, а потом бросаем этот объект вверх, пока его кто-то не словит.
то есть для того, чтобы не обработать исключение, мне надо написать дополнительно код? Забавно, я думал мне приходится писать код для того, чтобы словить его и обработать где надо :) Получается я для каждого блока кода должен писать не список исключений, которые хочу ловить, а список исключений, которые ловить не хочу? Иначе я вполне могу забыть в вызывающем коде обработать этот сигнал, он поднимется на самый верх и заруинит программу. То есть этот сигнал может быть не обработан ни на одном уровне программы, при чём не специально, а просто по ошибке (забыли при написании кода добавить try...catch)
Вы под контрактом понимаете расширительное понятие, в которое включаете все договорённости о действиях при его же нарушении. Это как прочитать в инструкции к устройству «если устройство зависнет — выключите и включите питание» и говорить, что одной из функций устройства является зависание, а одной из функций пользователя устройства — выключение и включение питания. Хотя на самом деле одно является ошибкой, а другое просто реакцией на ошибку… но для Вас если в инструкции что-то написано, значит это часть контракта.
Того, что программист далеко не всегда может сам решать каким будет контракт. Некоторые контракты являются просто бессмысленными и противоречивыми. Потому я и привёл в пример функцию валидации данных, которая при обнаружении невалидности данных генерирует исключение — тут контракт функции явно противоречит её сути, когда по контракту в функцию данные с ошибкой переданы быть не могут и это породит исключение, а сама суть функции в том, чтобы проверить переданы ли ей данные с ошибкой или без.
да, я её изложил. Объективная потому, что я не сам её выдумал, а сослался на источник, который находится вне меня (вне субъекта)
это то же, о чём и я толкую. Что исключения нужны там, где произошло что-то, что никогда произойти не должно было.
«исключительные» не значит «единственные». «исключительные» значит «те которые исключаются, находятся вне основной массы».
Естественно. В том же, о чём писал я. Чтобы обработать в коде ситуацию, которая не должна была возникнуть и с которой этот код не предназначен справляться. Например когда при попытке сохранить изменения в БД рвётся соединение, тогда бросается исключение имеющее смысл «мне обещали, что предоставят ресурс для сохранения данных, но не предоставили — разбирайтесь кто из вас лажанул» (это так, простыми словами :)) )
P.S. Последнее Ваше сообщение похоже на троллинг. Давайте более содержательно, пожалуйста. Я же отвечал на Ваше сообщения и все эти «примера чего?» и «иии что?» содержали ответ в Вашем же сообщении, на которое я отвечал :)
Описание исключений в контракте подобно описанию неустойки в договоре. Его там описывают не с расчётом на «неустойку описали, ну и хорошо, теперь можно нарушать пункты договора, всё предусмотрено», а с расчётом на «другая сторона может не выполнить свои ОБЯЗАТЕЛЬСТВА по договору и тогда мы поступим вот так». То есть неустойка хоть и является частью договора, но применяется тогда, когда его кто-то уже нарушает. Так и исключения, хоть и описываются в контракте, но применяются когда этот контракт уже нарушается.
Я же подумал с Ваших слов, что Вы предлагаете исключение сделать частью сути контракта, вида «функция генерирует число от 1 до 10, но если сгенерированное число больше 5, то функция сгенерирует исключение...», потому и сказал, что это гарантирует какую-то избыточность.
В том, что говорю только те вещи, в которых уверен, а если вдруг ошибаюсь, то признаю ошибки? — да, я крайне редко встречаю подобных людей и считаю это серьёзным преимуществом. Но ни о каком «я лучше» в общем понимании речи не идёт
Это не совсем так. Показательный пример — функция валидации данных, которая в случае невалидности данных бросает исключение. А данном случае явное нарушение контракта, потому что сама функция теряет смысл и не должна была реализоваться, если ошибочность данных являлась недопустимой. Очень многие элементы контракта в коде устанавливаются не разработчиком, или устанавливаются им в неявном виде (как я привёл сейчас). Часто они продиктованы техзаданием, где описаны возможные события и состояния системы, а также описаны невозможные
У меня есть объективная причина полагать, что я излагал правильную идею. Как минимум это подтверждается по меньшей мере одним уважаемым и рекомендуемым многими источником.
это не меняет сути. Ну и по контексту там понятно, что они называют утверждениями (несколькими пунктами выше про assert речь шла). А вот сутью тут является «for events that should never occur»
почему они перестают быть «исключительными»? Вы или в это слово вложили непонятный для меня смысл, или сказали что-то странное. И связь с типизацией я не понял. Если компилятор в момент компиляции обнаружит несоответствие типов, он вообще код не скомпилирует, а вот если он по какой-то причине не обнаружит этого (ну скажем типизация прикручена не на уровне компилятора, а где-то в рантайме), то когда код будет вызван с неправильными типами, он как раз таки исключение и будет бросать, потому что передача параметра неправильного типа — это нарушение контракта.
очень часто можно встретить выход в середине метода, потому что дальше он не может выполняться. Например когда происходит валидация массива значений, но сразу же обнаруживается, что там не массив, или когда был введён адрес АПИ к которому нужно было сделать запрос, но сам адрес оказался ошибочным и потому выполнение запроса невозможно и локальный код приходится завершать. Но если такие ситуации были предусмотрены по контракту, то тут нет причины бросать исключение и вполне логично вернуть код ошибки (которых там может быть 100 штук, начиная от недоступности АПИ и завершая ответом от АПИ, что пользователь неправильно ввёл пароль или указал недопустимый возраст).
В статье указан основной недостаток — запутанность кода и нарушение инкапсуляции. Мы должны знать не только контракт вызова кода (функции), но и учитывать его внутренние особенности. Знать, что в каких-то вполне штатных ситуациях он может просто оборвать цепочку вызовов внешнего кода. Одно дело когда он обрывает цепочку вызовов потому, что его самого вызвали неправильно (передав неверные параметры или не позаботившись об окружении), а совсем другое дело, когда его и вызвали правильно, и всё в него правильно передали, а он БАЦ и исключение бросил.
Вырвали из контекста. Речь была про то, что любое исключение должно быть обработано. То есть исключения нужны не для того, чтобы ронять программу, а для того, чтобы правильно обрабатывать возникшие ошибки. Одним из аргументов того, что клиентский ввод не может обрабатываться как исключение, я видел в интернете утверждение типа, что нельзя ведь взять и прервать (уронить) выполнение программы просто потому, что человек опечатался. Так вот я и говорю, что обработка ситуации посредством порождения исключения не означает, что программу надо уронить. Как минимум на верхнем уровне всегда должен присутствовать обработчик всех необработанных ранее исключений, который будет логировать ошибки, показывать сообщения об ошибках пользователям и т.д. Это было к тому, что бросать исключения или не бросать никак не зависит от источника данных или чего либо ещё. И клиентский ввод может обрабатываться как исключение.
Я не могу вернуть неизвестный код ошибки, потому что это будет нарушением контракта. Код точно знает какие ошибки он возвращает и внешний код должен точно знать, какими могут быть результаты выполнения вложенного кода (что он получает в ответ). Но когда код часть возвращаемых значений отдаёт не как возврат, а бросая исключение — это может стать серьёзной проблемой. Насколько я помню я саму статью писал под впечатлением от беседы на форуме, где человек рассказывал насколько круто он реализовал проброс ошибок валидации данных с помощью исключений сразу на несколько уровней и как это упростило его код. Потому я в статье уделял такое внимание именно случаем неуместного использования исключений (значительно больше, чем случаям их уместного использования). То есть человек вызывает функцию валидации для того, чтобы проверить верны ли данные, а в этой функции, обнаружив, что неверны, порождает исключение (как будто бы это что-то невообразимое, что потенциально ошибочные данные оказались ошибочными)
Также я немного скорректировал ту идею, о которой писал в статье и продолжаю ею пользоваться годами: любой код должен вызываться по контракту, и если обнаруживается, что контракт был нарушен (ему передали неверные данные или не обеспечили заявленное окружение), то код должен бросить исключение, но ни в каких других случаях исключения не уместны. По сути исключение — это когда код говорит «я не знаю, что с этим делать, решайте это без меня»
Ни разу не видел код, который бы работал иначе и не порождал бы при этом лишних проблем.
Ну и Вы просили ссылки предоставить ранее. Вот например Макконнелл в «Совершенный код» говорит в пункте 8.4 то же самое (ну или как минимум очень близкое). Там у него тоже про «Исключения используются в
таких же обстоятельствах, как и утверждения: для событий, которые не просто редко
происходят, а которые никогда не должны случаться»
Учитывая, что идею я излагал достаточно правильную (может неточную в некоторых мелочах), очень удивлён, что её так задизлайкали. Видимо что-то я сделал не так и где-то в самом изложении проблема.
Я рекомендую, а не пытаюсь кого-то заставить… описанный метод (и соответственно определения) я применяю в своей работе и он работает. Потому да, я предлагаю работающую схему (механизм) по которому у меня не возникает вопросов «вернуть ли код ошибки, false или бросить исключение». Задавая себе один простой вопрос я сразу принимаю решение о реакции на провал операции.
Если Вас поместить в стабильное окружение, где постоянно есть еда, вода и воздух в достаточных количествах, можете ли вы исключить ситуацию, что находясь в этом окружении задохнётесь от нехватки воздуха, умрёте от голода или жажды? Я вот исключил бы. То есть, я бы бросил исключение «наверх», если бы в какой-то момент почувствовал, что умираю от голода!
Он не умалчивает. Он всё ещё исключает возможность возникновения такого случая, так же, как это исключал код уровнем ниже. Позиция разработчика при написании такого кода приблизительно такая: «тот, кто вызовет этот код должен позаботиться о доступности папки на запись, её наличии и о работоспособности накопителя». То есть в этом коде всё ещё исключена невозможность записать файл! И если файл не записался, то исключение, которое бросил код уровнем ниже следует пропустить дальше по цепочке!
Я не говорил что нельзя. Я говорил что в указанном контексте это плохо. Именно по причине того, что Вы написали далее
У этой функции по факту есть 3 результата выполнения:
1. Объект удачно сохранён
2. Поля объекта не прошли валидацию (заполнены неверно)
3. Валидация или сохранение объекта невозможны (завершились ошибкой)
Таким образом у функции есть 2 штатных результата: сохранён/не сохранён. И нештатный результат: невозможно сохранить/проверить. Так зачем ШТАТНУЮ ситуацию представлять в виде исключения? Для меня вполне ожидаемо, что пользователь при регистрации допустит опечатку или не обратит внимания на заявленный шаблон заполнения поля.
В то же время я не ожидаю ситуации, что в момент записи в базу оборвётся соединение. А потому да, обрыв соединения — это исключение! Это значит, что произошло что-то такое, чего произойти в условиях моего кода не может! В момент работы было недопустимо изменено окружение, в котором код выполнялся.
Не любое… но многие из них! В моём коде иногда исключения присутствуют… очень часто я пропускаю исключения на самый верх и отдаю их пользователю в виде ошибки… вроде «недостаточно прав для сохранения файла, свяжитесь с администратором для решения проблемы»
Но на то они и исключения, что бы их было мало, а не весь код был ими напичкан по 3 штуки на функцию!
Я понимаю, что Вы можете быть со мной не согласны. Но как я писал ранее, это работающая схема, которая имеет полное право на жизнь. Я не пытался кого-то переубедить или что-то доказать. Как я и писал, эта статья — совет новичкам по позиционированию исключений как таковых… чем они являются и когда нужны. А учитывая, что это работает и работает неплохо, значит в согласии других не очень нуждается (грустно конечно, что многие оказались несогласны со мной, но всё же… суть статьи не в переубеждении)
По моему мнению такое определение лучше всего описывает саму суть исключений. Источника нет, как и у статьи в целом. Статья основана на опыте и ранее прочитанных и переваренных материалах
Разумеется именно задачей и определяется. Но процитированная фраза была вырвана из контекста. А контекст был такой: источник получения данных не может сам по себе быть аргументом за или против порождения исключения
Здравый смысл подсказывает, что при правильно работающем окружении программы такая ситуация во многих случаях исключена.
И не надо исключение на каждом уровне обрабатывать. Его надо породить на том уровне, где ситуация возникла, а обработать на том уровне, на котором эта ситуация была предусмотрена.
Это, например, когда функция сохраняя данные в базу проводит их валидацию. Эта функция может вернуть объект, если тот был удачно сохранён или ошибку валидации. Ошибка валидации — отрицательный результат выполнения (объект не сохранён). Встречал случаи, когда эту ошибку передавали в виде исключения, хотя пользователь просто опечатался при вводе e-mail адреса или телефона :)
В статье есть ответ на этот вопрос