Шаблон MVC. Мысли про “состояние” модели 
В связи с комментариями Andy к посту про MVC я невольно задумался: а правильно ли я понимаю концепцию MVC? Начал разбираться, и вот к каким мыслям пришел.
У модели должно быть “состояние”
Как правило, модель описывают достаточно просто, мол - это нечто описывающее бизнес-логику приложения. Что такое бизнес-логика приложения и как с ней работать особо нигде не поясняется. Отсюда возникают различные интерпретации и реализации, многие из которых оказывается “не MVC”.
Если верить Wiki, то основная ошибка веб-программистов сводится к тому, что они выносят бизнес-логику из модели в контроллер. В результате получая «Толстые тупые уродливые контроллеры».
В той же Wiki дано очень хорошее опрделение модели, которое, как мне кажется, является ключом к правильному построению модели: “Модель предоставляет данные (обычно для View), а также реагирует на запросы (обычно от контроллера), изменяя своё состояние” Здесь очень важно обратить внимание на фразу “изменяя свое состояние“.
Получается, что у модели должно быть “состояние“. И вот об этом понятии я хочу немного порассуждать.
Что такое состояние модели с позиции реализации
Я не знаю какое определение “состояния модели” дают в умных книгах, но для себя я сформулировал так, состояние модели - это набор характеристик которые однозначно определяют, что можно (или нельзя) сделать с моделью в текущий момент времени. И на этом с теорией можно покончить.
Более интересно, на мой взгляд, понять, что из себя должна представлять модель на практике и как ее состояние передать конкретными возможностями используемого языка программирования (далее под “языком программирования” я буду подразумевать PHP). И здесь у меня в голове формируется единственная реализация, которая сводится к тому, что модель - это класс. Никакие другие реализации я рассматривать не буду.
Понятно, что класс - это только описание модели. У него не может быть никакого состояния. Поэтому состояние может появится только у конкретного экземпляра класса - объекта. И в таком случае внутреннее состояние объекта можно интерпретировать как состояние модели. А отсюда следует, что состояние модели - это набор внутренних переменных с их значениями.
Значит, с точки зрения реализации “состояние модели” - это просто набор переменных. Замечательно, я пришел к тому, что и раньше прекрасно знал - модель должна содержать переменные.
Естественно, что для более правильного понимания модели этого мало. И вот почему - понятие “состояния модели” должно появляться на этапе проектирования (продумывания) модели. Если задачи модели формулировать с позиции “состояния“, то и код модели не будет попадать в контроллер.
Что такое состояние модели с позиции проектирования
Обычно я не представляю себе модель как объект с набором состояний. Поэтому пример, который я рассматриваю далее, не очень удачный. Но все же попробую представить себе совсем простую модель. Например, модель получения данных из БД. Я накидал простенькую диаграмму (State Machine Diagram):

