14 May

Современные архитектуры фронт-энда (часть 2)

Website developmentProgrammingSystem Analysis and DesignDesigning and refactoringDevelopment Management
Original author: Harshal Patil
image

Вторая часть статьи "Contemporary Front-end Architectures", в которой рассмотрены архитектуры фронт-энда с точки зрения распределения потоков данных. Начало здесь

Реализация


Алгоритмы, порожденные DOM (DOM-infused algorithms)


Методика, внедренная и освоенная библиотекой jQuery, действительно стала началом написания крупномасштабных клиентских приложений, хотя на самом деле jQuery не решала архитектурные проблемы. Она была разработана для упрощения манипулирования деревом DOM когда в поведении браузеров находилось слишком много несоответствий. Это обеспечило независимый от браузера API.

Я не думаю, что это было намеренно, но jQuery упростил API DOM до такой степени, что его было трудно отличить от API обычных языков программирования. Это, в свою очередь, позволило разработчикам буквально смешать уровень DOM API (View) с бизнес-логикой (Model).

Еще раз отметим, что мы все еще находимся в контексте того же серверного MVC. Это просто продолжение. Там нет реального инверсии контроля. Общий контроль над представлениями / страницами все еще определяется кодом на стороне сервера.





В приведенном выше фрагменте кода Модель, Представление и Презентатор/Контроллер в некотором роде объединены в одну монолитную структуру кода. Это тот случай, когда Модель состоит только из одного свойства. Представьте себе попытку создания веб-приложения без цикла просмотра сервера (например, SPA). Было бы невозможно справиться со всем этим каким-либо удобным образом. Код для взаимодействия с DOM пронизан остальной логикой приложения, и поэтому он известен как DOM-infused алгоритм (я не уверен, что официально есть такой термин)

Backbone.js — MV*


Как мы видели, в jQuery при разработке приложений путь структурирования и организации нашего кода явно отсутствует. Именно здесь Backbone.js появился в качестве следующего эволюционного решения. Это была одна из первых библиотек, которая принесла преимущества стиля MVC на стороне клиента.



Если мы посмотрим на диаграмму потока данных Backbone, то ясно увидим модель и представление, но нет объекта, эквивалентного контроллеру. Шаблоны развиваются, и MVC на стороне клиента — это просто эволюция предыдущих архитектур MVC. В ходе этой эволюции большая часть сообщества JavaScript согласилась с определением модели и представления, но не было единого мнения о контроллере. Учитывая окружение клиента, идея Controller не очень подходит. Контроллер оставлен открытым для интерпретации.

Что касается Backbone, то в нем контроллер отсутствует. Итак, что это? Это MVC, MVP или MVVM? Заимствуя из определения серверного MVC, контроллер имеет две обязанности, а именно: отвечать на действия пользователя в форме входящих HTTP-запросов и управляйте моделью для создания представления (HTML-страница). В случае Backbone эти обязанности распределяются между View и Router. Но независимое понятие Контролера или Презентера отсутствует.
Некоторые разработчики считают, что Backbone — это MVP, где View это аналог Presenter, Template — это View, а Model и Collection составляют Model.

Как пишет в своем блоге Адди Османи, в конечном итоге лучше не заставлять Backbone соответствовать каким-то конкретным шаблонам дизайна. Шаблоны проектирования следует рассматривать как гибкие руководства по структурированию приложений, и в этом отношении Backbone не подходит ни под MVC, ни под MVP. Вместо этого он заимствует некоторые из лучших концепций из нескольких архитектурных шаблонов и создает гибкую структуру, которая просто хорошо работает.

Вот так рождается MV* или Model-View-Whatever(«что угодно»). Для подробного обсуждения настоятельно рекомендуется ознакомиться с блогом Адди Османи

По сравнению с предшествующим jQuery, Backbone помог создавать более структурированный код.









