Pull to refresh

Comments 108

Lamo code? Не согласен. Дебажить Pro code намного сложнее, потому что… до сих пор нет нормального способа получить список навешенных через addEventListener обработчиков.
Кадр вырван из контекста доклада. Используя обработчиков событий в атрибутах элементов, вы переходите на сторону зла! Смешивать представление и логику ради сомнительных бонусов при отладке…

Нормального нет(вообще это реально нужно?), но способы есть: сделать хук HTMLElement.prototype.addEventListener, FireQuery, Visual Event
Почему я перехожу на сторону зла? Не понимаю…

Представление и логику никто не смешивает, если переложить логику на представление.

Приведу простой пример. Вы придумываете идентификаторы, имена классов, которые нигде в CSS не используются, вводите новые, бесполезные с точки зрения «представления» сущности, только для того, чтобы работала ваша «логика». Таким образом «логика» влияет на «представление» даже если вы использовали ненавязчивый JS. Зачастую «ненавязчивые» скрипты требуют для работы вполне жестко описанную структуру DOM-дерева. Изменив структуру HTML все приходит в негодность и перестает работать. Чтобы скрипт снова начал работать, ему нужно или рассказывать постоянно про структуру, что откуда и по какому принципу брать, или же… переложить эту работу на само представление. Представление лучше знает, как оно устроено, и нужно всего лишь научить его попутно выполнять действия.

В свое время я извратил свое мышление в сторону, обратно-пропорциональное ненавязчивому JS. И как итог получил реально ненавязчивый JS.
Зависит от того, что у вас меняется чаще: логика или представление.

У вас приведён хороший пример, когда изменения в структуре HTML заставляют переколбашивать JS. Но бывает и наоборот: меняется структура и логика скриптов, и тогда вместо того, чтобы поправить список навешенных обработчиков в одном месте, придётся скакать по всему HTML и вносить изменения во многих местах. Что неизбежно повышает вероятность ошибки.
Пример можно?

Обычно представление доминирует в WEB. Генерировать динамически контент на основании данных и шаблонов очень затратный способ, хотя именно в нем гораздо удобнее использовать ненавязчивый JS
Я не про динамическую генерацию, я про изменения, вносимые в процессе разработки. Потвикал какой-нибудь модуль, изменил пару функций — и скачи по всему HTML-у, правь вызовы.
Да, такое есть. Вот только на практике получается так, что это дешевле все равно. Ты точно знаешь что ожидается от этого элемента, а не лазишь по файлам в надежде найти реальное место вызова.
Доля правды в этом есть, но на моей практике получается так: если верстальщики не дураки, то изменение представления делается через css, разметка меняется не сильно. А правильные классы позволяют также понять что это за элемент, и не трогать js.
>Чтобы скрипт снова начал работать, ему нужно или рассказывать постоянно про структуру, что откуда и >по какому принципу брать, или же

Эмм, даже в простейшем варианте без любых фреймворков и библиотек, разве document.getElement[s]By… не для этого то и создан был?

>Представление лучше знает, как оно устроено, и нужно всего лишь научить его попутно выполнять >действия.

Наглая ложь. Статическая часть представления после отрисовки тихо висит и молится, пока из-за пользовательский действий не наступит её удаление. А если в том представлении было что то на манер Lamo Code, то логика, которая якобы отлично смотрелась там, тупо исчезает, и в результате можно часами курить свой собственный код.
>> Эмм, даже в простейшем варианте без любых фреймворков и библиотек, разве document.getElement[s]By… не для этого то и создан был?

Таблица из 50 элементов, по 5 управляющих кнопок в каждой строке. Предлагаете по идентификатору к каждому элементу обращаться?

>> Наглая ложь. Статическая часть представления после отрисовки тихо висит и молится, пока из-за пользовательский действий не наступит её удаление. А если в том представлении было что то на манер Lamo Code, то логика, которая якобы отлично смотрелась там, тупо исчезает, и в результате можно часами курить свой собственный код.

Пример можно? Возможно мы про разные вещи говорим.
>>Таблица из 50 элементов, по 5 управляющих кнопок в каждой строке. Предлагаете по идентификатору к каждому элементу обращаться?

