6 способов вызвать сбой во время выполнения Elm приложения
Перевод статьи Noah: Top 6 ways to make your Elm app crash at runtime.
Elm славится тем, что у него «нет исключений во время исполнения», и по большей части язык делает действительно, действительно отличную работу! Возможно писать Elm приложения без исключений во время исполнения, к тому же большинство пользователей их и так никогда не увидит.
Некоторое время назад я писал в twitter о 9 различных способах, как сделать исключения во время выполнения, которые нескольких дней я так и не смог выкинуть из головы. Вот небольшое исследование 6 способов, с которыми я столкнулся в реальности, и есть некоторые правила, которым я бы следовал, чтобы избежать возможных сбоев. И я следую этим правилам, чтобы гарантировать, что мои приложения Elm никогда не будут давать сбой, но в любом случае все эти эксперименты я делаю просто для собственного удовольствия.
Все способы актуальны для Elm 0.18.
Номер #1 — Регулярные выражения
Какое-то время регулярные выражения были поломаны, тем самым их использование создавало ошибки во время работы Elm приложения. Вот самый простой пример (пример в Ellie app):
Если вы перейдете на вкладку Results
(прим. пер.: этот и дальнейшие примеры рассматриваются как запущенные в Ellie app), вы ничего не увидите! Это связано с тем, что Regex.regex
дает сбой, когда вы передаете ему недопустимое регулярное выражение. В этом случае я начал описывать группу в регулярном выражении, не закрывая ее, что означает, что мое Elm приложение даст сбой. Это приводит к сбоям при загрузке, поскольку Elm не является ленивым для значений верхнего уровня, однако, если вы будете использовать встроенные (inline) Regex, тогда сбоя при загрузке не будет, все это означает, что ошибки во время исполнения могут легко оказаться и в продакшене (пример на Ellie app):
Перейдите на вкладку результатов, затем нажмите на кнопку и посмотрите, как ничего не меняется! Это связано с тем, что ошибка по время выполнения возникает только, когда функция update
выполнена. Представьте, если бы это были несколько глубоко вложенных функций! Довольно запутанно, чтобы разобраться в этом.
Мое правило: задавайте регулярные выражения только в начале области видимости.
Номер 2 — Массивы
Подобно регулярным выражениям, массивы также были сломаны в течение длительного времени! Вот небольшой пример (пример в Ellie app):
Перейдите на вкладку результатов, и вы ничего не увидите! Это происходит из-за того, как реализовано Array
в основной библиотеке. Внутри реализации используется структура, основанная на числе 32, для размещения вложенного дерева массивов, что позволяет быстро индексировать. Вы можете узнать об этом больше, исследуя альтернативную реализацию, elm-array-exploration от Робина. Первоначальная реализация была почти полностью написана на JavaScript, но документация и автор уже давно пропали, как старый дуб в ночи. Реализация Робина направлена на то, чтобы писать как можно больше на чистом Elm - и использовать JavaScript исключительно для реализации необходимых ключевый частей.
Мое правило: никогда не используйте массив из библиотеки elm-lang/core
, если вы хотите, чтобы все работало. Используйте elm-array-exploration до тех пор, пока не изменится реализация ядра.
Номер #3 — Эквивалентность функций
Эквивалентность функций одна из довольно сложных вещей для понимания в языках, где возможно частичное применение функций. Что означает для функции — быть эквивалентной другой функции? Например, в Python, я бы сказал, что если функции были бы одним и тем же объектом функции с одинаковыми аргументами, то это была бы одна и та же функция.
Однако в Elm функция эквивалентности не поддерживается (пример в Ellie app):
Проверьте вкладку результатов в Ellie app, и вы ничего не увидите. Больше нечего сказать. Возможно следовало бы поддерживать эквивалентность функция, а возможно и нет. Я больше склоняюсь к тому, что нет, это как ни рыба ни мясо.
Мое правило: вы, вероятно, не должны использовать эквивалентность функций. Но если это необходимо, тогда свяжите их как значение с идентификатором какого-нибудь типа в словаре.
Номер 4 — Elm не ленивый язык!
Общей ошибкой разработчиков, которую я встречаю в каналах Slack, является то, что Elm рассматривается как ленивый язык программирования, когда это не так. Пример этого ниже (пример в Ellie app):
Обратите внимание на то, как Maybe.withDefault
может показаться безобидной функцией, но на самом деле, если вы перейдете к результатам, то получите абсолютно пустую страницу. Это потому, что Debug.crash
выполняется в то же время, когда вы передаете функции строку, не помещая ее в функцию, он просто запускается сразу же, даже если у нас есть Just
!
Чтобы исправить это, достаточно использовать старое доброе case
выражение:
Мое правило: никогда не имейте дело с функцией Debug.crash, которая не используйте внутри выражения case или внутри функции.
Номер 5 — не всему следует быть закодированным
В алгоритмах ядра Elm существует небольшое отличие между JSON объектом и структурой записи. Фактически, разница между ними может быть найдена только во время компиляции. Union типы несколько отличаются — они содержат магическое поле ctor
, одновременно с _n
полем для каждого аргумента, который эти типы получают. После того как мы смогли создать эти объекты во время исполнения через Json.Encode
, мы можем вызвать сбой с помощью трюка с использованием ==
или целым рядом других методов (пример в Ellie app):
Обратите внимание, что нам пришлось создать новый объект дважды: иначе бы в Elm использовалось ссылочное равенство и этот трюк не сработал бы. Тем не менее, на практике я столкнулся с этими проблемами только один или может быть два раза — и ни разу этот трюк не был устранен Elm! У меня есть некоторая дополнительная документация об этих структурах здесь.
Мое правило: не когда не используйте ==
, toString
и тому подобное для Json.Value
. Используйте только функции, сигнатуры которых похожи на Json.Value -> _
.
Номер 6 — Невалидная функция Html.Attributes
В библиотеке Elm-Html
возможно использовать невалидные свойства для Html-элементов. Например в функцию Html.select
нельзя передать значение с числовым типом. Тем более это просто не имеет смысла! К тому же это вызвать сбой Elm приложения (пример в Ellie app):
Мое правило: убедитесь что вы действительно знаете спецификацию Html (шутка).
Заключение
Возможно, это далеко не то, с чем вы сталкиваетесь на практике, но когда вы с столкнетесь с этим, это может стать неприятным сюрпризом. Благодаря прилагаемым усилиям, мы придерживаемся в Elm высоких стандартов, чтобы предотвратить подобные способы, которые могут вызвать сбой. Я рад, что только какой-то непонятный JSON объект, сначала закодированный, а затем сравниваемый с другим, является одним из тех немногих способов, которые способны вызвать сбой приложения в моем любимом языке! И я не могу сказать то же самое про многие другие языки. А ты?
Примечание переводчика
На момент перевода версия Elm 0.19, и актуальным из этой статьи является только последний эксперимент. Это показывает, что разработчики Elm постоянно работают над качеством языка, придерживаясь принципов, где одним из них является отсутствие исключений во время исполнения.
Слушайте наш подкаст в iTunes и SoundCloud, читайте нас на Medium, контрибьютьте на GitHub, общайтесь в группе Telegram, следите в Twitter и канале Telegram, рекомендуйте в VK и Facebook.
Если вам понравилась статья, внизу можно поддержать автора хлопками 👏🏻 Спасибо за прочтение!