Шпаргалка по MV-паттернам для проектирования веб-приложений

в 0:59, , рубрики: amd, hmvc, mvc, mvp, mvvm, patterns, web, Веб-разработка, паттерны, шпаргалка, метки: , , , , , , , ,

mv-patterns
В Интернет можно найти множество различающихся реализаций и схем, уже набившего оскомину, паттерна MVC. В разных книгах я также встречал разные схемы. Это порождает некоторую путаницу и комментарии к моей предыдущей статье: "Реализация MVC паттерна на примере создания сайта-визитки на PHP" тому подтверждение. В поисках истины, я попытался расставить все по местам… перечитал некоторую литературу и статьи по паттернам проектирования и написал дополнение к упомянутой статье. Но решил запостить это дополнение, как отдельный топик в надежде на фидбэк. Под катом вы найдете несколько часто встречающихся схем MVC и MVP с описанием жизненного цикла приложения, а также описание менее популярных паттернов HMVC, MVVM и схемы AMD (Asynchronous Module Definition), которая актуальна для клиент-сайд приложений. Разумеется, некоторые из перечисленных паттернов применимы не только к веб-приложениям, но в статье они рассматриваются именно в этом контексте.

MVC

Шаблон MVC (Модель-Вид-Контроллер или Модель-Состояние-Поведение) описывает простой способ построения структуры приложения, целью которого является отделение бизнес-логики от пользовательского интерфейса. В результате, приложение легче масштабируется, тестируется, сопровождается и конечно же реализуется.

Некоторые умозаключения об MVC
Модель — содержит бизнес-логику приложения и включает методы выборки (это могут быть методы ORM), обработки (например, правила валидации) и предоставления конкретных данных, что зачастую делает ее очень толстой, что вполне нормально.
Модель не должна напрямую взаимодействовать с пользователем. Все переменные, относящиеся к запросу пользователя должны обрабатываться в контроллере.
Модель не должна генерировать HTML или другой код отображения, который может изменяться в зависимости от нужд пользователя. Такой код должен обрабатываться в видах.
Одна и та же модель, например: модель аутентификации пользователей может использоваться как в пользовательской, так и в административной части приложения. В таком случае можно вынести общий код в отдельный класс и наследоваться от него, определяя в наследниках специфичные для подприложений методы.
Вид — используется для задания внешнего отображения данных, полученных из контроллера и модели.
Виды cодержат HTML-разметку и небольшие вставки PHP-кода для обхода, форматирования и отображения данных.
Не должны напрямую обращаться к базе данных. Этим должны заниматься модели.
Не должны работать с данными, полученными из запроса пользователя. Эту задачу должен выполнять контроллер.
Может напрямую обращаться к свойствам и методам контроллера или моделей, для получения готовых к выводу данных.
Виды обычно разделяют на общий шаблон, содержащий разметку, общую для всех страниц (например, шапку и подвал) и части шаблона, которые используют для отображения данных выводимых из модели или отображения форм ввода данных.
Контроллер — связующее звено, соединяющее модели, виды и другие компоненты в рабочее приложение. Контроллер отвечает за обработку запросов пользователя. Контроллер не должен содержать SQL-запросов. Их лучше держать в моделях. Контроллер не должен содержать HTML и другой разметки. Её стоит выносить в виды.
В хорошо спроектированном MVC-приложении контроллеры обычно очень тонкие и содержат только несколько десятков строк кода. Чего, не скажешь о Stupid Fat Controllers (SFC) в CMS Joomla. Логика контроллера довольно типична и большая ее часть выносится в базовые классы.
Модели, наоборот, очень толстые и содержат большую часть кода, связанную с обработкой данных, т.к. структура данных и бизнес-логика, содержащаяся в них, обычно довольно специфична для конкретного приложения.

По запросу «MVC» в интернете можно найти множество различных схем, в которых очень легко запутаться. Попробуем расставить все по местам. Рассмотрим схему 1:
mvc1

1. При заходе пользователя на веб-ресурс, скрипт инициализации создает экземпляр приложения и запускает его на выполнение.
2. Выполняется действие index фронт-контроллера, которое генерирует представление главной страницы.
3. Представление отображается пользователю.

Первые три шага — это простая цепочка, без использования модели. Далее идет последовательность, где задействована модель:

4. После того, как приложение получит запрос от пользователя, создается экземпляр запрошенного контроллера и вызывается указанное действие.
5. В этом действии вызываются методы модели, изменяющие ее.
6. Генерируется представление (или же представление оповещается об обновлении модели).
7. Представление запрашивает данные для отображения.
8. Модель возвращает запрошенные данные.
9. Представление отображает результаты пользователю.

Встречается и такая схема — схема 2:
mvc2

1. Контроллера получает следующий запрос от пользователя.
2. Далее в зависимости от внутренней логики:
      2a. Формируется представление какой-то страницы.
      2b. Либо, вызываются методы модели.
3. Модель уведомляет представление об изменениях.
4. Представление обновляется (если в цепочке была задействована модель) и отображается пользователю.

