framework.zend.com
Stable релиз 2.0 / 1.12

Модель и паттерн MVC (Model-View-Controller)

Неделю назад известный в кругах Zend Framework сообщества девелопер Pádraic Brady написал замечательную статью о понятии Модели в паттерне MVC. С полным текстом вы можете ознакомиться по ссылке.

Что же поведал нам Pádraic. Далее, мой очень вольный и краткий перевод.

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

1.    Модель отвечает за сохранение состояния приложения между HTTP запросами

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

2.    Модель включает все правила, ограничения и поведения, используемые для управления и работы с информацией

На практике это означает  что любой функционал тем или иным образом оперирующий с состоянием вашего приложения, то есть вашими данными это модель. Такая модель называется толстой (fat model)

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

Хорошее MVC приложение должно исходить из вышеизложенных принципов. На практике же произошло по другому, многие разработчики стали понимать модель как «общий» термин обозначающий работу с базой данных.

И что же получилось в итоге, разработчики придумали новую концепцию. ТТУК - Толстые тупые уродливые контроллеры (Fat Stupid Ugly Controllers, так назвал ее Pádraic :)). Среднестатистический ТТУК получал данные из БД (используя уровень абстракции базы данных, делая вид, что это модель) или манипулировал, валидировал, записывал, а также передавал данные в Вид. Такой подход стал очень популярен, потому что использование таких контроллеров похоже на классическую практику использования отдельного php файла для каждой страницы приложения.

Заметили что-то странное? Контроллеры стали выполнять практически всю работу с данными, ведь если эту работу не выполняет Модель – она должна сместиться в Контроллер. Итак, мы получили Контроллер - Модель мутант. А это в корне не правильно, такой толстый контроллер практически не передается переносу и тестированию (TDD). Ведь мы не можем создать экземпляр класса контроллера вне фреймворка, контроллер жестко привязан к определенному фреймворку. Модель же должна исповедовать принцип «подключил и работает». Например, вы можете взять модель, написанную для Zend Framework и перенести ее на Symfony, и это не будет очень сложной задачей. А тестирование! Ведь нам придется прогнать весь цикл работы фреймворка что бы оттестировать только один контроллер.

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

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

Мое мнение, что Вид вообще должен по возможности избегать контакта с Контроллером и получать данные напрямую из модели. В Zend Framework это можно делать с помощью помощников вида. Самый лучший контроллер это пустой контроллер!

Конец перевода. Далее от своего лица.

Подведу итог, Pádraic настойчиво убеждает минимизировать функциональность контроллеров, перенеся ее в модели. сделав контроллеры худыми, а модели толстыми. Более того в комментариях к статье Matthew Weier O'Phinney поддержал автора и добавил что сам он был против введения  в Zend Framework такого помощника вида как action. На первый взгляд этот помощник является очень удобным, например, так можно построить меню, или вывести блок последние  новости. Но по сути своей этот помощник раздувает наши контроллеры, эти лишние обращения к действиям не обоснованны, более того использование помощника сильно сказывается на производительности. При вызове action() клонируется объекты запроса и ответа, вызывается контроллер и действие итд.

Помощники вида, что обращаются напрямую к модели, дают возможность избавиться от использования action(). Пример такого помощника вы можете увидеть здесь

И напоследок напутствие от Pádraic:

«Думайте товарищи, желание думать должно быть основным, спрашивайте везде, анализируйте, протестуйте, когда что-то вам кажется не разумным. Если вы все принимаете на чистую веру, значит вы заслуживаете того что получаете.»

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

А что вы думаете о модели?