И так что мы имеем? 50 строчек копипаста вида
<a onclick='u touch my talala'>TOUCH NOW!</a>

каждой по 5 раз.
Или строку вида
 $('table > tr ').each(function(){}) 

и 5 строк селекторов с
 bind('click', callback)

для управляющих элементов.
>>Пример можно? Возможно мы про разные вещи говорим.
Да пожалуйста, я только за. Было у нас короче всё тоже самое
 $('table > tr ').each(function(){}) 

Мы когда то js'ом выбирали 1ю таблицу из документа при условии что её родитель не был DIV с ID=TABLE и убивали в ней все ссылки. Таблица в диве раньше была первой, но из-за дива, мы выбирали 2ю, потому что её родитель боди к примеру.
Спустя некоторое время мы убрали у первой таблицы DIV скрипт не поменяли, и что вышло.
Теперь мы убиваем ссылки в нашей первой таблице, хотя надо во второй. А в первой у нас была наша ЛОГИКА без которой мы теперь в просаке. Надо менять скрипты.
А если бы мы селекторами аккуратно сами всё выбирали и вешали эвенты то такой бы беды и не всплыло.
>> И так что мы имеем? 50 строчек копипаста вида

Данные генерируются скриптом. Поэтому получаем всего одну строчку в исходниках.

По второму примеру слабо понял в чем проблема. На аналогичные проблемы можно и с jQuery нарваться. Особенно когда два модуля работают с одним и тем же контентом или DOM-структурой.
>>Данные генерируются скриптом. Поэтому получаем всего одну строчку в исходниках.
Ну здрасьте приехали. Тут играем, тут не играем, а тут рыбу заворачиваем. Если генерим скриптом, что что сложно сделать усилие и повесить ещё и бинды? или просто нравится ощущение от надписи при наведении на ссылку javascript:doSomeReallyBigShit()??
Никогда не использую в href протокол javascript:

А я нигде не писал, что это статическая таблица, сделанная руками. Мы же вроде в рамках статьи обсуждение ведем, нет? А там про сложные веб-системы речь идет, а не о простых вебсайтах…
Напомню, что в данном примере уместнее было бы написать так:

$('table > tr ').delegate(, 'click', callback);
HTMLElement.prototype.addEventListener, FireQuery, Visual Event
Такой способ работает в ие? На сколько я знаю в ие HTML элементы наследуются не от одного, а от разных обьектов, или я ошибаюсь?
В ИЕ8- html элементы берутся как будто из воздуха :D
>>document.createElement('div').constructor
//undefined -- даже не null...

>>document.createElement('div') instanceof Object
//false -- забавно, правда? хотя магия с toString говорит обратное
>>Object.prototype.toString.call(document.createElement('div'));
//"[object Object]"

Ну и соответственно нет никаких конструкторов (Node → Element → HTMLElement → HTMLDivElement), которые мы могли бы пропатчить без плясок с бубном.
UFO just landed and posted this here
Не языка, объектной модели DOM
UFO just landed and posted this here
Почему это сложнее?
Никто не мешает из одной большой пожатой свалки модулей выдать браузеру кучу маленький распакованных кусочков.
//@ sourceURL=
UFO just landed and posted this here
В статье есть упоминание о нем.
Извините, статью просмотрел по диагонали.
UFO just landed and posted this here
пока не пробовал, я стараюсь держать как можно меньше логики в шаблонах и поэтому пока такой надобности не возникало
Один из лучших докладов на субботнике. Спасибо за текстовый вариант.
$.on('event', function (e) {
console.log(e.data);
});

