Pull to refresh
8
0
Send message
В таком случае, на мой взгляд, желательно сохранить информацию об изначальном исключении, но не давать к нему программного доступа — т.е. выводить только где-нибудь в стектрейсе. Как раз чтобы избежать ситуации, когда пользователь библиотеки привяжется к деталям реализации, но при этом позволить в ручном режиме диагностировать возможные проблемы с внешним миром.

Ну я вижу два варианта решения данной ситуации.


Первый — это вывалить наружу "кишки", т.е. просто не обрабатывать ошибки типа ETIMEDOUT или какого-нибудь socket.gaierror, а просто передать их наружу вызывающей стороне. Минус такого подхода — если мы реализуем что-то посложнее http-клиента (например, какой-нибудь ORM, который может работать сразу с кучей разных БД), мы утекаем наружу детали реализации, и делаем эти детали реализации неявной частью контракта. В будущем мы не сможем просто взять и прозрачно перейти с BSD sockets на какой-нибудь WinSock, т.к. код вызывающей стороны уже рассчитывает получать исключения вполне определенного образца. На мой взгляд, это проблема.


Поэтому альтернативным решением может быть обработка того же таймаута внутри клиента. В самом простом случае "обработка" будет заключаться только в том, что мы перевыбросим исключение о таймауте, но уже обернув его в наш объект исключения (или вернув какой-нибудь наш собственный retval_t и т.д.). Это позволит авторам библиотеки менять реализацию с сохранением интерфейса.


В более сложном случае, http-клиент может иметь какую-нибудь условную настройку аля retriesOnConnectionFailure=5, и только затем выплевывать TimeoutException, если эти пять попыток не увенчались успехом.

Ах да, важный момент, который я упустил в своих объяснениях, касательно обработки.

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

2. Эти ошибки должны быть словлены и обработаны в пределах нашей зоны ответственности, т.е. не покидая пределов кода, который мы написали.

3. Эти ошибки нельзя ловить ни для каких целей, кроме протоколирования, и запрещено игнорировать. В идеале это один глобальный обработчик, который сохраняет требуемую диагностическую информацию, после чего с чистой совестью падает.
В рантайме, да, пардон — реалтайм в этому отношения не имеет ни малейшего.
Я бы предложил разделение ошибок (не исключений) на три класса в зависимости от того, что можно с этой ошибкой сделать, и кто в ней виноват. Например,

1. Нарушение пред-условий — внешний мир попросил фигню.

Мы — библиотека с функцией `createUser`, и ее вызвали с недопустимыми знаками в имени пользователя. Мы — Calculator-as-a-Service, и нас попросили поделить на ноль. Мы — драйвер TCP, и нам прислали сегмент с seqnum за пределами окна приема.

Виноваты ли мы в этой ошибке? Нет. Может ли повторение операции проверки данных, кода, который обнаружил ошибку, привести к другому результату? Бесполезно, чистые функции на то и чистые.

Значит, нам нужно на некорректный запрос вернуть корректный ответ — выбросить исключение на неправильное имя пользователя, вернуть HTTP 400 Bad Request в ответ на деление на ноль, и отправить RST в ответ на запоздалый сегмент.

2. Нарушение пост-условий — внешний мир ответил фигню.

HTTP-запрос отвалился по таймауту. При попытке открыть файл нам говорят EAGAIN или «device is busy». Мы скачиваем страницу, а там неразбираемая белиберда вместо содержимого.

Виноваты ли мы в этой ошибке? Нет. Может ли повторение операции (запрос внешнего ресурса) привести к другому результату? Да.

Значит, нам нужно выбросить исключение, которое имеет общепринятый способ обработки, или повторить операцию энное количество раз с учетом rate limit-ов, или перепоставить операцию в очередь, или вывести интерактивное окно с вопросом «ну что, еще разок?».

3. Нарушение инварианта — мы сотворили фигню.

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

Мы виноваты? Да. Может ли повторение операции привести к другому исходу? Нет, так как все поведение нечистых функций, работающих с внешним миром, закрыто обработкой ошибок из пп.1 и 2.

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

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


Почему бы всякие утилиты вида "отцентровать строку" не вынести в функцию? Почему бы не повыносить в функции кучу других утилит? Почему не оформить Chart или Plot как класс с методами для рисования?


Да даже с точки зрения UX, зачем спрашивать pace, когда его можно высчитать, исходя из ширины окна терминала?


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


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


Вы парсите '%10.6g', просто беря символы с 1 по 3 невключительно. Это так не работает! Я хочу поле шириной 100 знаков, и что теперь? Или 9 знаков? Зачем в принципе использовать устаревшие %s, когда есть {}?


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

Наконец-то из ядра уберут убийства детей, упоминания демонов, рабства и прочего изнасилования!
Такая статья, а ни слова ни про CQRS, ни про ES, ни про DDD, а некое подобие process manager-ов вообще обозвали «хореографическими сагами».
Первый процессор, получивший действительно массовое распространение – это 8086 от компании Intel, разработанный в 1978 году. Тактовая частота работы 8086 составляла всего 8 МГц. Спустя несколько лет появились первые процессоры внутри которых было 2, 4 и даже 8 ядер.
А можно для тех, кто все проспал — что в 1980 году были за многоядерные процессоры с 2, 4 и даже 8 ядрами?
Тогда почему же в C++ не превратился C#, в котором перегрузка операторов есть с незапамятных времен, а еще есть unsafe, PInvoke и другие страшные вещи? ;)
Ого, неужели, глядишь, лет через восемь и перегрузку операторов добавят?
Зачем? Это же неэффективно. Просто проверяют, установлен ли лицензионный Касперский. Если нет — запрет въезда на три года, чтобы поумнели. А там люди сами разберутся.
Кроме случаев, когда зараза сама в гости приходит через уязвимости удаленного выполнения кода.
— Гражданин, предъявите компьютер к осмотру. Так, еще один без касперского — Коля, пакуем его.
Принудительно ставить на них шиндовс, и уже на нее — анальный зонд от господина Касперского.
Бесплатная lifetime лицензия? Или счет за антивирус будет в коммунальных платежках приходить?

Как быть с линуксами и маками? Как быть с теми, кто хочет купить чистый компьютер без операционной системы?

Спасибо за бдительность, гражданин, администрации уже направили запрос на удаление https://habr.com/post/*.

Пока все в посте обсуждают политическую компоненту данного решения, мне стало интересно — а каким таким образом MTProto "«маскируется» то под https, то под данные антивируса"? Я невнимательно читал спецификации MTProto? Промежуточные пакеты (после установления сессии) чем-то статистически отличаются от шума?

Information

Rating
Does not participate
Registered
Activity

Specialization

Software Architect