Прежде всего; посмотрите на все эти сокращения. Я это сделал. Ура.

Перед тем, как показать твид, мне нужно объяснить причины его появления, добавив немного истории. При желании вы можете перейти к заголовку Введите твид. Пожалуйста.

В последнее время произошел небольшой разрыв между двумя парадигмами в веб-пространстве. Функциональное реактивное программирование, возглавляемое React, с одной стороны, и объектно-ориентированное программирование, поддерживаемое Angular и веб-компонентами, с другой.

Образ мышления и традиции этих двоих привели к твердой позиции с обеих сторон по вопросам, казалось бы, не связанным с этими парадигмами.

Виртуальный дом

Одним из таких противоречий является объектная модель документа.

Стандартные веб-API JavaScript в браузерах с самого начала использовали объектно-ориентированное представление HTML. HTMLButtonElement — это экземпляр HTMLElement, который, в свою очередь, является экземпляром базового DOM-узла Node и т. д.

Поскольку эти объекты напрямую связаны с макетом и отрисовкой пользовательского интерфейса, работа с этими объектами может привести к снижению производительности, мерцанию, отставанию и так далее.

Появление Virtual DOM, популяризированное Elm и React, привело к идее отдельного представления DOM, которое не было связано с пользовательским интерфейсом. Эта структура данных только для JS может быть сгенерирована, обработана и заменена с очень небольшим влиянием на производительность. Фактический DOM затем разумно манипулировался самым маленьким и быстрым способом, что делало его неотличимым от тщательного ручного управления мутациями DOM.

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

JSX и защита платформы

Чтобы осуществить переход от HTML к Virtual DOM, Facebook выпустил React с новой языковой функцией, специально разработанной для того, чтобы создание VDOM было похоже на написание HTML — JSX. Он превратил непривычный React.createElement(‘div’) в гораздо более удобный ‹div /›. Кроме того, это позволило разработчикам создавать свои собственные компоненты в виде элементов XML-подобного дерева, например ‹This /›.

Первоначально это считалось кощунственным, потому что в то время идея объединения разметки и поведения пользовательского интерфейса считалась «плохой практикой».

Постепенно, по мере того как сообщество осознавало привлекательность объединения вещей, которые меняются по одним и тем же причинам — разметки и поведения, — в толпе ОО возник аргумент Работа с платформой, а не «поверх» этого. В конце концов, все веб-API являются объектно-ориентированными.

Это разделение сделало Virtual DOM эксклюзивным для разработчиков FRP.

Вяз Архитектура

Как вы можете знать или не знать, React на самом деле был вдохновлен другим проектом под названием Elm, который является не библиотекой JS, а совершенно другим языком программирования. Он имеет синтаксис, аналогичный ML-семейству, подобно Haskell, и является строго типизированным, чисто функциональным языком программирования.

Elm представил так называемую Архитектуру Elm, которая заменила доминирующую архитектуру MVC. Идея состоит в том, что у вас есть модель, функция представления и функция обновления. Эти три работают вместе следующим образом:

Представление получает Модель и отображает на ее основе пользовательский интерфейс (VDOM). Затем действия пользователя запускают функцию Обновить, которая, учитывая тип действия, снова запускает функцию Просмотр с измененной версией Модели. , эффективно обновляя пользовательский интерфейс.

Дело против Elm Architecture

Однако у меня есть одна проблема со всем этим подходом — способ обработки зависимостей исходного кода.

Функция View получает только Model, а поскольку Elm функционален, это означает, что весь пользовательский интерфейс должен быть конкретно сгенерирован. Если нам нужна боковая панель, View должен выбрать реализацию для этой боковой панели. Таким образом, исходный код функции View зависит от всей кодовой базы пользовательского интерфейса.

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

Наконец, следует упомянуть, что Elm также немного ограничен в своей реализации на момент написания этой статьи. В частности, в нем нет классов типов, как в Haskell. Классы типов позволят функции View вызывать функции с неизвестными реализациями, которые затем будут реализованы по-разному в зависимости от типов данных в Model.