Простите, или я что-то путаю, или вместо on должно быть bind/one.
Спасибо за интересную статью!
У функции подписки на событие много имен: addEvent, attachEvent, addEventListener, bind, on, subscribe, listen,… кто-нибудь продолжит? :) Как вы его назовете это не важно — я выбрал самый короткий.
Думаю тут опять проблема в том, что человек не понял что бакс в данном случае не jquery.
Да, возможно. Мне подобный вопрос задали на субботнике (по слайду 24). Добавлю примечание.
Хороший пример из серии «Масштабируемые JavaScript приложения» это ExtJs 4.
Спасибо большое. После вдумчивого прочтения статьи понял какую каку написал и, надеюсь, что надо исправить.
Я хорошо посмеялся, представив, что эти слава были сказаны человеком с этой аватаркой image
UFO just landed and posted this here
Активно используем. В данный момент еще и допиливаем, делая для себя плагины к vim/WebStorm.
Все там просто и удобно — получается полноценное ООП и куча плюшек аля type checking, области видимости и т.п.
Но ни столько library, сколько linter + compiler
UFO just landed and posted this here
У нас успешный опыт исп. данной библиотеки. Мы отказались от всяких свестелок-перделок типа JQuery (для того, чтобы не было клубка как нарисовано в начале поста). С комьюнити конечно напряг, приходится читать исходники closure-library (благо они очень хорошо документированы). В итоге написать сложное RIA приложение like Gmail просто не возможно с помощью чего-то другого без проблем с утечками памяти, наследовании.
>> Избегайте объявления обработчиков событий в атрибутах.

Почему? Три основные причины назовете?
1. MVC
2. Отладка
3. Поддержка
1. Выше писал, что логика зачастую диктует правила для представления. Поменяйте структуру HTML кода, и ваша логика рухнет в большинстве случаев.
2. Отладка событий, навешенных через addEventListener еще та боль. Тем более, без открытия трех исходников (а иногда и больше), в том, как работает код очень тяжело разобраться. Отладка проще, говорите?
3. Что с поддержкой не так? Детальнее можно?
>Поменяйте структуру HTML кода, и ваша логика рухнет в большинстве случаев.

Только если навешивание обработчика завязано на структуру (а не на идентификатор или класс элемента).
Если вы игнорируете глубину вложенности, то можете напороться на баг. У вас есть некий управляющий элемент с кнопкой «Закрыть», внутри которого есть несколько аналогичных элементов с кнопочками «Закрыть». Вам нужно навесть на одни кнопочки обработчик «сохранить_и_закрыть» а на другие «закрыть».

Ваши действия:

Вариант 1
Идентифицировать дополнительно кнопки, чтобы их типы явно отличались друг от друга. Тогда можно легко найти нужную кнопку по уникальному идентификатору. Как итог — проблема уникальности идентификаторов или ошибки неправильного определения функциональности кнопки.

Вариант 2
Привязаться к структуре самого управляющего элемента, ограничить распространение поиска кнопок до определенной глубины. Чревато багами из-за случайного изменения структуры.

Чем крупнее проект, тем изощреннее баги будут вылазить.
>Как итог — проблема уникальности идентификаторов или ошибки неправильного определения функциональности кнопки.

Как-то не возникало у меня доселе проблемы уникальности имён переменных.

Понятно, что если называть элементы button1, button2, то проблема уникальности встанет во весь рост, вот только проблема тут явно не связана с темой обсуждения.

А если присваивать осмысленные идентификаторы (closePageBtn, closePanelBtn, closeSmthElseBtn), то никакой проблемы не будет. А если таки будет, то тут уже нужно пересматривать весь UI, т.к. такое количество кнопок «Закрыть», да ещё и схожего назначения (в результате чего появляются схожие идентификаторы) — явный провал в дизайне UI.
Проблем уникальности нет, если интерфейс статический. Если добавить подгружаемые модули по мере работы пользователя с интерфейсом, то можно выхватить все прелести дубликатов.

Давайте рассмотрим следующий пример. У вас есть дерево-раскрывашка (как список директорий в проводнике). Есть замечательный элемент [+], при нажатии на который нужно открыть дочернюю ветку. Логично подравнять структуру HTML под такую, чтобы было легко выполнять данные манипуляции. Действия, которые нужно производить, просты — найти некий родительский элемент и ему присвоить класс, что ты показывай свои дочерние элементы. Но случилась «беда», дерево не просто огромное, а очень огромное, например, список улиц всех городов всех регионов страны. И было принято решение догружать данные по мере поступления. Другими словами, нужно найти некий контейнер, в который догрузить контент. И контейнер с дочерними элементами нужно не просто найти, а тот, который соотвествует элементу, а не все дочерние внутри него. Написать селектор можно, но как только изменится HTML структура, все сломается.