Ранее в этой статье я назвал Backbone следующим эволюционным решением. Причина в том, что он просто расширил MVC на стороне сервера, дополнив его. Например, если наш сервер является RESTful и подразумевается, что код фронт-энда — это просто средство для представления модели на стороне сервера, то Backbone предварительно настроен для синхронизации с API:



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

Knockout.js — привязка данных (data binding) для фронт-энда


Knockout.js — это наш последний пример использования базовых шаблонов. Он имеет целью реализацию MVVM — Model-View-ViewModel для JavaScript. И это так. В то время как Backbone занимался решением проблемы организации и структуры кода, Knockout — это эффективная реализация уровня View с помощью декларативных привязок данных (Declarative Data Bindings). Преимущества декларативных привязок такие же, как и у любых конструкций декларативного программирования:

  1. Легко читается: декларативный код помогает в программировании
  2. Сокращение стандартного шаблона: привязки позволяют нам автоматически обновлять DOM при каждом изменении ViewModel, а также обновлять ViewModel при каждом изменении View через пользовательский ввод.
  3. Наблюдаемые (Observable): Knockout обеспечивает более высокий уровень абстракции для событий. Это позволяет Knockout автоматически отслеживать зависимости между ViewModel свойствами. При необходимости мы можем подписаться на Observable свойства.





В то время как Knockout предоставляет четко определенные конструкции для View и ViewModel, в нем ничего не говорится о том, какой должна быть модель приложения. Это делает Knockout остро сфокусированным и универсальным, поскольку его можно использовать в качестве библиотеки вместо фреймворка. По своему опыту я видел, что он использовался для создания мини-приложений SPA, где веб-приложение состоит из нескольких страниц, и каждая страница представляет собой небольшое приложение Knockout. Этот ответ на StackOverflow четко определяет область применения MVVM в Knockout.
Часто предполагается, что с моделью у Knockout находится на стороне сервера. ViewModel просто запрашивает модель на стороне сервера, используя Ajax или его эквивалент.

Knockout заменяет jQuery и шаблонные решения типа Handlebars для обновлений DOM, но по-прежнему использует jQuery для анимации, Ajax и других утилит. В сочетании с Backbone он может служить полной реализацией шаблона MVVM. Теоретически это могло бы произойти, но до того, как это могло произойти, эти концепции уже развивались в инструментах следующего поколения.
Здесь начинается революционное движение по Angular 1, Aurelia, Ember.js и т.д.

Благодаря тесной связи с миром .NET, Knockout широко использовался в приложении ASP.NET MVC. Как и Backbone, это было еще одно эволюционное решение немного иной проблемы. И опять же, предположение о том, что код на стороне клиента является просто расширением для шаблона MVC на стороне сервера, не изменилось. Серверная сторона была все еще доминирующей архитектурой.

И Knockout, и Backbone являются библиотеками JavaScript. Так или иначе, Backbone рассматривался как фреймворк. Почему? Нет определенного ответа, но это, вероятно, было в перспективе. Backbone всегда обрабатывался с абстракцией более высокого уровня из-за его акцента на структуру кода. Более того, Backbone никогда не предназначался для замены вездесущего jQuery (даже в 2019 году 70% топ-10000000 веб-сайтов используют jQuery), тогда как Knockout перекрывался с ядром jQuery, то есть, DOM-манипуляциями, что, естественно, усложняло Knockout. Таким образом, адаптация Knockout была ограничена по сравнению с Backbone. Но это все еще была одна из первых реализаций декларативных привязок данных для интерфейсного сообщества, и она заслуживает отдельного упоминания.

Angular 1 — дай мне контроль


Что jQuery сделал с DOM, Angular 1 сделал с экосистемой фронт-энда в целом. Это навсегда изменило представление о создании масштабных клиентских приложений. В качестве основы он представил множество концепций — модульная система, внедрение зависимостей, инверсия управления, более более простое связывание данных и т.д.

