Интерфейсы. Прочь от MVC
Большинство сложных программных систем создаются с использованием паттерна MVC.
Многие программисты, приходя на javascript с других языков, по инерции используют этот подход.
Однако, при программировании javascript-интерфейса он зачастую бесполезен, приводит к тормозам, переусложнению приложений...
В javascript-интерфейсах, в отличие от Java/C++ и других - обычно не нужен паттерн MVC.
Применение паттерна MVC заключается в разделении собственно данных, их отображения и обработки действий пользователя по трем компонентам.
- Модель (Model)
- Собственно данные, методы для работы с данными, изменения и обновления данных.
- Представление/Вид (View)
- Отображение данных, оформление и другие аспекты презентации модели
- Контроллер (Controller)
- Реагирует на действия пользователя, интерпретирует данные, введенные пользователем, и информирует модель и производит необходимые манипуляции с моделью и видом.
Между компонентами есть взаимодействия, изображенные стрелочками на рисунке (один из устоявшихся вариантов MVC).
Главный тезис статьи можно сформулировать так:
Controller пусть остается отдельно, а Model от View отделять не надо. Особенности Javascript/DOM/CSS позволяют успешно реализовывать аспекты Model средствами View.
Дальнейшая часть статьи - обоснование с примерами, почему именно так, а не иначе, и почему устоявшаяся практика MVC для javascript-интерфейсов работает плохо.
Никто не говорит о том, что MVC вообще - это плохо. Наоборот, MVC - это хорошо. Но вся штука в том, что при программировании для Web есть как минимум 3 важных особенности.
Паттерн MVC увеличивает количество кода за счет появления дополнительных межкомпонентных коммуникаций. То есть, не "сделай это", а "попроси компонент XXX сделать это и обеспечь его данными".
Будем исходить из предположения, что разрабатываем сложный интерфейс.
В самом деле, если интерфейс заведомо простой (и таким останется) - то лишние паттерны тем более не нужны.
Javascript/DOM в браузере - не самая быстрая платформа, а приложения фактически являются real-time, т.е интерфейс должен реагировать и отображаться по возможности мгновенно, плавно, и не сильно жрать память.
Межкомпонентные коммуникации Model-View добавляют тормозов. Это повод их убрать.
Далее, и модель и вид в javascript, как правило, оперируют данными в одинаковом формате.
То есть, значение в форме input.value - не рисованный объект типа GraphicsTTFString , как это может быть в обычном десктоп-програмировании, не кодированная строка пикселей, а обычный текст.
Поэтому отделение Model от View приводит к излишнему дублированию данных.
Что такое View в javascript-интерфейсах?
Это в первую очередь DOM и CSS. Модель DOM заранее включает в себя следующее:
При этом основные аспекты оформления задаются вообще отдельно от DOM, при помощи CSS.
Вы видите, DOM - это совсем не тот "классический" View, который обычно имеется в виду. Он гораздо мощнее.
Так зачем нам поддерживать иерархию, средства выборки и контейнеры для свойств в специальных javascript-объектах Модели, если с этим замечательно справляется DOM/View ?
Минусы, как и плюсы, связаны с производительностью.
При работе исключительно с javascript, работа идет в едином пространстве интерпретатора javascript. Это куда быстрее, чем обращаться к DOM-объектам, который в Microsoft относятся к COM, в Firefox - к XPCOM, в общем - живут отдельно от javascript-движка.
Эта проблема раньше была очень актуальна для Internet Explorer.
На момент написания статьи она фактически решена как библиотечными средствами (clobbering, учет и зачистка назначаемых DOM-элементам свойств), так и патчами.
В частности, как в IE7, так и в IE6 с обновлениями середины 2007 связка DOM-javascript почти не течет.
При разработке приложений надо смотреть, насколько тесно изменение ее модели (данных) завязано на изменение представления (DOM).
Если работа с объектом преимущественно не требует обновления внешнего вида, то можно подумать о выделении модели в целях производительности.
Однако обычно обновление данных тесно завязано с обновлением их вида, и это еще один довод к тому, чтобы их не разделять.
Что касается утечек памяти - в зависимости от аудитории и типа вашего ресурса, вы можете использовать специальные библиотеки и практики кодирования, либо просто игнорировать эту проблему.
Современные js-фреймворки (YUI, dojo, jQuery) ликвидируют бОльшую часть утечек памяти.
Полностью впихивать Model во View, конечно, не обязательно. Да оно обычно и не нужно.
Можно выделить три устоявшихся практики.
Создается единый объект, который существует над компонентами интерфейса и хранит данные всех моделей, задействованных в данном интерфейсе.
Например, во вложенном меню это будет единый объект Menu, который умеет show/hide любые подменю. При этом подменю как таковое не является javascript-объектом.
Аналогично, в javascript-дереве это может быть единый объект Tree, который манипулирует узлами, а сами узлы - просто элементы DOM и хранят данные непосредственно в DOM.
Существует единый объект, который при небольшой "доинициализации" может выполнить роль любой из однотипных компонент интерфейса.
Например, рассмотрим контекстное меню для javascript-дерева, которое вызывается правым кликом мыши на элементе.
Вместо пачки меню - для каждого элемента дерева своё, создается единый объект ContextMenu .
При клике на узел:
- ContextMenu инициализуется нужным узлом
- В зависимости от узла и прав на этот узел включает-выключает пункты подменю
- Показывается на нужном месте экрана
Приспособление ContextMenu к конкретному элементу выполняется очень просто. В данном случае - не нужно создавать DOM-структуру меню, она и так есть. Не надо и создавать новый объект со своими методами - достаточно тех что есть.
Наконец, иногда целесообразно частично отделить некоторые аспекты Model от View.
Обычно при этом выводится в модель то, что во View хранить нельзя или неудобно, так чтобы не возникало дублирование.
В этой статье содержатся те мысли и подходы, которые отличают профессионального JS-программиста от обычного десктоп-кодера, подсевшего на javascript.
Их применение ведет к уменьшению и упрощению кода. Успехов.
|
Замечательная статья, хорошая и нужная.
Для некоторых компонентов применение MVC, по моему, необходимо. Так, в свое время, мы делали виджет - аналог Exel'елевской таблицы, по ячейкам которой можно было бегать при помощи клавиатуры, а так же, совершать еще некоторые операции. Без применения MVC, мне кажется, этот код превратился бы в неудобоваримый киш-миш.
Да, но часть данных удобно держать именно не в M, а в V. То есть, держать информацию напрямую в DOM, а не в JS-объектах.
Илья, согласен, удобно. Но не быстро. Если у вас моделька небольшая (по количеству айтемов) - держите данные в ДОМ.
Для нескольких тысяч айтемов поиск в ДОМе существенно грузит проц.
Вобщем, исходите из задач.
а как насчёт быстрого изменения движка под другой проэкт, (самой главной цэлью создания mvc является полная абстракция модэли контроллера и вида, вид не должен знать что происходит в модели) поэтому если нужно будет поменять дизайн придётся поработать)))
Если не предполагается сильно менять DOM, то здесь все ок.. Большая часть изменений интерфейсов обычно описывается CSS.
Абсолютно все то же самое можно написать о любом другом языке. Нафига в PHP использовать MVC, да и вообще разделение PHP и HTML, если они прекрасно уживаются вместе? А от MVC одни тормоза.
Низачет вообщем.
Kolyaj - а Вы прочитали статью? Там как бы все именно исходя из контекста Web..
В php все по-другому вообще. Это даже не десктоп, это сервер-программинг. Тут именно специфика JS/Web.
Я делаю вывод, что вам достаточно знать, что происходит у вас в коде, а как потом в этой каше разбираться нормальным программистам, вас уже не волнует.
MVC - это единственный правильный подход для php на данный момент. Он отделяет логику от источников данных и представлений. Имея подобное разделение кода, ваши проекты становятся значительно более расширяемыми, код становится упорядоченным и понятным для большинства программистов, работать в команде становится значительно проще. Без MVC очень сложно написать большой проект, чтобы потом его поддерживать, наращивать функционал и так далее.
Я не вижу ни одного случая, когда MVC будет хуже, чем спагетти из php, sql и html/css/js.
А что вообще такое MVC?
Это абстракция, за которой в реальности стоит банальное разделение функционала, без которого не обходится ни одна программа. Утрированно,
- это тоже MVC, в которой alert- это view, "Hello" - это model, а контроллер - это вызывающий скрипт.
Поэтому с одной стороны соглашаясь с Вами, Armen Markossyan, о необходимости разделения источников и обработчиков данных (как актив-пассив в бухучёте ), и соглашаясь с тем, что статья, в общем-то, ни о чём, хочу сказать, что "единственный правильный подход" - это в корне неверная фраза, чем-то напоминающая о 1937 годе. Для каждого проекта нужен свой подход. (Извиняюсь, что это напоминает о другой фразе...)
В принципе, при грамотно поставленном процессе разработки такие вещи, как читаемость кода и скорость его выполнения, и так рассматриваются, и нужды заострять на этом внимание в отдельных статьях попросту нет. А если не рассматриваются, то ... RTFM
Вы правы: я действительно погорячился, сказав, что MVC - это единственный правильный подход, но стоит отметить, что этот паттерн универсален и подходит для приложений практически любого масштаба (будь то веб или десктоп приложения).
Если вы собрались делать большой проект, то никто вам, конечно, не запретит придумать свой паттерн и правила, согласно которым будет все спроектировано. Это займет много времени и вам будут нужны действительно опытные программисты и "архитекторы", чтобы они ничего не упустили на этом важном этапе. А MVC - это уже почти общепринятый стандарт, из чего следует, что вам не придется учить новеньких программистов тому, как писать код, какие правила и ограничения на него накладываются, не придется изобретать велосипед и морочить себе голову, придумывая грамотную архитектуру. Порог вхождения в разработку вашего проекта становится ниже, что нельзя не считать большим плюсом.
В то же время MVC - это не самый "экономичный" с точки зрения производительности паттерн, но в современных условиях данный показатель уступает по важности таким показателям, как расширяемость, скорость разработки и дальнейшего развития проекта.
>>
alert("Hello")
>>- это тоже MVC, в которой alert- это view, "Hello" - это model, а контроллер - это вызывающий скрипт.
Спорно, alert - это команда контроллера к view, он сказал сделать alert, а как уже это сделает view его не интересует.
"Hello", да - это данные, вы их не получили из модели и это создаст вам проблемы, если вы захотите сделать интернационализацию сайта, например. Но если мультиязычность не важна, то все ок.
Долой MVC - да, здравствует MVC.
DOM документа сама построена в соответсвие с MVC. Поэтому подгружая свои свойства иметоды к DOM мы все равно включаемся в этот паттерн. Существенным удобством такого подключения является возможность использовать this в событиях, привязанных к элементу. Естественным ограничением для использования такого подхода является сложность объектов. Для сложных объектов, изменение состояния которых затрагивает сразу несколько элементов DOM (например вышеупомянутые таблицы), естественно легче организовать модель в объектах JavaScript.
Как правильно здесь заметили, идея MVC именно в абстрагированности этих компонентов. Второй аспект в том, что MVC это больше академический пример и реализация его в чистом виде не всегда приводит к желаемому результату.
Данный паттерн имеет много "подвидов", обусловленных структурой модели и логикой обработки событий, поскольку события могут быть не только пользовательскими кликами.
Веб приложения имеют специфику - в частности, они "от рождения" имеют выделенный View и интегрированный в него Controller. Кстати: вариант, когда Контроллер интегрирован в Предствление, также является классическим MVC. В данной статье, думаю, автор подменяет понятия Модели неким Кэшем - как промежуточного элемента хранения данных полученных от Модели.
Я некоторое время занимаюсь проблемой MVC для javascript и думаю, специфика не позволяет применить десктоп-наработки в неадаптированном виде.
Но идея однозначно востребована. Основными требованиями считаю:
1) Необходимость иметь любое количество Представлений (в т.ч. параллельных) одной Модели.
2) Контроллер должен уметь обслуживать все Представления
3) Модель ничего не должна знать о Представлениях
4) Представление не имеет права влиять на Модель
В реализации Контроллер может быть или не быть медиатором между Моделью и Представлениями.
В любом случае главная задача это определение внятных контрактов между Моделью, Контроллером и Представлением.
Аффтар, Вы не учли, что контроллер нужен не просто для связи модели и представления, а также для обработки данных между ними. А Вы так просто предлагаете его исключить. Тогда нафига нам нужен аякс? Давайте грузить сразу все возможные данные в js файлах...
Я бы понял еще объединение модели и контроллера, как обработчики данных ajax-запросов, но то, что Вы предлагаете - просто чудовищно.
И кстати я бы больше предпочел, чтобы некоторые данные обрабатывались все же не стороне клиента, чем на шаред-хостинге )))
В целом согласен с последними комментариями.
ХА!
А реально, нафига Вам нужен аякс, когда данные точно известны и размер их с гулкин нос? Запихните в javascript hash их и будет всем счастье!
Оно конечно понятно, что когда в руках молоток все вокруг похоже на гвозди, но...
Согласен - в статье речь идет о правильных вещах, но они в большнй степени касаются не совсем правильных фреймворков.
Все меняется в сфере вебпрограммирования, и очень быстро!
Считаю, что все сказанное здесь выше не относится к YII Framework...
Любое знание - палка о двух концах. Только здравый смысл поможет решить в каждом конкретном случае, за какой конец взяться и браться ли вообще
Люди, покажите код с использованием MVC и без него, пожалуйста)
Бред! Чушь полная!
Искренне жалко юных девелоперов, которые проникнутся этой статьей
Конкретно, где чушь:
1. В аспекте данной статьи - автор ВООБЩЕ не имеет практического понятия об MVC. Так, верхушех нахватал...
2. "Паттерн MVC увеличивает количество кода за счет появления дополнительных межкомпонентных коммуникаций" - если это происходит, следует немедленно уволить программиста! Ибо каменщик он, или фрезеровщик, но ни разу - не программист.
3. "Межкомпонентные коммуникации Model-View добавляют тормозов" - смешно. Здесь и далее по тексту - человек не имеет ни малейшего понятия в том, о чем говорит.
Уважаемый, а Вы сами программируете на JS?
сплошные эмоции
а аргументы где?
Нормальная статья! Если че хранить надо, можно всегда в input hidden строке засунуть виде JSON. Особенно это хорошо работает с такими библиотеками как JQuery, MooTools и иже с ними.
Внесу свои 5 копеек по теме JavaScript MVC: http://javascriptmvc.com
Стиль текста автора заставляет усомниться в опыте разработки на javascript.
Любой паттерн влияет на количество кода, но MVC за эту часть кода дает гибкость и поддерживаемость. Кстати, в рамках MVC в javascript, модель ничего не знает о контроллере, только о модели. Вот храните вы данные в верстке, представление поменялось раз, у вас добавились новые вычисляемые поля, часть старых скрылось (как предложили тут, стали hidden), потом еще и еще. После пятой итерации такая модель будет хуже представлений в MVC, а я считаю что представления — главное слабое место в MVC, там много избыточности, плохая связь с логикой приложения, и высока вероятность, что во время поддержки там будут дописывать код, вместо обновления старого добавляя лишние условия (if (false), ага).
Вы сами представляете что будет если в верстке хранить части логики, "если значение поля больше трех то ставить переключатель в положение 1" и при этом попытаться часть данных вынести сервис, часть вынести в модальное окно. Придется переписывать весь код, вместо внесения пары правок в модель и представление.
Ну, в общем, я не согласен со статьей. Начальная идея правильная, но выводы крайне странные.
>Вы сами представляете что будет если в верстке хранить части логики
Автор вроде бы такого и не предлагал. Да и как вообще возможно в вёрстке хранить логику? Как вы себе это представляете?
А если, чисто гипотетически предположить, что мы имеем дело с разработкой javascript приложения, которое в своей работе использует webworkers. Webworkers-объект ведь не знает, что такое DOM. Соответсвенно в данном случае модель может быть представлена только javascript-объектами, никак не DOM-объектами. И концепция, предложенная автором, уже не подходит для описанного случая. Просто размышление.
спасибо большое
А я поддерживаю автора в том, что такие вещи как роутер, контроллер - это черный ящик, и ошибку можно искать очень долго.
А если весь код написан без всяких шаблонов... то и баг найти гораздо быстрее!
Я бы сравнил MVC и ASP.NET
это как подобие макроязыка и обычного языка высокого уровня.
Где сейчас макроязыки? всем известно, что MS больше не развивает эту тему, ибо она тупиковая!
Так что asp.net без серверных контролов + js + c#
гораздо приятнее и удобнее!
В свете появления knockout.js рассуждения о MVC вызывают улыбку
Я серьезно, если кто-то еще не знаком с паттерном MVVC, попробуйте Knockout или его аналоги.
И очень нужен нокаут для среднего сайта? Это сродни попыткам добавить классы в джиэс, когда там есть прототипы, с помощью которых и так все прекрасно строится.
Если человек не обделен мозгом, то он архитектуру и так прекрасно вообразит и реализует, а не будет использовать трактор для того, чтобы вскопать грядку в 5 метров длиной.
Большое спасибо за информацию о Knockout!
Помоему бред- я все коменты не читал - но точно знаю и скажу -
MVC - + XML(template)
+php mvc фреймворк
вот это нормально - а js придуман для других целей - подгрузка данных и т.п.
я например совмещаю PHP MVC + JS(JSON) -
джава скрипт подгружается именно тот и с тем контроллером что нужен - и скрипт джейсон обращается непосредственно к методам контроллеров.
И работают оба подхода. И никаких тормозов. И смысл ничего не меняется - так же оч легко меняется шаблон, легко заменить или переписать джейсон, также поправить методы контроллера нужного.
MVC используется в случаях: различных источников данных и одного их представления (редкий случай), одного источника данных и множества представлений (частый), а также если реализовано множество источников с множеством представлений (как MS Access например). В иных случаях использовать MVC глупо. Если у вас за один раз обрабатывается один запрос то оно вам к чему? " вас одна модель и одно представление + вырожденный контроллер.
Для всего свои задачи. В spa-приложениях сложно обойтись без mvc. В приложениях, в которых дом генерируется серверным приложением - можно и даже нужно. Иногда бывают сложные, реально сложные интерфейсы. В таком случае, лучше сложно обойтись без MVVM. Мне печально смотреть как трудяги пытаются выстроить, например, готовой фин отчет по департаментам, сотрудникам с разбивкой по датам, возможностью горизонтального/вертикального "сворачивания" таблиц и динамическим фильтрованием данных без ajax запросов только лишь с помощью jQuery. Это больно. В таким случаях сложно без mvvm.
имхо, для рекламной странички достаточно будет грамотного ванила-js.
и вообще, для многих javascript - это jQuery
Реализовывать MVC, когда представление идет по средствам DOM действительно (может быть) затратно. Приходится размывать границы модели и представления, что не оправдывает такой (MVC) подход; в последнем проекте весь интерфейс делали на canvas'е и MVC себя полностью оправдал, особенно с точки зрения того, что представление _полностью_ независимо от модели (клиенты часто хотят новые фичи интерфейса и смешивание модели и представления приводит к (почти) полному переписыванию некоторых частей).
У меня обычно Model - это данные в формате JSON, которые приходят с сервера. Соответственно, контроллеры посылают AJAX запросы, получают результат и вызывают методы представлений с новыми параметрами для обновления интерфейса.
Использование таких штук как W3View позволяет забыть об особенностях View в браузере и работать с представлениями в любом стиле - хочешь MVC, хочешь MVVM, Flux, можно ещё что нибудь придумать, если надо
https://habr.com/post/348258/
https://habr.com/post/349866/
Если работа с объектом преимущественно не требует обновления внешнего вида, то можно подумать о выделении модели в целях производительности.
.
У меня обычно Model - это данные в формате JSON, которые приходят с сервера. Соответственно, контроллеры посылают AJAX запросы, получают результат и вызывают методы представлений с новыми параметрами для обновления интерфейса.