Мало того, в подгружаемых элементах нужно тоже каким-то способом активировать наши плюсики [+]. А все работает асинхронно… Вроде бы проблем нет. Но они почему-то всегда есть.
>Если добавить подгружаемые модули по мере работы пользователя с интерфейсом, то можно выхватить все прелести дубликатов.

В этом случае отлично работает связка «класс элемента + id с порядковым номером». Класс задаёт общее поведение, id идентифицирует конкретный экземпляр.

А в общем и целом, всё это дело вкуса, а о вкусах не спорят. Хотя если разобраться, то в большинстве случаев спорят как раз о вкусах %)
На порядковые номера нужно заводить менеджер идентификаторов. Иначе будет myID_1 и подгрузится еще раз myID_1. Я столько уже навыхватывал проблем с дубликаторами идентификаторов, что решил их использовать как можно меньше.

Тут спор даже не о вкусах, и даже и не спор. Я описываю типичные проблемы, которые возникают как раз при перегибах палки как в пунктах 6, 7, 10 общих тезисов статьи автора. Хотя, чего я так переживаю, каждый волен выбирать то, что ему ближе.
1. Смешивание логики и представления (JavaScript в шаблоне).
2. Невозможно навесить несколько обработчиков (но чаще всего бывает 1 обработчик).
3. Для событий в атрибутах необходимы глобальные объекты (чаще глобальные объекты и так торчат).
Забавно, что к примеру knockoutjs.com не считает п.1 зазорным. MVVM, однако.
[sarcazm]Да то наверное какие-то лошки-студенты писали...[/sarcazm]

Я похожий принцип уже года 4 в разработке использую. На jQ теперь смотреть не могу без слез. Вот такой я лошара.
По поводу JS в шаблоне. Как в таком случае следует расматривать такую, довольно таки удачную фичу, как _.template в underscore.js? С одной стороны конечно с ним очень частые проблемы, но зато крайне удобно.
Поступая так, вы не сможете использовать в обработчике внутреннее состояние какого-либо объекта, не делая его глобальным. Представьте, что у вас 50 модулей — что, всех их делать глобальными, чтобы обработчики могли с ними работать? Статья как раз про то, что подобные вещи мешают масштабируемости приложения.
У вас ООП мышление. Это не единственно правильное мышление в разработке. JS- скриптовый язык, и позволяет более гибко подходить к созданию приложений.

Например, я использую принцип активатор-диспетчер-обработчик. Событийная модель. При таком подходе становится банально все равно, сколько модулей, глобальные они или локальные, API диктует условия. И масштабируемость реализуется дешевле чем ядра, песочницы и прочее.
Расскажите подробнее, пожалуйста, про «принцип активатор-диспетчер-обработчик» желательно с небольшим примером. Буду признателен.
UFO just landed and posted this here
UFO just landed and posted this here
UFO just landed and posted this here
Примерно тоже самое предлагаю и я. Только вместо перечисления всех модулей используется функция препроцессора buildFrom (чтобы не копипастить имена).
UFO just landed and posted this here
Спасибо за статью. До многих вещей доходил самостоятельно. В частности, о пользе событий и слабого связывания. Но вместо событий jQuery стал использовать js-signals — библиотека помощнее, да и работает в разы быстрее. У них же есть сравнение между разными реализациями событий.
кстати, тоже пришел к этой же идеи и этой же библиотеке :)
Это закономерное движение в сторону event-based бибилиотек. Потому что они проще и легче масштабируются. Но требуют подготовки разработчика. С мышлением jQuery, mootools и прочих аналогов переходить на такие библиотеки гораздо сложнее
замена вызова метода на возбуждение события имеет и другую сторону: если запускается одно событие, а ловится другое (опечатка, неудачный рефакторинг, вливание стороннего кода несовместимой версии), то мы не получим в консоли ошибок вменяемого сообщения. вместо этого надо будет плясать с бубном в поисках этого расхождения. с тем же успехом можно написать что-нибудь типа try { Module2.getSomeValue() } catch( e ){ }
вызов метода — простейший способ доставки сообщения _с уведомлением о доставке_ (точнее с уведомлением о недоставке, но не принципиально). без этой фичи передача сообщений превращается в хаос, где никто ни за что не отвечает. я всё послал, какие претензии?: О а я ничего не получал, работать не буду!: О

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

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

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

