13​ ​выводов​ ​которые​ ​я​ ​сделал,​ ​после​ ​4​ ​лет​ ​использования​ ​Ext JS

в 9:38, , рубрики: adminpanel, extjs, javascript, Библиотека ExtJS/Sencha, Блог компании Онлайн школа EnglishDom, Разработка веб-сайтов

Привет. Хочу поделиться опытом использования Ext JS для быстрого построения сложных интерфейсов. Я фронтенд-разработчик в EnglishDom, и мы разрабатываем онлайн-сервисы для изучения английского языка. У меня 6 лет коммерческого опыта в фронтенде, и 4 из них я работаю с Ext JS. Также имею опыт работы с Backbone, React и Ember. Сегодня поговорим про Ext JS, я расскажу свою историю использования, особенности разработки и после каждой небольшой истории я буду делать вывод. Прошу всех под кат.

Небольшая предыстория

Я пришел в EnglishDom в 2013 году, и первая моя задача была — разработать административную панель для текущего функционала и для будущих сервисов. Мне хотелось взять Backbone и Bootstrap или Ember и Bootstrap слепить из этого архитектуру и написать свой UI фреймворк. Одним из вариантов было использовать Ext JS как UI фреймворк, что показалось мне интересным, несмотря на то, что я не имел опыта работы с ним.

Я пошел разбираться в документации, смотреть примеры, и через полдня я написал первую таблицу (grid) с локальными данными.

Вывод 1: порог вхождения небольшой, все ясно и просто.

Выглядит это модуль сейчас так же как и раньше.

image

Обратил внимание, что за первые 2 дня работы я не написал ни одного html-тега и уже забыл, как пишутся селекторы в CSS. Но то, что у меня получилось, было кроссбраузерно.

Вывод 2: в Ext JS создавать UI кроссбраузерно приятно и быстро.

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

Вывод 3: код на Ext JS напоминает большой конфигурационный файл.

Например, вот так выглядит код таблицы: 109 строк и много вложенности, и это без хранилища, только представление.

Код представления таблицы

Ext.define('KitchenSink.view.grid.ArrayGrid', {
    extend: 'Ext.grid.Panel',
    requires: [
        'Ext.grid.column.Action'
    ],
    xtype: 'array-grid',
    store: 'Companies',
    stateful: true,
    collapsible: true,
    multiSelect: true,
    stateId: 'stateGrid',
    height: 350,
    title: 'Array Grid',
    viewConfig: {
        stripeRows: true,
        enableTextSelection: true
    },

    initComponent: function () {
        this.width = 600;
        this.columns = [
            {
                text     : 'Company',
                flex     : 1,
                sortable : false,
                dataIndex: 'company'
            },
            {
                text     : 'Price',
                width    : 75,
                sortable : true,
                renderer : 'usMoney',
                dataIndex: 'price'
            },
            {
                text     : 'Change',
                width    : 80,
                sortable : true,
                renderer : function(val) {
                    if (val > 0) {
                        return '<span style="color:' + 'green' + ';">' + val + '</span>';
                    } else if (val < 0) {
                        return '<span style="color:' + 'red' + ';">' + val + '</span>';
                    }
                    return val;
                },
                dataIndex: 'change'
            },
            {
                text     : '% Change',
                width    : 75,
                sortable : true,
                renderer : function(val) {
                    if (val > 0) {
                        return '<span style="color:' + 'green' + '">' + val + '%</span>';
                    } else if (val < 0) {
                        return '<span style="color:' + 'red' + ';">' + val + '%</span>';
                    }
                    return val;
                },
                dataIndex: 'pctChange'
            },
            {
                text     : 'Last Updated',
                width    : 85,
                sortable : true,
                renderer : Ext.util.Format.dateRenderer('m/d/Y'),
                dataIndex: 'lastChange'
            },
            {
                menuDisabled: true,
                sortable: false,
                xtype: 'actioncolumn',
                width: 50,
                items: [{
                    iconCls: 'sell-col',
                    tooltip: 'Sell stock',
                    handler: function(grid, rowIndex, colIndex) {
                        var rec = grid.getStore().getAt(rowIndex);
                        Ext.Msg.alert('Sell', 'Sell ' + rec.get('company'));
                    }
                }, {
                    getClass: function(v, meta, rec) {
                        if (rec.get('change') < 0) {
                            return 'alert-col';
                        } else {
                            return 'buy-col';
                        }
                    },
                    getTip: function(v, meta, rec) {
                        if (rec.get('change') < 0) {
                            return 'Hold stock';
                        } else {
                            return 'Buy stock';
                        }
                    },
                    handler: function(grid, rowIndex, colIndex) {
                        var rec = grid.getStore().getAt(rowIndex),
                            action = (rec.get('change') < 0 ? 'Hold' : 'Buy');

                        Ext.Msg.alert(action, action + ' ' + rec.get('company'));
                    }
                }]
            }
        ];

        this.callParent();
    }
});

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

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

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

