// codeart.ru / Вопрос/Ответ / Шаблон MVC. Мысли про «состояние» модели Форум

Шаблон MVC. Мысли про «состояние» модели rss подписка

Автор: Evgeniy Sergeev

В связи с комментариями Andy к посту про MVC я невольно задумался: а правильно ли я понимаю концепцию MVC? Начал разбираться, и вот к каким мыслям пришел.

У модели должно быть «состояние»

Как правило, модель описывают достаточно просто, мол — это нечто описывающее бизнес-логику приложения. Что такое бизнес-логика приложения и как с ней работать особо нигде не поясняется. Отсюда возникают различные интерпретации и реализации, многие из которых оказывается «не MVC».

Если верить Wiki, то основная ошибка веб-программистов сводится к тому, что они выносят бизнес-логику из модели в контроллер. В результате получая «Толстые тупые уродливые контроллеры».

В той же Wiki дано очень хорошее опрделение модели, которое, как мне кажется, является ключом к правильному построению модели: «Модель предоставляет данные (обычно для View), а также реагирует на запросы (обычно от контроллера), изменяя своё состояние» Здесь очень важно обратить внимание на фразу «изменяя свое состояние«.

Получается, что у модели должно быть «состояние«. И вот об этом понятии я хочу немного порассуждать.

Что такое состояние модели с позиции реализации

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

Более интересно, на мой взгляд, понять, что из себя должна представлять модель на практике и как ее состояние передать конкретными возможностями используемого языка программирования (далее под «языком программирования» я буду подразумевать PHP). И здесь у меня в голове формируется единственная реализация, которая сводится к тому, что модель — это класс. Никакие другие реализации я рассматривать не буду.

Понятно, что класс — это только описание модели. У него не может быть никакого состояния. Поэтому состояние может появится только у конкретного экземпляра класса — объекта. И в таком случае внутреннее состояние объекта можно интерпретировать как состояние модели. А отсюда следует, что состояние модели — это набор внутренних переменных с их значениями.

Значит, с точки зрения реализации «состояние модели» — это просто набор переменных. Замечательно, я пришел к тому, что и раньше прекрасно знал — модель должна содержать переменные. :-) Естественно, что для более правильного понимания модели этого мало. И вот почему — понятие «состояния модели» должно появляться на этапе проектирования (продумывания) модели. Если задачи модели формулировать с позиции «состояния«, то и код модели не будет попадать в контроллер.

Что такое состояние модели с позиции проектирования

Обычно я не представляю себе модель как объект с набором состояний. Поэтому пример, который я рассматриваю далее, не очень удачный. Но все же попробую представить себе совсем простую модель. Например, модель получения данных из БД. Я накидал простенькую диаграмму (State Machine Diagram):
state

Из диаграммы должно быть видно, что у модели всего три состояния: «нет данных«, «сформулированы условия фильтрации данных» и «данные загружены«. Состояния выражаются через флаги — has_data и has_filter. Кроме этого, есть методы, которые переводят модель из одного состояния в другое: where и load.

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


class DB_Model extends Model {
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();
}
}

В контроллере метод работающий с БД мог бы выглядеть так:

public function some_action() {
$someModel = new DB_Model();
$someModel->load();

return $someModel->has_data ? new MainView($someModel) : new EmptyView();
}

Контроллер, представление и состояние модели

Вроде бы все хорошо, но меня смущает один момент: «А правильно ли я использовал контроллер?». Ведь до сих пор я ни слова не сказал о том, как должны взаимодействовать модель, контроллер и представление в контексте «состояния модели». Здесь я не буду оригинальным и приведу три известных правила:

Во-первых, и «представление», и «контроллер» должны иметь возможность получать текущее состояние модели;
Во-вторых, «контроллер» должен иметь возможность влиять на состояние модели;
В-третьих, «модель» ничего не должна знать ни о «контроллере», ни о «представлении», зато они в свою очередь должны знать о модели все (точнее они должны знать об интерфейсе по которому необходимо взаимодействовать с моделью).

Теперь, чтобы проверить правильно ли написан код функции «some_action», попробую представить его в другом виде:

public function some_action() {
return new MainView(new DB_Model);
}

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