далее, ты пишешь «Модули веб-приложений состоят из HTML + CSS + JavaScript + Ресурсы» но тут же приводишь в пример структуру директорий, где НЕТ МОДУЛЬНОСТИ. я не могу добавить или удалить модуль, без рассовывания всех его ресурсов по разным директориям и ручного контролирования всех зависимостей (а событийная модель лишь маскирует зависимости, но они всё-равно есть — добавлять модуль А может быть совершенно бессмысленно без модулей Б, В и Г). я пробовал писать много мелких модулей (не более нескольких килобайт каждый) с ручным прописыванием зависимостей, но уже при количестве в районе 50 начинается настоящий ад — мало того, что на каждый чих надо лезть в список зависимостей и добавлять нужное, так ещё и надо не забыть удалить ненужную зависимость, иначе она притянет тебе модули, которые будут висеть мёртвым грузом. поэтому первое что должен делать модульный фреймворк — обеспечить автоматическое управление зависимостями.

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

MySuperPuperCore.defineModule( function( sandbox ){
sandbox.DataGenerator= {

}
})

и пусть оно само заботится обо всём?

«sandbox.getResource('interval')» — надеюсь эта волшебная функция позволит мне задавать, чтобы один дата-генератор выдавал данные с одним интервалом, а другой — с другим?

«Нам необходимо загружать и регистрировать модули. Мы должны это уметь делать как при сборке так и динамически.» — то есть вместо того, чтобы сделать какой-нибудь index.js в который прилинковать сразу все необходимые модули с указанием их версий и быстро загрузить скопом только изменившиеся файлы, вы загружаете 1 модуль, когда он обратится к другому модулю — загружаете его, и так далее? если до сервера всего 5 мегабит через двойной впн, то это превращается в диалап.
О гарантированный доставке сообщения. В среде браузера событие доставляется всегда. Управлением ошибками транспортов занимается ядро — оно может генерировать то или иное событие в зависимости от результата транспортировки данных.
обеспечить автоматическое управление зависимостями
Про это я не упомянул, но при разработке чего-то более-менее большого без автоматизации никуда. Безусловно нужен скрипт, который будет создавать все эти мелкие файлы, будет управлять зависимостями и т.п. Вообще все что напрягает нужно автоматизировать.

О виде модуля. Я писал, что модули имеют не очень удобный формат из-за выбранной архитектуры и моих предпочтений писать максимум руками. Согласен, что можно подумать о более удачном формате при такой архитектуре. Например, мне очень нравится такой вид модуля Modules/Wrappings-Explicit-Dependencies
module.declare(function(require, exports, module) {
    exports.foo = "bar"; 
});
надеюсь эта волшебная функция позволит мне задавать, чтобы один дата-генератор выдавал данные с одним интервалом, а другой — с другим
Предполагается, что модули существуют в единственном экземпляре.

то есть вместо того, чтобы сделать какой-нибудь index.js в который прилинковать сразу все необходимые модули с указанием их версий и быстро загрузить скопом только изменившиеся файлы, вы загружаете 1 модуль, когда он обратится к другому модулю — загружаете его, и так далее?
для продакшен версии все статически собирается (все необходимые модули), подключаются зависимости (в итоге получается один файл). Некоторые опциональные части могут загружаться динамически — каждый модуль состоит из нескольких частей мелкие части мы можем собрать статически, а крупные (логика модуля) могут подключаться динамически. Так может быть, поэтому я заложил такую возможность в архитектуру. Подобное сделано в Я.Почте.
ну разумеется оно всегда доставляется, только не всегда тому, кто его ждёт ибо баг.

какой смысл автоматически генерировать эти мелкие файлы, чтобы с их помощью генерировать сборки, если можно сразу генерировать сборки?

