Pull to refresh

Comments 52

Как можно реже используйте комментарии. Чем больше комментариев вы пишете, тем больше программисты не обращают на это внимания.

Прям выглядит как шутка. У меня раз в полгода-год просят добавить какие-то параметры в форме из 150 значений (проектирование в строительстве). И везде в коде стоят комментарии что и куда прописать. Читаю комментарии, делаю по алгоритму, может даже что-то добавляю в комментарии и забываю на следующие полгода-год. )))

Во всей этой чехарде с исключениями, особенно когда их много больше всего меня напрягали формулировки, потому что даже при логировании достаточно трудно провести поверхностный анализ того, что происходит, т.к. формулировки в логах могут совпадать. Потом я попробовал применить уникальную нумерацию сообщений в исключениях. И это дало приличные результаты: пользователь звонит и говорит номер ошибки, а что написано в сообщении уже почти не важно. Теперь легко сопоставить ошибку с кодом, а в логах найти историю этой ошибки по другим номерам от других сообщений. Своеобразный stackTrace по бизнеслогике. И пользователю не надо сильно распинаться и разработчику и саппорту проще понять, что происходит и как начать разговор. Например, вместо долгих объяснение что делалось, что ожидалось и т.д. просто говоришь номер ошибки, а т.к. они все уникальны, то выспрашивание контекста можно делать на самой последней стадии общения. И, кстати, нумерация исключений вполне может скрывать реализацию исключений. От пользователя иногда достаточно получить номер ошибки, чтобы понять контекст. Кстати, введение нумерации добавляет уверенности пользователю, что это не он дурак, а в системе предусмотрен обработчик и пользователю нужно запомнить, что сделано не так, чтобы избежать такой ошибки в будущем.

Честно говоря, примеры исключений, вписанных в статье, лично мне кажутся не очень хорошей практикой. Нет четкой связи с кодом, где возникло исключение. Там, где хоть какое-то описание контекста попадает в исключение ещё можно связать с местом в коде, а там где исключение просто бросается, например, что «нет такой валютной пары», так и потом даже с логами не понять, что произошло: в логах нет намёка, что исключение брошено, а брошенное исключение никак не связано с записью в журнале логов. Может добавить сообщение в конструктор исключения при вызове исключения + нумерация? (Это как предложение) Например, «5843. Нет такой валютной пары» и «6432. Нет такой валютной пары» могут быть в разных местах кода и по номеру проще понять где они брошены.

Используйте Mapped Diagnostic Context (MDC) для логирования. Пишите в логи stackTrace тогда понять где была ошибка будет не проблемой. Пользователю как раз надо отдавать traceId из этого MDC.

Название ошибок существует в основном (но не только) для чтения кода. Одно исключение должно кидаться как можно в меньшем количестве мест и должно быть как можно более уникальным - тогда не будет проблем с поиском по коду - откуда вылетеле именно это исключение.

И в результате мы исключаем возможности пользователя (и любого ИТ-стафа вокруг него) по диагностике и исправлению ошибки. Хотя ошибки бывают тривиальные и могут быть исправлены самим пользователем, но сообщения об ошибках вида "что-то пошло не так" (как раз идеально не раскрывающие сути) не оставляют ему шансов.
Но и это не единственное. Ваш подход делит сообщение об ошибке и теперь оно вместо 1 места показывается/хранится по частям в нескольких: одна часть у пользователя, одна часть в логе. И потеря любой части теперь критична. Пользователь вспомнил об ошибке, с которой столкнулся полтора месяца назад и прислал скрин? А у нас логи ошибок обрезаются по истечении 30 дней и поэтому больше никакой инфы уже не осталось — до свидания.


Я бы отнес это скорее к современным отвратительным практикам, которые сильно уменьшают и первичную диагностику на стороне пользователя, и объем обратной связи.

Использование MDC относится к практике observability.

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

То есть если карта пользователя истекла - надо отобразить ему какую-то ошибку - попробуйте другой картой. Это вполне ожидаемый сценарий.

Если у нас где-то произошла сетевая проблема между сервисами - то пользователь ничего с этим не сделает. Отображать ему что-то нет смысла.