Из диаграммы должно быть видно, что у модели всего три состояния: “нет данных“, “сформулированы условия фильтрации данных” и “данные загружены“. Состояния выражаются через флаги - has_data и has_filter. Кроме этого, есть методы, которые переводят модель из одного состояния в другое: where и load.
Все, на этом проектирование простой модели закончено. В коде, данная модель могла бы выглядеть так:
var $has_data = false;
var $has_filter = false;
public function where($conditions) {
$this->has_filters = $this->db->where($conditions);
}
public function load() {
$this->data = $this->db->get();
$this->has_data = (bool) $this->data;
}
public function get() {
return $this->data();
}
}
В контроллере метод работающий с БД мог бы выглядеть так:
$someModel = new DB_Model();
$someModel->load();
return $someModel->has_data ? new MainView($someModel) : new EmptyView();
}
Контроллер, представление и состояние модели
Вроде бы все хорошо, но меня смущает один момент: “А правильно ли я использовал контроллер?”. Ведь до сих пор я ни слова не сказал о том, как должны взаимодействовать модель, контроллер и представление в контексте “состояния модели”. Здесь я не буду оригинальным и приведу три известных правила:
Во-первых, и “представление”, и “контроллер” должны иметь возможность получать текущее состояние модели;
Во-вторых, “контроллер” должен иметь возможность влиять на состояние модели;
В-третьих, “модель” ничего не должна знать ни о “контроллере”, ни о “представлении”, зато они в свою очередь должны знать о модели все (точнее они должны знать об интерфейсе по которому необходимо взаимодействовать с моделью).
Теперь, чтобы проверить правильно ли написан код функции “some_action”, попробую представить его в другом виде:
return new MainView(new DB_Model);
}
При этом я рассуждал так - если контроллер не обрабатывает данные от пользователя, то он и не должен ничего делать. Поэтому я решил перенести загрузку и отображения данных в представление:
<body>
<?php $model->load()
if ($model->has_data) {
?>
… здесь идет отображение загруженных данных …
<?php }else{?>
… здесь сообщение об отсутствии данных …
<?php>
</body>
</html>
Как только я посмотрел на код представления, я сразу понял, что так делать нельзя! Проблема в том, что код представления не должен изменять состояние модели (см. правила выше), а метод load относится к методам изменяющим состояние модели. Поэтому, согласно приведенным выше правилам, загрузка данных из БД должна выполняться в контроллере. А это значит, что первый пример был абсолютно правильным.
Заключение
Конечно в данной заметке приведены далеко не все мысли, которые у меня возникли относительно шаблона MVC. Многое еще нужно сказать про получение и валидацию данных от пользователя, про то что программирование через флаги (has_data и has_filter) - не очень хорошая идея и т.д. Но я оставлю эти вопросы для тем будущих постов. Пока же я предлагаю обсудить то, что сказано здесь.
Особо отмечу, что все сказанное - это мое понимание и восприятие шаблона. Поэтому я буду благодарен за указание на ошибки и неточности.
подписаться на блог
Andy
Гость
В шаблоне Active Record модель это одна запись из таблицы. Моя любимая реализация модели, поэтому, расскажу про нее.
Там есть понятие “грязный” и “чистый объект”.
Грязный объект, это тот объект, данные которого не хранятся в БД. Т.е., например, мы получили эти данные из формы и передали объекту модели. В этом случае мы можем проверить, “грязный” ли объект примерно так (ruby):
user = User.new
user.name = ‘Innokentiy’
user.email = ‘kesha@mail.ru’
user.new_record? # => true
Вызвали метод new_record? и получили true, т.к. объект “грязный”. Дальше:
user.save! # Сохраняем объект
user.new_record? # => false
Мы сохранили объект и снова проверили его на “грязность”. Объект успешно сохранился и синхронизирован с БД, значит, теперь он “чистый”.
Кажется, именно это подразумевается под понятием “состояние” для модели в AR. Ну и конечно, я до сих пор убежден, что модель это не только методы работы над данными, но и сами даные.
Arconas
Гость
А Я вот еще больше запутался в этом паттерне. Сейчас предстоит разрабатывать и подымать проект довольно объемный по коду. Понял - без ООП и паттернов проектирования не обойтись. Сам Я люблю раскладывать всё по полочкам. До селе это решалось include(some_functions.php). Но с течением времени, Я как и все столкнулся с проблемой сопровождения и развития.
и наверное Я туп….
Мозг рвут в клочья различные книги по проектированию объектно ориентированных приложений и паттернов проектирования. Авторам настолько все это проело мозг, что чёткого определения, что именно должна содержать в себе модель нет нигде. Одна вода или в основе лежит какой-нибудь фреймворк, где “всё как вам уже надо, господа не парьтесь используйте”. >. авторизуется
1) Контроллер отправил запрос Модели - “Пробей человечка плиз”.
2) Модель подключилась к базе и взяла оттуда данные. Вот тут вопрос - кто должен проверять данные и делать дальнейшие действия? Контроллер или модель? Если следовать логике и товарищу, который говорит что не надо делать ТТУК, то модель. Она же описывает бизнес-логику (а бизнес-логика это реализация предметной области приложения. А что такое ПО и так понятно).
3) Модель передала своё состояние контроллеру - “проверяю данные, погоди пять сек”.
4) Контроллер принял к сведению состояние модели и передал вьюверу - “покажи пользователю часики и попроси подождать”.
5) Модель проверила данные и передала контроллеру: “Это наш Великий Создатель. У меня прописано его пускать”.
6) Контроллер получил от модели подтверждение, проверил по какому маршруту подключить шаблон главной панели управления, нашел необходимый шаблон и передал всю это вьюверу.
7) Вьювер отобразил необходимую страничку и Автор остался доволен, приступая к написанию поста.
Это правильный MVC, как Я его понимаю или Я иду не в том направлении.
Evgeny Sergeev
Веб-разработчик, автор блога codeart.ru
Arconas, мне Ваше объяснение очень даже нравится. Полностью совпадает с моим пониманием MVC шаблона.
Arconas
Гость
Evgeny Sergeev, спасибо за ответ.
Значится Я иду верным путем, ну или по крайней мере верно ступаю по минному полю.
Arthur
Гость
Здравствуйте, уважаемые разработчики.
Я тоже интересуюсь данной темой. Сейчас пишу игру похожую на тетрис на Java. Использую принцип MVC, тоже ломал голову что к чему…
Спасибо за ваши комментарии - я Вас поддерживаю!
Arthur
Гость
Arconas, как Вам данная статья?
http://hexlet.ru/blog/112.html
Arconas
Гость
Arthur, если честно, то не ахти. Во-первых, это выдержки из учебного курса, который по своему определению напихан кучей умных слов и нет ничего по делу. Единственное полезное - это графики и конечный абзац. Но это всё теория.
Всё самое интересное начинается, когда программист делает над собой неимоверное усилие и начинает с нуля писать, ну… допустим, CMS для блога. И делает он это с применением MVC (ну или там MVC2, 3,4… без разницы… это всего-лишь один из способов “нарисовать круг”) и в процессе работы наглядно показывает почему он сделал выбор именно в пользу этого паттерна. И самое главное он пишет систему полностью, а не “кустисто” типа статей на Хабре: “Вот тут мы забабахаем class bla_bla_bla extend tru_lia_lia, а вот тут жахнем контролер ошибок, а здесь прикрутим шаблонизатор, и вот у нас готовая система”. Старые матерые прогеры почешут заросший щетиной подбородок и кивнут типа: “да чел ты крут, но в топку ваше говнище, надо использовать ZEND(можно заменить на любой сейчас дико модный фрейм) ибо он тащит, а еще накрутить Yii, добавить jQuery”. Интернет подобным просто кишит. Это просто ужас и нежелание помочь подрастающему поколению. А ответы типа “открой код любой CMS и разберись” вымораживают. Хочется ответить - открой капот автомобиля и разберись как двигатель работает. И да поставь мне туда турбину. Если не рванет - ты справился с заданием.
Я немного сейчас отошел от программирования и учусь рисунку. И вот преподаватель с которым Я занимаюсь рисует вместе со мной показывая как это обычно делается. Сидим рисуем зерна кофе, не получается. Преподаватель садиться и рисует, а я наблюдаю. Потом сажусь и повторяю. За крайне короткий промежуток времени по её словам Я рисую на уровне студента конца первого курса. То же самое должно быть и в программировании с немного правда другим подходом, но не в этом суть.
Еще ни разу мне не попадалась статья или цикл статей, где бы обучали не теории и заумным словам аля БИЗНЕС МАТЬ ЕЁ ЛОГИКА или КОНТРОЛЕРРР, состояние модели, а пошагово, с нуля, без использования “супер фраймов” (для некоторых программистов это как серпом по яйцам) и адски навороченных шаблонизаторов писали бы… там тот же блог или гостевую книгу. Что-то простое, но на чём можно обучится. Раньше это было. Серии книг Кузнецова и Симдянова, множество орейлевской литературы. Но они не позволяют двигаться дальше, предел знаний есть. Сейчас как-то всё “быстро-быстро-быстро и вуаля”. А потом мы удивляемся - почему ломают вроде бы неприступные сайты, почему они падают при высокой посещаемости и почему вокруг того же php крутится огромное количество быдлокодеров.
Я давно уже хочу начать в своем блоге цикл статей типа: “пишем с нуля без купюр и теоретической мутатени”, но пока что уровень моих знаний оцениваю на троечку и продолжаю собирать грабли. Как вот набью тучу шишек, как только моя CMS будет написана и возьмет порог в 30 000 пользователей, обязательно примусь за написание развернутых статей или может даже скринкастов.
Arthur, ой, кстати. Вы меня извините, но не принимайте это всё как критику или еще что-то. Просто наболело =D, такой выплеск графоманства.
Leave a Reply