Обновить
0
0
Дмитрий @qrKot

Энтузиаст

Отправить сообщение

Будет лучше

Или еще лучше

Вкусовщина же, чесслово. И даже не короче получилось...

  • обработка ошибок уезжает ниже;

А оно настолько круто, чтобы заради этой "фишки" целые исключения городить?

А не вы ли говорили, что бизнесовые проверки, типа UserExists() или user.CanPostComments() лучше во флоу исключений не ссыпать? Да еще и продемонстрировали (!TryCheckCanComment(user.Id, out var badRequestResponse))

Если так, то ведь оно вообще страшненько получится:

// чем, по сути, вот это:
if (!TryCheckCanComment(user.Id, out var badRequestResponse)) {
  return badRequestResponse;
}

// отличается от вот этого:
c

// тем, что дальше еще обязательно надо exception обработать?
try {
  if (!TryCheckCanComment(user.Id, out var badRequestResponse)) {
    return badRequestResponse;
  }
} catch e ErrorException {
  // здесь тоже надо что-то сделать
}
  • блок try{...} задает границы, выделяющие зависимые части алгоритма.

// блок, даже прям с ограниченной областью видимости
if ok, err := TryCheckCanComment(user.Id); err != nil || !ok {
  return badRequestResponse(err);
}

// не знаю, тоже не вижу проблем с идентификацией, к чему проверка относится
ok, err := TryCheckCanComment(user.Id)
if err != nil || !ok {
  return badRequestResponse(err);
}

В итоге код бизнес-логики читается гораздо легче:

Дело привычки же. Мне вот ваш вариант не нравится - мозг менее приучен такое парсить.

И тут же приводите пример, где для GetUser обрабатываются разные типы ошибок.

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

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

Однако, цель здесь - демонстрация того, что условный C#, несмотря на наличие исключений, при обработке ошибок может запросто "деградировать" до подхода Go там, где нужна наглядность обработки ошибок

Деградировать - это в легкую! Можно и до return-codes деграднуть, чо останавливаться-то?)

Только он становится еще более многословным и неудобным, чем Go, на таких кейсах.

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

А, ну да, забыл, можно же еще боксинг-анбоксинг накрутить!

раскрутка стека вызовов не нужна

Так в том и прикол, что раскрутка стека вызовов в Go работает ровно до первого go func() в коде.

Т.е., по факту, ее нет. И перехватить исключение выше вы не можете. А "исключения" в виде синтаксического сахара для группового сравнения err с nil... А надо оно вообще?

Кто обработает some error? Никто, эта ошибка была потеряна.

Все верно, только возвращаем мы таки не строку, а ошибку. Но в данном контек.

Пофиг, в текущем контексте все верно.

Почему потерянная ошибка - нормально, а потерянное исключение - страшно-страшно?

Потому что потерянная ошибка, в отличие от потерянного (не обработанного) исключения, не приводит к крашу приложения?

Но даже в Go не любая функция предназначена для запуска в горутине.

В том и дело, что все функции в Go одинаковы. И все могут быть запущены в горутине, а значит неизбежно будут.

Понимаете, в C# есть правило "любая функция может выбросить исключение", в го - "любая функция может быть запущена в горутине". Вы живете с одним ограничением, я - с другим.

