13 conclusions that I made after 4 years of using Ext JS

    Hello, Habr. I want to share my experience using Ext JS to quickly build complex interfaces. I am a front-end developer at EnglishDom, and we are developing online services for learning English. I have 6 years of commercial experience in the front end, and 4 of them I work with Ext JS. I also have experience with Backbone, React and Ember. Today we’ll talk about Ext JS, I’ll tell you my usage history, development features and after each small story I’ll draw a conclusion. I ask everyone under cat.

    A little background


    I came to EnglishDom in 2013, and my first task was to develop an administrative panel for the current functionality and for future services. I wanted to take Backbone and Bootstrap, or Ember and Bootstrap to mold from this architecture and write my own UI framework. One option was to use Ext JS as a UI framework, which seemed interesting to me, despite the fact that I had no experience with it.

    I went to understand the documentation, watch examples, and after half a day I wrote the first table (grid) with local data.

    Conclusion 1: the entry threshold is small, everything is clear and simple.

    This module now looks the same as before.

    image

    I noticed that in the first 2 days of work, I did not write a single html tag and already forgot how to spellCSS selectors . But what I did was cross-browser .

    Conclusion 2: in Ext JS, creating UI cross-browser is pleasant and fast.

    Another point that I noticed: these are long (more than two hundred lines) configurations for views, storage (store) and transport (proxy). It was unusual to write them, because instead of definitions, I wrote objects nested in arrays, which are nested in other objects, and so on. For better or worse, I don’t know, but then it was unusual for me.

    Conclusion 3: Ext JS code resembles a large configuration file.

    For example, this is how the table code looks: 109 rows and a lot of nesting, and this is without storage, just a view.

    Table view code
    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 '' + val + '';
                        } else if (val < 0) {
                            return '' + val + '';
                        }
                        return val;
                    },
                    dataIndex: 'change'
                },
                {
                    text     : '% Change',
                    width    : 75,
                    sortable : true,
                    renderer : function(val) {
                        if (val > 0) {
                            return '' + val + '%';
                        } else if (val < 0) {
                            return '' + val + '%';
                        }
                        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();
        }
    });
    


    After some time, more complex tasks began to come. For example, in one task it was necessary to dynamically change the configuration of the view, in another to change the standard transport for the backend, in the third you need to get the context of the current view in one of the methods. I also noticed that duplicate code is already appearing in several components.

    Conclusion 4: the entry threshold is small, but building a high-quality architecture at once will fail.

    To solve these problems, I had to pause and re-read the documentation and specialized sites. Having made several discoveries, I began to more thoughtfully, scalably, modularly and expandably, write new code and refactor the old one.

    Conclusion 5: The framework promotes its architectural approach (MVC and MVVM), following which you will not have bicycles and problems

    After that I began to spend more time reading documentation. In the documentation, each component has a component hierarchy (inheritance chain), which modules it uses, you can see the source code of a particular method, see public / private / forbidden / new / chain methods, and a list of all events.

    Conclusion 6: The documentation is great, JSDuck is a good tool.

    This is how inheritance hierarchy, dependencies, subclasses for a table component look like in JSDuck.



    And so the documentation for the tables.



    I wrote mostly simple components, since the tasks were also simple. Most often it is to display a table, make a tree ( treepanel) But after accepting the new functionality by the product team, they pointed out some of the shortcomings of the provided interface.
    It needed another pagination, filtering the table and a couple of little things that were not in the standard set. And they were not even in the official plugins.
    For example, tables have 184 methods and 105 different events. Like this should be enough even for the most tricky task and interface.

    105 table events
    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

    It seemed to me that the current functionality is also suitable and it solves the user's problems, but since there was time, it was decided to write the interface, as required. I went to the official forum and on GitHub to look for plugins for these tasks. There were enough of them, of different quality. There were plugins that just clearly solved the tasks, but they were unofficial, without good documentation, and they had bugs. I had to rewrite them or generally rewrite a lot.

    Conclusion 7: although the framework contains many various components and APIs for them, not all tasks can be solved, and open source plugins do not always work out of the box.

    Time passed, and we already had more than 20 sections in the admin panel: they allowed us to finely work and manage content, users, student appeals, mailings, server monitoring and errors. I was glad as a developer - everything worked, there were almost no bugs. At some point, appeals and complaints began from users of the admin panel. The problem is that there were freezes and lags in their favorite browser.
    This was due to the fact that Ext JS creates many DOM nodes, a lot of repaint happens, and fps sometimes drops to 0.
    The solution to this problem is to optimize the code (there are tips on how to do this) and upgrade the hardware.

    Conclusion 8: Ext JS is a "heavy" framework.

    It also happened that I could not find the answer to my questions. In general, I knew how to solve this problem (another bike), but I wanted to write “in the right way”, and left the “bike” for the most extreme case. I asked questions on the forum, and surprisingly, they answered me quickly enough and helped solve problems.

    Conclusion 9: the community is actively helping to solve problems and the framework is really lively.

    Of course, in light of the popularity of open source, with Ext JS, not everything is so simple and clear. There is a good article about licensing on Habré ; comments on it are also useful.

    Conclusion 10: you need to carefully read the license and find your own version of using the framework.

    Sencha has many other products. I did not use all the tools, but for example React Ext JSand Sencha Architect, I would love to try it out, as I have never seen such products before.

    Conclusion 11: A good ecosystem that is developing.

    Since our company is very worried about customers and their training progress, and wants to follow every aspect of training. To complete this task, good CRM is indispensable. It was decided by the technical department to write a tool, guess what on what? What do we write it with the new digital textbook. The task turned out to be simple and in 1 sprint (10 days) by 2 developers (frontend and backend) a simple MVP CRM was written that aggregated all the requests of students and teachers, created tasks in the system and the system itself was like a Kanban board with ticket statuses. And for each appeal, you can solve the problem in a couple of clicks and correspond with the user (parsing email letters and correspondence with students and teachers).
    I am sure that if we chose a different framework, this task would take much more time.

    This is what this tool looks like.



    Tasks can be moved between columns (drag and drop). Each task opens in a modal window. Where you can see the entire history of calls and there to solve the ticket itself.

    Conclusion 12: Allows you to focus on the business logic of the application and write it from the first minutes of the task.

    Here I would like to stop in more detail.

    I consider this conclusion to be one of the most important that I made after a long time working with Ext JS and parallel work with tasks on the client application, which is written in Backbone and ReactJs. I have something to compare.
    This is one of many examples of the successful choice of technology for solving a specific problem. Writing business logic is what the customer expects from the developer and for what he is actually paid.

    More often it happens - they take a fashionable framework and spend a lot of time making friends with different plugins (for example react-redux with react-router using react-router-redux), write another component and put it into opensource, write their own cool 100500- th router or plugin for babel. And you can even make your own component IF, Switch for JSX.

    All this is great, but if you look at it from the side of business, it’s like the developer creates a problem for himself , speaks at every corner about the complexity of its solution, and after a while he heroically solves it, and those watching him clap. Something like this.

    Still, back to the main topic.
    I was the only person who wrote this system, and I was always tormented by the question: can a newcomer to our project, who has never worked with Ext JS, figure out the system and how soon it will be able to produce a result. After introducing a new employee and briefing on working on this project, the result was very decent. Fears did not materialize.

    4 years have passed since the beginning of the development of the administrative panel. New frameworks, techniques and approaches have appeared, the old ones became not fashionable, some were not very fashionable. Part of our functionality is no longer needed by business, part of it we rewrote a long time ago, and part of that code is still in production and it works and does the same thing as before!

    Conclusion 13: Ext JS code passed the test of time.

    Summary


    Thanks to the various tasks that we had to face, I really liked the experience in developing on Ext JS and it is incomparable with other experience on other frameworks. I really liked some architectural methods, approaches and beauty of the API. I even dreamed of implementing the same approaches on my own in other frameworks (another bike).

    Based on the foregoing, I concluded - Ext JS is perfect for solving the problem of building a complex administrative panel.
    Please share in the comments what tools and frameworks you use to solve such problems, what difficulties have you encountered and how much time do you spend writing business logic?

    Reader Bonuses




    We give free access for three months of learning English using our online courses. To do this, simply follow the link until December 31, 2017. We will be glad to see you in the individual classes of the English for IT Professionals course. Take a free introductory lesson and get comprehensive feedback on your level of knowledge, then choose a teacher and a training program to your liking!





    Also popular now: