Как я встретил вяз
Я занимался функциональным программированием время от времени несколько лет. Я немного выучил Haskell, я написал немного кода на Эликсире, но все равно не понимал, как я могу написать что-нибудь серьезное на функциональном языке. Экспериментируя с функциональным программированием, я довольно быстро увидел преимущества неизменяемого состояния и чистых функций, но заблудился, когда дело дошло до работы с побочными эффектами, которые фактически сделали код полезным в реальном мире.
Я случайно наткнулся на язык вязов. Это было на Strange Loop 2015, где я впервые увидел, как Ричард Фельдман и его команда продемонстрировали фронтенд-работу, которую они проделывали с Elm. Код выглядел просто и элегантно, и больше всего казалось, что он решает проблему состояния, от которой страдает так много интерфейсных проектов.
Управление состоянием в JavaScript, как известно, сложно. Состояние хранится во всей модели DOM и управляется кодом JavaScript. Это означает, что одна часть одной и той же кодовой базы может манипулировать состоянием способами, которые могут противоречить тому, как другие части кодовой базы используют то же состояние. В результате код становится хрупким, и его трудно поддерживать. Фреймворки JavaScript пытались решить эту проблему, сохраняя состояние в коде JavaScript и отображая HTML на основе этого состояния. С одной стороны, это помогло решить проблемы, но с другой стороны, добавило еще один уровень сложности во интерфейсные проекты. Иногда просто поддержание среды сборки для современной кодовой базы JavaScript может приблизиться к сложности реального кода.
Итак, где здесь в игру вступает Вяз? Elm - это больше, чем просто функциональный язык программирования. В базовый язык встроена простая, но мощная инфраструктура приложения, которая требует, чтобы приложение использовало неизменяемое состояние и было отделено от чистого функционального кода и побочных эффектов.
Именно это сразу сделало Вяза полезным для меня. Вместо того, чтобы просто получить действительно крутой язык, который полностью изменил мой способ написания кода, я выбрал действительно крутой язык и связанную с ним архитектуру, которая позволила мне сразу погрузиться в написание веб-приложений.
Вяз Архитектура
Архитектура Elm состоит из трех основных компонентов.
Модель
Модель - это место, где хранится все состояние вашего приложения. Главное помнить, что это состояние неизменяемо. Невозможно изменить какую-либо отдельную часть состояния. Все изменения приводят к созданию полностью новой копии модели. Это состояние также можно изменить только одним способом (с помощью функции обновления).
Вот простой пример модели и функции, которая инициализирует модель.
type alias Model = { xCoord: Int , yCoord: Int } init : Model init = { xCoord = 0 , yCoord = 0 }
Вид
Представление - это функция, которая принимает модель и создает HTML. Для меня это был момент эврики изучения Вяза. Превращение создания HTML в чистую функцию значительно упрощает тестирование и отладку приложений. Мы знаем, что никакой побочный эффект не может повлиять на обработанный HTML. Любые изменения должны быть связаны с изменением модели.
Вот пример представления, в котором используется модель, определенная выше. Он просто отображает координаты x / y, хранящиеся в модели, и предоставляет четыре кнопки, которые можно использовать для изменения модели.
view : Model -> Html Msg view model = div [] [ div [] [ text (toString model.xCoord) ] , div [] [ text (toString model.yCoord) ] , button [ onChange Up ] [ text "Up" ] , button [ onChange Down ] [ text "Down" ] , button [ onChange Left ] [ text "Left" ] , button [ onChange Right ] [ text "Right" ] ]
Обновлять
Функция обновления - единственный способ изменить модель. Модель принимает сообщение и модель и создает новую модель. Сообщение - это тип, который определяет действие, которое может быть применено к модели.
Вот пример, в котором используются модель и представление, определенные выше. Обратите внимание, что типы сообщений отображаются непосредственно в параметрах атрибутов onChange в представлении. Последовательность выполнения программы выглядит так:
- Нажатие кнопки вызывает выполнение функции обновления с определенным сообщением.
- Функция обновления создает новую версию модели.
- Новая модель приводит к повторной визуализации представления с использованием нового значения модели.
type Msg = Up | Down | Left | Right update : Msg -> Model -> Model update msg model = case msg of Up -> { model | yCoord = model.yCoord + 1 } Down-> { model | yCoord = model.yCoord - 1 } Left-> { model | xCoord = model.yCoord - 1 } Right-> { model | yCoord = model.yCoord + 1 }
Собираем все вместе
С этими компонентами пора создавать приложение верхнего уровня. Это делается с помощью функции App.program, включенной в ядро Elm. Получающееся в результате приложение верхнего уровня очень просто.
Мы просто передаем три функции, которые мы создали, в соответствующие параметры beginnerProgram, и все готово. У нас есть полноценное веб-приложение, написанное на Elm.
main : Program Never main = App.beginnerProgram { init= init , view = view , update = update }
Мои выводы
Это было моим знакомством с Вязом. Даже на таком маленьком примере я смог увидеть, как неизменное состояние и чистые функции были секретом создания понятных и поддерживаемых приложений. Я мог понять, как можно распространить это на гораздо более крупные приложения, которые все еще будут иметь эти преимущества. И все это я сделал, не зная ничего о лямбда-функциях, монадах, функторах или любых других эзотерических концепциях функционального программирования, которые ставили меня в тупик в прошлом.
Сначала я опасался переходить на компилируемый и строго типизированный язык. Я был убежден, что споры с системой типов и компилятором замедлили бы меня и, как правило, сделали бы меня несчастным. Вместо этого я обнаружил, что компилятор Elm сделал меня более эффективным. Все ужасные ошибки с нулевым и неопределенным значениями, с которыми я боролся в JavaScript, исчезли. Система типов Elm и ее дружественные сообщения компилятора упростили создание пуленепробиваемых интерфейсных приложений с небольшими хлопотами и трудностями.
Что еще более важно, мой опыт работы с Elm заставил меня задуматься о том, как я могу перенести эту простоту в другие аспекты моей жизни программирования. Если функциональное программирование может сделать мой интерфейс намного приятнее, как я могу применить полученные знания в других областях, в которых я работаю?
- Могу ли я подумать о том, как лучше использовать состояние в моем коде Ruby?
- Стоит ли мне подумать о том, чтобы заняться бэкендом в Elixir?
- Будет ли теперь легче изучать Haskell, когда Эльм избавил меня от страха перед функциональным программированием?
Все эти вопросы побудили меня побольше узнать о функциональном программировании. И мне нужно поблагодарить Элма за то, что он привел меня в этот водоворот знаний, который заставляет меня пересмотреть так много из того, что я знал о программировании. Elm - это лекарство, которое я настоятельно рекомендую, если вы хотите перевернуть свое мышление программирования с ног на голову.