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

Форум

Учебник Node.JS скринкаст Стандарт языка

Справочник

Discord чат

 
Статьи Тест знаний Аналоги функций PHP

Курсы javascript

 

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

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

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

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

Два слова об 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 приводит к излишнему дублированию данных.

Богатое(Rich) представление

Что такое 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 ?

Минусы использования DOM/View как Model

Минусы, как и плюсы, связаны с производительностью.

Скорость доступа к свойствам элементов DOM

При работе исключительно с javascript, работа идет в едином пространстве интерпретатора javascript. Это куда быстрее, чем обращаться к DOM-объектам, который в Microsoft относятся к COM, в Firefox - к XPCOM, в общем - живут отдельно от javascript-движка.

Утечки памяти при коммуникации DOM-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.

Паттерн Flyweight (приспособленец)

Существует единый объект, который при небольшой "доинициализации" может выполнить роль любой из однотипных компонент интерфейса.

Например, рассмотрим контекстное меню для javascript-дерева, которое вызывается правым кликом мыши на элементе.

Вместо пачки меню - для каждого элемента дерева своё, создается единый объект ContextMenu.

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

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

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

Частичное отделение

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

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

Заключение

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

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


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

#permalink

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


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

#permalink

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


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

#permalink

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


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

#permalink

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

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





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

#permalink

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

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


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

#permalink

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

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

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


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

#permalink

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

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

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

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


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

#permalink

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

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


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

#permalink

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

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

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


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

#permalink

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


Автор: Regent, дата: 21 ноября, 2009 - 23:22

#permalink

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


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

#permalink

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

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


Автор: Гость (не зарегистрирован), дата: 9 сентября, 2010 - 08:44

#permalink

Нормальная статья! Если че хранить надо, можно всегда в input hidden строке засунуть виде JSON. Особенно это хорошо работает с такими библиотеками как JQuery, MooTools и иже с ними.


Автор: monolithed, дата: 7 января, 2011 - 18:11

#permalink

Внесу свои 5 копеек по теме JavaScript MVC: http://javascriptmvc.com


Автор: Гость (не зарегистрирован), дата: 9 августа, 2011 - 06:24

#permalink

Стиль текста автора заставляет усомниться в опыте разработки на javascript.

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

Любой паттерн влияет на количество кода, но MVC за эту часть кода дает гибкость и поддерживаемость. Кстати, в рамках MVC в javascript, модель ничего не знает о контроллере, только о модели. Вот храните вы данные в верстке, представление поменялось раз, у вас добавились новые вычисляемые поля, часть старых скрылось (как предложили тут, стали hidden), потом еще и еще. После пятой итерации такая модель будет хуже представлений в MVC, а я считаю что представления — главное слабое место в MVC, там много избыточности, плохая связь с логикой приложения, и высока вероятность, что во время поддержки там будут дописывать код, вместо обновления старого добавляя лишние условия (if (false), ага).
Вы сами представляете что будет если в верстке хранить части логики, "если значение поля больше трех то ставить переключатель в положение 1" и при этом попытаться часть данных вынести сервис, часть вынести в модальное окно. Придется переписывать весь код, вместо внесения пары правок в модель и представление.
Ну, в общем, я не согласен со статьей. Начальная идея правильная, но выводы крайне странные.


Автор: zz top (не зарегистрирован), дата: 4 декабря, 2011 - 03:57

#permalink

А если, чисто гипотетически предположить, что мы имеем дело с разработкой javascript приложения, которое в своей работе использует webworkers. Webworkers-объект ведь не знает, что такое DOM. Соответсвенно в данном случае модель может быть представлена только javascript-объектами, никак не DOM-объектами. И концепция, предложенная автором, уже не подходит для описанного случая. Просто размышление.


Автор: Гость (не зарегистрирован), дата: 23 апреля, 2012 - 10:52

#permalink

спасибо большое


Автор: flash (не зарегистрирован), дата: 15 мая, 2012 - 17:58

#permalink