У вас всегда есть стектрейс от любой точки приложения до точки входа (до main'а), у меня - совершенно не обязательно. Зато у меня есть горутины (M:N-асинхронность), у вас - нет.

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

Почему нет-то? Если меня не волнует возвращаемый результат функции, кто мне запретит?

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

Наличие ошибки сообщает вызывающему коду о том, что остальным возвращаемым параметрам нельзя доверять. Там может быть nil, может быть неудобоваримое говно, может быть невалидный результат. Мы не можем с ним дальше работать. Это, бесспорно, грустно... Но...

go _, _ = someFunc() - посмотрите внимательно, мы и не собирались работать с этим результатом. Нельзя уронить программу по обращению к nil, если ты к нему не обращаешься!

Добавьте во второй блок кода...

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

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

Единичная ошибка в Go обрабатывается проще ценой бойлерплейта if err != nil , без которого можно бы было обойтись при наличии групповой обработки (пара RFC, кстати, есть на эту тему).

Групповая обработка исключений в try/catch в разы удобнее, но ценой меньшей гибкости в обработке единичных ситуаций.

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

А что вы делаете в этом случае на go? Ну вот вы вызвали go handleItems(ctx), а handleItems вернула ошибку. Кто её обработает? Никто.

Ну, для начала, я увижу в сигнатуре handleItems сам факт того, что она ошибку может вернуть. Если мне на ошибку по барабану , я сделаю go _ = handleItems(ctx) . Если не по барабану, то буду делать что-то такое:

go func() {
  if err := hanldeItems(ctx); err != nil {
    // обработаю здесь
  }
}()

В чём разница с исключениями? Будь у меня исключения, я бы это делал каждый раз, а сейчас - когда мне это надо.

Следовательно, в вашем коде все ошибки handleItems обязана обрабатывать сама. Но тогда и исключения она должна перехватывать сама же. А значит, вопрос "Кто перехватить должен?" не имеет смысла, исключение функцию handleItems не покинет.

Посмотрите внимательно, у меня нет ключевого слова async в сигнатуре функции. У меня его в языке нет.

В Go буквально любая функция может быть запущена в горутине. Что превращает концепцию "асинхронная функция обязана обработать исключение сама" в концепцию "любая функция обязана сама обрабатывать все исключения".

Ну и зачем они тогда нужны?

Хватит нести чушь, нет ни единой причины, которая бы помешала добавить try/catch в green thread (при наличии языка, который бы поддерживал их одновременно).

Это вам хватит нести чушь, не разобравшись в вопросе.

Я понимаю, вы привыкли к асинхронной модели того же C# или Rust. async/await - отличная штука, даже вопросов не имею. Но... async для вас - атрибут функции, для меня - вызова.

Нет в Го асинхронных/не асинхронных функций. Любой метод может быть вызван как синхронно, так и асинхронно, в зависимости от того, написал ли я ключевое слово go перед ним.

При этом асинхронная модель в Go достаточно ощутимо отличается от async/await. Это не то же самое. У функции, запущенной в отдельной горутине по определению не может быть "предка", которому она может отдать исключение на обработку. Это отдельный процесс, управляемый шедулером.

Если кода выше нет, то перехватывать надо. Всё. Точка.

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

Ну, если у вас шедулер занимается чтением сообщений из MQ - то да, исключения надо обрабатывать в нём же. Однако, насколько я знаю, шедулеры этим не занимаются.

go func() - прямое указание отдать функцию в очередь выполнения шедулера. Функция в этом месте даже не вызывается, ее вызов передается планировщику.

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

Оно может вам не нравиться, но оно позволяет писать синхронный код и запускать нужные куски асинхронно. Это - цена удобоваримой M:N асинхронности.

Она не везде нужна, да и в принципе нужна ровно в одном сценарии - максимально быстрая обработка потока сообщений/событий, не связанных друг с другом. Но ведь буквально весь веб ровно этим и занят!

В конечном итоге, вот ровно заради этой одной фичи и сделан целый язык. Он из нее буквально состоит. А исключения - ну, они эту фичу ломают, поэтому от них отказались.

Вы таки хотите сказать, что в Go нет функций, способных вызывать другие функции?

Я хочу сказать, что в Го вызывающая функция не обязана дожидаться выполнения функции, которую вызвала.

func doSomeWork() {
  // что-то важное делается
  // предположим, что в Го появились исключения
  throw SomeWorkException
}

func handleSomeJob() {
  go doSomeWork()
}

hanldeSomeJob зашедулила doSomeWork в отдельной горутине и завершилась. Предположим, doSomeWork выбросила исключение SomeWorkException.

Внимание, вопрос: кто перехватит исключение? handleSomeJob? А как, если она завершилась?

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

В Го любая функция может быть запущена в горутине. Т.е. это равносильно тому, чтобы никогда не передавать ошибку выше по стеку. А в случае использования исключений - код всех функций оборачивать в try {} catch e Exception {}

Асинхронщину же на PHP делают, предполагаю, что должны быть средства и стейт иметь.

PHP "создан, чтобы умирать". Т.е. буквально на каждый запрос создается новый процесс операционной системы, который умирает сразу по завершению запроса. Бонусы - насрать на память, даже сборщика мусора нет, потому что все подчистит ОС. Минусы - нет средств иметь стейт приложения.

Логи в контейнере как-то запрещают подключать метрики?

Логи в контейнере и логи приложения - это разные сущности.

Это должно помешать ее пропатчить? Или компилятор Go.

Если вы берете левый билд, то на выходе можете получить что его автору угодно.

При чем тут левый билд-то? При чем тут специально сломанные компиляторы/ядра? Официальный билд ломает совместимость. PHP 7.4 рантайм не гарантирует работоспособность кода под версию 7.3. Да хрен бы с ним, 7.3.1 вполне может не заработать на 7.3.2-рантайме. На официальных билдах.

Да, но это не повод выдавать некоторые риски за нестерпимую боль.

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

А старый веб с js/jquery вполне себе жив. Wordpress жив и всё ещё популярен.

Один только вопрос: зачем "старому" вебу новый PHP?

Если "старому вебу" все еще норм на jQuery, за который "в приличном обществе гоняли ссаными тряпками" еще лет 6-8 назад, когда я еще был как-то связан с фронтенд-разработкой (фулстечил). Если "старый веб" до сих пор работает на 4-5 версии PHP (т.е. на версиях языка 20-летней давности!), и ему норм...

Зачем слушать, что там хотят WordPress'еры и Jooml'еры, если они все равно на свежие версии языка не торопятся и, видимо, торопиться не собираются? PHP нужен вордпрессу, вордпресс PHP не нужен.

Видимо, разработчики языка и коммунити вокруг не хотят, чтобы php стал языком одного фреймворка (Ruby-On-Rails уже есть, зачем второй такой же?). Поэтому пытаются как-то выправить ситуацию, в которой оказался язык (и которая своими очертаниями подозрительно напоминает жопу).

Вы говорите, что язык у вас в какую-то не в ту сторону идет, но при этом сопровождаете легаси-говно, работающее на версиях языка 10-20 летней давности. И вы, может быть, и рады бы смигрировать, но не сможете. Ну потому что это легаси-говно, подпертое палками со всех сторон и обмотанное скотчем для солидности, работает только на эпмирически-подобранной комбинации из версии ОС, версии языка с точностью до x.x.x.patch145.build_vasyan2001 и билд-версии CRMки. Любая попытка что-то изменить/обновить приводит к неработоспособности системы вообще.

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

По факту, язык похорошел. Сильно лучше стал, и даже движется в верном направлении. Одна беда - родовая травма "создан, чтобы умирать" делает все эти потуги с приведением языка в порядок сизифовым трудом. Нишу серьезной продуктовой разработки PHP уже конкурентам проиграл, нет его там. Дальше рынок применимости PHP сужается до короткоживущих небольших проектов (в которых пока еще бытует мнение, что php дает какие-то выгоды) и хоумпейджей - а это путь к вымиранию.

Php изначально был разработан, когда автор языка задолбался на предыдущих языках кодить

И взлетел php именно потому, что был простым

Ну да, так оно и было, я в курсе. Это были лихие 90-е, мы развлекались как могли Было это в 1994 году, из альтернатив были C/C++, Lisp и Perl. Даже Java появилась на 2 года позже.

С тех пор прошло 30 лет, а простоту PHP в веб-разработке до сих пор демонстрируют сравнением с C++. Ну за 30-то лет можно было выделить недельку на обзор того, что происходит у соседей?

Как и js (и именно поэтому же все альтернативы js так и не взлетели - слишком сложно)

Между "js - самый простой язык, работающий в браузере" и "js - единственный язык, работающий в браузере" - пропасть.

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

Веб-фронтенд - узкая ниша? Какая широкая?

Куча сайтов без фреймворков вообще. Куча cms с чистым js или вообще на js+jquery

Куча сайтов без фреймворков - одностраничники? CMS с чистым JS - это какие? Вордпресс/Joomla? Широкий рынок разработки - ага...

js+jquery... Кхм, вот за это вас и не любят (с) кто-то из мудрых

jQuery-то вам зачем? Все полезное, что в нем было, уже в стандарт JS занесли!

(один вордпресс бОльшую часть всех cms занимает!).

Ну, как я и думал, широкий рынок (противопоставляемый узкой нише веб-разработки) - это легаси-хоумпейджи на вордпрессе (и иногда на jooml'е), работающие на мешанине из древних версий php, приправленные кашей из рандомных версий jQuery на фронте? Широкий рынок, ага.

Typescript - требует квалификации.

Золотые слова! А PHP не требует??? Откровения!

Его уже нельзя просто так взять и поправить через ftp в блокноте, если припёрло.

Лучшие практики продуктовой разработки как они есть...

И в итоге побеждает js из-за бОльшей простоты.

Т.е. точно не из-за того, что браузер ничего, кроме js, запускать не умеет?

Просто не всем нужны большие проекты, понимаете?

Большие - это больше одной страницы? Ну да, не всем нужны. Но там и nocode-решения подойдут.

"В PHP творят фигню, которую никто не заказывал" - с этого моего утверждения вся ветка комментариев и началась. 

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

Ну вы, конечно, можете доказать это чем-то, да?

Доля языков с динамической типизацией падает, в Python и PHP завозят аннотации типов... Что еще доказывать надо?

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

Фронтенд-то тут каким боком? Отделяйте уже котлеты от мух. PHP - язык бекенда, каким боком фронтенд-кухня к нему относится. Даже там, к слову, движ в сторону явной типизации заметен.

Тот же TypeScript до сих пор не получил заметного распространения - а уж сколько лет его пиарили!

Вот это поворот! А не назовете ли мне хотя бы парочку сколько-нибудь популярных фреймворков для фронта, которые на TS не переползли?

Просто начиная с определенного размера проекта динамическая типизация делает очень болезненным сопровождение/развитие. Причем этот размер настолько невелик (обычно не превышает одностраничного сайта), что даже в PHP стали приматывать скотчем всякие аннотации типов.

Языки без системы типов массово отмирают.

В коде всегда есть место багу. Если его не видно - не значит, что его нет) Причем с течением времени код меняется - и приносит новые баги, которые тоже не видно.

Дык, может не будем плодить новые без надобности?

У вас какой-то чудо-компилятор.

Обычный компилятор. Не собираться при потере совместимости - обычная фича обычного компилятора.

Ага. Говорит. И вот там, где он не сказал - оно всегда и падает )