Одно исключение должно кидаться как можно в меньшем количестве мест и должно быть как можно более уникальным - тогда не будет проблем с поиском по коду

Честно говоря я не согласен с этим потому что в моём примере в проекте последний номер ошибки на сегодняшний день 2051. Как в этом случае вы предлагаете мне поступить - создать примерно такое количество классов исключений? (Я не думаю, что вы хотели, чтобы я сделал именно так, но исходя из вашего предложения я не могу представить себе чего-то другого).

P.S.

Меня тема исключения очень волнует, т.к. пользователи обожают параметризацию, поэтому за вводом параметров нужно следить очень точно, а ошибки, похожие друг на друга, встречаются как раз в большом количестве случаев, потому что выход из контекста бывает только на втором или третьем слое бизнес-логики. Получается такой своеобразный подъём с глубины от случая, когда просто не хватает какого-то параметра, до случая, что операцию сделать нельзя, потому что три-четыре-пять параметров находятся в противоречии друг с другом. Вроде как это не исключение, но дальше проблемы копятся как снежный ком - с одной стороны очень хочется бросить исключение, но с другой было бы неплохо проверить работу остальных параметров, которые не связаны с параметрами, которые породили текущее исключение. Т.е. хорошо бы пользователю давать подробный отчёт о качестве всех его данных, а не только о тех, на которых получено первое исключение, а до следующего просто "руки"/"код" не дошёл.

P.P.S.

Тему вы подняли очень важную - исключения - это только только верширна айсберга при обработке ошибок. )))

Вы храните где-то отношение что код 2051 = неправильный параметр номер телефона (к примеру). Вот если бы вместо него было UserPhoneValidationException - это был бы перенос документации в код. Пользователю в этом случае наверно надо было бы отобразить - введите друго телефон, а не код ошибки 2051 - смотрите по доке что это значит

Кстати, может быть вместо очень большого описания проблемы посмотрим на коде? Вы можете примеры привести на псевдокоде?

Вы можете примеры привести на псевдокоде?

Да, конечно. Можно прямо в коде:

Пример предупреждения пользователю (сорри если некоторые тексты сообщений не очень понятны - уж что попросили конструкторы, то я и написал. На мои вопросы они отвечают - "мы знаем что это значит, оставьте так". Ок):

Пример в логах:

Пример исключения для логов (в данном случае исключение 172 чуть позже бросается):

Пользователю в этом случае наверно надо было бы отобразить - введите другой телефон, а не код ошибки 2051 - смотрите по доке что это значит

Так я же не требую выводить только код ошибки. Добавьте после кода ошибки сопроводительный текст и информация будет предоставлена в том же виде, что и раньше. 3-5 символов на числовой код ошибки не сильно что-то испортят в сообщение, но зато у пользователя и разработчика/оператора программы будет предметный разговор. Например, мне звонит сотрудник и говорит, что у меня на экране сообщение: "...", и сообщает оператору первое же число - код ошибки: "172" А у оператора перед глазами список действий, которые он может предложить пользователю по этому номеру. Согласитель, общение же более конкретное, чем спрашивать, как он к этому сообщению попал? Примерно всегда можно установить даже ФИО разработчика, который этот генератор/обработчик ошибки написал. Известное выражение: "У каждой ошибки есть имя и фамилия". /s

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

Да, и напомню, что мне всё ещё интересно как вы предлоагаете выйти из ситуации с количеством классов исключений для большого количества ошибок? Писать же отдельный класс на каждую ошибку очень накладно.

А зачем пользователю отдавать номер ошибки если есть описание и то, что он должен сделать? Это не трата денег - звонить оператору? Разьве оператору надо звонить не только если произошло что-то неожиданное?

По поводу исключений, которыми мы отвечаем пользователю для меня вообще не выглядит исключением. То есть мы скорее всего ожидаем что пользователь может ввести email или телефон неправильно. Это не исключение - это не прошедшая валидация

P.S. Я не понял чем код ошибки лучше чем traceId по которому поддержка может посмотреть что не так (если учесть что пользователь звонит только в случае ошибки которая требует оператора)

Я не понял чем код ошибки лучше чем traceId

