В одном из наших последних проектов нас попросили создать фреймворк для микросервисов. Мы хотели сделать что-то декларативное и простое в использовании. Мы также хотели скрыть сложность, вызванную несколькими общими средствами (ведение журнала, трассировки Zipkin, метрики InfluxDB и т. Д.). Для этого мы взяли несколько подсказок из инструмента, которым пользуемся каждый день: React.
Как работает React: версия TL; DR
В React мы используем JSX, чтобы объявить, каким должен быть наш UI. В следующем примере мы определяем компонент HelloWorld
с помощью свойства name
. Он, в свою очередь, использует компоненты p
и span
, которые предоставляются React.
JSX - это просто синтаксический сахар и должен использоваться вместе с транспилером, таким как Babel. Если вы запустите пример через Babel (с включенной поддержкой preset-react
), вы получите результат, очень похожий на этот:
Мы видим, что компоненты - это просто функции. Мы используем их для создания элементов. Элемент - это просто метаинформация об иерархии компонентов и их свойствах (свойствах). В этом легко убедиться, если вы просто выведете JSX:
Итак, элемент - это просто структура данных. Он сообщает нам, к какому типу компонента принадлежит элемент, каковы его свойства и отношения между родительскими и дочерними компонентами (с помощью специального свойства children
). Вы можете прочитать этот пост в блоге React, чтобы разобраться в этом подробнее. Там это гораздо лучше объяснено :)
Магия React происходит в ReactDOM.render
. С помощью этой информации React создает виртуальную модель DOM и определяет наиболее эффективный способ визуализации представления, обрабатывает состояние пользовательского интерфейса, проксифицирует события DOM и т. Д. Он просто абстрагирует детали управления DOM, в то время как разработчик сосредотачивается на описании того, как UI должен быть. Аккуратный!
Наши цели
В этой статье мы постараемся решить лишь минимальную часть реальной проблемы. Мы хотим:
- Создавайте микросервисы, использующие промежуточное ПО, и делайте это декларативно.
- Скрыть тот факт, что мы внутри компании используем Koa.js в качестве базового фреймворка. Также сделайте возможным переход на другой фреймворк в будущем.
- Добавьте одно общее средство к каждому микросервису: журнал запросов без дополнительного кода.
- Никаких проверок работоспособности, никаких оптимизаций. Это просто игрушка 😉
Мы собираемся провести рефакторинг этого микросервиса Koa.js:
Записано так:
Как видите, здесь нет ссылок на Koa.js, общее ведение журнала будет добавлено службами, а код просто объявляет, как микросервис должен шаг за шагом реагировать.
Заимствование из React
Первым шагом должно стать создание наших компонентов. Компонент - это просто функция, которая с заданными реквизитами возвращает структуру данных (элемент). Мы будем использовать фабрику компонентов baseComponent
, чтобы определить все наши компоненты.
Помимо хранения некоторой метаинформации, вновь созданный компонент будет иметь два метода: mix
и handler
.
mix
позволяет нам добавлять новые методы в компонент и иметь гибкий API. Это немного страшно, но если вы не торопитесь, вы увидите, что мы просто добавляем и привязываем функции к нашему недавно созданному объекту. Эти функции могут возвращать либо значение, либо объект, что позволяет объединить в цепочку больше методов (следовательно, гибкий API).
handler
- это свойство, которое дает нам реальный код, реализующий поведение компонента (это наш «рендер», похожий на реакцию). Он использует функцию построения. Мы поговорим об этих build
функциях позже.
Каждый компонент в системе определяется с помощью baseComponent
, устанавливая метаинформацию и смешивая некоторые методы.
service
можетuse
несколько промежуточных программ.middleware
является оболочкой для асинхронной функции Koa.js.middleware
, в свою очередь, используется как базовый компонент для определения конкретных промежуточных программ. В нашем случае:status
, который устанавливает код состояния HTTP, иbody
, который устанавливает содержимое тела ответа.
Функция сборки
Второй и последний шаг - определить функцию build
, которая принимает элемент и создает настоящий микросервис Koa.js:
- Мы регистрируем разные конструкторы, по одному для каждого типа компонента / элемента в системе.
- Функция
build
находит построителя для данного элемента, вызывает его и передает себя, чтобы позволить строителям рекурсивно создавать его дочерние элементы. - Конструктор
service
создает приложение Koa.js, добавляет промежуточное ПО для общего журналирования и, наконец, строит и добавляет промежуточное ПО, добавленное вservice
с помощьюuse
. - Строитель
middleware
просто возвращает обернутую функцию.
Подводя итоги
С помощью кода, который мы видели, мы можем декларативно определить наш микросервис. Нам не нужно беспокоиться о деталях, связанных с Koa.js, и мы можем добавить столько общей логики, сколько нам нужно, без шаблона.
Хотя это всего лишь игрушечная версия, ее можно использовать как основу для создания чего-то большего. Или это может быть просто вдохновением для применения умных идей, на которых построен React, в других сценариях.
PS, еще кое-что перед отъездом
Просто ради развлечения.
Как мы видели в начале, JSX - это просто синтаксический сахар и переводится в вызовы функций с помощью Babel. Разве нельзя было бы написать наши микросервисы на JSX так:
Ага. Возможно. Babel позволяет нам настроить способ преобразования JSX в вызовы функций, используя параметры pragma
в presect-react
.
Как мы видели ранее, переведенные вызовы функций получают компонент, свойства и дочерние элементы как параметры. Наш гибкий API не подходит для этого. К счастью для нас, от этого не нужно избавляться: просто отбросьте несколько оболочек и наш собственный createElement
, добавьте функцию listen
для запуска сервера и вуаля!
Так весело! 😂