Elm – забава или серьёзный инструмент?

от автора

Привет, Хабр!

Данный обзор познакомит вас с частичкой мира функциональных языков программирования, а именно с Elm, кто-то узнает про этот инструмент, кто-то про то, что фронтенд – это не только HTML, CSS и JS.

Elm – это функциональный язык программирования, который компилируется во всеми любимый javascript. Он обладает всеми плюсами и минусами этого семейства языков. Из самых важных особенностей стоит отметить, что язык является компилируемым. А также свойства языка принуждают вас сразу обдумать архитектуру вашего приложения: расписать, что попадёт в конкретную функцию, что из неё выйдет, и куда пойдёт дальше.

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

Начну сразу с архитектуры приложений на Elm, которая показана на картинке ниже:

Elm генерирует HTML для отображения на экране, а затем приложение отправляет обратно сообщения (Msg) о каком-либо событии (например, нажатие кнопки).

Любое SPA (single page application) на Elm состоит из следующих элементов:

Init – начальное состояние модели.

Model — текущее состояние проекта.

View — отображение model.

Update — обновление состояния проекта на основе сообщений (Msg).

Что мы будем делать?

Для того что бы разобраться как работает Elm, было реализовано великое и могучее SPA под названием To-Do List (список дел) с возможностью записи дел и проведения некоторых операций над ними. Для демонстрации работы с запросами было добавлено соединение с БД (базой данных).

Наше SPA To-Do List будет обладать следующими возможностями:

·        создание элемента To-Do List’а;

·        редактирование (изменение названия и статуса выполнения задачи);

·        удаление;

·        сохранение в БД списка дел.

А реализовывать всё это мы будем с помощью следующих технологий:

1.     Elm – виновник торжества.

2.     Json-server и db.json в роли базы данных (БД).

3.     Bootstrap – будет отвечать за красоту.

 

Начинаем с начала

Для того что бы использовать Elm, как бы это странно не звучало, необходимо установить Elm. Лучше скачивать с официального сайта (elm-lang.org). Так же на нём находится самая актуальная документация языка, которая по своей структуре напоминает обучающий курс. Можно скачать и с pypi, но пакет там не обновлялся с конца 2018 года.

После того как Elm установился, необходимо перейти в директорию проекта и запустить его с помощью команды:

elm reactor

Проект запустится на localhost:8000 и всё, достаточно изредка нажимать ctrl+s для сохранения и проект будет автоматически обновляться, не нужен даже LiveServer.

Архитектура приложения

Приложение состоит из 3-х модулей, каждый из которых вынесен в отдельный файл структура проекта показана на изображении ниже.

  1. Main – основной модуль приложения, в котором происходит его инициализация, добавление в проект теги html, body и всех статичных элементов, а также вызов других модулей. Код данного модуля находится в файле с логичным названием Main.elm.

Main : Program Value Model Msg Main =      Browser.document         { init = =init,         , view = view         , update = update         , subscriptions = subscriptions         }  type Msg = NoOp | TodosMsg TodosMsg.Msg  type alias Model = {todos : List Todo, todoEditView : TodoEditView}  init : flags -> ( Model, Cmd Msg ) init fs =      let model = Model [] None         cmds = Cmd.batch[ Cmd.map TodosMsg Todos.Models.fetchAll ]     in ( model, cmds)  update : Msg -> Model -> ( Model, Cmd Msg ) update msg model =      case msg of         let             ( newTodoEditView, newTodos, cmd ) = Todos.Models.update subMsg mod-el.todoEditView model.todos             newModel = { model | todoEditView = newTodoEditView, todos = newTodos }         in ( newModel, Cmd.map TodosMsg cmd )          view : Model -> Document Msg view model =      { title = "Туду"     , body =          [ div []              [             Html.map TodosMsg <| Todos.Models.viewEdit model.todoEditView             , br [] []             , Html.map TodosMsg <| Todos.Models.viewList model.todos             ]            ]     }
  1. Models – модуль приложения, который отвечает за список дел. Из-за того, что пример небольшой, всё хранилось в одном месте. Но при более серьёзном проекте, хорошим тоном будет разделить код на разные модули. Здесь лежит таблица, которая хранит в себе дела, а также осуществлялись все действия с ними. Ниже приведена часть кода из данного модуля, который лежит в директории Todos и называется Models.elm.

