Sep 4 · 8 min read
Реконструкция Гродненского Старого Замка, 2019, Фото Басак Артур

Архитектура фронтенда: Средний круг

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

Архитектурный план — Frameworks, Libraries, Components, Rendering Model, Content
Архитектурный план — Frameworks, Libraries, Components, Rendering Model, Content
Архитектурный план. Приближаясь к ядру, мы делаем технические выборы, которые в наибольшей степени имеют ценность для бизнеса и конечного пользователя
  • Фреймворк — каркас приложения
  • Сервисы и библиотеки (сторонние и собственные)
  • Визуальные элементы и компоненты
  • Модель рендеринга и тип приложения
  • Контент — данные, тексты, изображения и медиа

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


Сторонние модули

Вторичные библиотеки важнее фреймворка? Да, да и еще раз, да. А все потому, что они не вызывают такого ажиотажа и обсуждений, как фреймворки, тем самым усыпляя бдительность технических лидеров и архитекторов программных систем.

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

С одной стороны, можно выбрать настолько монструозный каркас, что в его коробке будет практически все, что необходимо для разработки вашего приложения. С другой стороны, в определенных случаях, нам не нужна такая машина, нам надо всего 10–20% от всего функционала, который находится в коробке.

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

Граница размыта, потому что прикладник может и не использовать каркас в принципе, он может все собрать из независимых модулей различных разработчиков. Для шаблонов взять nunjucks или mustache, для маршрутизации sammy.js, для AJAX-запросов axios, для обработки потоков данных RxJS и т.д.

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

Помните шум вокруг ситуации с выгрузкой из npm 250 модулей в 2016? Это выгрузка уронила множество проектов в продакшене.

Delex Conference, 2018, Фото Басак Артур

А все почему? Потому что автор этих модулей Азер Кочулу (Azer Koçulu) просто психанул. Потому что разработчики относились халатно к зависимостям своих проектов, они просто тянули все подряд. Надо сделать проверку на то, что литерал имеет примитивный числовой тип? О! Скачаю библиотеку is-number для этого (десятки вариаций подобных модулей нахожу в зависимостях многих аутсорс проектов). Серьезно? Вы будете подвергать сборку риску из-за 20 строк кода? В чем проблема? В нежелании понять как устроены механизмы типизации в JavaScript?

С того времени подход к управлению зависимостями немного изменился. Npm предоставил возможность пометить модуль как неактуальный (deprecated), вместо того чтобы совсем его удалить из реестра (unpublish).

На самом деле существует только две возможные стратегии управления зависимостями:

  • хранить фиксированные версии зависимостей на своей стороне (приватный реестр /private npm registry, хранение node_modules в виде git submodule, расположить библиотеки вендоров на собственной CDN — каждый из подходов имеет свои плюсы и минусы); переход и миграции на новые версии тщательно планировать
  • тянуть при сборке и разработке зависимости из online (open public registry, CDN), но убедиться, что версия зафиксирована (package-lock.json, yarn.lock, npm ci); переход и миграции на новые версии тщательно планировать

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

Использование проверенных и безопасных модулей и библиотек это прямая обязанность проектировщика, именно он несет за это ответственность.

Чуть подробнее как проверять модули на вшивость я описывал в отдельной серии своих статей. Если коротко, то npm audit — это первый хороший шаг к тому, чтобы избежать неприятных неприятностей.

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

Но не забывайте и о плюсах лицензионных платных модулей и библиотек.

Покупать, а не создавать. Наиболее радикальное возможное решение при создании программ — вообще не создавать их.

Ф.Брукс, “Мифический человеко-месяц”, 1995

Мне вспоминается опыт моего взаимодействия с командой Highcharts.js. У меня была лицензия на эту библиотеку визуализации данных, купленная под нужды проекта на котором я работал пару лет назад. Вообще, highcharts.js это достаточно мощное и богатое решение. Но у меня возникли проблемы с реализацией Synchronized Charts.

Торстейн Хонси (Torstein Hønsi) из команды поддержки Highsoft достаточно быстро ответил мне и привел пару примеров кода, также дав рекомендации по использованию данного вида диаграмм.

Те самые Synchronized Charts по которым мне нужен был совет
Те самые Synchronized Charts по которым мне нужен был совет

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

В то же время, в проектах с открытым исходным кодом, даже самых популярных, ответа на свой вопрос или помощи можно ждать месяцами (сделал запрос на фичу в Jest, до сих пор не обработана никак с апреля месяца, хотя команда Oculus на ReactVR отвечала, в свое время, быстрее).

