Обновить
102
Роман Смирнов@Source

Head of Elixir at Ecom.tech

0,2
Рейтинг
52
Подписчики
Отправить сообщение
Причиной такой долгой загрузки рельсов (15-20 сек) может быть большое кол-во мелких гемов.

Или просто размер приложения :-)
Впрочем, на мой взгляд, даже 3-4 секунды — это не очень быстро, хотя это уже приемлемо.
А "очень быстро" — это про миллисекунды.

(resources :pages 'page-id pages-controller)

А почему не сделать resources макросом и до конца уж эмулировать роутинг в стиле Rails? Это ж Lisp, тут милое дело DSL создавать.


(def routes
  (build-routes
    (resources :pages)))

Кстати, есть поддержка неймспейсов и вложенных ресурсов? Что-то типа:


(def routes
  (build-routes
    (namespace :admin
      (resources :pages
        (resources :comments)))))
Еще рельсы очень быстро запускаются.

Шутите? 15-20 секунд — это очень быстро?
Чтобы хоть как-то снизить время ожидания, придумана куча воркэраундов типа Zeus, Spork, Spring.

Если воспользоваться метафорой, то я Вам про BMW X6 рассказываю, а Вы мне упорно доказываете, что Дэу Нексия лучше Лады Веста.
Проблема Go не в том, что сложно написать panic(err), а в том что в нём нет поддержки recovery-политик от слова "совсем". Ну и да, проверять err в каждой штатной ситуации это тоже на порядки неудобнее сопоставления с образцом.
Например, написать вот так (основной happy path отдельно, обработка штатных ошибок отдельно, исключений тут нет) в Go невозможно by design.


    with {:ok, res1} <- first_function(),
         {:ok, res2} <- second_function(res1),
         :ok <- save_result(res2) do
      :ok
    else
      {:error, err} ->
         case err.type do
           Postgrex.Error ->
               # handle err
           _ -> ...
         end
    end

А зачастую бывает удобно именно так. При этом вариант написать аля Go никуда не исчезает для особо разветвлённых happy paths.
Впрочем, насколько я понял, читать про что-то отсутствующее в Go, а тем более изучать, Вы не желаете… Посему опять пытаетесь съехать на хорошо знакомую Вам тему сравнения Дэу с Ладой )))


а вы то к термину "исключение" прицепились и всё запутали.

Ахах, т.е. я виноват, что у вас термин "исключение" при обсуждении Go ассоциируется с control-flow и Java?

Этот подход хорош для очень узкого круга задач

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


вы уронили программу

Let It Crash в принципе не предполагает ронять программу, скорее наоборот. Практически ничто не способно уронить программу, написанную в таком стиле.
Прочитайте, пожалуйста, маленькую статью на эту тему LetItCrash. И когда будете в ней встречать слово process мысленно переводите его как корутина, а не как процесс уровня OS, так будет понятнее суть. А то получается, что Вы какой-то свой смысл вложили в термин и исходя из него делаете неверные выводы.


Вы будете ронять GUI приложени?

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


Или веб-сервер, которые получил неверный вход?

Если входные данные невозможно обработать, то упадёт не сервер, а один из воркеров, которые обрабатывают входные данные. После чего он сразу будет перезапущен супервизором и будет готов принимать новые входные данные с чистого листа. Это кардинально отличается от ручного recover, когда вы рискуете не идеально восстановить состояние go-рутины после сбоя.


Это не boilerplate-код, это просто «код».

Ох, мы опять по второму кругу… Просто код — это всё тот же happy path (как в вашем примере открой либо первый файл, либо второй)


А boilerplate-код это:


res, err := some.Function();
panic(err)

И ещё recover, сиротливо воткнутый куда-то.

Вот тут между нами разница. Я писал на Go, в том числе для production. Вы же тот подход, о котором я пишу, на практике не пробовали, а сравнить пытаетесь на основании субъективных предубеждений. Для меня нет сомнений, что если Вы попробуете Let It Crash, то тоже осознаете, что подход Go примерно так же коряв, как подход Java. Те же грабли, только в профиль.

Вы просто не понимаете Let It Crash, потому что не пробовали его никогда… Во-первых, под процессом там понимается что-то типа горутины. Во-вторых, в Go нет поддержки этого подхода из коробки, попробуйте сначала один из языков, который это наивно поддерживает. Пойдет любой ЯП для Erlang VM.

