Pull to refresh

А MVC ли это?

Reading time6 min
Views25K
Добрый день!

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

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

В чем же разница? Чтобы это понять, давайте сформулируем задачи MVC:

1. Экранировать модель – то есть, сделать так, чтобы модель не “знала” ничего, о технической реализации приложения, о пользовательском интерфейсе, сетевых протоколах, работе с базой и даже архитектуре системы. Модель должна отображать предметную область и быть вне технологий.

2. Отделить слой представления – значит, иметь возможность создать несколько представлений для одной и той же модели, которые могут существовать параллельно, например, для разных пользовательских устройств, браузеров, мобильных платформ и оконных приложений. Еще это дает возможность распараллелить работу, вводя разделение труда с GUI программистами и даже дизайнерами, которые могут делать шаблоны отображения, но в код лезть не должны.

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

Первое, в чем мнения расходятся, это где должна располагаться логика приложения. Одни помещают всю логику в модель и делают из контроллера тонкую прослойку, другие же, наоборот – наращивают функциональность контроллера, оставляя в модели только данные. В этом случае контроллер наполняется классами, имена которых говорят о их принадлежности к предметной области с приставками “Manager”, “Dispatcher”, “Logic”, “Controller” и т.д. По сути, есть два варианта: сделать контроллер ядром системы или сделать его прокси-прослойкой. Но есть и класс задач (графические приложения с развитой визуализацией и игры), когда представление настолько тесно связано с моделью, что модель содержит непосредственно координаты, поведение и особенности рендеринга, а контроллер испаряется. Это называется MVVM (Model-View-ViewModel), а как оказалось в последствии, это удобно и для широкого круга прикладных задач, связанных с вводом данных, управлением оборудованием, и т.д.

Второе разногласие в том, кто должен работать с базой данных. Кто-то помещает запросы к данным в модель и говорит, что модель должна сама знать как ей “подыматься” и сохраняться, другие – помещают обращения к СУБД в контроллер, третьи – выделяют еще одну составляющую системы специально для работы с базой, называя ее “Хранилище”, “Репозиторий” или даже “ORM” (то есть объектно-реляционное отображение). По запросу контроллера, ORM порождает объект модели и, по его же запросу, ORM может сохранить, модифицировать или синхронизировать объект с базой данных.

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

Наконец, последний пункт разночтений проявляется в смешении архитектурного подхода MVC с трехзвенной архитектурой: СУБД-СерверПриложений-Клиент, которая надолго закрепилась в умах, особенно у старшего поколения разработчиков. На самом деле MVC и трехзвенка, это не одно и то же, но они могут существовать параллельно. Например, в веб-приложениях, все три звена могут располагаться на сервере и только лишь рендеринг готовой страницы будет происходить в веб-браузере. Другой вариант, и он более современный, когда в браузере запускается клиентское JavaScript приложение, полностью или частично реализующие слой представления. Для этих целей появились даже JavaScript-шаблонизаторы. Но полностью перенести представление в браузер на сторону клиента нам не удастся, разве что, при полном отказе от HTML и сведении страницы к одному тегу подключения JavaScript. Это уже экстремизм, я даже не говорю про SEO, мобильные браузеры и отключенный JavaScript.

Таким образом, все представляют себе MVC по-разному, и реализуют под этой вывеской совершенно разные архитектуры, условно обозначим их: Mvc, MVc, mvC, mVC и т.д. Все это происходит потому, что сама задача таит в себе противоречие. Чтобы сделать модель и представление независимыми, совсем не нужно разделять данные, логику и отображение. Это совсем разные вещи. В каждом отделенном звене все равно будут находиться данные, логика и отображение, например: логика данных в базе и хранимые процедуры; логика отображения в пользовательском интерфейсе; бизнес-логика или логика модели; данные содержатся и в пользовательском интерфейсе и в контроллере; интерфейс – это не только интерфейс, но и интерфейс пользователя между моделью и контроллером.

Получается, отделить модель от контроллера и вью невозможно? Возможно, но для этого нужно отказаться от разделения данных, логики и представления. Как это ни парадоксально, но MVC работает только в случае, если Model, View и Controller реализованы на разных уровнях абстракции. Model – должен содержать как данные, так и логику предметной области и в грамотном объектно-ориентированном программировании должен совпадать с понятием “объект предметной области” или “отображение объекта реального мира”. Model – это, прежде всего, моделирование, а это включает в себя информационную модель, логическую модель и даже модель визуализации, для некоторых задач. Объект предметной области не должен знать, как он хранится в базе данных, передается между программными модулями и по сети. Он запускается в приложении, как в виртуальной машине и, в идеальном случае, должен быть переносим даже между системами. Как раз по этому, я настаиваю на написании логики модели на скриптовых, интерпретируемых языках (личное предпочтение – JavaScript). Это не исключает скорости работы модели, потому, что скрипт может компилироваться в код нативного языка или сразу в байт-код и кэшироваться на продолжительные отрезки времени. Что же касается пользовательского интерфейса, то часть модели всегда будет содержаться и в нем, а если она будет на JavaScript, то мы сможем запускать такие вещи, как бизнес-логику, валидацию и матмодель, частично на сервера, а частично на клиенте. Некоторые части только на клиенте или только на сервере, а некоторые – и там и там, не переписывая их по много раз. Что же тогда View? А View – это рендерер (для веб-приложений – браузер), плюс библиотека визуальных компонентов (уж простите старого дэлфиста), плюс шаблоны и стили.

Что же остаетсается контроллеру? Controller – это та виртуальная машина, в которой запускается объект предметной области. Контроллер не должен переписываться для каждого приложения, это Application Framework (прикладная платформа). Причем, часть контроллера работает на стороне сервера, а часть в браузере. Контроллер забирает данные у модели на стороне сервера и передает по сети. С другой стороны, в браузере, контроллер же ловит данные и передает их для визуализации, а так же, разворачивает часть модели, которая нужна на клиенте, чтобы не гонять данные по сети при каждом действии пользователя. Откуда я это взял? А вспомните семь уровней модели ISO/OSI, кроме вертикального взаимодействия между слоями, в ней есть еще и горизонтальное (логическое) взаимодействия – протоколы. На разных сторонах соединения транспорт логически взаимодействует с транспортом, а модель должна взаимодействовать с моделью, а фреймворк – с фреймворком (см. рис.). При этом, они имеют разные уровни абстракции в вертикальном взаимодействии, а в горизонтальном, находятся на одном уровне.



Таким образом, у нас появилась модель Storage-Model-Application-Renderer-Template-Model, сама собой, хорошо сокращаемая в SmartModel, что отражает смысл подхода. Но это уже из области метапрограммирования, и подробнее об этом я расскажу в отдельной статье.

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

Спасибо за внимание.
Tags:
Hubs:
+67
Comments47

Articles

Change theme settings