В принципе, если traceid детерминантный (т.е. на одну и ту же ошибку в одном и том же месте программы выдаётся один и тот же код), то разницы нет. А вот если разный, то это плохо. Но я работаю на C# и у меня нет MDC. Кстати, при изменении исходного кода изменяется traceid?

Но вы ещё так и не ответили на мой вопрос. )

Для C# есть библиотека с реализацией MDC https://nlog-project.org/documentation/v4.3.0/html/T_NLog_MappedDiagnosticsLogicalContext.htm - не знаю на сколько она является стандартом. Но скорее всего есть аналоги которые являются стандартом.

Код ошибки и traceId совершенно для разных целей. Первое для наблюдаемости. Второе для того чтобы пользователь мог сам решить свою проблему.

Код ошибки и traceId совершенно для разных целей

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

Я не понимаю, почему по traceId можно решить свою ошибку, а по коду ошибки нет? (В случае проблем при взаимодействии с вашей системой пользователь видит два числа Код Ошибки и TraceId или что-то одно?)

P.S.

Спасибо за подсказку с библиотекой, посмотрю.

Ошибок которые может решить сам пользователь обычно не очень много, если только в приложении нет бизнес логики как таковой. Чаще всего именно исключения (не ошибки) возникают в бизнес логике. Надо разбираться со стектрейсом - что произошло. Исправлять, заводить техдолги и тд

Еще не понял про того - кто добавил этот обработчик ошибки. Несколько людей могут изменить - что-то добавить в любой обработчик. Как вы определяете ответственного за весь класс / обработчик?

P.S. Вы не пользуетесь подходом общего владения кода? Это очень важный подход в крупных компаниях.

У нас ответственность на уровне модуля. Ставится задача отдельному сотруднику, он пишет небольшой модуль. Из него делается nuget-пакет и он попадает в проект.

Общего владения кодом пока нет и не думаю, что он появится. Совершенно разные специфики по работам. Компания небольшая.

Ок, но пусть даже и большая компания, но взять тот же синий экран "смерти" Windows. У него есть число и, может быть, файл с трассировкой стека. Но ведь число? О нём речь и идёт, о числе.

Отличный пример про PSOD. Такого не должно быть впринципе. Если такая ошибка случилась - это должно быть что-то неожиданное и серьезное. Вариантов того, почему это произошло может быть огромное количество. И понимание даже конкретного эксепшна не дает полной картины - что произошло. Поможет только traceId (или логи ошибки со стектрейсом, которые и просят отправить когда падает ПО запущенное на личном компе).

Но разбор таких ошибок - это уже немного другая область. Но опять же, в инете можно поискать что означает ошибка синего экрана с номером x80005142563 и т.д. Т.е. поиск можно начать с конкретного числа. Сам stacktrace уже вторичен. Но опять же - всё сходится на определённом числе независимо от типа исключения. Это же хорошо?

Получив такой код начинаешь рыться по форумам поддержки - документации этого ПО. В итоге это обычно приводит к тому, что ошибка в каком-нибудь драйвере видеокарты. Примерно то же самое (только чуть быстрее) было бы если бы я получил ошибку GriphicsDriverException

Я вроде ответил на ваш вопрос по количеству exception. Для отображения пользователю я вообще не стал бы их использовать.

Для кода приложения можно использовать сколько угодно исключений и фраза "накладно" совсем мне не понятна. Возможно вы пишете код для микроконтроллеров, но тогда непонятно почему вы это делаете на C#

Для отображения пользователю я вообще не стал бы их использовать.

Теперь я вас понял. Но, как тогда общаться с пользователем, у которого возникло исключение (за исключением ситуации, когда исключения можно обработать автоматически)

Возможно вы пишете код для микроконтроллеров

Нет, я выше написал, что речь о проектировании в строительстве. Там на пожеланиях пользователей чёрт ногу сломит. "Шаг вправо, шаг влево - побег, прыжок на месте - провокация." )))

Для отображения пользователю я вообще не стал бы их использовать.

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

Мой ответ такой: для каждой неожидаемой ситуации в системе использовать исключение (нормально если их сотня и больше). Это исключение не должно показываться пользователю. Если исключение случилось - значит проблема какая-то которую пользователь не может решить - для общения по этой проблеме используем traceId

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