Было тогда и остается сейчас трудной задачей выбор правильных библиотек JavaScript и создание идеального технологического стека для фронтэнда. Angular 1 просто предоставил более простую, но сплоченную альтернативу. То же самое можно сказать и о Ember.js и других подобных системах, но применимость Angular 1 была на ином качественно уровне, чем у его альтернатив того времени.
Angular 1 — это революционное решение в том смысле, что оно явно ознаменовало отход от идеи простого расширения MVC на стороне сервера с клиентским кодом, разбросанным по страницам. Angular 1 сделала SPA первоклассным, практически де-факто решением для создания взаимодействия с пользователем следующего поколения.

Фреймворк или библиотека?


Предыдущие решения были больше библиотеками, чем фреймворком. Angular 1, без сомнения, является четко определенной структурой. Необходимый отличительный фактор между платформой и библиотекой — IOC — Inversion of Control (инверсия управления). Далее для квалификации Angular 1 в качестве фреймворка, можно отметить:

  1. Четко определенные MVVM: Angular 1 имеет четкие объекты Model, View и ViewModel.
  2. Внедрение зависимостей (DI): Angular 1 имеет первоклассную поддержку DI, которая обеспечивает управляемый жизненный цикл для объектов Model. В Angular 1 Модель приложения реализована с использованием Сервиса (Service). Сервис по умолчанию является одноэлементной сущностью, что часто желательно для объектов модели.
  3. Привязка данных (data binding) и обнаружение изменений: привязки данных являются декларативными, а обнаружение изменений происходит автоматически. Данные связывают с необходимым компонентом, чтобы квалифицировать его как MVVM. Привязки были двунаправленными. Дальнейшее обнаружение изменений было почти автоматическим (Angular 1 был действительно волшебным). Это уменьшило много шаблонного кода для разработчиков. Использование событий и общий механизм подписки были сокращены. Это очень распространено в системах на основе MVC. События также снижают читабельность кода, поскольку поток данных для определенного рабочего процесса распространяется по всему коду.
  4. Модульная система: Angular 1 представляет модульную систему, специфичную для фреймфорка. Модули являются основой организации кода практически для каждого языка. У JavaScript не было модульной системы до 2015 года (браузеры не поддерживали его до 2018 года). Angular значительно опередил свое время с точки зрения организации.

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

  1. Коллизия пространства имен: хотя DI был великолепен, но он был реализован с использованием шаблона Service Locator, который использовал глобальное пространство имен. Это сделало почти обязательным префикс услуг.
  2. Двунаправленные привязки данных. Возможно, в то время это была отличная идея, но с течением времени стало ясно, что она не очень хорошо масштабируется. Появление React сделало двустороннее связывание данных необязательным. Двунаправленные привязки могут создать много спагетти-кода, если не соблюдать осторожность.
  3. Использование запутанной терминологии. Некоторые из терминологий, используемой Angular 1, явно сбивают с толку. Например, Angular 1 имеет $scope, который действует как ViewModel, но также имеет Controller, который увеличивает объект $scope. Вероятно, правильное имя могло быть VMFactory или эквивалентным. Кроме того, в Angular 1 есть три типа способов создания Сервиса, один из которых называется Сервис.

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



За прошедшие годы были небольшие релизы Angular 1, в которых исправлено множество небольших сложностей его использования. Наиболее значительным из них было добавление Component Model, в которой сошлась большая часть направлений развития фронт-энда.

Angular 1 долго жил и продолжает жить среди фронт-энд сообщества. Со всеми своими плюсами и минусами он помог сообществу понять важность архитектуры программного обеспечения и обеспечил основу для написания масштабируемых приложений. Его минусы и недостатки стали основой решения проблем для будущих архитектур.
Tags:фронт-эндархитектура програмной системыфреймворки
Hubs: Website development Programming System Analysis and Design Designing and refactoring Development Management
+8
8.2k 115
Comments 1
Popular right now