Продолжим говорить о Elm 0.18. Elm. Удобный и неловкий
Elm. Удобный и неловкий. Json.Encoder и Json.Decoder
Elm. Удобный и неловкий. Http, Task В этой статье рассмотрим вопросы архитектуры Elm приложения и возможные варианты реализации компонентного подхода разработки. В качестве задачи рассмотрим реализацию выпадающего окна, которое позволяет зарегистрированному пользователю добавить вопрос. В случае анонимного пользователя предлагает сначала авторизоваться или зарегистрироваться.  Так же предположим, что впоследствии может потребоваться реализовать прием других типов пользовательского контента, но логика работы с авторизованными и анонимными пользователями останется прежней. Исходный код наивной реализации. В рамках этой реализации будем все хранить в одной модели. Все данные необходимые для авторизации и опроса пользователя лежат в модели на одном уровне. Такая же ситуация и с сообщениями (Msg).  Тип интерфейса описан в виде union type Ui, который используется с типом Maybe.  Таким образом ui = Nothing описывает отсутствие выпадающего окна, а Just  — попап открыт с конкретным интерфейсом.
 В функции update происходит сопоставление пары, сообщение и данные пользователя. В зависимости от этой пары выполняются различные действия.  Допустим при клике на кнопку “Open popup” генерируется сообщение OpenPopup. Сообщение OpenPopup в функции update обрабатывается различным образом. Для анонимного пользователя генерируется форма авторизации, а для авторизованного — форма, в которой можно оставить вопрос. Очевидно, у данного подхода возможны проблемы с ростом функций приложения: Исходный код удобной реализации. В рамках этой реализации попробуем разделить проект на самостоятельные компоненты. Допустимы зависимости между компонентами. Структура проекта: Каждый компонент, исходя из архитектуры языка, должен содержать: Каждый компонент может содержать подписку (subscription) в случае необходимости. 
Рис. 1. Диаграмма активности компонента Каждый компонент должен быть инициирован, т.е. должны быть получены: Перечень аргументов функции инициализации (init) зависит от логики работы компонента и может быть произвольным. Функций инициализации может быть несколько. Допустим, для компонента авторизации может быть предусмотрено два варианта инициализации: с токеном сессии и с данными пользователя. Код, использующий компонент, после инициализации должен передать команды в elm runtime при помощи функции Cmd.map. Функция компонента update должна быть вызвана для каждого сообщения компонента. В качестве результата выполнения функция возвращает тройку: Код, использующий компонент, после мутации должен обновить модель компонента и передать команды в Elm runtime при помощи функции Cmd.map. Обязательные аргументы функции update, в соответствии с архитектурой Elm приложений: При необходимости перечень аргументов можно дополнить. Функция представления (view) вызывается в момент, когда необходимо в общее представление приложения вставить представление компонента. Обязательным аргументом функции view должна быть модель компонента. При необходимости перечень аргументов можно дополнить. Результат выполнения функции view должен быть передан в функцию Html.map. В примере описано два компонента: Auth и Question. Компоненты описанным выше принципам. Рассмотрим каким образом они могут быть интегрированы в приложение. Для начала определим то, как наше приложение должно работать. На экране имеется кнопка, при нажатию на которую: Для описания приложения необходимы: Модель содержит информацию о пользователе (user) и типе текущего интерфейса (ui). Интерфейс может быть либо в состоянии по умолчанию (Nothing), либо одним из компонентов Just a. Для описания компонентов мы используем тип Ui, который связывает (тегирует) каждую модель компонента с конкретным вариантом из множества типа. Например, тег AuthUi связывает модель авторизации (Component.Auth.Model) с моделью приложения. В сообщениях необходимо тегировать все сообщения компонентов и включить их в сообщения приложения. Тег AuthMsg и QuestionMsg связывают сообщения компонента авторизации и задания вопроса пользователем соответственно. Сообщение OpenPopup необходимо для обработки запроса на открытие интерфейса. Входная точка приложения описана типично для Elm-приложения. Функция инициализации создает стартовую модель и не требует выполнения команд. Т.к. модель и сообщения приложению связаны, будем обрабатывать пару сообщение (Msg) и тип интерфейса (model.ui: Ui). Если получено сообщение OpenPopup и в модели указан интерфейс по умолчанию (model.ui = Nothing), то инициализируем компонент Auth. Если компонент Auth сообщает, что пользователь авторизован — инициализируем компонент Question сохраняем в модель приложения. Иначе, сохраняем в модель приложения модель компонента. Если получено сообщение с тегом AuthMsg a и в модели указан интерфейс авторизации (model.ui = Just (AuthUi authModel)), то передаем сообщение компонента и модель компонента в функцию Auth.update. В результате получим новую модель компонента, команды и результат. Если пользователь авторизован инициализируем компонент Question, иначе обновляем данные об интерфейса в модели приложения. Аналогичным компоненту Auth образом обрабатываются сообщения для компонента Question. В случае успешного размещения вопроса, интерфейс меняется на по умолчанию (model.ui = Nothing). Все остальные случаи игнорируются. Функция представления в зависимости от типа интерфейса (model.ui) генерирует либо интерфейс по умолчанию, либо вызывает функцию представления компонента и отображает тип сообщения компонента в тип сообщения приложения (Html.map). Подписка отсутствует. Данный пример хоть и чуть удобнее, но достаточно наивный. Чего не хватает: Разработчик