недостаточно денег - используйте другую карту

Или больше работайте. ))) (сарказм) Эта ситуация как раз не исключение, а штатная и комментария будет вполне достаточно, чтобы пользователь понимал что случилось, хотя я бы не был так уверен, что всё корректно, ведь недостаток средств может быть порождён какими-то внутренними проблемами банка. (Но это нюансы).

Мне не очень понятно, почему вы считаете, что исключение, которое нельзя обработать автоматически, не должно показываться пользователю? Он же всё равно не может выполнить какую-то операцию? Что ему тогда показывать? (или я чего-то не понимаю?)

А что вы ему покажете если один микросервис системы не смог по сети сходить в другой микросевис?

В лучшем случае просто техническую ошибку. И начать разбираться даже еще до звонка пользователя (триггер на ошибки если это серьезная ошибка).

В худшем случае дать ему стектрейс и скомпрометировать код системы.

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

Но вот я и спрашиваю - а писать новый класс для каждого из 100-200 исключений нужно ли?

Хорошо, я вас понял. Но предлагаете ли вы таким образом использовать один класс для одного случая? (В идеале).

Простите мне мою дотошность, я хочу понять принципиальное отличие от нумерации. Я рассматривал ваш вариант, но пришёл к выводу, что мне проще нумеровать исключения, чем строить иерархию как раз потому, что не хотел писать 100-200 и более классов исключений и столько же обработчиков. При том, что у меня сквозная нумерация и по исключениям и по предупреждающим сообщениям. Т.е. у меня уникальное число независимо от того, кто его сгенерировал - исключение или просто предупреждение в интерфейсе или вывод в лог. Соответственно формат всех чисел в исходном коде у меня начинается с символа подчёркивания и вид числа _1234 никогда не встречается в коде. Поэтому я всегда однозначно могу найти место в программе, которое генерирует сообщение вообще без контекста - исключение ли это, предупреждение или запись в логи.

вид числа _1234 никогда не встречается в коде

Я имел в виду повторно не встречается в коде.

Если у вас есть throw new UserInputException("E111"), то в любом try вы не поймете что именно это за ошибка туда попала при чтении кода. А если UserPhoneException и UserEmailException - то поймете.

Я понял что не написал с самого начала. Речь вообще про сообщения при взаимодействии пользователя с сервером, а не только Exception. Сообщения от сервера могут быть очень разнообразными, поэтому я и предлагаю их нумеровать не зависимо от того - это сообщение от исключения или от сообщения от бизнес-правила.

Т.е. у вас UserInputException("E111. Текст1") должно быть одно. Т.е. все сообщения, которые куда-то должны вернуться должны иметь уникальные идентификаторы прямо в тексте: UserInputException("E112. Текст2") /UserInputException("E113. Текст3")/return "E114. Текст4."/Log.Add("E115. Транзакция {NNN} прошла успешно."). Т.е. вообще любое взаимодействие с пользователем, возврат простого сообщения, запись в журнал лога нумеруется уникальным числом и поясняется текстом. Просто сообщения всех устраивают, а уникальные числа в сообщениях почему-то вызывают дискомфорт?

Если так можно выразиться - провести unicalization сообщений. Тогда общение пользователей с техподдержкой и техподдержки с разработчиками становится прозрачным.

Я неоднократно встречался с тем, что получаю сообщение об ошибке в какой-то утилите с исходным кодом, идешь в исходный код, находишь там шаблон этого сообщения и он там встречается 10 раз. Вот какое место в программе выдало моё сообщение об ошибке, когда текстовые шаблоны сообщений одинаковые? - Это уже риторический вопрос, потому что дальше только отладка.

Мы рассматриваем поддерживаемость / читабельность кода (в первую очередь потому что именно эти показатели влияют на развитие продукта). Использование одного UserInputException с этой точки зрения противоречит этому, потому что когда разработчик читает код без текста ошибки (его нет потому что приложение не запущено) он не может понять его логику.

Что касается общения с внешними пользователями, у нас подход такой: платеж если он завершается не успешно имеет статус Declined. В самом обьекте платежа лежит enum - код ошибки.