-- Корпус таблицы viewList : List Todo -> Html Msg viewList todos =     Table.table{ options = [ Table.striped ]     , thead = Table.thead []         [ Table.tr []             [ Table.th [] [ text "Название" ]             , Table.th [] [ text "Готово" ]             , Table.th [] [                      div [][ text "Действия" ]                     , div[][ delCompl ]                     ]             ]         ]     , tbody = Table.tbody [] ( List.map todoRow todos )     }  -- Строки таблицы todoRow : Todo -> Table.Row Msg todoRow t =      let          { id, title, completed } = table         ( completedText, buttonText, buttonMsg ) =              if completed then ("Да", "Невыполненно", Revert )             else ("Нет", "Выполненно", Complete)         in         Table.tr []             [ Table.td [] [ text title ]             , Table.td [] [ text completedText ]             , Table.td [] [                  Button [ onClick <| buttonMsg t ][ text buttonText ]                 , Button [ onClick <| ShowEditView <| Editing t ][ text "Редактиро-вать" ]                 , Button [ onClick <| Delete t ][ text "Удалить" ]             ]              -- Функция удаления delCompl : Html Msg delCompl = Button[ onClick DeleteCompleted ][ text "Удалить выполненные" ]
  1. Utils – модуль связи с БД. Здесь находится всё, что связано с данными, а именно: кодирование и декодирование json’а и запросы, для выполнения которых использовался пакет Http.request. Пример запроса показан ниже. Код вынесен из модуля Utils.elm.

--запрос для удаления delete : a -> String -> Platform.Task Http.Error a delete a url =     let decoder = Json.Decode.succeed a         request =              Http.request                 {method = "DELETE"                 , headers = []                 , url = url                 , body = Http.emptyBody                 , expect = Http.expectJsopn decoder                 , timeout = Maybe.Nothing                 , withCredentials = False                 }             in Http.toTask request

После реализации всех указанных модулей получится следующий результат:

Для тестового проекта, который никто не увидит – сойдёт. Но я делаю его для души, поэтому просто необходимо добавить немного красоты. И Elm в этом поможет, с помощью тесной интеграции с Bootstrap. Подключаем его следующей строкой в main:

import Bootstrap.CDN as CDN 

А также импортируем bootstrap классы добавляя элиасы для простоты вызова:

import Bootstrap.Button as Button  # и т.д. по необходимости

Благодаря bootstrap’у и небольшой доработке кода получается следующая картина:

При изменении названия, кнопка «Новая задача» заменяется на поля для редактирования наименования дела.

База данных

Для подъёма базы данных я использовал json-server, который был запущен на 4000 порту. Всего БД имеет 3 поля для каждого дела, а именно:

title <str> - название дела;

completed <boolean> - готовность дела;

id <int> - идентификатор дела.

Команда для запуска следующая:

Json-server db.json -p 4000

В итоге база данных выглядит следующим образом:

Что касается ответа на вопрос:

«Elm — забава или серьёзный инструмент?», он очень прост — всё зависит от вашего проекта. От себя скажу, что изначально программирование на Elm было похоже на поход в магазин на руках. Из-за того, что всё было непривычно, Elm требовал на разработку часы, когда с javascript на то же самое хватило бы и нескольких минут. Данное неудобство связано скорее с изначальным обучением программированию в императивном стиле и обычной привычкой.

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

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

Полный код приложения доступен по ссылке: github.com/MikhailOznobikhin/ELM_todo

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

 

Только зарегистрированные пользователи могут участвовать в опросе. Войдите, пожалуйста.
А пробовали ли вы писать код в функциональной парадигме?
45.45% Да 5
45.45% Нет 5
9.09% Другое: опиши в комментариях 1
Проголосовали 11 пользователей. Воздержавшихся нет.

ссылка на оригинал статьи https://habr.com/ru/post/696718/


Комментарии

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *