Мастер-классы по Javascript, AJAX/COMET, jQuery Узнать больше...
Javascript.RU

Интерфейсы. Прочь от MVC

Большинство сложных программных систем создаются с использованием паттерна MVC.

Многие программисты, приходя на javascript с других языков, по инерции используют этот подход.

Однако, при программировании javascript-интерфейса он зачастую бесполезен, приводит к тормозам, переусложнению приложений...

В javascript-интерфейсах, в отличие от Java/C++ и других - обычно не нужен паттерн MVC.

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

Модель (Model)
Собственно данные, методы для работы с данными, изменения и обновления данных.
Представление/Вид (View)
Отображение данных, оформление и другие аспекты презентации модели
Контроллер (Controller)
Реагирует на действия пользователя, интерпретирует данные, введенные пользователем, и информирует модель и производит необходимые манипуляции с моделью и видом.

Между компонентами есть взаимодействия, изображенные стрелочками на рисунке (один из устоявшихся вариантов MVC).

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 заранее включает в себя следующее:

  • Хранение любых свойств:
    var div = document.createElement('div')
    div.myProperty = 123
    
    //..  и даже ... 
    div.myMethod = function() {
        alert(this.innerHTML)
    }
    
  • Древовидную иерархию - дерево элементов DOM
  • Средства поиска, выборки элементов. Наиболее известнен метод document.getElementById. Сложные CSS-селекторы и XPath постепенно приходят в браузеры, и успешно эмулируются JS-библиотеками.

При этом основные аспекты оформления задаются вообще отдельно от 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.

При клике на узел:

  1. ContextMenu инициализуется нужным узлом
  2. В зависимости от узла и прав на этот узел включает-выключает пункты подменю
  3. Показывается на нужном месте экрана

Приспособление ContextMenu к конкретному элементу выполняется очень просто. В данном случае - не нужно создавать DOM-структуру меню, она и так есть. Не надо и создавать новый объект со своими методами - достаточно тех что есть.

Наконец, иногда целесообразно частично отделить некоторые аспекты Model от View.

Обычно при этом выводится в модель то, что во View хранить нельзя или неудобно, так чтобы не возникало дублирование.

В этой статье содержатся те мысли и подходы, которые отличают профессионального JS-программиста от обычного десктоп-кодера, подсевшего на javascript.

Их применение ведет к уменьшению и упрощению кода. Успехов.


Автор: hogart, дата: 28 мая, 2008 - 20:46
#permalink

Замечательная статья, хорошая и нужная.


Автор: tenshi, дата: 29 мая, 2008 - 16:13
#permalink

в мозилле используется этот flyweight.. тормозня страшная...
по каждому пункту меню происходит куча проверок и меню собирается в рилтайме.

ps: как меня заебали эти куки...

.ня


Автор: barbiturat, дата: 23 июня, 2008 - 13:27
#permalink

Для некоторых компонентов применение MVC, по моему, необходимо. Так, в свое время, мы делали виджет - аналог Exel'елевской таблицы, по ячейкам которой можно было бегать при помощи клавиатуры, а так же, совершать еще некоторые операции. Без применения MVC, мне кажется, этот код превратился бы в неудобоваримый киш-миш.


Автор: Илья Кантор, дата: 16 июля, 2008 - 15:30
#permalink

Да, но часть данных удобно держать именно не в M, а в V. То есть, держать информацию напрямую в DOM, а не в JS-объектах.


Автор: freeman (не зарегистрирован), дата: 16 июля, 2008 - 13:27
#permalink

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


Автор: Илья Кантор, дата: 16 июля, 2008 - 15:31
#permalink

Если не предполагается сильно менять DOM, то здесь все ок.. Большая часть изменений интерфейсов обычно описывается CSS.


Автор: Kolyaj, дата: 1 сентября, 2008 - 11:41
#permalink

Абсолютно все то же самое можно написать о любом другом языке. Нафига в PHP использовать MVC, да и вообще разделение PHP и HTML, если они прекрасно уживаются вместе? А от MVC одни тормоза.

Низачет вообщем. Sad


Автор: Илья Кантор, дата: 10 сентября, 2008 - 12:47
#permalink

Kolyaj - а Вы прочитали статью? Там как бы все именно исходя из контекста Web..

В php все по-другому вообще. Это даже не десктоп, это сервер-программинг. Тут именно специфика JS/Web.


Автор: zaremba (не зарегистрирован), дата: 15 декабря, 2008 - 01:02
#permalink

Долой MVC - да, здравствует MVC.

DOM документа сама построена в соответсвие с MVC. Поэтому подгружая свои свойства иметоды к DOM мы все равно включаемся в этот паттерн. Существенным удобством такого подключения является возможность использовать this в событиях, привязанных к элементу. Естественным ограничением для использования такого подхода является сложность объектов. Для сложных объектов, изменение состояния которых затрагивает сразу несколько элементов DOM (например вышеупомянутые таблицы), естественно легче организовать модель в объектах JavaScript.


Автор: 4pcbr, дата: 20 марта, 2009 - 00:55
#permalink

В корне не согласен с участниками отношений модели и вида.

В данном подходе выделяется визуальная часть элементов и css как участники отношений "вид" и манипуляция с элементами в отношение "модель".

В рамках javascript-приложения как некоего замкнутого объекта архитектура MVC действительно не имеет применения в классическом своем представлении, да и об изолированности участников говорить не приходится - она попусту не нужна. Но если рассматривать javascript-приложение как некий интерактивный элемент, котрый постоянно общается с удаленным сервером посредством ajax-запросов, то MVC незаменим.