load()
if ($model->has_data) {
?>
... здесь идет отображение загруженных данных ...

... здесь сообщение об отсутствии данных ...



Как только я посмотрел на код представления, я сразу понял, что так делать нельзя! Проблема в том, что код представления не должен изменять состояние модели (см. правила выше), а метод load относится к методам изменяющим состояние модели. Поэтому, согласно приведенным выше правилам, загрузка данных из БД должна выполняться в контроллере. А это значит, что первый пример был абсолютно правильным.

Заключение

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

Особо отмечу, что все сказанное — это мое понимание и восприятие шаблона. Поэтому я буду благодарен за указание на ошибки и неточности.

  1. Немного про State тестирование в TDD
  1. В шаблоне 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. Ну и конечно, я до сих пор убежден, что модель это не только методы работы над данными, но и сами даные.

  2. А Я вот еще больше запутался в этом паттерне. Сейчас предстоит разрабатывать и подымать проект довольно объемный по коду. Понял — без ООП и паттернов проектирования не обойтись. Сам Я люблю раскладывать всё по полочкам. До селе это решалось include(some_functions.php). Но с течением времени, Я как и все столкнулся с проблемой сопровождения и развития.

    и наверное Я туп….

    Мозг рвут в клочья различные книги по проектированию объектно ориентированных приложений и паттернов проектирования. Авторам настолько все это проело мозг, что чёткого определения, что именно должна содержать в себе модель нет нигде. Одна вода или в основе лежит какой-нибудь фреймворк, где «всё как вам уже надо, господа не парьтесь используйте». >. авторизуется
    1) Контроллер отправил запрос Модели — «Пробей человечка плиз».
    2) Модель подключилась к базе и взяла оттуда данные. Вот тут вопрос — кто должен проверять данные и делать дальнейшие действия? Контроллер или модель? Если следовать логике и товарищу, который говорит что не надо делать ТТУК, то модель. Она же описывает бизнес-логику (а бизнес-логика это реализация предметной области приложения. А что такое ПО и так понятно).
    3) Модель передала своё состояние контроллеру — «проверяю данные, погоди пять сек».
    4) Контроллер принял к сведению состояние модели и передал вьюверу — «покажи пользователю часики и попроси подождать».
    5) Модель проверила данные и передала контроллеру: «Это наш Великий Создатель. У меня прописано его пускать».
    6) Контроллер получил от модели подтверждение, проверил по какому маршруту подключить шаблон главной панели управления, нашел необходимый шаблон и передал всю это вьюверу.
    7) Вьювер отобразил необходимую страничку и Автор остался доволен, приступая к написанию поста.

    Это правильный MVC, как Я его понимаю или Я иду не в том направлении.

  3. Arconas, мне Ваше объяснение очень даже нравится. Полностью совпадает с моим пониманием MVC шаблона.

  4. Evgeny Sergeev, спасибо за ответ.
    Значится Я иду верным путем, ну или по крайней мере верно ступаю по минному полю.

  5. Здравствуйте, уважаемые разработчики.
    Я тоже интересуюсь данной темой. Сейчас пишу игру похожую на тетрис на Java. Использую принцип MVC, тоже ломал голову что к чему…

    Спасибо за ваши комментарии — я Вас поддерживаю!

  6. Arconas, как Вам данная статья?
    http://hexlet.ru/blog/112.html

  7. Arthur, если честно, то не ахти. Во-первых, это выдержки из учебного курса, который по своему определению напихан кучей умных слов и нет ничего по делу. Единственное полезное — это графики и конечный абзац. Но это всё теория.

    Всё самое интересное начинается, когда программист делает над собой неимоверное усилие и начинает с нуля писать, ну… допустим, CMS для блога. И делает он это с применением MVC (ну или там MVC2, 3,4… без разницы… это всего-лишь один из способов «нарисовать круг») и в процессе работы наглядно показывает почему он сделал выбор именно в пользу этого паттерна. И самое главное он пишет систему полностью, а не «кустисто» типа статей на Хабре: «Вот тут мы забабахаем class bla_bla_bla extend tru_lia_lia, а вот тут жахнем контролер ошибок, а здесь прикрутим шаблонизатор, и вот у нас готовая система». Старые матерые прогеры почешут заросший щетиной подбородок и кивнут типа: «да чел ты крут, но в топку ваше говнище, надо использовать ZEND(можно заменить на любой сейчас дико модный фрейм) ибо он тащит, а еще накрутить Yii, добавить jQuery». Интернет подобным просто кишит. Это просто ужас и нежелание помочь подрастающему поколению. А ответы типа «открой код любой CMS и разберись» вымораживают. Хочется ответить — открой капот автомобиля и разберись как двигатель работает. И да поставь мне туда турбину. Если не рванет — ты справился с заданием.

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

    Еще ни разу мне не попадалась статья или цикл статей, где бы обучали не теории и заумным словам аля БИЗНЕС МАТЬ ЕЁ ЛОГИКА или КОНТРОЛЕРРР, состояние модели, а пошагово, с нуля, без использования «супер фраймов» (для некоторых программистов это как серпом по яйцам) и адски навороченных шаблонизаторов писали бы… там тот же блог или гостевую книгу. Что-то простое, но на чём можно обучится. Раньше это было. Серии книг Кузнецова и Симдянова, множество орейлевской литературы. Но они не позволяют двигаться дальше, предел знаний есть. Сейчас как-то всё «быстро-быстро-быстро и вуаля». А потом мы удивляемся — почему ломают вроде бы неприступные сайты, почему они падают при высокой посещаемости и почему вокруг того же php крутится огромное количество быдлокодеров.

    Я давно уже хочу начать в своем блоге цикл статей типа: «пишем с нуля без купюр и теоретической мутатени», но пока что уровень моих знаний оцениваю на троечку и продолжаю собирать грабли. Как вот набью тучу шишек, как только моя CMS будет написана и возьмет порог в 30 000 пользователей, обязательно примусь за написание развернутых статей или может даже скринкастов.

    Arthur, ой, кстати. Вы меня извините, но не принимайте это всё как критику или еще что-то. Просто наболело =D, такой выплеск графоманства.

  8. В любом случае Модель не должна знать о существовании Контроллера и Вьювера. На то она и есть Модель.

Leave a Reply

« »