Вывод 5: Фреймворк пропагандирует свой архитектурный подход (MVC and MVVM), следуя которому у тебя не будет велосипедов и проблем

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

Вывод 6: Документация великолепна, JSDuck — хороший инструмент

Вот так в JSDuck выглядит иерархия наследования, зависимости, саб-классы для компонента таблицы.

13​ ​выводов​ ​которые​ ​я​ ​сделал,​ ​после​ ​4​ ​лет​ ​использования​ ​Ext JS - 2

А так документация к таблицам.

13​ ​выводов​ ​которые​ ​я​ ​сделал,​ ​после​ ​4​ ​лет​ ​использования​ ​Ext JS - 3

Я писал в основном простые компоненты, так как задачи были тоже простые. Чаще всего это вывести таблицу, сделать дерево (treepanel). Но после приемки нового функционала продуктовой командой они указали на некоторые недостатки предоставленного интерфейса.
Необходимо была другая пагинация, фильтрация таблицы и еще пару мелочей, которых в стандартном наборе не было. И их не было даже в официальных плагинах.
У таблиц например 184 метода и 105 разных событий. Вроде этого должно хватать даже для самой каверзной задачи и интерфейса.

105 событий таблиц

activate
add
added
afterlayout
afterrender
beforeactivate
beforeadd
beforecellclick
beforecellcontextmenu
beforecelldblclick
beforecellkeydown
beforecellmousedown
beforecellmouseup
beforeclose
beforecollapse
beforecontainerclick
beforecontainercontextmenu
beforecontainerdblclick
beforecontainermousedown
beforecontainermouseout
beforecontainermouseover
beforecontainermouseup
beforedeactivate
beforedeselect
beforedestroy
beforeexpand
beforehide
beforeitemclick
beforeitemcontextmenu
beforeitemdblclick
beforeitemmousedown
beforeitemmouseenter
beforeitemmouseleave
beforeitemmouseup
beforereconfigure
beforeremove
beforerender
beforeselect
beforeshow
beforestaterestore
beforestatesave
blur
boxready
cellclick
cellcontextmenu
celldblclick
cellkeydown
cellmousedown
cellmouseup
close
collapse
columnhide
columnmove
columnresize
columnschanged
columnshow
containerclick
containercontextmenu
containerdblclick
containermouseout
containermouseover
containermouseup
deactivate
deselect
destroy
disable
dockedadd
dockedremove
enable
expand
filterchange
float
focus
glyphchange
headerclick
headercontextmenu
headertriggerclick
hide
iconchange
iconclschange
itemclick
itemcontextmenu
itemdblclick
itemmousedown
itemmouseenter
itemmouseleave
itemmouseup
lockcolumn
move
processcolumns
reconfigure
remove
removed
render
resize
select
selectionchange
show
sortchange
staterestore
statesave
titlechange
unfloat
unlockcolumn
viewready

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

Вывод 7: хоть фреймворк содержит много всевозможных компонентов и API к ним, не все задачи можно решить, а open source плагины не всегда “из коробки” работают.

Прошло время, и у нас уже было более 20 разделов в админке: они позволяли тонко работать и управлять контентом, пользователями, обращениями студентами, рассылками, мониторингом сервера и ошибками. Я был как разработчик рад — все работало, багов почти не было. В какой-то момент начались обращения и жалобы от пользователей админки. Проблема в том, что были подвисания и лаги в их любимом браузере.
Это было связанно с тем, что Ext JS создает много DOM узлов, очень много происходит repaint, a fps иногда опускается до 0.
Решение этой проблемы — оптимизировать код (есть советы, как это делать) и апгрейдить железо.

Вывод 8: Ext JS — «тяжелый» фреймворк.

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

