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 - 19:46
#permalink

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


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

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


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

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


Автор: Rom (не зарегистрирован), дата: 17 июля, 2013 - 23:50
#permalink

Илья, согласен, удобно. Но не быстро. Если у вас моделька небольшая (по количеству айтемов) - держите данные в ДОМ.
Для нескольких тысяч айтемов поиск в ДОМе существенно грузит проц.

Вобщем, исходите из задач.


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

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


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

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


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

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

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


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

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

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


Автор: Armen Markossyan (не зарегистрирован), дата: 28 декабря, 2010 - 11:25
#permalink

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

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

Я не вижу ни одного случая, когда MVC будет хуже, чем спагетти из php, sql и html/css/js.


Автор: yks (не зарегистрирован), дата: 29 декабря, 2010 - 00:51
#permalink

А что вообще такое MVC?
Это абстракция, за которой в реальности стоит банальное разделение функционала, без которого не обходится ни одна программа. Утрированно,

alert("Hello")

- это тоже MVC, в которой alert- это view, "Hello" - это model, а контроллер - это вызывающий скрипт.
Поэтому с одной стороны соглашаясь с Вами, Armen Markossyan, о необходимости разделения источников и обработчиков данных (как актив-пассив в бухучёте ), и соглашаясь с тем, что статья, в общем-то, ни о чём, хочу сказать, что "единственный правильный подход" - это в корне неверная фраза, чем-то напоминающая о 1937 годе. Для каждого проекта нужен свой подход. (Извиняюсь, что это напоминает о другой фразе...)
В принципе, при грамотно поставленном процессе разработки такие вещи, как читаемость кода и скорость его выполнения, и так рассматриваются, и нужды заострять на этом внимание в отдельных статьях попросту нет. А если не рассматриваются, то ... RTFM


Автор: Armen Markossyan (не зарегистрирован), дата: 16 января, 2011 - 13:49
#permalink

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

Если вы собрались делать большой проект, то никто вам, конечно, не запретит придумать свой паттерн и правила, согласно которым будет все спроектировано. Это займет много времени и вам будут нужны действительно опытные программисты и "архитекторы", чтобы они ничего не упустили на этом важном этапе. А MVC - это уже почти общепринятый стандарт, из чего следует, что вам не придется учить новеньких программистов тому, как писать код, какие правила и ограничения на него накладываются, не придется изобретать велосипед и морочить себе голову, придумывая грамотную архитектуру. Порог вхождения в разработку вашего проекта становится ниже, что нельзя не считать большим плюсом.

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


Автор: Василий Д (не зарегистрирован), дата: 9 апреля, 2011 - 22:53
#permalink

>>alert("Hello")
>>- это тоже MVC, в которой alert- это view, "Hello" - это model, а контроллер - это вызывающий скрипт.

Спорно, alert - это команда контроллера к view, он сказал сделать alert, а как уже это сделает view его не интересует.

"Hello", да - это данные, вы их не получили из модели и это создаст вам проблемы, если вы захотите сделать интернационализацию сайта, например. Но если мультиязычность не важна, то все ок.


Автор: 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 добавляют тормозов" - смешно. Здесь и далее по тексту - человек не имеет ни малейшего понятия в том, о чем говорит.


Автор: ps99 (не зарегистрирован), дата: 19 ноября, 2010 - 11:27
#permalink

Уважаемый, а Вы сами программируете на JS?


Автор: Гость (не зарегистрирован), дата: 16 ноября, 2012 - 15:31
#permalink

сплошные эмоции
а аргументы где?


Автор: Гость (не зарегистрирован), дата: 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" и при этом попытаться часть данных вынести сервис, часть вынести в модальное окно. Придется переписывать весь код, вместо внесения пары правок в модель и представление.
Ну, в общем, я не согласен со статьей. Начальная идея правильная, но выводы крайне странные.


Автор: Alex654 (не зарегистрирован), дата: 25 февраля, 2019 - 16:50
#permalink

>Вы сами представляете что будет если в верстке хранить части логики

Автор вроде бы такого и не предлагал. Да и как вообще возможно в вёрстке хранить логику? Как вы себе это представляете?


Автор: 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 или его аналоги.


Автор: Гость (не зарегистрирован), дата: 18 июня, 2013 - 15:08
#permalink

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

Если человек не обделен мозгом, то он архитектуру и так прекрасно вообразит и реализует, а не будет использовать трактор для того, чтобы вскопать грядку в 5 метров длиной.


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

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


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

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

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

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

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

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

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


Автор: Darklordis (не зарегистрирован), дата: 30 октября, 2013 - 23:35
#permalink

MVC используется в случаях: различных источников данных и одного их представления (редкий случай), одного источника данных и множества представлений (частый), а также если реализовано множество источников с множеством представлений (как MS Access например). В иных случаях использовать MVC глупо. Если у вас за один раз обрабатывается один запрос то оно вам к чему? " вас одна модель и одно представление + вырожденный контроллер.


Автор: 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 запросы, получают результат и вызывают методы представлений с новыми параметрами для обновления интерфейса.


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

Учебник javascript

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

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

Интерфейсы

Все об AJAX

Оптимизация

Разное

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

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