(Архив) Matreshka.js — долгожданная реализация TodoMVC

    Введение
    Наследование
    MK.Object
    MK.Array
    Matreshka.js v0.1
    Matreshka.js v0.2
    Реализация TodoMVC

    Cайт Матрешки
    Github репозиторий.

    Всем привет! В этом кратком посте, представляю на суд общественности долгожданную реализацию «Hello, world на стероидах» — TodoMVC на базе фреймворка Матрешка.



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

    1. Никакой логики в HTML коде. Мне, как человеку, который с трепетом относится к JavaScript и HTML, хотелось бы, чтоб язык программирования так и остался языком программировния, я язык разметки — языком разметки.
    2. Не нужно отдельно слушать события данных, для того, чтоб обновить UI, и слушать события UI для того, чтоб обновить данные. Это возволяет избежать ошибок, типа «забыл повесить обработчик», так как не приходится хранить в голове несколько сущностей сразу. Вы задаёте правила, как данные синхронизируются с видом, а дальше работаете исключительно с данными.

    this.bindNode( 'x', 'select.my-select' );
    


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

    Реализацию приложения на базе Матрешки можно посмотреть здесь. А по этой ссылке — исходный код с аннотациями. Для тех, кто предпочитает русский язык английскому, прошу сюда.

    Приложение, как вы можете видеть, состоит из трех файлов:
    app.js — инициализация глобальных переменных (требуемых спецификацней TodoMVC) и приложения.
    todos.js — само приложение (список дел) и коллекция этих дел. Включает в себя основную часть логики приложения и реакцию интерфейса. Там можно увидеть специальный переопределяемый метод itemRenderer, который возвращает HTML узел (или HTML строку), являющийся HTML узлом модели. Напомню, масссив можно менять: добавлять, удалять элементы, сортировать (с помощью методов, позаимстсованных из Array.prototype), UI будет реагировать сaмостоятельно, без вмешательства разработчика.
    todo.js — элемент коллекции (пункт списка дел).

    Обратите внимание на несколько особенностей реализации:

    1. Почти вся логика, отвечающая за внешний вид, находится в привязках. HTML код почти не тронут, не считая подключения скриптов и вывода одного шаблона в отдельный тег.
    2. Минимум сущностей. По сути, два класса: класс отвечающий за коллекцию (Todos) и класс отвечающий за модель (Todo). Здесь мне могут возразить, мол, а как же паттерны проектирования, и будут правы: Матрешка не диктует требований использования MVC, который, на мой взгляд, часто избыточен. Вопрос идеологии и подхода: мне импонирует мысль о том, что вся логика, отвечающая за некий виджет находится в одном единственном файле. Если виджет состоит из других виджетов, их логика так же полностью выводится в JS файлы. Дробление виджета на несколько сущностей мне кажется неудобным. Хотя… если задуматься, можно сказать, что Model — данные приложения, View — HTML код, Controller — привязки. Если сильно хочется, то можно разделить Model и Controller (или, точнее, ViewModel), поместив их в два отдельных файла и связать их зависимостями.
    3. Минимум абстракций. Здесь нет раздражающего «умного» кода, только код, который делает то, что ему положено (камень в огород фреймворка JavaScriptMVC).
    4. Минимум кода: взгляните сами, из-за отсутствия излишнего абстрагирования, кода и вправду мало.
    (Здесь был текст о том, что более 90% кода понятны людям, которые не знакомы с фреймворком, но я посчитал это нечестным и вынес в опрос)

    В заключение, хочу сказать, что я не считаю другие фреймворки плохими. Ангуляр, например, очень неплох, но реализация паттерна MVVM, перекочевавшая из .NET среды в веб, мне кажется лишней. Этот вопрос, конечно, спорный, и, хорошо это или плохо, вам решать. Другой вопрос Backbone: с ним HTML код остаётся HTML кодом. Но его API меня не устраивает, а терминология кажется странной (ну как контроллер можно было назвать «View»?).

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

    Всем добра. Надеюсь на конструктивную критику в комментариях.

    Только зарегистрированные пользователи могут участвовать в опросе. Войдите, пожалуйста.

    Понятен ли код, представленный в реализации TodoMVC?

    Приемлема ли логика в HTML коде?

    Интересна ли тема Матрешки? Стоит ли, по вашему мнению, писать более подробные статьи?

    Matreshka.js
    24,00
    JavaScript фреймворк
    Поделиться публикацией

    Похожие публикации

    Комментарии 26

      0
      Приемлема ли логика в HTML коде?

      Странный вопрос. Что вы называете HTML кодом и что имеете ввиду под логикой? Шаблонизацию? Ну так ее использование неизбежно.
        0
        Я имею в виду именно логику. Вот несколько примеров из туториала AngularJS:

        <li ng-repeat="phone in phones | filter:query">
        
        Допустим, указание на то, что именно нужно вывести — приемлемо (хотя этого можно избежать), но указание на то, как фильтровать данные — лишнее. Этим должен заниматься JS код (опять же, по моему скромному мнению).

        <html ng-app="phonecatApp">
        ...
        <body ng-controller="PhoneListCtrl">
        
        Это уже не шаблонизация, это — программировние. HTML код не должен знать какой модуль/контроллер управляет им. По идеологии Матрешки об этом знает только JS код.

        <button ng-click="hello('Elmo')">Hello</button>
        
        Без комментариев.

        Пример из KnockoutJS:

        <a href='#' data-bind='click: $root.removeContact'>Delete</a>
        
        Тоже без комментариев.

        В Матрешке нет шаблонизации. Если говорить о коллекции, то мы ей должны дать элемент, который будет отрендерен, а какие именно туда попадут свойства (что к чему должно быть привязано) определяется в JavaScript.
          0
          Я для Knockout сделал свой велосипед, вынеся привязку в отдельный файл(когда надоели многострочные привязки)
              app.page<MusixBox.Main.Controller, MusixBox.Main.ViewModel>('main', p =>
                  p.template("common", "/Client/Pages/Main/View.html")
                      .viewBinder("common", (c, vm, ctl) => {
                          c['categoryList'] = {
                              template: {
                                  foreach: vm.Categories,
                                  name: '/Client/Pages/Main/cl-IT.html'
                              }
                          };
          
                          c['performerList'] = {
                              virtualScroll: <virtualScrollSettings>{
                                  loadFn: (l, f, c) => ctl.loadPerformers(vm.activeCategory().folderName, l, f, c),
                                  groups: vm.performersIndex,
                                  activeValue: vm.activePerformer,
                                  headerTemplate: '/Client/Pages/Main/pl-HT.html',
                                  headerHeight: 46,
                                  itemTemplate: '/Client/Pages/Main/pl-IT.html',
                                  itemHeight: 34,
                                  heightOverflow: 100,
                                  containerTemplate: '/Client/Templates/VirtualScroll/vlist-group-template.html',
                                  activeIndex: vm.activePerformerIndex
                              }
                          };
          

          И в коде html получается

          <!-- ... -->
          <div class="scroll-viewport" data-bind="bindId: 'performerList'"></div>
          <!-- ... -->
          
            0
            Ну вот сейчас я как раз пишу первое приложение на ангуляре, так и подумал что вы про него.
            Интересно что вы скажите о Shadow DOM, который является логичным развитием современного веба.
            Я раньше тоже был против логики в html, о которой вы говорите. Но эта самая логика позволяет очень сильно ускорить разработку и уменьшить кол-во шаблонного кода, который неизбежно приходится писать в Backbone и других подобных фреймворках.
            Например в популярном php шаблонизаторе Twig есть подобная фишка twig.sensiolabs.org/doc/tags/for.html#adding-a-condition, вроде пользуются, никто не считает что это плохо.
            Мне кажется в шаблонах можно описывать логику отображения, иначе код превращается в абстракции ради абстракций.
              0
              Интересно что вы скажите о Shadow DOM, который является логичным развитием современного веба.

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

              … кол-во шаблонного кода, который неизбежно приходится писать в Backbone и других подобных фреймворках
              Вот вот. Я достаточно спотыкался о шаблонный код, хочу писать меньше, получать больше. Самым оптимальным вариантом для меня было создание своего фреймворка, которому, кстати говоря, около двух лет, но выложен в качестве опен-сорц сравнительно недавно.

              Например в популярном php шаблонизаторе Twig есть подобная фишка twig.sensiolabs.org/doc/tags/for.html#adding-a-condition, вроде пользуются, никто не считает что это плохо.

              Сравнение шаблонизатора для PHP и для клиентского JS, на мой взгляд, — неверно. PHP не манипулирует элементами динамически при наступлении каких-то событий, он генерирует статичный HTML. Ангуляр, на мой взгляд, — идеальный инструмент для простого вывода данных. Если требуется только лишь это + простые дополнения, типа события нажатия кнопки, лучше этого инструмента я и не знаю. В PHP, да и в любом другом серверном языке, я бы тоже использовал шаблонизатор.
          +3
          Хороший код, тот которого нет. А в контексте приложения и концепта — логика как энергия, если она пропадает в одном месте, то обязательно должна появится в другом. А архитектура, наподобии некой философии, определяет основы "мироприложениездания" обозначая сущности и слои, награждая каждого своей логикой, ролью и обязаностью.
          Если наделять html обьязанностями представления, тогда разумеется там же должна находится и логика связанная с предствалением. Где какие данные показывать(интерполяция), какие елементы обновлять при изменении модели(биндинг), какие комманды вызывать при неких действиях пользователя(сигналы/события) и т.д. Резумеется не любую логику можно описать в html, в силу специфики синтаксиса, но подобные простые вещи отлично ложатся на плечи html кода. А такие строки как this.bindElement( 'x', 'select.my-select' );) и this.on('click', '.mysuperselector', this.hello) создают ненужную зависимость контроллера от представления и раздувают сам контроллер.
            –2
            Самая большая проблема любых js фреймворков, это то что на них нельзя писать не зная это самый js.
              –1
              А в каком языке есть фреймворки, на которых можно писать не зная языка?
              А хотя постойте… Boost из C++ как раз подходит на эту роль.
              –1
              То есть контролируемая и исправимая ошибка вида «разработчик на месте забыл повесить обработчик» перетекает в «разработчик фреймворка допустил ошибку в коде биндинга», которые решаются только с помощью дичайших хаков?
                0
                Разработчик и в обработчике может допустить ошибку. А где, пардон, дичайшие хаки?
                  0
                  Вопрос в том, на каком уровне будет баг. Если фреймворк все взаимодействие берет на себя, то влезть и поправить будет намного сложнее, чем свой собственный код.
                    0
                    Это проблема любого фреймворка и библиотеки.
                      0
                      Неправда. Хороший фрэймворк позволяет эффективно работать с собственной структурой и предусматривает возможность «вклиниться» в критичных местах. У данного фреймворка логика биндингов критична и непонятно можно в нее вклиниться или нет.
                        0
                        Можно конкретнее? Что значит «вклиниться»?
                      0
                      Да, фреймворки — это зло, нужно все писать самим.
                        0
                        Неправда.
                          0
                          Тогда что это за фобия неизбежного? Лучше уж поймать дичайший баг в фреймверке, исправить его дичайшим хаком, замержить изменения в мастер, и проблема решиться у всех разом.
                  0
                  Очень интересный инструмент. Спасибо за старания. Думаю, это ценный вклад в развитие разработки для фронтенда.
                  Не понятны два момента по фреймверку:
                  * Зачем создавать дополнительную сущность, и связывать ее с элементом DOM? Если не удобно работать с DOM, может быть просто лучше сделать свой удобный DOM?
                  * Почему этот инструмент называется фреймверком? В нем ведь нет ничего кроме двухстороннего связывания элементов и переменных.

                  И один момент по TodoMVC. Вы писали:
                  класс отвечающий за коллекцию (Todos) и класс отвечающий за модель (Todo)
                  Почему Ваши классы отвечают за сферу деятельности, а не описывают сущности? Если это не ООП, тогда зачем говорить о классах, когда в JS классов вообще нет?
                    0
                    Почему этот инструмент называется фреймверком? В нем ведь нет ничего кроме двухстороннего связывания элементов и переменных.
                    Там еще много чего. Советую ознакомиться с предыдущими статьями.
                    Почему Ваши классы отвечают за сферу деятельности, а не описывают сущности?
                    Это претензия к реализации или просто игра терминами?.
                    Если это не ООП
                    весь JS — ОО язык.
                    когда в JS классов вообще нет
                    Их нет до тех пор, пока их не реализуешь.
                      0
                      Спасибо. Вы, видимо, пропустили первый вопрос:
                      Зачем создавать дополнительную сущность, и связывать ее с элементом DOM? Если не удобно работать с DOM, может быть просто лучше сделать свой удобный DOM?

                      Почему Ваши классы отвечают за сферу деятельности, а не описывают сущности?
                      Это претензия к реализации или просто игра терминами?
                      Вот это я и хотел узнать :) Ок, пошел по ссылкам посмотреть код. Вроде похоже на ООП. Тогда это, наверное, претензия к терминам :)
                        0
                        «сделать свой удобный DOM» — это как?
                          0
                          Ну, это имеет смысл только если верно мое предположение, что причина создания таких биндингов — неудобство работы с DOM.

                          Как? Ну вот так. Есть DOM. Это стандарт, но ведь кто-то его придумал. Придумайте свою нестандартную объектную модель документа, с удобным для работы интерфейсом. Или даже не модель документа, а интерфейс доступа к элементам документа, поверх DOM. Вот например ваш подход:
                          mk.bindElement( 'x', '.my-select' ); mk.x = 3;
                          В jQuery реализован как-то так:
                          $('my-select').val(3);
                          Т.е. делать не биндинг, а обертку. Интерфейс становится удобнее, а сущности не плодятся.
                            0
                            Мне кажется, ваша идея похожа на React.
                              0
                              Может быть. Но по-моему, он ужасен! Какой-то Франкенштейн программирования.

                              Но речь не о React. Я хотел узнать, почему Вы выбрали именно такой подход с созданием дополнительных сущностей.
                                0
                                Потому что я не считаю DOM чем-то неудобным (с некоторыми оговорками).
                                  0
                                  Ясно. Спасибо.

                  Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.

                  Самое читаемое