Лучший способ следить за обновлениями сайта это подписаться на RSS
Если информация была полезной для вас, вы можете поддержать сайт.
Комментарии:
mich 11.12.2008 23:23 #
Как правило, формы и правила валидации меняются от действия к действию, поэтому я предпочитаю инициализировать форму и добавлять нужные правила в контроллере в конкретном действии, а не в моделе, т.к. не вижу никакого преимущества делать это в модели. Пишу это в надежде, что вы мне их укажете :)
Ответить
san 11.12.2008 23:48 #
Я различные случаи использования форм оформляю в виде отдельных классов, к примеру есть у меня сущность статья, ее можно создавать, редактировать и переводить. У меня есть абстрактный класс My_Form_Article_Abstract который содержит общие для всех этих действий настройки. Далее я определяю My_Form_Article_Create, My_Form_Article_Edit и My_Form_Article_Translate как наследники этого абстрактного класса, каждую из этих форм я настраиваю нужным образом.

Это дает мне возможность избежать дублирования, кроме этого эти формы я могу легко использовать в любом действии. В контроллере же у меня только инициализация формы, вызов метода isValid и собственно передача объекта формы в вид.
Ответить
Romiz 19.05.2009 20:02 #
san дело говорит, у меня тоже так реализовано.
Очень удобно!
Ответить
Ckopoxod 14.12.2008 11:17 #
многие разработчики стали понимать модель как «общий» термин обозначающий работу с базой данных.

Похоже, это просто большой камень в огород CakePHP :)
Ответить
Silverstorm 20.12.2008 16:46 #
Спасибо за интересный материал, сам разрабатываю приложения в таком же ключе, но очень часто вижу как новички следуют как раз ТТУК, побольше таких статей.
Ответить
col 19.02.2011 02:55 #
ТТУК ..... эх...
- это как первый бодун после первой серьёзной пьянки
[херово конечно, но было прикольно]

- это как твой первый автомобиль [развалюха, но всёж лучше чем пешком]

=)
да сам когда-то писал ТТУК'и

PS
а за наведение резкости на понятие Модель спс.
Ответить
atukai 23.12.2008 13:49 #
А как же принцип MVC, что вью не должен напрямую обращаться к модели, а использовать для этого контроллер. и на данный момент я не представляю себе ZF без action helpera
Ответить
san 23.12.2008 17:53 #
Если взять стандартную MVC то везде существует возможность обращаться к модели с помощью get запросов. Подтверждение можно увидеть в русской или английской вики или например в схеме MVC от GoF.

А насчет экшн хелперов, так ведь вышеописанный подход их не отменяет.
Ответить
Ruslan 03.06.2009 13:15 #
в рамках WEB проектирования MVC get и POST можно считать дефолтовыми контроллерами, так что паттерн не нарушается
Ответить
atukai 29.07.2009 02:04 #
Уже представляю ))
Ответить
roller 18.01.2009 02:47 #
про хелпер action
Это все потому, что привязали Класс/функцияКласса/параметры напрямую к урлам типа так элегантнее и вообще проще. Ну не может мой класс (контроллер) АвторизацияПользователя в своем экшене index знать про все классы которые надо инициализировать чтобы по кусочкам собрать всю страницу из меню, блоков и тд, не его это работа.
Я вижу только один выход - наследовать все контроллеры от общего контроллера-мэппера который будет всегда запускать перед частным контроллером и у которого будет полная карта какие куски (классы) надо иницциализировать для конкретного урла чтобы собрать страницу. Возможно, каждый контроллер предварительно регестрируется самостоятель и указывает какие урлы он поддерживает и какие блоки на странице он (или пользователь) желает видеть активными.

вобщем все это очень близко крутится вокруг архитектуры чего-то типа Drupal
Ответить
White_Owl 21.02.2009 22:53 #
Например я помещаю формы в модели, потом создаю хелпер который вызывается во вьюве для вывода этой формы.
Я вполне согласен в котнтроллере по необходимости должны вызываться модели которой будут отдаваться данные для обработки. А дальше после обработки, если метод что-то возвращает, передаваться во вьюв в виде переменных. Где они будт просто выводиться или же обрабатываться с помощью хелперов вьюва, которые напрямую будут общаться с моделью.