Ориентация объекта и внедрение зависимостей

Достаточно сказать, что управление зависимостями исходного кода не очень интуитивно понятно в функциональном программировании, по крайней мере, не для такого разработчика, как я, который гораздо больше разбирается в ООП, чем в ФП.

Объектно-ориентированное сообщество долгое время имело дело с зависимостями исходного кода и сделало полиморфизм основным механизмом повторного использования кода. Традиционно это достигается с помощью наследования. Однако с этим возникает много проблем, поэтому лучше использовать абстрактную композицию с помощью внедрения зависимостей. Я имею в виду шаблон, а не автоматическое внедрение зависимостей с помощью библиотек или фреймворков.

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

Введите твид

Tweed — это реактивная библиотека пользовательского интерфейса на основе виртуальной модели DOM, которая использует объектно-ориентированную парадигму для решения проблемы поддержки сложного пользовательского интерфейса с отслеживанием состояния.

Вот простой компонент Counter:

На первый взгляд, он очень похож на компонент React, но без setState и вместо этого декоратора (at)mutating. Я думаю, вы, вероятно, можете себе представить, что это значит (это означает, что пользовательский интерфейс будет перерисовываться при изменении этого свойства), поэтому мы продолжим.

Теперь давайте посмотрим, как используется этот компонент:

Вы заметите, что мы не видим ‹Counter /› в методе render. Вместо этого мы отправляем экземпляр, который у нас уже есть. Это очень важно. В React каждый компонент повторно создается при повторном рендеринге, если иное не указано с помощью обратных вызовов shouldComponentUpdate и подобных механизмов. В Tweed методы рендеринга просто делегируются между постоянными экземплярами.

JSX как примитив

В Tweed JSX не содержит и не управляет экземплярами классов, которые следует или не следует заменять. Вместо этого JSX — это просто неизменяемые объекты, представляющие HTML. Ничего больше.

С таким мышлением вы можете думать о методе render как о toString для HTML или toHTML. На самом деле имя render вовсе не обязательно. Это просто соглашение, и, как видно из приведенного выше примера, если фабрика JSX получает объект, она неявно вызывает подобный метод .render() без аргументов.

Монтаж

Последним шагом является подключение этого класса App к браузеру, и это очень просто:

Как вы могли догадаться, легко использовать другие рендереры для выполнения начального рендеринга на сервере.

Рядом с родным

Поскольку метод render в Engine принимает экземпляр, а не конструктор класса, то, как вы получите этот экземпляр, полностью зависит от вас. До этого момента вы полностью контролируете свои объекты.

Кроме того, Tweed не предоставляет никаких средств управления зависимостями, таких как контейнер DI/IoC. Если вы хотите использовать один из них, вам придется выбрать один. Возможно, вам даже будет проще просто создать новые классы самостоятельно. Если вы будете придерживаться шаблона Внедрение зависимостей, вы получите огромное дерево инстанций, например следующее:

Хотя на первый взгляд это может показаться громоздким, на самом деле вы можете обнаружить, что это не только дает довольно полный обзор того, как выглядит ваш сайт; все независимые части сильно отделены от остальной части системы, что означает, что их можно легко заменить или независимо протестировать и обслуживать. И все можно отслеживать и составлять в этом файле верхнего уровня.

Еще одно преимущество заключается в том, что вы можете структурировать свое приложение, чтобы внедрить различные реализации для некоторых интерфейсов; один для клиента, один для сервера. Представьте себе интерфейс EmployeeRepository и его соответствующие реализации APIEmployeeRepository и DatabaseEmployeeRepository. Компоненту, внедряющему интерфейс EmployeeRepository, не нужно знать, как извлекаются сотрудники, а только то, что они есть.

Вот и все. Попробуйте Tweed, если вы опытный разработчик ООП или считаете, что функциональная парадигма React не соответствует вашей ментальной модели создания приложений.

Посетите домашнюю страницу Tweed, чтобы увидеть еще несколько примеров.