В серверных приложениях мы выносим все, что касается клиентской части в отношения вид. Почему бы и здесь так не поступить: рассматривать DOM и CSS как единое целое, а модели дозволить выполнять свои законные задачи: управление данными, т.е. вынести в модель хранение промежуточных данных, бизнес-логику их обработки и ajax-интерфейс.

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

Именно такой функционал возложен на модель данных в архитектуре google gears


Автор: Константин Д (не зарегистрирован), дата: 3 мая, 2009 - 15:30
#permalink

Как правильно здесь заметили, идея MVC именно в абстрагированности этих компонентов. Второй аспект в том, что MVC это больше академический пример и реализация его в чистом виде не всегда приводит к желаемому результату.
Данный паттерн имеет много "подвидов", обусловленных структурой модели и логикой обработки событий, поскольку события могут быть не только пользовательскими кликами.

Веб приложения имеют специфику - в частности, они "от рождения" имеют выделенный View и интегрированный в него Controller. Кстати: вариант, когда Контроллер интегрирован в Предствление, также является классическим MVC. В данной статье, думаю, автор подменяет понятия Модели неким Кэшем - как промежуточного элемента хранения данных полученных от Модели.
Я некоторое время занимаюсь проблемой MVC для javascript и думаю, специфика не позволяет применить десктоп-наработки в неадаптированном виде.
Но идея однозначно востребована. Основными требованиями считаю:
1) Необходимость иметь любое количество Представлений (в т.ч. параллельных) одной Модели.
2) Контроллер должен уметь обслуживать все Представления
3) Модель ничего не должна знать о Представлениях
4) Представление не имеет права влиять на Модель

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


Автор: Keltanas (не зарегистрирован), дата: 19 июня, 2009 - 12:14
#permalink

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

Я бы понял еще объединение модели и контроллера, как обработчики данных ajax-запросов, но то, что Вы предлагаете - просто чудовищно.

И кстати я бы больше предпочел, чтобы некоторые данные обрабатывались все же не стороне клиента, чем на шаред-хостинге )))

В целом согласен с последними комментариями.


Автор: Митяй (не зарегистрирован), дата: 26 июня, 2009 - 05:13
#permalink

Тогда нафига нам нужен аякс? Давайте грузить сразу все возможные данные в js файлах...

ХА!
А реально, нафига Вам нужен аякс, когда данные точно известны и размер их с гулкин нос? Запихните в javascript hash их и будет всем счастье!
Оно конечно понятно, что когда в руках молоток все вокруг похоже на гвозди, но...


Автор: GueST (не зарегистрирован), дата: 13 июля, 2009 - 13:30
#permalink

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

Все меняется в сфере вебпрограммирования, и очень быстро!

Считаю, что все сказанное здесь выше не относится к YII Framework...


Автор: Nick Pepper (не зарегистрирован), дата: 16 ноября, 2009 - 07:11
#permalink

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


Автор: Regent, дата: 22 ноября, 2009 - 00:22
#permalink

Люди, покажите код с использованием MVC и без него, пожалуйста)


Автор: artem-check (не зарегистрирован), дата: 18 апреля, 2010 - 03:25
#permalink

Бред! Чушь полная!
Искренне жалко юных девелоперов, которые проникнутся этой статьей Sad

Конкретно, где чушь:
1. В аспекте данной статьи - автор ВООБЩЕ не имеет практического понятия об MVC. Так, верхушех нахватал...
2. "Паттерн MVC увеличивает количество кода за счет появления дополнительных межкомпонентных коммуникаций" - если это происходит, следует немедленно уволить программиста! Ибо каменщик он, или фрезеровщик, но ни разу - не программист.
3. "Межкомпонентные коммуникации Model-View добавляют тормозов" - смешно. Здесь и далее по тексту - человек не имеет ни малейшего понятия в том, о чем говорит.


Отправить комментарий

Приветствуются комментарии:
  • Полезные.
  • Дополняющие прочитанное.
  • Вопросы по прочитанному. Именно по прочитанному, чтобы ответ на него помог другим разобраться в предмете статьи. Другие вопросы могут быть удалены.
    Для остальных вопросов и обсуждений есть форум.
P.S. Лучшее "спасибо" - не комментарий, как все здорово, а рекомендация или ссылка на статью.
Содержание этого поля является приватным и не предназначено к показу.
  • Адреса страниц и электронной почты автоматически преобразуются в ссылки.
  • Разрешены HTML-таги: <strike> <a> <em> <strong> <cite> <code> <ul> <ol> <li> <dl> <dt> <dd> <u> <i> <b> <pre> <img> <abbr> <blockquote> <h1> <h2> <h3> <h4> <h5> <p> <div> <span> <sub> <sup>
  • Строки и параграфы переносятся автоматически.
  • Текстовые смайлы будут заменены на графические.

Подробнее о форматировании

CAPTCHA
Антиспам
8 + 5 =
Введите результат. Например, для 1+3, введите 4.
 
Текущий раздел
Поиск по сайту
Вакансии
Содержание

Учебник javascript

Основные элементы языка

Сундучок с инструментами

Интерфейсы

Все об AJAX

Оптимизация

Разное

Дерево всех статей

Статьи и мероприятия

Будьте в курсе наших последних новостей!

Последние обсуждения на форуме
Forum
Последние комментарии