Pull to refresh

Comments 27

Основные тезисы статьи опираются на игру терминов MVC/P и на понятие «размытости компонентов». Но на самом деле MVC (как и MVP) не является как таковым шаблоном проектирования (я имею ввиду GoF-паттерны), это набор таких шаблонов, причём самых разнообразных. Т.е. это архитектурный (enterprise) паттерн. Оттого и компоненты размыты, имхо.
Ну я и не говорил про банду четырех.

А размытость действительно объясняется архитектурностью (так сказать) паттерна, но далеко не у всех архитектурных паттернов присутствует размытость.

Я намеренно смешал паттерн банды Observer и архитектурный паттерн, т.к. начинающие программисты-архитекторы, у которых еще не сформировался свой взгляд на этот мир узнают MVC еще до прочтения о Singleton. Тут то и начинается поиск серебряных пуль.
А размытость действительно объясняется архитектурностью (так сказать) паттерна, но далеко не у всех архитектурных паттернов присутствует размытость.
Ну а как может не быть размытости? Это же просто архитектура приложения в самом общем виде. У этого «шаблона» нет какой-то конкретной цели и поведения (как например у того же упомянутого Singleton или других шаблонов проектирования), просто общая идея разделения на три компонента.
а что мешает в любой момент в любом контроллере подгрузить другой контроллер?

простой пример:
у тебя был блок выводящий лучшие статьи за день. сам список кэшировался, но информация о пользователях обновлялась потому что они любят менять аватарки, ники и статусы. потом ты решил вывести блок с лучшими комментариями. и опять список берётся из кэша, а за пользователями мы лезем в базу (уже второй раз за запрос). а потом ещё блок, ещё… сколько запросов будет? дофига.

а всё почему? а потому, что в роли контроллера выступает шаблон.

как правильно сделать?

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

почему-то многие программисты стараются переложить координацию действий на верстальщика, вынуждая его для каждой страницы писать отдельный шаблон, хотя он во многих случаях состоит из типовых блоков. да, это позволяет уменьшить число контроллеров, но не на много, так как всё-равно почти на каждый шаблон потребуется свой контроллер.
всё-равно для каждой страницы должна быть где-то расписана логика её формирования. у языка программирования выразительных средств для этого куда больше чем для языка шаблонизации.
Именно так и следует поступать, а не рвать шаблоны, оправдываясь размытыми границами.
Лично я (т.е. ИМХО) придерживаюсь правила такого: Модель предметной области != ViewModel. взято тут
Т.е. контроллер не должен сам лезть в базу данных/ к другому звену. Он должен запросить модель (которая всё запросит и расформирует), потом из этой модели сформировать ViewModel, а уже её отдать во View.
тогда тебе придётся ввести специальные модели для каждой страницы, единственной функцией которых будет координация других моделей — это и будут контроллеры.
Скорее для каждой страницы нужно будет делать маппер, который будет из модели бизнес-логики создавать модель представления, и вызывать этот маппер в каждом экшне контроллера.
Наоборт, чтобы не вынуждать писать верстальщика отдельный шаблон я использую инструкцию include/apply шаблонизатора. Потому блок с новостями может быть вставлен в любое место шаблона или лэйаута.
Один раз сверстав составляющую новостей верстальщик пользуется тегом {{include /}}. Но я говорил о том, что данные нужно выбирать только там, где они нужны, а потому иерархия наследования контроллеров (на мой взгляд) здесь не подходит.

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

нафига ты сюда приплёл наследование? это единственный способ реюзинга кода, который тебе известен?