А я поддерживаю автора в том, что такие вещи как роутер, контроллер - это черный ящик, и ошибку можно искать очень долго.
А если весь код написан без всяких шаблонов... то и баг найти гораздо быстрее!
Я бы сравнил MVC и ASP.NET
это как подобие макроязыка и обычного языка высокого уровня.
Где сейчас макроязыки? всем известно, что MS больше не развивает эту тему, ибо она тупиковая!
Так что asp.net без серверных контролов + js + c#
гораздо приятнее и удобнее!


Автор: Гуест (не зарегистрирован), дата: 21 июля, 2012 - 11:14

#permalink

В свете появления knockout.js рассуждения о MVC вызывают улыбку
Я серьезно, если кто-то еще не знаком с паттерном MVVC, попробуйте Knockout или его аналоги.


Автор: Гость (не зарегистрирован), дата: 10 января, 2013 - 13:08

#permalink

Большое спасибо за информацию о Knockout!


Автор: Гость (не зарегистрирован), дата: 2 июля, 2013 - 23:13

#permalink

Помоему бред- я все коменты не читал - но точно знаю и скажу -

MVC - + XML(template)
+php mvc фреймворк

вот это нормально - а js придуман для других целей - подгрузка данных и т.п.

я например совмещаю PHP MVC + JS(JSON) -

джава скрипт подгружается именно тот и с тем контроллером что нужен - и скрипт джейсон обращается непосредственно к методам контроллеров.

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


Автор: raqy.style (не зарегистрирован), дата: 12 февраля, 2014 - 16:56

#permalink

Для всего свои задачи. В spa-приложениях сложно обойтись без mvc. В приложениях, в которых дом генерируется серверным приложением - можно и даже нужно. Иногда бывают сложные, реально сложные интерфейсы. В таком случае, лучше сложно обойтись без MVVM. Мне печально смотреть как трудяги пытаются выстроить, например, готовой фин отчет по департаментам, сотрудникам с разбивкой по датам, возможностью горизонтального/вертикального "сворачивания" таблиц и динамическим фильтрованием данных без ajax запросов только лишь с помощью jQuery. Это больно. В таким случаях сложно без mvvm.

имхо, для рекламной странички достаточно будет грамотного ванила-js.

и вообще, для многих javascript - это jQuery


Автор: Гость (не зарегистрирован), дата: 26 февраля, 2014 - 12:06

#permalink

Реализовывать MVC, когда представление идет по средствам DOM действительно (может быть) затратно. Приходится размывать границы модели и представления, что не оправдывает такой (MVC) подход; в последнем проекте весь интерфейс делали на canvas'е и MVC себя полностью оправдал, особенно с точки зрения того, что представление _полностью_ независимо от модели (клиенты часто хотят новые фичи интерфейса и смешивание модели и представления приводит к (почти) полному переписыванию некоторых частей).


Автор: Гость (не зарегистрирован), дата: 3 июля, 2016 - 04:08

#permalink

У меня обычно Model - это данные в формате JSON, которые приходят с сервера. Соответственно, контроллеры посылают AJAX запросы, получают результат и вызывают методы представлений с новыми параметрами для обновления интерфейса.


Автор: Гость (не зарегистрирован), дата: 9 июня, 2018 - 17:18

#permalink

Использование таких штук как W3View позволяет забыть об особенностях View в браузере и работать с представлениями в любом стиле - хочешь MVC, хочешь MVVM, Flux, можно ещё что нибудь придумать, если надо

https://habr.com/post/348258/
https://habr.com/post/349866/


Автор: antiguans2000, дата: 28 декабря, 2021 - 18:31

#permalink

Если работа с объектом преимущественно не требует обновления внешнего вида, то можно подумать о выделении модели в целях производительности.
.


Автор: James Linm (не зарегистрирован), дата: 28 декабря, 2021 - 18:32

#permalink

У меня обычно Model - это данные в формате JSON, которые приходят с сервера. Соответственно, контроллеры посылают AJAX запросы, получают результат и вызывают методы представлений с новыми параметрами для обновления интерфейса.


 
Текущий раздел
Поиск по сайту
Содержание

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

Последние темы на форуме
Forum