На Lition Energy мы стартовали с тем, что было в коробке фреймворков next.js (целевые страницы и сайт продаж / SSR) и react-create-app (трейдинг платформа / SPA). Далее добирали уже необходимые модули по мере поступления соответствующих задач. Старались выбирать только популярные, проверенные и всем известные решения, которые использует сообщество. Axios для ajax-запросов, Joi для валидации данных, Moment.js - работа с датами и временем, Web3.js для взаимодействия с блокчейн клиентом, Swiper для мобильного UI и Focus-Manager для доступности, пару функций lodash, устанавливаемых по раздельности.Средний круг это не только о кодовых модулях и библиотеках, это еще и об online сервисах или устанавливаемых на ваш сервер готовых компонентах системы. К примеру, Auth0 для SSO входил бы как раз именно в этот круг.В нашем приложении была возможность оплаты электроэнергии криптовалютой Bitcoin. Для этого мы использовали сторонний сервис bitpay.com. Пару месяцев назад у нас случился интересный казус, этот сервис запретил производить подобные оплаты в Германии. В результате нам пришлось выключить относительно важную фичу в нашей системе.Это говорит о том, что не только кодовые модули и библиотеки надо выбирать с умом, но и сторонние сервисы. Предвидеть подобные риски и планировать какие-то обходные стратегии. В общем, продолжаем учиться на ошибках.
https://lition.de (Signup — Payment Data)
https://kundenportal.lition.de (Profile — Payment Data)

Собственные модули

Фреймворки, библиотеки, собственный код — Р. Мартин в своей “чистой архитектуре” называет это все деталями. Все верно, ведь как по мне, то суть как раз в деталях. Архитектор может сформулировать концепцию, но кто будет соблюдать концептуальную целостность? Она как раз в деталях. Именно исполнитель / разработчик должен следовать заданному курсу. В противном случае при должной свободе, падение 2016-го года будет повторяться снова и снова. Кто-то должен брать на себя ответственность, в том числе и за детали. В чем-то даже ограничивать исполнителя.

На практике коэффициент стоимость/эффективность созданного продукта больше зависит от исполнителя, а простота его использования — от архитектора.

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

Ф.Брукс, “Мифический человеко-месяц”, 1995

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

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

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

Все начиналось с шаблона Модуль, потом, решая проблему одинаковых имен и инкапсуляции, стал популярен подход с пространством имен и IIFE. Позже нас начал раздражать порядок подключаемых модулей и появились AMD и CommonJS. Дальше с этим зоопарком надо было как-то жить и родился подход UMD. Теперь все стандартизировано и ES6 является предпочтительным способом организации модулей. Правда, зоопарк еще долго будет оставаться открытым и работающим.

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

Хотя в JavaScript модуль это не всегда класс, для него, как по мне, справедливы все те же хорошие принципы проектирования из мира ООП (к примеру SOLID). Но, помимо всего прочего, стиль коду задает парадигма. CSS или CSS-in-JS? HTML или JSX? Императивное или функциональное?

Это детали, но в то же время, и технические решения, которые должен принимать проектировщик системы, а не исполнители.

Уж так сложилось, что любая нативная система визуальных компонентов (по крайней мере, те, с которыми сталкивался я в своей работе — Swing, AWT, SWT, JavaFX, HTML/DOM, WinForms, VCL) основана на событиях и по средствам этих событий пользователь взаимодействует с данными. Это накладывает определенные ограничения на программный код — один поток, событийный цикл, асинхронность.

А это значит только одно, от событийно-ориентированной парадигмы программирования не уйти и с ней надо как-то управляться. Нужно договориться, как именно организовывать такой код. Это детали, но опять же, как по мне, так именно проектировщик должен направлять исполнителей по дороге от обратных вызовов (callbacks) до линейных async/await вместе с обещаниями (promises).

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

Гордон Глегг, “Дизайн дизайна (Кембридж Пресс)”, 1969

Говоря о собственном коде Lition Energy, надо упомянуть об однозначно трактуемом манифесте чистого кода, подписанным всеми разработчиками проекта. Каждый понимает где и в каком слое должен находиться определенный функционал, будь то редукторы или ajax-сервисы (старая кодовая база трейдинг платформы лежит на github, мы ее специально открывали перед ICO, сейчас приложение выглядит по-другому).Есть устоявшийся подход к работе с асинхронностью (action performers). И творчество тут в реализациях, которые находяться в рамках заданной концепции.CSS - это мощный самостоятельный и самодостаточный инструмент (я бы даже сказал "материал", но об этом в следующей статье), именно его мы и используем в чистом виде, не смешивая код стилей с каким-либо другим кодом. Этим мы поощряем подход при котором существует разделение ответственностей (Separation of Concerns / SoC).Библиотека визуальных компонентов (UI Kit) собирается, как универсальный модуль и переиспользуется как на сайтах с серверным рендерингом, так и на трейдинг платформе. Зависимость описывается как отдельный git-репозиторий из которого npm забирает собранную библиотеку. В описании сырого кода мы следуем последней спецификации EcmaScript и используем модульную систему ES6.

Продолжение следует…

PS: Если у вас есть какие-то мысли на тему, то смело пишите на artur.basak.devingrodno@gmail.com

Артур Басак, 2019

Front-end in regions. Grodno. Belarus

Notes and articles about web, front-end and automated tests.

Artur Basak

Written by

Lead Programmer, UI Engineer. Passionate about Web, Human-Computer Interaction and Automated Testing.

Front-end in regions. Grodno. Belarus

Notes and articles about web, front-end and automated tests.

Welcome to a place where words matter. On Medium, smart voices and original ideas take center stage - with no ads in sight. Watch
Follow all the topics you care about, and we’ll deliver the best stories for you to your homepage and inbox. Explore
Get unlimited access to the best stories on Medium — and support writers while you’re at it. Just $5/month. Upgrade