Это может быть нехватка денег на карте или неправильные реквизиты, например - то есть то, что мы можем сообщить пользователю. Он может что-то сделать с этим.

Или если внутри системы вылетел какой-то неожиданный Exception - мы обрабатываем его через общий ExceptionHandler и логируем. Пользователю отвечаем технической ошибкой (у нас что-то сломалось) и traceId.

Использование одного UserInputException с этой точки зрения противоречит этому, потому что когда разработчик читает код без текста ошибки

Так я же не говорил, что задача использовать только одно исключение. Можено, но это не обязательно. Я предлагал пронумеровать все сообщения, которые куда-либо записываются или выводятся.

Код ошибки и traceId совершенно для разных целей

Так я вот как раз и против такого использования. С моей точки зрения число должно быть одно и оно должно вести к строке исходного кода, где возникла проблемная ситуация - исключение или просто предупреждение (потому что пользователь может быть не согласен с предупреждением и либо надо где-то к номеру привязать более корректное описание или доработать систему). Конечно, в сообщении, которое отображается пользователю могут быть указаны ещё параметры, например, номер транзакции, который сам по себе уникален (и любые другие параметры, которые могут указывать на какой-то бизнес-контекст), но изначально ошибка генерируется в определённом месте программы и нужны её точные "координаты". Это может быть только число (или уникальная строка, но числа всё-таки проще читать и проверять на уникальность, чем рандомные строки).

Или если внутри системы вылетел какой-то неожиданный Exception - мы обрабатываем его через общий ExceptionHandler и логируем. Пользователю отвечаем технической ошибкой (у нас что-то сломалось) и traceId.

Честно, я до сих пор не понимаю - traceId он вообще ведёт к точному месту в исходном коде, где возникла ошибка или нет? Или он ведёт к записи в логах и только там можно прочитать внутренние сообщения об ошибках? (но тогда не ясно - а эти сообщения об ошибках точно и однозначно ведут с конкретной строке исходного кода?) Понимаете, я хочу построить однозначный и прозрачный алгоритм сопоставления какого либо/любого сообщения, генерируемого системой (исключение, предупреждение, запись в логи) с конкретной строкой исходного кода, где это сообщение возникло, чтобы любой человек с доступом к исходному коду мог за пару секунд найти эту строку в программе, а только потом разбираться в контексте, что там с бизнес-логикой. TraceId позволяет это сделать? (я надеюсь, что формулировку задачи я выразил полностью?)

P.S.

Я тоже логирую Stacktrace, но его не так просто читать, особенно, когда сообщения об ошибках всплывают из глубины системных библиотек.

P.P.S.

Вот что меня смущает в stacktrace - версионность исходных кодов программы. Как только вы внесёте изменения в программу, то stacktrace становится невалидным и все сообщения, даже имеющие traceid, становятся бесполезными.

TraceId - это идентификатор в которому привязаны все логи в рамках одного процесса. Например, вы в контроллере на входе пишете logger.info("Get request with params: ..."), дальше пишете в других местах куда зашел код и что произошло. Где-то вылетел Exception. В Exception handler или в ближайшем коде catch вы пишете logger.error("Catched exception", exception) и в лог у вас пишется стектрейс, так же привязанный к traceId.

То есть когда вы спрашиваете у пользователя traceId вы можете понять - какой флоу он вызвал. С какими параметрами к нам пришел. И что за exception у него вылетел.

На счет версионности - пишите в лог версию сборки приложения (обычно она итак пишется). Из нее понятно какой коммит соответствует времени когда был записан лог.

P.S. Если честно - то мне кажется вам надо посмотреть статью по ключевому слову наблюдаемость / трассировка / логировние потому что на очень долго затянулась переписка.

P.P.S. Я пользуюсь удобным инструментом копируя с прода записанный стектрейс и вставляю сразу в своей IDEA - это вообще золото - может у вас есть такое же https://www.jetbrains.com/help/idea/analyzing-external-stacktraces.html

Первый пример:

} catch (exception: TGetCommission) {

/** Раскрываем подробности того, что ходим в сервис комиссий */

throw CommissionServiceTimeout()

}

Вы можете пояснить как из TGetCommission вы получили таймаут? А может там не таймаут, может там 500 из-за бага в коде? Как вы так "кастите" TGetCommission именно в CommissionServiceTimeout?