Вывод 9: сообщество активно помогает в решении проблем и фреймворк действительно живой.

Конечно, в свете популярности open source, с Ext JS не все так просто и понятно. Про лицензирование на Хабре есть хорошая статья, комментарии к ней тоже полезны.

Вывод 10: надо внимательно читать лицензию и находить свой вариант использования фреймворка.

У компании Sencha много других продуктов. Я всеми инструментами не пользовался, но например React Ext JS и Sencha Architect я бы с удовольствием опробовал в деле, так как раньше я не встречал таких продуктов.

Вывод 11: Хорошая экосистема, которая развивается.

Так как наша компания очень сильно волнуется за клиентов и их прогрессом обучения, и хочет следить за каждым аспектом обучения. Чтобы выполнить эту задачу, без хорошей CRM не обойтись. Было принято техническим отделом написать свой инструмент, угадайте — на чем? При чем мы его написали вместе с новым цифровым учебником. Задача оказалось простой и за 1 спринт (10 дней) силами 2 разработчиков (frontend и backend) была написана простая MVP CRM которая агрегировала все обращения студентов и преподавателей, создавала задачи в системе и сама система была похожа на Kanban доску со статусами тикета. А по каждому обращению можно в пару кликов решить проблему и вести переписку с юзером (парсинг email писем и переписка со студентом и преподавателями).
Я уверен, если бы мы выбрали другой фреймворк, эта задача заняла намного больше времени.

Вот так выглядит этот инструмент.

13​ ​выводов​ ​которые​ ​я​ ​сделал,​ ​после​ ​4​ ​лет​ ​использования​ ​Ext JS - 4

Задачи можно переносить между столбиками (drag and drop). Каждая задача открывается в модальном окне. Где можно увидеть всю историю обращений и там же решить сам тикет.

Вывод 12: Позволяет сосредоточиться на бизнес-логике приложения и писать ее с первых минут задачи.

Тут я хотел бы остановиться поподробнее.

Я считаю этот вывод одним из самых важных, который я сделал после долгого времени работы с Ext JS и параллельной работе с задачами по клиентскому приложению, которое написано на Backbone и ReactJs. Мне есть с чем сравнить.
Этот один из многих примеров удачного выбора технологии для решения конкретной задачи. Написание бизнес логики — это то, что от разработчика ожидает заказчик и за что ему собственно и платят.

Чаще бывает так — берут модный фреймворк и тратят кучу времени на то, чтобы подружить разные плагины (например react-redux с react-router при помощи react-router-redux), пишут очередной компонент и выкладывают его в opensource, пишут свой крутой 100500-й роутер или плагин под babel. А можно вообще сделать свой компонент IF, Switch для JSX.

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

Все же вернемся к основной теме.
Я был единственным человеком, который писал эту систему, и меня всегда мучал вопрос: сможет ли новичок на нашем проекте, который ни разу не работал с Ext JS, разобраться с системой и как скоро он сможет выдавать результат. После ввода нового сотрудника и инструктажа по работе над этим проектом результат оказался очень достойный. Опасения не оправдались.

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

Вывод 13: код на Ext JS прошел проверку временем.

Итоги

Благодаря различным задачам, с которыми нам приходилось сталкиваться, опыт в разработки на Ext JS мне очень понравился и он несравним с другим опытом на других фреймворках. Некоторые архитектурные методы, подходы и красота API мне очень понравилось. Я даже мечтал реализовать такие же подходы самостоятельно на других фреймворках (очередной велосипед).

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

Бонусы для читателей

13​ ​выводов​ ​которые​ ​я​ ​сделал,​ ​после​ ​4​ ​лет​ ​использования​ ​Ext JS - 5

Мы дарим бесплатный доступ на три месяца изучения английского с помощью наших онлайн-курсов. Для этого просто перейдите по ссылке до 31 декабря 2017 года.

13​ ​выводов​ ​которые​ ​я​ ​сделал,​ ​после​ ​4​ ​лет​ ​использования​ ​Ext JS - 6

Будем рады видеть вас на индивидуальных занятиях курса «Английский для IT-специалистов».
Пройдите бесплатный вводный урок и получите комплексную обратную связь по своему уровню знаний, затем выбирайте преподавателя и программу обучения себе по душе!

Автор: nicksyndicate

Источник


https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js