ну так чем не угодил commonjs?

то есть как это в единственном? то есть я не могу вставить на страницу два датапикера чтоли?

ну разумеется для продакшена модули рассовываются по пакетам (пакетам модулей! модули вообще не должны знать как их раскладывают по пакетам и динамически грузиться должны именно пакеты, а не модули). речь шла о разработке, если это не очевидно.
только не всегда тому, кто его ждёт ибо баг
Частично этот баг устраняет дескриптор (песочница проверяет имя события перед биндом по дескриптору). Дескриптор же мы можем проверять автоматизированно.
какой смысл автоматически генерировать эти мелкие файлы
чтобы разделить соответствующие части модуля и модули друг от друга.
то есть как это в единственном? то есть я не могу вставить на страницу два датапикера чтоли?
Модули состоят из блоков/компонентов, определяемых версткой и css и js. Датапикер — компонент.
речь шла о разработке, если это не очевидно.
Как правило у разработчика бывает широкий канал, да и сервер часто бывает под боком. Так что загрузить 100 файлов не будет большой проблемой. Зато при возникновении ошибки в каком-либо модуле мы сразу будем знать его имя и строку(хороший бонус). В любом случае все можно гибко переделать. Например, в проекте над которым работаю я все собирается в 1н файл.
что если та же опечатка и в дескрипторе?

почему не разбить модули по директориям?

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

а иногда канал не очень широкий и тогда хочется громко материться. у вас в 1 файл при разработке пакуется? ну тогда сами себе злобные буратины. а по поводу бонуса — посмотри как сделано тут habrahabr.ru/blogs/css/96434/ то же самое не сложно сделать и для js
> что если та же опечатка и в дескрипторе?
Дескриптор можно проверить автоматизированно исходя из имеющегося списка событий(который тоже сферический в вакууме). Да и вообще от ошибок ни кто не застрахован при любом раскладе.

> почему не разбить модули по директориям?
Да, это как вариант структуры. Так будет даже лучше. Тот пример из статьи — это попытка обратить внимание разработчиков на правильный подход (я не утверждаю, что мой пример идеален и в нем нет изъянов).

>у вас в 1 файл при разработке пакуется?
не минимизируется(ибо глупо), но пакуется gz

>посмотри как сделано тут
Посмотрел. Посмотрите и вы clubs.ya.ru/bem/ ну хотя бы видео :)
А почему вы решили, что этот подход правильный?
Задача ставилась такая: «Показать, что поддерживать крупное веб-приложение с кодом как у типичного сайта невозможно» — причины я объяснил и показал возможный вариант решения. Опять же не утверждаю, что он идеален. Но поддерживать такой код более чем реально.
Что вам конкретно не нравится?
ещё раз: у нас есть 2 модуля, один бросает событие, другой ловит. как в дескрипторах указать, что событие которое ловит второй должно быть то же самое, что бросает первый? это не повод предоставлять для ошибок благодатную почву.

я лично присутствовал и был просто в ужасе от того, что вы наворотили. у вас абстракции лишь увеличивают сложность системы, вместо того, чтобы её уменьшать. яваскрипт, который парсится яваскриптом, чтобы сформировать яваскрипт, который формирует хтмл с инлайновым яваскриптом. собственный примитивный язык запросов с яваскриптовыми вставками, для которого даже подсветки синтаксиса нигде нет, что уж говорить о чём-то большем. в погоне за байтиками (которая началась слишком поздно — широкополосный инет уже стал массовым) вы наворотили настолько сложную систему с кучей условностей, что вливание нового человека в разработку без многодневных семинаров просто невозможна, а разработка возможна исключительно на сервере, ибо на локалхосте запаришься создавать всю необходимую инфраструктуру. казалось бы, зачем сервер для разработки яваскриптового модуля, который исполняться будет на клиенте?
trigger:newData
listen:newData
яваскрипт, который парсится яваскриптом, чтобы сформировать яваскрипт...
Сейчас вы говорите о препроцессоре, участвующий в сборке проекта, которому подсветка синтаксиса и тп не нужно. Он вставляется 1 раз в код и на века.
зачем сервер для разработки яваскриптового модуля, который исполняться будет на клиенте
сборка