Давайте лучше не вводить искусственных ограничений… Если говорить о том, что лучше, то равняться надо на лучшие подходы, а не только на самые популярные в данный момент (C#, Java) и самые старинные (C, Go).

В Go не хватает нативной поддержки варианта, когда это нештатное поведение. Достаточно было бы сделать аля сопоставление с образцом
file, nil = os.Open("file.txt")


Но так как этого нет, то происходит навязывание рассматривать абсолютно все ошибки, как штатное поведение. Это порождает совершенно лишний boilerplate-код. И я не понимаю, о чём тут спорить… Попробуйте хоть один ЯП, который не принуждает Вас выбирать что-то одно (код возврата vs исключение) в 100% случаев и сами всё поймёте.

Я не пойму, у Вас на эту тему какая-то домашняя заготовка что-ли?
Я Вам про Let It Crash, а Вы мне про "кто эту ошибку словит", "try и скобочки"… Не надо исключения перехватывать, они на то и исключения, чтобы уронить подпроцесс и дать ему перезапуститься с чистого листа.
Непонятно в каком месте тут жертвы в читабельности, производительности и понятности? Кода обработки исключений нет вообще, читаемость и понятность у happy path самая шикарная из всех возможных. Если у Вас исключения происходят настолько часто, что затрагивают производительность, то либо Вы их используете для штатных ситуаций (control flow), либо у Вас общесистемные проблемы, возможно SSD на сервере пора менять или что-то в этом роде.

А мне понравилась статья. На мой взгляд она не столько про конкретный код, сколько про то, что не нужно увлекаться оверинженерингом. Задача то на самом деле была нетиповая и получившееся решение выглядит весьма элегантно. Код, конечно, можно ещё подшлифовать, но куда ж без этого.
Плюс я узнал про существование Vivus и Writage. Кстати, интересно, насколько хорошо Writage справляется со своей задачей в плане истории изменений? Т.е. насколько сильно результат отличается от ручного редактирования Markdown, если отличается?

Вот тут я вижу в ваших словах непримиримое противоречие.

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


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

Очевидно же, она должна позволять работать в обоих режимах. Если я ожидаю ошибку, то вызову вариант возвращающий статус, если нет — то вариант, кидающий исключение. Я начинаю понимать, что Вы смотрите на этот вопрос с позиции, что надо выбрать что-то одно, но нет! Необходимости выбирать что-то одно для всех случаев тут нет.

Это в каких языках?

Ну, например, в Elixir. Там по соглашению, имена методов, которые могут вызвать исключение заканчиваются на !. Допустим, File.open и File.open!. Весьма удобно для разделения штатных и исключительных ситуаций на уровне кода.


P.S. Обратите внимание, что я не говорю, что использовать повсюду исключения — это хорошо, наоборот, это так же плохо как повсюду проверять код возврата :-)
А главная проблема в том, что нет изоляции на уровне пакетов. Если в чужом коде возникла ошибка, она имеет все шансы добраться до вашего основного приложения и даже уронить его.

Timeout в Java и C# являются исключительной ситуацией, но в большинстве случаев это не Let It Crash, а стандартное поведение того же сетевого кода, которое можно или игнорировать, или использовать для попытки переподключения.

Так Let It Crash как раз и организует Вам переподключение. Это дефолтное поведение в рамках этой методологии: убить корутину и перезапустить её с чистого листа, чтобы ещё раз попробовать.


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

Ну это скорее от стандартной библиотеки ЯП зависит, а не от факта поддержки исключений. Ну и даже если stdlib подкачала, есть же варианты… Например, перед открытием файла можно проверить, что он существует. Да это не гарантирует, что он откроется, но всё же если он существовал на момент проверки, но не открылся — это уже будет ближе к исключительной ситуации.

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

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


как «штатное поведение», так и «исключительная ситуация» — это определяется вашей бизнес-логикой.

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

Как нескромно, о себе во множественном числе ))) Впрочем, давайте не будем опытом мериться.
Лучше приведите хоть 1 пример исключительной ситуации, когда проверка статуса возврата хоть чем-то лучше Let It Crash. Пока Вы приводите примеры штатного поведения… Применять к ним термины "ошибка" и "исключение", на мой взгляд, в принципе некорректно. В случае же исключительной ситуации единственное возможное поведение — это как можно быстрее привести в систему в рабочее состояние после сбоя.

Я знаю, просто divan0 смешивает запасной вариант и исключение на уровне понимания.
В зависимости от контекста одна и та же вызов функции может приводить и к тому и к другому, но концептуально это разные вещи. Поэтому во многих языках библиотечные функции имеют 2 формы: одна возвращает статус и результат, а вторая — только результат, а в случае ошибки кидает исключение.
В Go для второго случая придётся в куче мест писать if err != nil { panic(err) }

Вы понимаете, что такое исключительная ситуация?


А если вам нужно при ошибке открытия файла, попытаться открыть другой файл?

То это не исключение, т.к. у нас есть другой файл.


А если при ошибке чтения вам нужно использовать дефолтное значение?

То это не исключение, т.к. у нас есть дефолтное значение.


А если при записи, вы должны залоггировать ошибку, а при закрытии — проигнорировать?

То это прописанная бизнес-логика.


Всё, что Вы приводите в качестве примера, строго говоря, не имеет отношения к исключительным ситуациям. Т.к. исключение — это неожидаемое поведение, обработка которого не описана в требованиях.


«Отсутствующий код для проверки ошибок» — это точно не лучший вид кода, вот гарантирую.

См. мой комментарий чуть выше. Разработчики отказоустойчивых систем с Вами категорически не согласны :-)

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

Разбаловала Вас дешёвая ОЗУ, я помню лет 8 назад сталкивался по работе с аналогичной задачей… И свелась она к тому, чтобы построчно читать XML и как только нужный узел был прочитан, он сразу отправлялся в обработку, освобождая память для следующего. В итоге программа не выходила за 100 Mb по памяти (точное значение уже не помню), несмотря на 2 Gb обрабатываемого XML.

Информация

В рейтинге
3 430-й
Откуда
Россия
Работает в
Зарегистрирован
Активность