Не надо экстраполировать ваш опыт работы с мешаниной php-скриптов поверх каши из различных CRM-ок различной степени паршивости на все остальные языки. Не везде такая жесть, честное слово.

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

И с какой частотой это случается?

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

Повторяю: инкапсуляция, изоляция. Пишите код так, чтобы методы делали ровно то, что заявлено, и будет вам счастье.

Ну, возможно у вас там получше в этом смысле

Так я про то и говорю, что получше.

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

Мы ВЫНУЖДЕНЫ полагаться на компилятор (точно так же, как и вы - на транслятор). Мы НЕ можем учесть в коде косяки компилятора, поэтому исходим из позиции, что с ним все ок. Если не ок - у нас лапки (так же, как и у вас). Проблема работы корректного кода в некорректной среде исполнения в общем случае неразрешима.

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

Дык, от бага в коде вас ничего не спасёт. Я же вам про ситуацию говорю, когда бага нет. Когда происходят валидные изменения контракта.

Был у вас метод какой-то, который локальные вычисления делал. Все было отлично, никаких ошибок он не возвращал, никаких исключений не кидал.

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

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

Причем вам не надо поиском по коду или вдумчивым чтением записной книжки с заголовком "все паровозики моей программы" искать, где не забыть исправить. Вам компилятор говорит: логика поменялась тут, тут и тут, остальное без изменений.

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

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