Уверен что это далеко не идеальный вариант :) Но пока что я именно так себе представляю, работу приложения на базе паттерна MVC.
Ответить
vs 04.03.2009 11:36 #
По моему необходимо контролер разделить еще на два типа контроллер - логика и контроллер обработка данных а модель должна быть чиста чтобы общение с базой или другим типом хранения данных было прозрачным
Ответить
lcf 04.03.2009 11:54 #
Почему "ещё"? Как будто какие-то шаги уже сделаны в этом направлении. Статья же напротив, о том что контроллер не должен ни на что делится и должен служить только лишь посредником - все остальное в моделях. И модели (если это классический функционал, например работа с табличными данными из той или иной субд) уже да,- лучше разделять на логику обработки и логику выполнения запросов к бд и писать адаптер для каждой субд, которая может потребоваться.
Ответить
IgorN 16.05.2009 20:29 #
Статья интересная но немного мне не понятно, можно привести пример "тупого контроллера". В принципе в модель я бы добавил еще валидацию данных и праверку прав пихать туда не стал бы. Но так как в зф есть формы, то валидация в форме. Немного не понятно зачем Саша делает 4 класса для работы с сущностью статьи. Как по мне именно это является избыточностью. У меня одна форма отвечает за создание и редактирование данных. Может у меня просто задачи еще такой не было где столько форм надо для одной сущности, хотелось бы понять такое зачем так усложнять.

P.S Странная защита от спама, цифры не меняются.
Ответить
lcf 16.05.2009 20:44 #
Можешь посмотреть пример тупого контроллера в моем проекте с открытым кодом, заметочках:
http://code.google.com/p/lcf-notes/downloads/list

Посмотри контроллер index и модели в версии 1.2 и сравни с последней версией, в последней версии сделано как надо.

Ты как-то писал что ты "не любитель толстых контроллеров", так что я предполагаю, что можешь поискать где-то у себя допольнительные примеры (шучу ^_^).

P.S предлагаю ввести специально для Игоря интегральные формулы с динамически изменяющимися параметрами. (хы хы ^_^)
Ответить
Александр Махомет 17.05.2009 13:37 #
Статья интересная но немного мне не понятно, можно привести пример "тупого контроллера". В принципе в модель я бы добавил еще валидацию данных и праверку прав пихать туда не стал бы. Но так как в зф есть формы, то валидация в форме.
Форма для меня часть модели.

Немного не понятно зачем Саша делает 4 класса для работы с сущностью статьи.
Я делаю столько сколько нужно в конкретной задаче. Каждый класс имеет свои особые настройки, например не все поля заполняемые при создании могут быть доступны для редактирования, кроме того при редактировании поля должны быть заполнены данными, плюс мы имеем разный экшн. Избыточности никакой нет, потому что все общее собрано в классе Article_Abstract. А 4ре у меня получилось потому что я ипользовал еще форму для перевода статьи, там тоже свои особенности.

P.S Странная защита от спама, цифры не меняются.
Защита отлично работает для автоматического спама. Как повесил ни одного спам сообщения ;) Что в общем и вполне логично.
Ответить
Денис 22.06.2009 15:43 #
Допустим, есть такая сущность как Пользователь. У неё может быть некая информация типа имени, года рождения и аватар - картинка. Информация хранится в БД, аватар - в специальной папке. Как в данном случае более грамотно организовать модель, которая может добавлять пользователя, редактировать его и т.д.?
Ответить
Александр Махомет 22.06.2009 15:54 #
Например, как в официальном quickstart. Там сущность - гостевая книга, но концептуально от вашего пользователя это не отличается.
Ответить
AlucardMC 29.10.2009 16:57 #
Эмм все понятно для чего служат модели, спс.
Одна проблема, не могу найти как вообще использовать эти модели, то есть как их подключать, как они вообще выглядят =) Дайте ссылки на примеры, плиз
Ответить
Snowcore 14.12.2009 18:16 #
Особенно понравился абзац в оригинальной статье:

"Since Models are so lame to developers, they invented a new concept. Fat Stupid Ugly Controllers (FSUC). I put the SUC in FSUC on purpose. It seemed funny at 10pm after a few drinks :-)"
Ответить
Комментарии временно отключены, вы можете воспользоваться форумом.