В сети есть много сравнений между двумя самыми популярными интерфейсными фреймворками — React и Angular. Однако все эти сравнения часто фокусируются на их конкретных особенностях, а не на сравнении их архитектур; Следовательно, они не дают четкого представления о том, каковы последствия использования одного над другим. Я чувствую, что необходимо прояснить механику между React и Angular на более высоком уровне, чтобы разработчик, пытающийся принять решение, имел более фундаментальное понимание возможных вариантов.

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

Перво-наперво — фреймворк против библиотеки

Вы, наверное, уже знаете, что React — это библиотека, а Angular — это фреймворк (я объясню это в следующем абзаце). Поэтому, чтобы сделать сравнение справедливым и структурно правильным, я в основном сосредоточусь на их общих чертах, и я построю архитектурное видение и заявления поверх этих особенностей.

React — это библиотека, потому что она обрабатывает только небольшую часть того, что делает полноценный фреймворк (например, Angular). например, Angular поставляется со встроенным механизмом внедрения зависимостей, в то время как в React вам нужно импортировать дополнительные библиотеки, если вы хотите иметь аналогичную возможность. Напротив, Angular также диктует некоторые архитектурные решения, в то время как в React у вас больше свободы. Мы поговорим об этом подробнее, когда я опишу архитектуру этих фреймворков, так что потерпите меня.

Реагировать на архитектуру

React — это попытка архитектуры MVC. Я говорю попытка, потому что это нарушает пару основных принципов структуры MVC, но об этом позже. Давайте сначала посмотрим на визуальное представление архитектуры React. Обратите внимание, что на предоставленном рисунке направление стрелок представляет зависимость/осведомленность, а не поток данных.

В React все является компонентом, и внутри компонента вы можете выделить три классических члена шаблона MVC — Модель, Представление и Контроллер. Поэтому я могу назвать архитектуру React «модульным MVC», потому что она разделяет структуру MVC на модули внутри компонентов. Другими словами, каждый компонент является границей изолированной реализации MVC. Давайте углубимся в компонентную архитектуру.

  • Действия (выполняют роль контроллеров в MVC). Это функции javascript, которые реагируют на взаимодействия, происходящие в основном из JSX (представление). В конце своего выполнения действие обычно отправляет (вызывая setState()) состояние (модель), к которому JSX может привязаться позже в жизненном цикле рендеринга. Все соответствует обязанностям контроллера из шаблона MVC, за исключением того факта, что иногда вы слишком много знаете о представлении. например, для обработки всех данных формы в действии (например, после отправки формы) вам потребуется получить элемент HTML-формы и получить значения из полей в нем. В идеальной реализации MVC вы должны получать простой объект JSON, содержащий значения из всех полей формы. Еще один печальный пример — необходимость получать событие в качестве аргумента действия, когда вам нужно выполнять пользовательские действия, такие как предотвращение поведения распространения по умолчанию. Такие мелочи ломают паттерн MVC, а потому React становится просто попыткой для него.
  • Состояние (выполняет роль модели в MVC) отправляется действием (контроллером), а JSX (представление) привязывается к нему. Эта часть хорошо вписывается в шаблон MVC.
  • JSX (выполняет роль представления в MVC) привязывается к состоянию (модели), полученному от действия (контроллера). Кроме того, он может вызывать контроллер для каждого взаимодействия с пользователем, явно вызывая его. Поэтому в React View знает о контроллере, который снова следует шаблону MVC. Если бы только контроллер мог меньше знать о представлении — это позволило бы избежать циклических зависимостей в архитектуре, но, вероятно, в другой версии или в другой жизни.
  • Компонент, хотя и помогает модульизовать приложения React в целом, также имеет архитектурный запах: он заставляет вас объединять действия, состояние и JSX (все три элемента шаблона MVC). Более того, эти три элемента всегда тесно связаны друг с другом, что делает невозможным их разработку или модульное тестирование по отдельности (например, в традиционном MVC мы хотели бы отдельно тестировать контроллеры). Кстати, говоря о юнит-тестах, официальный сайт React даже не объясняет, как юнит-тестировать компонент — может быть, потому, что это не так просто сделать? Так или иначе, компонент поставляется с описанным архитектурным антипаттерном, и, к сожалению, простого выхода из него нет.