trigger:newData
listen:mewData

и никакие автогенерированные тесты это не отследят
От ошибок, опечаток мы не застрахованы, все это знают. Но такую проблему мы можем отловить руками, подсчитав все события:
newData - 6 слушателей
mewData - 1 слушатель (подрзрительно)
когда число таких событий достигает сотен — обнаружить такое подозрительное место крайне сложно.
Согласен. Но большую часть их можно отловить. Вот другая идея. Есть модули с дескрипторами у некоторых модулей могут быть криво написаны события и дескрипторы.
Случай 1: кривой дескриптор, парильный модуль или наоборот
— при тестировании мы собираем логи песочниц и в этот лог попадет запись о том, что модуль пытается слушать или вызывать событие, которое не задекларировано.
Случай 2: у 1го модуля все кривое, соответственно тесты собраны тоже криво
— мы проводим статический анализ дескрипторов и смотрим, что такое-то событие слушает такой-то модуль, но другой модуль не порождает и наоборот. Так же у нас может быть список правильных событий, по которому мы можем сверять их имена.

Это не панацея против ошибок, но большую часть таким способом мы можем выловить.
Мне тоже не нравится лишняя сложность, и я каждый раз ищу компромиссы, в зависимости от проекта.
Да описанный подход имеет минусы, но также дает плюсы, вносит порядок. Я, конечно, не буду оригинальным в своей просьбе, но вы бы показали как правильно надо делать.
Спасибо, интересная статья. Многие рекомендации из нее можно использовать не только в клиентских js-приложениях.
Много слов, много перегруженных примеров, мало внятной и новой информации. Не зная таких простейших вещей, не стоит даже начинать писать «тяжелое приложение», лучше для начала саму дисциплину программирования подучить немного.

Все сказанное в статье можно описать тремя тезисами: 1) абстракция; 2) абстракция; 3) абстракция.

Не увеличивайте энтропию.
Мне кажется, что данное решение проблем расширяемости и поддержки приводит к другой проблеме — нарушению Главным Техническим Императивом Разработки ПО — управлением сложностью.

Совершенное необязательное увеличение сложности приведет к повышению порога вхождения в проект, вы пишете под номером 1: «С вами работают другие люди — уважайте их труд и цените их время»

Представьте ситуацию — главный архитектор по какой-либо причине недоступен. Приходит новый программист. Насколько легко ему будет влиться в проект?

Спасибо за статью, но вам не кажется, что описанная архитектура несколько излишняя?
В любом случае есть какой-то порог вхождения. Нельзя знать всего в первый же день.
описанная архитектура несколько излишняя?
Единственное, что мне кажется подозрительным — это обретка над базовой библиотекой.
Гм, по моему, это уже перебор (вспоминается статья про расчет факториала на Яве с абстрактными фабриками). Ну, ок, я могу еще понять использование слотов и сигналов для UI-компонент, это может быть полезно для наведения порядка в коде, но предложенный вами фреймворк крайне сложен для понимания. Я смотрю на структуру папок. и понимаю, что с такой структурой только разбираться, с чего начать создавать модуль, надо полчаса.

Касательно проблемы, упомянутой в начале статьи: связанности модулей и необходимости писать примитивный код инициализации в большом количестве экземплятров: а если переложить это на бекенд? То есть вы в шаблоне сайта (на сервере, не на клиенте), допустим, пишете: {insert tree datasource=someTreeModel} или {insert gallery images=«1.jpg,2.jpg,3.jpg»}, а этот шаблонизатор сам строит нужную HTML-структуру (с graceful degradation) и генерирует нужный JS-код инициализации дерева. Поменялся фреймворк/код для работы с деревом/галерееей — меняете шаблон этого самого дерева/галереи. И вся эта затея с модулями и событиями становится не нужна, так как у нас больше нет дублирования JS-кода.

Также, можно вспомнить примеры из реальной жизни: vkontakte — крупный сайт, не использует подобного, ограничивается в общем обычным, немодульным JS (и, что приятно, без jQuery! хоть в этом молодцы).