На некоторых схемах можно увидеть стрелку от представления к контроллеру. Рассмотрим этот случай — схема 3:
view-controller

  1. Приложение получает еще один запрос от пользователя: создает экземпляр запрашиваемого контроллера и вызывает указанное действие.
  2. В действии генерируется представление содержащее некоторую форму ввода данных.
  3. Представление с формой отображается пользователю.
  4. После того как пользователь заполнит форму и нажмет на кнопку «Submit» вызывается тот же контроллер, который проверяет и обрабатывает полученные из формы данные и формирует другое представление или же обновляет текущее.

Шаг 4, по сути, эквивалентен еще одному шагу 1, инициализирующему новый цикл… Поэтому на всех схемах можно предполагать неявную связь в направлении от вида к контроллеру.

MVP

А теперь посмотрим на схему паттерна MVP (Model-View-Presenter) — схема 4:
mvp

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

Помимо MVP существуют и другие, производные от MVC, паттерны, например MVVM и HMVC.

HMVC

Реализация паттерна HMVC (Hierarchical Model View Controller — Иерарархические Модель-Контроллер-Вид) используется в веб-фреймворке Kohana. Рассмотрим в чем же ключевое отличие от MVC.

hmvc
Приложение представляет иерархию независимых друг от друга MVC триад. При этом, каждая триада может напрямую обратиться к контроллеру другой триады. Такой подход позволяет решить некоторые проблемы масштабируемости приложений, имеющих классическую MVC-архитектуру, уменьшить зависимость между различными частями приложения, облегчить дальнейшую поддержку и повторное использование кода. Более подробно о преимуществах данного подхода можете прочитать в статье "Масштабирование веб-приложений с помощью HMVC".

MVVM

MVC прижился в веб-приложениях во многом потому, что он отлично справляется со сценарием запрос-ответ.
Основная черта такого сценария — короткое время жизни View. Приходит запрос, который передается на соответствующий контроллер, он инициирует какие-то процессы в модели, а затем создается View, который просто заполняется данными из модели и передается клиенту в браузер. Все в один проход.

Когда появился Ajax и богатые клиент-сайд приложения (RIA), оказалось, что MVC не очень хорошо подходит для работы с областями страницы или приложения, что привело к несколько иным моделям: MVP (Model View Presenter) и затем к MVVM (Model View ViewModel). Если c паттернами MVC и MVP большинство более-менее знакомо, то о последнем слышали очень немногие.

Первоначально MVVM был описан для Silverlight и имеет преимущества для сложных интерфейсов с определенной логикой, которая отличается от логики приложения. MVVM отличается более «тесной» связью между Моделью и Представлением посредством слоя Представление-Модель, который синхронизирует данные как при событии на стороне Модели, так и на стороне Представления. Рассмотрим его схему:
mvvm
Вы определяете видимую область экрана и задаете самые общие данные о нем, не зная, какое содержание будет показываться во время выполнения. Для HTML схема MVVM особо удачна благодаря DOM, который, как известно, вполне может вмещать данные. Поэтому MVVM была успешна реализована во фреймворке KnockOut.JS. Изначально все просто. Есть Модель данных, предоставленная сервером. Есть Представление в виде DOM, в виде разметки. А есть Представление-Модель (Вид Модели, если хотите), которая описывает изменение Представления, связывает Модель и Представление, причем синхронизует эту связь.

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

Не нужно пытаться ответить на вопрос, какой из упомянутых паттернов лучше и т.п… нужно вынести только главную идею — «разделяй и властвуй», потому как очень важно чтобы слои были максимально независимыми и легко заменяемыми, как это сделано в схеме AMD.

AMD

AMD (Asynchronous Module Definition) — спецификация, описывающая модульные приложения, в которых элементы приложения оформлены блоками интерфейса и реализованы каждый в своем модуле. Эти модули друг с другом не обмениваются. Они знают только о песочнице, в которой происходит их выполнение. Песочница, в свою очередь, имеет дело с ядром приложения, которое запускает процесс и следит за последовательностью действий. Само ядро при этом не последнее в цепочке (вызывов): ниже есть стандартные библиотеки по технической работе с окружением, вроде jQuery, вместе с плагинами. Схема AMD представлена на рисунке:

amd
Логика и UI здесь реализуется в модулях. В MVC же логика зашита в Модели, ее можно также помещать в Контроллер, но это справедливо подвергается критике (Stupid Fat Controller). В MVVM, напротив, логика помещается в «промежуточный» слой ViewModel.

Преимущество такой архитектуры заключается в том, что можно основываться на любой из стандартных библиотек типа jQuery и менять их без проблем, внося минимальные изменения в уровень Application Core. Легко добавлять модули и «выключать» их, что прекрасно сказывается на масштабируемости приложения. Причем, модули могут быть реализованы на схемах MVC в частности.

Чуть более подробнее о AMD, MVVM, MVP и MVC применительно к клиент-сайд приложениям вы можете прочитать здесь:

Подборка полезных ссылок

Полезные ссылки

Основная подборка:

IoC & DI

АОП

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

Автор: vitalyswipe

* - обязательные к заполнению поля


https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js