конечно по разному. толковых программистов на всех не напасёшься. что уж говорить о толковых архитекторах…
С тезисом по поводу размытости границ в MVC согласен (да кто не согласен, по-моему это достаточно очевидно). Но вот пример Вы выбрали ужастный. У Вас там размылась граница между МОДЕЛЬЮ и ПРЕДСТАВЛЕНИЕМ, что не есть гут. Выборку послдених пяти новостей (да скольки угодно, хоть пятнадцати, хоть только про Путина), имхо, нужно делать в модели, а контроллер должен уже эту выборку передавать в шаблон (каким угодно способом). Товрищ tenshi выше очень хорошо всё описал.
А выборка и пойдет в модели, но вызов модели будет не в контроллере с последующим PUSHем в шаблон, а непосредственно в шаблоне:
$news = News::findByCriteria(Criteria::contains('name','Путин'),array('limit'=>5,'order'=>array('date'=>'desc'))

На мой взгляд автор не осилил само понятие паттерна MVC и что за что в этой связки отвечает :(
Например, в случае с корзиной, которая хранится на клиенте, все нормально. Модель же это не только голые данные. Модель это также код который обрабатывает эту модель. В случае с WebRiсh приложением надо рассматривать само приложение как отдельный слой/звено. Т.е. на клиенте используется JS MVC приложение, которое генерирует HTML как View, классы обработчиков кликов как контроллеры, а модель это тот слой который общается с серверным приложением при помощи ajax(json/html). Серверная часть это тоже отдельное приложение, к которого View — json/html, контроллеры это обработчики post/get запросов, а model это слой общения с другими сервисами/базой данных. Я уж не говорю что другие сервисы/базы данных тоже (возможно) реализуют модель MVC.
Не нужно все приложение загонять в рамки одного MVC, это не правильно…
Автор осилил понятие MVC, похоронив 3 собственных PHP-фреймворка, являясь коммитером одного из мало-популярных фреймворков и найдя порядка 20 багов/граблей в одном из популярнейших фреймворках.

Пример про новости, конечно надуман, но часть реальной ситуации он отражает. Никто не говорит, что в шаблоне будет использован прямой SQL-запрос — там будет что-то вроде $lastNews = News::getLastPublished(5)

На моей практике встречалось немало ситуаций, где приходилось рушить и без того размытые рамки MVC. Где-то ради производительности, где-то ради читабельности кода.

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

Заметьте, я не сказал, что так нужно делать везде — через всю статью проходит мысль о том, что все зависит от специфики проекта. И цель статьи — предупредить шаблонный способ мыслить у новичков, прочитавших предыдущую статью в блоге «Разработка».
Мне кажется, концепция виджето-сайдбаров вообще порочна, лучше заменить её на подвызовы контроллеров из шаблонов, сократим количество кода, код будет более униформным.
У себя реализовал именно так, доволен.
Возможно вы правы, но повторю, что реализацию часто диктует специфика проекта
Либо спецификой являются ошибки проектирования =)
Что ж, бывае и такое. Кстати даже не редко!
UFO just landed and posted this here
Иногда это нормально, иногда действительно предпочтительнее Observer, в некоторых фреймворках есть специальные решения для этой задачи. Бардак начинается, если базовые классы начинают дублировать функционал друг-друга.
Если выстраивать иерархию наследования контроллеров — обычно начинается бардак.
Договоримся, что если класс наследует другой класс, то к имени родителя добавляется буква.
Имеем классы a,ab,ac,aba,abb,abc,aca,acb,acc,ad,ada,adb,adba
Если в классе adba нужен функционал, определенный в классе ab, но в классе adb он совсем не нужен, как мы будем поступать? В Pyton мы наверное будем использовать множественное наследование, но я пока плохо представляю, как оно работает. В PHP6 мы будем использовать Traits. А что делать в PHP5 ??? Выход: copy_paste === Бардак.

А если, как сказали Вы наследовать контроллеры от разных БАЗОВЫХ классов — то бардак более чем очевиден.

Или я не так Вас понял?
В примере с новостями все просто, обычно решается виджетами, веб-частями, компонентами и т.п. (в зависимости от фреймворка), что прекрасно вписывается в идеалогию MVC. У меня лично с разделением на слои проблем не возникает, правда иногда модель разрастается из-за сложной бизнес-логики в этом случае пишу вспомогательные классы.
Опять же! Все зависит от проекта!
Иногда нужно тупо поставить костыль или написать спагетти-код. Это не плохо! Это один из вариантов решения задачи!

Ответственность за то, какой вариант выбрать лежит на разработчике. Городить иерархию классов для вывода символа Евро в одном месте (надуманный пример) — тоже плохой вариант.
Когда модель растет — есть тоже несколько вариантов выхода из ситуации. И снова ответственность за выбор лежит на разработчике.

1. Писать Helpers — ваш вариант
2. Строить иерархию наследования.
3. Делить модели
В текущем проекте у нас целый зоопарк php+python+orbited+mootools+js+css3 (проект с тяжелым прошлым).
И чтобы не свихнуться во всем этом бардаке нужно не просто думать «о, какой бы сюда паттерн еще впихнуть, чтобы код стал еще запутанее для другого разработчика», а использовать их только по мере необходимости, когда код дублируется.

Золотая середина — это использовать все по мере необходимости.
В ASP.Net MVC для случая с блоком новостей есть специальный механизм RenderAction, который позволяет прорендерить на странице результат экшна из другого контроллера, при чем этот же результат можно загрузить через AJAX-запрос. Я думаю, в РНР такое тоже вполне реализуемо.
Реализуемо, но инстанцировать другой контроллер бывает достаточно дорого в плане ресурсов (бутстрапинг контроллера). Снова сказывается специфика проекта.

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

Бывают случаи когда нужно писать говнокод, ибо привести в порядок унаследованное спагети дорого, а новая фича должна приносить деньги еще вчера и каждый день до релиза стоит компании порядка 1 000 000 рублей.
Будем три дня рефакторить или допишем спагетти за полдня, потом полдня потестируем и завтра — релиз ????????
Sign up to leave a comment.

Articles