Ну и насчет кем-то упоминавшегося ExtJS: ExtJS на меня производит впечатление монструозного, тяжелого, тормозящего фреймоврка, который пытается сделать программирование компонент сайта похожим на программирование в десктопном окружении (формы там, layouts, и все такое). Только вот непонятно, зачем.
Для того, чтобы в вебе делать настоящие веб-приложения, а не только сайты-странички
Ваш подход в целом подходит для обычных сайтов (пусть даже и с большим количеством JS), а не веб-приложений. VK — не веб-приложение.
А что тогда? о_О
А чем VK отличается от админки CMS?
> А чем VK отличается от админки CMS?
Тем, что никому не придет в голову админить сайт через мобильник с оплатой трафика по 10р/Мб (без учета роуминга)
Слишком слабая связанность и большое количество абстракций — тоже плохо. На мой взгляд, в вашем примере дескрипторы только мешают. Если поменялся один модуль, или поменялось отношение одного модуля от другого нужно руками править дескрипторы. Где гибкость? Большое количество событий только запутывает. Про проблемы с дебагом уже говорили. Нет ничего смертельного в том, что какой-то модуль системы знает о существовании другого и вызывает его методы. Эта та же зависимость, которую вы скрываете с помощью событий и дескрипторов.
Модуль — микроприложение он вправе подключать какие угодно компоненты и работать с ними как ему вздумается. Чем меньше модуль знает о других модулях — тем лучше, тем проще поддерживать все приложение(события этому способствуют).
Одна из ролей дескриптора — описывать те события, которые слушает и генерирует данный модуль. Верно, что при добавлении события нам придется исправить как в модуле так и в дескрипторе. Но дескриптор это плюс: мы можем построить карту событий — знать сколько модулей зависят от такого-то события(удобно при переименовании), можем автоматизированно генерировать тесты, можем отлавливать ошибки при сборке (подключаем модуль, который слушает событие А, но не подключаем модуль, генерирующий событие А — сборщик вызывает варнинг). Без дескриптора такого не получить(можно, но сложно).
Если бы я был девушкой, то я бы ему дала! :)
Эх зазеличь, зря я тебя в свое время не дотыкал носом в нашу модульную систему.
У вас не правильный мед(!), который, в том числе, не удовлетворяет заявленным параметрам. А точнее не препятствует доступу модуля к тому коду который ему «не надо».
Обязательно проконсультируюсь у тебя. Начало видел, все хотел спросить к чему вы пришли.
Главное отличие в том что модуль явно, в файле своего определения, говорит кто он, из чего состоит и _кого_ему_нужно_.
На твоем коде это будет образно говоря значить что только то что он просил попадет ему в global, до остального он вообще никак, никакими хаками добраться не сможет.
В итоге получаем полное знание того что где используется, ну и какие хреновины один модуль может представить другим.
Полная чистота и прозрачность связности, и техническая невозможность делать кольцевые зависимости :)
А как насчет пост написать?
Окей, только не забываем что я не так крут как наши главное js-обозреватели :)
А главные js-обозреватели — они где?
вот прямо сейчас — на 5ом и 6ом месте в общем рейтинге :)
мне иногда кажется что одни придумывают как сделать код более запутанным, другие кричат как это круто и правильно и начинают реализовывать тонны кода ради простейшей вещи, а третьи пишут как проще разбираться в искусственно осложненном коде попутно делая еще одно наложение на нативный код, на который уже наложили 100500 крутых модных штук
в итоге вместо простого и красивого чистого кода получаем кучу библиотек, которые к 2кб реальных нужных данных подгружают еще 1-2 мб фигни… зато «модно выглядит» и «все так делают»
Когда ваше приложение разрабатывает, скажем, 5 человек (вероятно не супер-звезд), то 1-2 мб фигни оправдывают вообще не работающий код в противном случае.
А в фабрике loaderFactory нет ли ошибки? Там self в аргументе функции и переопределение ее в произведенной функции
Выбрал в качестве альтернативы для загрузки модулей require.js. Простая и удобная вещь.
Sign up to leave a comment.

Articles