"Паровозик" из функций - это такая точка в коде, где вероятность, что код грохнется, стремится к 100%.

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

онкретно сегодня код может именно в этом месте и не падать. Но код живет и развивается - и эта вероятность растет.

Изоляция, инкапсуляция... С чего растет-то?

Причем уже через полгода особенность работы алгоритма именно в этом месте вы просто не вспомните.

Зачем мне их вспоминать, если они у меня прямо в контракте метода описаны? func someAlogorithm() error. Вот там есть буквы error - это явное описание такой особенности алгоритма, как умение возвращать ошибку.

В Rust'е, говорят, еще список конкретных ошибок можно посмотреть, какие бывают у метода.

И завтра, после 1001-ой правки кода вас ждет увлекательный процесс отладки рандомно возникающего исключения в коде, который выглядит как "да тут падать вообще нечему!"

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

Видимо, мы по-разному понимаем слово "интегрированы". Не понимаю, почему у вас в результате интеграции получаются взаимозависимые отношения между всеми компонентами.

https://ru.wikipedia.org/wiki/%D0%98%D0%BD%D1%82%D0%B5%D0%B3%D1%80%D0%B0%D1%86%D0%B8%D1%8F

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

Я пишу о том, что входит в стандартный набор фреймворков, а то вы до пары библиотек всё сводите.

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

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