Вполне вероятно. Надо смотреть как устроен трифт и когда он кидает эту ошибку. Это мешает понять мысль, которую описывает этот код?

Согласно чистому коду - код как раз должен быть таким чтобы не надо было смотреть как устроен трифт. А код который надо смотреть как устроен - и я могу написать.

Трифт - это сторонняя библиотека бинарных сообщений отправляемых по сети https://thrift.apache.org/ (аналог protobuf)

Не следует выкидывать из функций исключения из стандартной библиотеки

И эта практика отвратительно себя показывает в языках, где в сигнатуры функций не включается описание исключений — например, в python. Потому что теперь документация становится архикритичной.
Я с этим сталкивался в следующем варианте: имеем функцию, которая по описанию явно использует http запрос, но в документации нет ничего похожего на характерные исключения. Функция использует пакет requests, значит будет логично предположить, что его исключения и надо перехватывать. Но… нет, потому что автор этой функции решил перехватить и вместо них бросать свои кастомные и теперь я должен изучить все возможные ветвления и вызовы его функции, чтобы найти эти кастомные — "очень занимательно".

Что значит "использует пакет requests, значит будет логично предположить, что его исключения и надо перехватывать"? Искать все exceptions этого пакета?

Как по мне очень удобно если вы хотите обработать исключения - чтобы класс кидал исключения которые определены только в этом классе.

Что значит "использует пакет requests, значит будет логично предположить, что его исключения и надо перехватывать"? Искать все exceptions этого пакета?

Да, но их искать не надо. Этот пакет (requests) распространенный и к нему хорошая документация плюсом.

Это вы просто знаете что функция использует http и какой пакет в добавок. А могли и не знать, так что проблема не в кастомных исключениях. Были бы исключения в каком то виде перечислены и всё было бы ок независимо от их кастомности или наличия у вас доп знаний.

Вы пишите на языке с проверяемыми исключениями? Если да - то вам знакомо когда весь код выглядит как сплошной catch() (слава богу еще что в новых версиях java и в kotlin можно указывать исключения в catch через | - или)

Понимать Дадюшку Боба очень сложно. Первый пример из статьи:

Не раскрывай детали реализации используя исключения.

Если обработка ошибок раскрывает реализацию — то это неправильная обработка ошибок

Не цитата Дяди Боба, но на этом принципе построен первый пример.

Представьте, если ваша упоминаемая http библиотека будет бросать исключение - UnableToDoNeededHttpRequest, что переводится как "НеУдалосьВыполнитьHttpЗапрос". И ты хрен поймешь в чем там проблема - DNS не нашел имя, connect на порт не удался, сервер ответил 500. Детали реализации то мы не раскрываем.

Хорошо, но для решения проблемы есть пункт

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

Т.е. проблема решается такими исключениями, которые говорят сами за себя.

Попробуй теперь выполнить сразу 2 правила.

  1. И не раскрыть что мы делаем DNS запрос.

  2. И сообщить, что проблема в шаге с DNS запросом.

Сразу и не придумаешь как это реализовать.

Это не шаблонный и понятный DnsErrorException (который нарушает оба правила, зато придумывается за 1 секунду и получается в итоге достаточно "шаблонный" квадратно-ездовой код).

Hidden text

Будет UnableToFindServerByName исключение.

И не раскрывает детали реализации (только совсем верхнеуровнево), и говорящее само за себя имя исключения.

Еще надо подумать как дать красивое название исключению.

Итог: Если ты взял часть правил из рекомендаций Дядюшки Боба и выполнил, а часть правил понял неправильно, и не выполнил - то получится лютый говнокод. Т.к. применяя первую часть правил ты сильно усложняешь код, и создал сложные ситуации, и чтобы решить сложные проблемы ты не смог применить вторую часть правил.

Т.е. без правил Дядюшки Боба - получится средний, шаблонный, стандартный код. Но если ты освоишь все правила Дядюшки Боба, то получится шедевр. Но если не освоишь - получится наоборот - говнокод.