Анализируя его с более высокого уровня, React стоит довольно близко к шаблону MVC и создает впечатление жизненного цикла запроса/ответа с каждым взаимодействием, происходящим из представления. Каждый запрос проходит действие, приводит к новому состоянию и, наконец, завершается привязкой представления к полученному состоянию; Но естественно ли ожидать такого поведения во внешних приложениях? Лично мне это кажется немного неуклюжим, потому что я считаю экран состоянием, а не потоком данных. React пытается немного изменить это видение и делает его похожим на веб-сервер. Действительно, на обычном веб-сервере (например, с ASP.NET MVC) получение запросов от представления, отправка модели и привязка представления к ней во время рендеринга выглядят гораздо более естественными. Наоборот, в клиентских приложениях видеть конвейер, похожий на запрос/ответ, в лучшем случае странно, если не анти-шаблон. Кроме того, популярный фреймворк Redux, который часто используется в сочетании с React, выводит концепцию потока на новый уровень, что делает React еще менее похожим на интерфейсный фреймворк. Может быть, поэтому кривая обучения React (и Redux) такая крутая и, что важно, неудобная для большинства инженеров.

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

Угловая архитектура

Angular — это попытка архитектуры MVVM. Часто ошибочно думают, что Angular реализует паттерн MVC, потому что в версиях 1.x в Angular раньше был контроллер. Тогда он реализовал что-то более похожее на MVC, что уже не так, начиная с Angular 2 и более поздних версий.

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

В Angular все начинается с компонента. В наборе инструментов есть гораздо больше (например, службы, фильтры, маршрутизация, внедрение зависимостей и т. д.), но это выходит за рамки данного обсуждения. Вот разбивка обязанностей различных элементов, когда дело доходит до реализации шаблона MVVM:

  • Компонент (играет роль ViewModel в MVVM) определяет и предоставляет свойства (Model), к которым может быть привязан шаблон (View). Он также определяет функции, которые шаблон может вызывать при взаимодействии с пользователем. В конце выполнения эти функции изменяют значения свойств и тем самым сообщают шаблону о необходимости повторного рендеринга. Это поведение является стандартным с точки зрения шаблона MVVM. Нарушение становится очевидным, потому что компонент — через декоратор — упоминает имя шаблона. Это означает, что ViewModel тесно связана с одним конкретным представлением, и поэтому представление нельзя заменить. В типичном MVVM одна ViewModel может использоваться с несколькими представлениями, если все эти представления могут принимать одну и ту же ViewModel. Говоря об идеальных решениях, Angular должен был возложить ответственность за привязку ViewModel к View где-то еще, а не к самой ViewModel (хотя это всего лишь декоратор, он все же статически применяется к классу Component).
  • Свойства (выполняют роль модели в MVVM) определяются в компоненте и становятся доступными для шаблона (представления). Когда какое-либо из свойств изменяет свое значение, шаблон автоматически обнаруживает это и перерисовывает себя. Все хорошо в рамках шаблона MVVM.
  • Шаблон (выполняет роль представления в MVVM) привязывается к свойствам компонента (модель, отправленная ViewModel), и поэтому он знает об экземпляре компонента. Эта осведомленность является здоровой с точки зрения шаблона MVVM, в то время как проблема заключается в том, что компонент знает о шаблоне.

Архитектура приложений более высокого уровня с Angular выглядит более естественно для интерфейсных приложений, поскольку она фокусируется на изменении состояния (т. е. экран — это состояние — естественно), а не заставляет вас думать с точки зрения потоков данных. Поэтому я предпочитаю интерфейсные приложения всегда отдавать предпочтение Angular. Хотелось бы, чтобы в нем не было той маленькой архитектурной неточности (которая, надо сказать, незначительна по сравнению с тем, что есть у нас в React), но будем надеяться, что когда-нибудь разработчики Angular это заметят и исправят.

* * *

Вот и все с архитектурным сравнением.

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

Прочитайте оригинальную историю на http://www.tutisani.com/software-architecture/react-vs-angular-architecture-comparison.html