Болячка, стоит признать, постепенно отходит в прошлое (все же язык постабильней стал, хотя до сих пор вижу в резюме кандидатов строчки о достижениях на прошлых местах работы типа "переписал проект с php7.3 на php7.4"). Но привычка, мол, это типа круто и у подхода есть какие-то достоинства будет отмирать еще долго. Дольше PHP.

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

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

Не хочется ради пары скриптиков тащить этот нодовый тулинг.

Ну, положите эту пару скриптиков в одну папочку и одним статическим хендлером отдавайте наружу. PHP/Go тут вообще каким боком? Они ж бандлером JS работать все равно не умеют.

Имел в виду отложенные, не параллельные (если вы об этом подумали).

А вот это:

а) просто еще одна php-специфичная проблема, которую приходится решать сторонними средствами по типу cron'а (потому что процесс короткоживущий)

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

Ну тоже мне, счастье великое нашли.

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

Ну! В том и смысл же! Я не забыл пройтись по тем местам, где логика изменилась.

Ах да, типизированный язык же: if тоже переписать придется, а то типы значений в сравнении разные будут...

Все же верно говорите. И о том, что что-то изменилось, я узнаю на этапе компиляции, а значит, это не пойдет в прод. В этом же весь смысл!

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

Откуда краш в рантайме-то? Чтобы в рантайме краш произошел, надо сначала скомпилировать. А нам компилятор ничего компилировать не будет. Даже наоборот, скажет "ваш паравозик не смог на 125-й строке"

Но не всегда это возможно и разумно. В частности - в публичном API, под капотом которого может быть куча логики с разными ошибками, которые пользователю может быть полезно отличать.

Но ведь это же как раз тот случай, когда ошибку надо обработать на месте.

user, err := users.GetUser(currentUserID)
if err != nil {
  if errors.Is(err, ErrUserUnknown) {
    return StatusNotAuthorized, fmt.Errorf("user unknown")
  }
  if errors.Is(err, ErrSessionExpired) {
    return StatusNotAuthorized, fmt.Errorf("session expored")
  }
  return StatusBadRequest, fmt.Errorf("something went wrong")
}

commentBlockRecord, exists, err := badUsersCache.Get(user.ID)
if err != nil {
  log.Printf("comment blocker unavailable")
}
if exists && commendBlockRecord.BlockedTill.After(time.Now) {
  return StatusBadRequest, fmt.Errorf("you are to comment after %v", commendBlockRecord.BlockedTill)
}

if user.IsBadGuy() {
  defer blockCommentsFor(user, time.Now().Add(5*time.Minute))
}

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

Псевдокод подозрительно напоминает C#, удивляет, что вы не использовали кортежи привычным образом)

Ну я специально написал, что псевдокод) А привычный образ для меня value, err := someFunc()

Да, можно сказать, что в здравом уме в Go никто не будет использовать это значение, но гарантии от компилятора - все равно прикольнее, чем сырая надежда на здравый смысл)

Ну, тут соглашусь.

На месте или выше по стеку вызовов.

Выше по стеку вызовов может не быть. Мы же в Go.

Так откуда он его увидит, если не знает, какие данные вы будете обрабатывать этим кодом? Это вам только статический анализатор warning выкинуть сможет.

Так в том и дело, что знает.

Если вы подумали, что именно тут оно сфейлится - о чем нет гарантии. Иначе бы все всегда писали 100% рабочий код)

Повторю: я гофер. У меня функция/метод возвращает ошибку (прямо в сигнатуре написано). Я не могу "подумать" или "не подумать", я прямо вижу.

Или конкретно 0xakljd832l выпадает один раз из ста запросов - а в остальное время там вообще другие ошибки, с которыми вы корректно работаете ибо соотв. код написали и отладили.

Дык, мы ждем html. Если там не html, оно выкинет ошибку. Если html - не выкинет. Не выкинуло ошибку - работаем, выкинуло - срем в лог для последующего анализа. Если выстрелило что-то, мы посмотрели, что это было, дописали кусок кода для обработки конкретно этой ситуации. Вуаля, стреляет реже

Информация

В рейтинге
Не участвует
Откуда
Бийск, Алтайский край, Россия
Дата рождения
Зарегистрирован
Активность