Но смысловая нагрузка UnableToFindServerByName ровно такая же, как и DnsErrorException. Более того, конечный пользователь уже знаком с термином DNS, а вы вместо него вставляете обобщенную конструкцию, теперь пользователю нужно догадаться, что эта конструкция развернется в реализацию (DNS). Что уже сложнее и часть пользователей отвалится на этом, что сократит обратную связь.
Более того, подозреваю, что обобщенная конструкция и не предусматривает какой-либо другой реализации, кроме DNS и скорее всего получилась лишним усложнением, от которого вы не получите никаких выгод.


Т.е. без правил Дядюшки Боба — получится средний, шаблонный, стандартный код. Но если ты освоишь все правила Дядюшки Боба, то получится шедевр. Но если не освоишь — получится наоборот — говнокод.

И тогда, я бы сказал, что лучше пользоваться средним шаблонным кодом ровно во всех случаях, когда это возможно. А методы дядюшки Боба с хорошим шансом выстрелить себе в ногу оставить лишь для случаев, когда средний шаблонный код ну совсем не подходит.

Т.е. без правил Дядюшки Боба — получится средний, шаблонный, стандартный код. Но если ты освоишь все правила Дядюшки Боба, то получится шедевр. Но если не освоишь — получится наоборот — говнокод.

Ну это мое видение как я применяю правила Дядюшки Боба. Т.е. можно попробовать другой подход - начать с малого, применять постепенно, как-то попробовать так. Т.е. если что-то не работает у меня, то это не значит что оно вовсе не работает и прям никто не применяет это правильно и все начинают применять одинаково и у всех все одинаково.

Представьте, если ваша упоминаемая http библиотека будет бросать исключение - UnableToDoNeededHttpRequest, что переводится как "НеУдалосьВыполнитьHttpЗапрос". И ты хрен поймешь в чем там проблема - DNS не нашел имя, connect на порт не удался, сервер ответил 500. Детали реализации то мы не раскрываем.

Пойму если положить изначальный exception в cause своего exception

Сразу и не придумаешь как это реализовать.

Я бы пользовался правилом количества подробностей в исключениях в зависимости от скоупа их использования.

Если это клиент который отправляет запрос и его вызывает сервис - то можно подробно описать вид ошибки ошибка DNS или что-то подобное.

Если это сервис, который вызывает другой сервис в пайплайне - то подробность о том, что мы не смогли рассчитать комиссию по платежу из-за DNS не важна для читающего код (для разбора проблем это важно - логируем cause)

Дядя Боб говорит, что размеры файлов должны быть от 30 до 100 строк.

и часто будет противоречить следующему ниже принципу "Группируй вместе все, что используется вместе".
Т.к. при группировке часто получаются большие куски кода, а маленькие наоборот при декомпозиции, но при этом теряется "вместе".

Как можно реже используйте комментарии. Чем больше комментариев вы пишете, тем больше программисты не обращают на это внимания.

Ну, будут комментарии с пояснениями пропускать и что с того? Я их писал не для чтения каждый день, а для разбирательств в тяжёлые времена.

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

Так не надо писать комментарии к реализации и уж тем более как пояснения к строчкам кода.

Комментарии нужны, чтобы указать на что-то важное, например подробно описать неочевидный костыль.

Или, например, если код содержит неочевидные расчёты, оставить ссылку на статью/статьи откуда это взято или описать всю логику этих расчетов.

Или когда когда код делает непонятно что, но есть понятное объяснение в терминах бизнес-задачи, тоже комментарий бывает не лишним.

Бывают места, которые очень хочется переписать, но это мягко говоря невозможно. Поэтому, если оставить комментарий вида "я знаю, что тебе очень хочется это переписать, но имей ввиду, что это сломает <список вещей >", я думаю это может сэкономить кучу времени следующему желающему.

В общем, понятное дело, что комментарии вида "запрашиваю список товаров из БД" бессмысленны) Это очевидно из кода)

Вы не обратили внимание что я написал выше про то, что устаревание важнее (ИМХО)?

Про термины бизнес задачи - все в названия и в код (тут DDD еще проклевывается - общий язык бизнеса и разработки)

Ссылку на статью / новость - кладем в тикет систему и пишем в описание коммита (коммит могут перетереть а коммент оставить)

Sign up to leave a comment.