Всем привет, меня зовут Дмитрий Карловский и я… хочу причинить вам боль. Много боли. Я напомню вам обо всех страданиях, что вы исптываете находясь в плену своего любимого js-фреймворка. Я опущу вас на самое дно самой глубокой безысходности. А потом, когда вы совсем отчаетесь и потеряете веру в комьюнити, я подам вам руку помощи и покажу светлое будущее.  Далее вашему представляется текстовая расшифровка одноимённого выступления c IT Global Meetup #11. Вы можете читать её как статью или же открыть в интерфейсе проведения презентаций. Приятного чтения. Вот выбрали вы фреймворк. Как вы представляете себе работу с ним? Ну, это должен быть богатый набор готовых решений, из которых можно легко и быстро собрать приложение любой сложности.  Примеры таких фреймворков: ExtJS, SAPUI5, VCL.JS, $mol — они предоставляют вам кучу готовых виджетов, от банальных кнопочек, до сложных гридов с сортировками, фильтрацией и прочими прекрасными дамами. Но могие ли слышали про них? А многие ли используют их в повседневной работе? Не многие. Что странно, не находите? К сожалению, более популярны сейчас низкоуровневые фреймворки, дающие только самые базовые абстракции над платформой, а всё остальное приходится реализовывать уже руками или искать на просторах интернета, и прикручивать синей изолентой. То есть для каждого проекта мы собираем уникальный высокоуровневый фреймворк на основе низкоуровневого.  Примеры таких фреймворков у всех на слуху. Это: Angular, VueJS, EmberJS и многие другие. В последнее время вновь набрал популярность тренд строить экосистему вокруг отдельных узкоспециализированных библиотек. Тут всё ещё хуже — в каждом проекте приходится сначала собрать из кучи библиотек низкоуровневый фреймворк по своему вкусу, а поверх него уже велосипедить компоненты, которые зачастую не отличаются переиспользуемостью за пределами разрабатываемого проекта.  Наиболее известные примеры: React, Backbone, jQuery Почему же высокоуровневые фреймворки так не популярны и из проекта в проект мы пилим одни и те же велосипеды?  Дело в том, что большинство из них имеют крайне низкое качество. Они огромные, тормозные, сложные в изучении, а главное — очень дубовые, из-за чего кастомизация их компонент под проект сравнима по трудоёмкости с написанием этих компонент с нуля. Но из общего ряда монстров выбивается фреймворк $mol. Он легковесней и шустрее многих низкоуровневых фреймворков, но при этом идет с богатым набором батареек в комплекте, позволяющих собрать сложное приложение буквально несколькими строками кода.  И это богатство совсем не отягощает конечное приложение, ведь включается в него лишь тот код, что реально необходим. Итак, возьмём наиболее ярких представителей из трёх разных уровней: библиотеку React, низкоуровневый фреймворк Angular и высокоуровневый $mol. Создадим каждым из них по тривиальному статичному приложению и посмотрим какие накладные расходы дают разные инструменты. Вручную создавать проекты на Реакте и Ангуляре — задача не тривиальная, поэтому используем стандартные кодогенераторы (create-react-app и angular/cli). Они около минуты генерируют кучу файлов, после чего вы уже можете удалить лишние и добавить нужные. В $mol же новое приложение создаётся просто созданием директории и расположением в ней нужных вам файлов, без установки восьми сотен зависимостей. Как видите высокоуровневый фреймворк $mol даёт в 3 раза меньшую прибавку к размеру страницы чем одна только библиотека React. Что обычно нужно для того, чтобы воспользоваться сторонним компонентом? Не очень удобно, правда? Основной принцип $mol — автоматизация, так что воспользоваться сторонним компонентом крайне просто.  Сборщик сам позаботится о скачивании его исходников и включении их в правильные места результирующих бандлов. А что обычно приходится делать, когда компонент больше не нужен? Столько всего нужно не забыть, чтобы в вашем приложении не было лишнего кода. А что же делать, когда вам больше не нужен какой-либо $mol компонент? Другой основной принцип $mol — не платить за то, что не используешь. А это значит, что достаточно перестать использовать компонент, чтобы он перестал включаться в бандл. Всё крайне просто и надёжно, ведь человеческий фактор исключён полностью. Допустим, вы нашли два замечательных компонента: красивый datepicker и продвинутый datagrid. Но вот беда, один во всю использует возможности новой версии фреймворка, а другой с ней ещё не совместим. Что же делать, если отказываться от одного из них не хочется, а хочется уже и самим использовать новые возможности, но переписывание всех старых компонент может занять не один месяц?  Вы можете попытаться включить в бандл обе версии фреймворка, но это мало того, что существенно раздует объём приложения, так ещё и скорее всего не заведётся. Хотя бы даже потому, что пакетный менеджер не позволит вам установить одновременно две версии одного фреймворка. А если это даже и удастся, то драки между версиями будет не избежать. Поэтому...  В $mol модули не имеют версий. Вместо этого они разрабатываются в соответствии с принципом "открытости/закрытости". Это значит, что вы можете безопасно обновлять все модули до последних ревизий, не беспокоясь о том, что у них изменился API. Но что же делать, когда нужно ввести более удобное API не совместимое с уже существующим? А всё просто — если API не совместимо, то это уже другой модуль с другим именем. Имя может быть и похожее. Например, с увеличенным числом в конце. А раз это будут два разных модуля, то и сосуществовать в проекте они смогут одновременно. При этом у них может быть много общего кода, вплоть до: один — это не более чем легковесный фасад для другого.  На диаграмме вы видите, что гипотетическая новая версия движка рендеринга $mol компонент, при сосуществовании с предыдущей, лишь незначительно увеличит общий объём бандла. Могли ли вы себе представить такое в каком-либо другом фреймворке? Кстати, не удивляйтесь тому, что модули в $mol такие маленькие, ведь при автоматизации работы с зависимостями, создавать и использовать микроскопические модули — одно удовольствие. Вручную рулить потоками данных — настоящий ад. Вы вроде бы продумали все варианты, учли все события, но стоит отдать результат тестировщикам, как на вас потоком начинает валиться куча баг-репортов, являющихся следствием противоречивой логики. Для совладания с оной у вас есть два пути. В Angular ставку сделали на концепцию стримов, где вы статически настраиваете потоки событий и реакции на них. К сожалению, любое нетривиальное приложение имеет много динамики, а значит составить для него эффективную конфигурацию потоков — настоящая головоломка. Посмотрите только как на стримах выглядит правильное условное ветвление по двум переменным. И это ещё довольно простой пример.  Реактивные ячейки же являются просто контейнерами, которые сами отслеживают зависимости между собой, динамически выстраивая потоки данных наиболее оптимальным образом. Тут мы просто объявляем свойство, которое является функцией от других свойств, при изменении которых наше тоже будет обновлено наиболее эффективным образом. Уверен вы слышали про VueJS или MobX — они как раз основаны на концепции ячеек. Но реализация в $mol — самая продвинутая. Вот, что умеет $mol, чего не умеет ни один другой фреймворк. Да-да, у нас есть деструкторы с предсказуемым моментом исполнения. Всё это — наглядный пример того, как грамотная архитектура позволяет писать гибкий, умный и эффективный код, не теряя при этом в наглядности и не раздувая его размеры. Наверняка каждый, съевший JavaScript собаку, может припомнить в своей практике не одну увлекательную историю, когда из-за одной маленькой опечатки он пол дня бился с каким-нибудь невозможным багом. Проблема в том, что человек — существо по природе своей невнимательное. Он легко допускает самые глупые ошибки, а потом может не видеть их, смотря на них в упор.  Решением этой проблемы является статическая типизация, позволяющая компьютеру автоматически и за конечное время проверить корректность кода, разгружая мозг программиста от кучи мелочей и позволяя ему концентрироваться на действительно важных вещах. Но много ли вы знаете фреймворков, написанных на TypeSript? Я знаю всего 4. Это низкоуровневые Angular и CycleJS, а также высокоуровневые VCL.JS, и… $mol. Все остальные попросту непригодны для разработки более-менее крупных проектов. Ну как не пригодны… вам просто нужно каждый год удваивать число разработчиков, чтобы только лишь сохранять прежний темп разработки.  Ок, прикрутили мы datepicker, и он даже работает. Да вот беда, выглядит он как белая ворона в чёрном квартале. Если разработчик компонента во имя великой инкапсуляции изолировал стили с помощью css-in-js, css-modules или даже web-components, то можно вас только поздравить с необходимостью стилизовать сторонний компонент через вязанку костылей. Например, такого рода селекторы у вас могут появиться при необходимости стилизовать дни в выпадающем календарике в datepicker-е. Важно понимать разницу между инкапсуляцией и изоляцией.  Инкапсуляция позволяет работать со сложной штукой через простой интерфейс, но не мешает и погрузиться во внутренности, когда это действительно необходимо. Изоляция же — гораздо более сильное ограничение, которое связывает нас по рукам и ногам, и заставляет форкать сторонний компонент, чтобы органично вписать его в своё приложение. $mol пронизан инкапсуляцией с ног до головы. Но изоляции в нём нет. Вообще. Никакой. Даже в скриптах. Зато в $mol есть глобальные уникальные человекопонятные имена и единые правила стилизации, что своих, что сторонних компонент. В приведённом примере, имя "my_date_calendar_day" формируется автоматически по следующему принципу… Сперва берётся глобальное имя компонента ("my_date"), потом к нему приклеивается локальное имя календарика в контексте владельца ("calendar") и так далее до нужного компонента, как бы глубоко в иерархии он ни находился. Самое приятное в стилизации $mol компонент — программисту не надо вручную прописывать портянку классов каждому дом-элементу — они генерируются автоматически исходя из сформированного дерева компонент. Вы только представьте: можно разрабатывать компонент совершенно не думая о его стилизации, но при этом иметь полный контроль за визуализацией любого дом-элемента. Без костылей, гор копипасты, увеличения специфичности селекторов и прочих гадких штук. Возьмём первый попавшийся шаблон на Angular из документации. Что не так с этим кодом? С точки зрения поддержки у него две беды: отсутствие уникального класса у каждого элемента и его неимоверная дубовость. Что мы будем делать, если на одной странице из 20 нам потребуется убрать подзаголовок, на другой добавить после него параграф с описанием, а на третьей выводить имена героев до идентификатора, а не после? Вариантов тут не очень много... Самое простое — скопипастить шаблон несколько раз и поправить его по месту. Но тогда мы получаем очень много дублирования и необходимость эти похожие, но разные дубликаты синхронно рефакторить. Эта мартышкина работа — тот ещё рассадник багов. Другая крайность — это научить компонент любым выкрутасам, которые от него могут где-либо потребоваться. И каждый раз когда кому-то потребуется что-то ещё — расширять компонент новыми возможностями. С таким подходом компонент очень быстро превращается в большой тяжёлый швейцарский нож, который неудобно использовать и очень сложно поддерживать. И всё-равно в нём появляется копипаста, когда требуется переставлять элементы местами, добавлять обёртки и другим образом изменять структуру в зависимости от состояния. Любая динамика в шаблонах — это боль и страдания от программирования на HTML. Размышление над проблемами шаблонов неизбежно приводят к мысли, что они… вообще не нужны. Если программист оперирует компонентами, а браузер JS и DOM объектами, то зачем нам эта мимикрия под HTML, не обладающего выразительной мощью для описания компонент? У HTML очень ограниченная модель. Это помимо его крайней многословности. А для компонент нужны: строки, числа, флаги, словари, массивы, пользовательские типы данных, двустороннее и одностороннее связывания свойств, уникальное имя каждого подкомпонента, наследование, смешивание, частичное переопределение и, наконец, программная логика написанная на полноценном языке программирования. Всё это с очень тугим скрипом натягивается на стержень HTML. Поэтому.. В $mol вообще нет шаблонов.  Никакого больше подражания HTML-у — только компоненты и их взаимоотношения. В $mol есть простой и наглядный язык для композиции компонент, который позволяет в декларативной форме описать какой компонент в каком лежит, какое имя в нём имеет и как с ним связан. Он настолько прост, что я научу вас его основам всего за 5 минут. Вот, мы создали компонент $my_heroes, который наследует свойства от самого базового компонента $mol_view. Одна строчка кода из двух имён. Что может быть проще? В том же Angular вам потребуется минимум 5, плюс ещё 2 на импорт и регистрацию. Чтобы объявить новое или переопределить существующее свойство — просто пишем его имя с отступом, а через пробел — значение по умолчанию. Тут мы переопределили свойство "sub", которое будет возвращать список вложенных компонент. Внутри у нас будет 3 компонента: заголовок, подзаголовок и собственно список героев. Стрелочка влево означает получение значения свойства, а после неё идёт собственно объявление этого свойства указанием его имени и значения через пробел. Всё, что начинается с "$" — это классы компонент. Их свойства тоже можно переопределять. Вводя всё новые и новые свойства мы можем построить наглядную иерархию любой нужной нам глубины. Тут например, сразу видно, что заголовок мы выводим во вложенный компонент по имени Title, подзаголовок — в Title_sub, а строчки с героями в Rows. Обратная косая черта предваряет сырые данные, которые могут содержать любые символы, кроме перевода строки. Мечтали ли вы о таком счастье в html или json? Зашивать тексты в коде, конечно, просто и быстро, но что насчёт локализации? Просто добавляем собачку и текст после неё будет вынесен в отдельный файл с переводами, а в сгенерированном из view.tree TypeScript классе будет лишь обращение по человекопонятному ключу. web.locale=en.json heroes.view.tree.ts Обратите внимание, что кусочек исходника, ответственного за данное свойство всегда выводится рядом в комментарии. Что позволяет очень быстро освоить синтаксис view.tree. Обычные свойства возвращают всегда одно значение. Мультисвойства могут возвращать разные значения в зависимости от переданного им ключа. В данном случае ключом для строк героев и всего, что в них находится у нас будет их порядковый индекс. Итак, зачем нам вся эта свистопляска с кучей свойств? Дело в том, что каждое такое свойство — это точка расширения. Мы можем изменить в компоненте любой аспект поведения, просто переопределив соответствующее свойство. Тут мы создали новый компонент на основе базового, но вместо вложенного компонента просто возвращаем null, что приводит к полному исключению его из рендеринга. Переопределяя списки мы можем добавлять новые компоненты между уже существующих. Тут мы объявляем компонент который является точь в точь компонентом $my_heroes, но после заголовков имеет дополнительный тут же объявленный блок с описанием. И разумеется мы можем легко и просто переставлять местами компоненты, где-нибудь в глубине. Например, имя и идентификатор героя. Язык view.tree настолько удобен для описания компонент, что его так и тянет использовать для описания вообще любых классов. И это на самом деле возможно, но только осторожно. Но иногда ведь нужна нетривиальная логика для вычисления свойств. А логику лучше всего описывать на языке для этого предназначенном. Поэтому мы просто наследуемся от автоматически сгенерированного из view.tree класса и переопределяем его свойства, реализуя любую хитрость. Тут мы загрузили json массив с данными героев с сервера, для каждого героя создали по строке отображения, объявленной во view.tree, и объявили мультисвойство возвращающее имя героя по его порядковому номеру. Как-то лишком просто, не находите? Но в этом вся и суть, что абстракции должны упрощать разработку, а не усложнять её. А теперь о грустном — проблеме петуха и яиц.  Разработчики не горят желанием изучать инструмент по которому мало вакансий. А компании — завязываться на инструмент по которому мало специалистов. Так и получается, что светлые идеи упрощающие и удешевляющие разработку помирают в тени более крупных, но менее функциональных библиотек, вынуждающих писать кучу однотипного кода с кучей велосипедов. Примечателен опыт Тинькофф банка, где команда из лучших чем я специалистов долго разрабатывала новую версию интернет-банка на модном Реакте. Получился довольно тормозной монстр с меньшей функциональностью, который потом ещё очень долго оптимизировали. Но результат всё ещё далёк от совершенства.  На $mol меньшей командой за меньший срок можно было бы достигнуть куда большей отзывчивости интерфейса. Причём сразу, а не после жалоб пользователей. Или пример с конференции РИТ 2017, где ребята из Wrike рассказывали про Angular и React. Слайды они показывали через специально написанное для выступления приложение, позволяющее аудитории в реальном времени голосовать за один из фреймворков.  Как вы думаете, на каком же фреймворке они его реализовали?  На jQuery. Потому что на нём оказалось это сделать проще. Кстати, мне оказалось проще запилить приложение на $mol. Делайте выводы. Есть более существенный недостаток малого сообщества...  Когда мейнтейнер обессиленно падает оземь, его флаг приходится подхватывать тому, кому это больше всего нужно. Понимая это, я разрабатывал $mol таким, чтобы поддерживать его было не более трудоёмко, чем конечное приложение на его основе. В нём не более 10 тысяч строк кода, сгруппированных в небольшие узкоспециализированные заменяемые модули, имеющие весьма плоскую структуру. Это капля в море по сравнению с любым более-менее крупным приложением. И это та капля в которой разобраться скорее всего будет проще всего. Не стоит забывать и про социальную составляющую. У нас нет огромных маркетинговых бюджетов, поэтому мы не можем позволить себе фрагментацию сообщества в духе Angular, где одна половина пилит приложения на TypeScript, другая половина на JavaScript, а третяя вообще на Dart. Мы концентрируемся на том, чтобы всё наше небольшое сообщество могло совместными усилиями развивать общую базу компонент. Незачем велосипедить каждому в своём проекте одни и те же типовые решения. Лучше посвятить время созданию чего-то по настоящему нового. Надеюсь мне удалось заразить вас идеями $mol. Предлагайте свои. Или просто расскажите о своей боли, а вместе мы что-нибудь придумаем, чтобы её больше не было. Адвокат Дьявола