About 1C web client

One of the nice features of the 1C:Enterprise technology is that the application solution developed using the managed forms technology can be launched both in a thin (executable) client under Windows, Linux, MacOS X, and as a web client for 5 browsers - Chrome, Internet Explorer, Firefox, Safari, Edge, and all without changing the source code of the application. Moreover, externally, the application in the thin client and in the browser functions and looks almost identical.
Find 10 differences (under the cut 2 pictures):

Thin client window on Linux:

About 1C web client

The same window in the web client (in Chrome browser):

About 1C web client

Why did we make a web client? Speaking somewhat pathetically, such a task has been set before us by time. For a long time, work over the Internet has become a prerequisite for business applications. First, we added the ability to work via the Internet for our thin client (some of our competitors, by the way, stopped there; others, on the contrary, abandoned the thin client and limited themselves to the implementation of the web client). We decided to give our users the opportunity to choose the client option that suits them best.

About 1C web client

Adding web capability to the thin client was a big undertaking with a complete change in client/server architecture. Creating a web client is a completely new project that started from scratch.

Formulation of the problem

So, the requirements for the project: the web client must do the same as the thin client, namely:

  1. Display user interface
  2. Execute client code written in 1C language

The user interface in 1C is described in a visual editor, but declaratively, without a pixel-by-pixel arrangement of elements; about three dozen types of interface elements are used - buttons, input fields (text, digital, date / time), lists, tables, graphs, etc.

Client code in 1C language can contain server calls, work with local resources (files, etc.), printing, and much more.

Both the thin client (when working via the web) and the web client use the same set of web services to communicate with the 1C application server. The implementation of the clients, of course, is different - the thin client is written in C ++, the web client is written in JavaScript.

A bit of history

The web client project started in 2006 with an (average) team of 5 people. At certain stages of the project, developers were involved to implement specific functionality (spreadsheet document, diagrams, etc.); as a rule, these were the same developers who made this functionality in the thin client. Those. developers rewrote components in JavaScript that they had previously created in C++.

From the very beginning, we rejected the idea of ​​any automatic (at least partial) conversion of thin client C++ code to web client JavaScript due to the strong conceptual differences between the two languages; the web client was written in JavaScript from scratch.

In the first iterations of the project, the web client converted the client code in the built-in 1C language directly into JavaScript. The thin client acts differently - the code in the built-in 1C language is compiled into bytecode, and then this bytecode is interpreted on the client. Subsequently, the web client began to do the same - firstly, it gave a performance gain, and secondly, it made it possible to unify the architecture of the thin and web clients.

The first version of the 1C:Enterprise platform with web client support was released in 2009. The web client at that time supported 2 browsers - Internet Explorer and Firefox. The original plans were to support Opera, but due to insurmountable problems with the application closing handlers in Opera at that time (it was not possible to track with 100% certainty that the application was closing, and at that moment to perform the disconnection procedure from the 1C application server) from these plans had to be abandoned.

Project structure

In total, the 1C:Enterprise platform has 4 projects written in JavaScript:

  1. WebTools - shared libraries used by other projects (here we include Google Closure Library).
  2. Control element FormattedDocument (implemented in JavaScript both in the thin client and in the web client)
  3. Control element Scheduler (implemented in JavaScript both in the thin client and in the web client)
  4. Web client

The structure of each project resembles the structure of Java projects (or .NET projects - whichever is closer to you); we have namespaces, and each namespace is in a separate folder. Inside the folder are files and namespace classes. There are about 1000 files in the web client project.

Structurally, the web client is largely divided into the following subsystems:

  • Managed client application interface
    • General application interface (system menus, panels)
    • Managed forms interface, which includes, among other things, about 30 controls (buttons, various types of input fields - text, digital, date / time, etc., tables, lists, graphs, etc.)

  • Object model available to developers on the client (more than 400 types in total: managed interface object model, data composition settings, conditional formatting, etc.)
  • Embedded language interpreter 1C
  • Browser extensions (used for functionality not supported in JavaScript)
    • Working with cryptography
    • Work with files
    • External component technology that allows them to be used in both thin and web clients

Features of the development

Implementing all of the above in JavaScript is not an easy task. Perhaps the 1C web client is one of the largest client-side applications written in JavaScript - about 450.000 lines. We actively use an object-oriented approach in the web client code, which simplifies the work with such a large project.

To minimize the size of the client code, we first used our own obfuscator, and starting from platform version 8.3.6 (October 2014) we began to use Google Closure Compiler. The effect of using in numbers is the size of the web client framework after obfuscation:

  • Own obfuscator - 1556 kb
  • Google Closure Compiler - 1073 kb

Using the Google Closure Compiler helped us improve the performance of the web client by 30% compared to our own obfuscator. In addition, the amount of memory consumed by the application has decreased by 15-25% (depending on the browser).

Google Closure Compiler works very well with object-oriented code, so its efficiency is the highest for a web client. The Closure Compiler does a few good things for us:

  • Static type checking at the project build stage (provided by the fact that we cover the code with JSDoc annotations). The result is static typing, very close in level to typing in C++. This helps to catch a fairly large percentage of errors at the compilation stage of the project.
  • Reducing code size through obfuscation
  • A number of optimizations of the executable code, for example, such as:
    • inline function substitutions. Calling a function in JavaScript is quite an expensive operation, and inline substitutions of frequently used small methods can significantly speed up the code.
    • Counting constants at compile time. If the expression depends on a constant, it will be substituted with the actual value of the constant

We use WebStorm as our web client development environment.

For code analysis we use Sonar Qube, where we integrate static code analyzers. With the help of analyzers, we monitor the degradation of the quality of the JavaScript source code and try to prevent it.

About 1C web client

What tasks did/are we solving

During the implementation of the project, we faced a number of interesting tasks that we had to solve.

Data exchange with the server and between windows

There are situations where obfuscation of the source code can interfere with the operation of the system. Code external to the executable code of the web client, due to obfuscation, may have function and parameter names that differ from those that our executable code expects. The external code for us is:

  • Code coming from the server as data structures
  • Code for another application window

To avoid obfuscation when interacting with the server, we use the @expose tag:

/**
 * @constructor
 * @extends {Base.SrvObject}
 */
Srv.Core.GenericException = function ()
{
    /**
     * @type {string}
     * @expose
     */
    this.descr;

    /**
     * @type {Srv.Core.GenericException}
     * @expose
     */
    this.inner;

    /**
     * @type {string}
     * @expose
     */
    this.clsid;

    /**
     * @type {boolean}
     * @expose
     */
    this.encoded;
}

And to avoid obfuscation when interacting with other windows, we use the so-called exported interfaces (interfaces in which all methods are exportable).

/**
 * ЭкспортируСмый интСрфСйс ΠΊΠΎΠ½Ρ‚Ρ€ΠΎΠ»Π° DropDownWindow
 *
 * @interface
 * @struct
 */
WebUI.IDropDownWindowExp = function(){}

/**
 * ΠŸΠ΅Ρ€Π΅ΠΌΠ΅Ρ‰Π°Π΅Ρ‚ Π²Ρ‹Π΄Π΅Π»Π΅Π½ΠΈΠ΅ Π½Π° 1 Π²ΠΏΠ΅Ρ€Π΅Π΄ ΠΈΠ»ΠΈ Π½Π°Π·Π°Π΄
 *
 * @param {boolean} isForward
 * @param {boolean} checkOnly
 * @return {boolean}
 * @expose
 */
WebUI.IDropDownWindowExp.prototype.moveMarker = function (isForward, checkOnly){}

/**
 * ΠŸΠ΅Ρ€Π΅ΠΌΠ΅Ρ‰Π°Π΅Ρ‚ Π²Ρ‹Π΄Π΅Π»Π΅Π½ΠΈΠ΅ Π² Π½Π°Ρ‡Π°Π»ΠΎ ΠΈΠ»ΠΈ ΠΊΠΎΠ½Π΅Ρ†
 *
 * @param {boolean} isFirst
 * @param {boolean} checkOnly
 * @return {boolean}
 * @expose
 */
WebUI.IDropDownWindowExp.prototype.moveMarkerTo = function (isFirst, checkOnly){}

/**
 * @return {boolean}
 * @expose
 */
WebUI.IDropDownWindowExp.prototype.selectValue = function (){}

We used Virtual DOM before it became mainstream)

Like all developers dealing with complex Web UI, we quickly realized that the DOM is not well suited to dynamic user interfaces. Almost immediately, an analogue of the Virtual DOM was implemented to optimize work with the UI. During event processing, all DOM changes are stored in memory and, only when all operations are completed, the accumulated changes are applied to the DOM tree.

Web client optimization

To make our web client work faster, we try to use the standard features of the browser (CSS, etc.) to the maximum. So, the form command bar (located on almost every application form) is drawn exclusively by the browser, dynamic layout based on CSS.

About 1C web client

The test is

For functional and performance testing, we use our own tool (written in Java and C++), as well as a set of tests built on the basis of S.

Our tool is universal - it allows you to test almost any window program, and therefore is suitable for testing both a thin client and a web client. The tool records the actions of the user who launched the 1C application solution into a script file. At the same time, the images of the working area of ​​the screen (standards) are recorded. When monitoring new versions of the web client, scenarios are played without user participation. In cases where the screenshot does not match the reference one at any step, the test is considered failed, after which the quality specialist conducts an investigation - is this a mistake or a planned change in the system behavior. In the case of planned behavior, the standards are automatically replaced by new ones.

The tool also measures application performance with an accuracy of 25 milliseconds. In some cases, we loop parts of the script (for example, repeating the order entry several times) to analyze the degradation of the execution time over time. The results of all measurements are recorded in a log for analysis.

About 1C web client
Our testing tool and application under test

Our tool and Selenium complement each other; for example, if some button on one of the screens has changed its location - Selenium may not track it, but our tool will notice, because makes a pixel-by-pixel comparison of the screenshot with the standard. Also, the tool is able to track down problems with processing input from the keyboard or mouse, since that's what it reproduces.

Tests on both tools (ours and Selenium) run typical work scenarios from our application solutions. Tests are automatically launched after the daily build of the 1C:Enterprise platform. If scripts slow down (compared to the previous build), we will investigate and fix the cause of the slowdown. Our criterion is simple - the new assembly should work no slower than the previous one.

Developers use different tools to investigate slowdown incidents; mainly used Dynatrace AJAX Edition production company DynaTrace. The logs of the execution of the problematic operation on the previous and on the new assembly are recorded, then the logs are analyzed. At the same time, the execution time of single operations (in milliseconds) may not be a decisive factor - service processes such as garbage collection are periodically launched in the browser, they can overlap with the execution time of functions and distort the picture. More relevant parameters in this case would be the number of JavaScript instructions executed, the number of atomic operations on the DOM, and so on. If the number of instructions / operations in the same script in the new version has increased, this almost always means a drop in performance that needs to be corrected.

Also, one of the reasons for the performance drop may be that the Google Closure Compiler for some reason could not make an inline substitution of the function (for example, because the function is recursive or virtual). In this case, we try to remedy the situation by rewriting the source code.

Browser extensions

In the case when an applied solution needs functionality that is not in JavaScript, we use browser extensions:

Our extensions consist of two parts. The first part is what is called a browser extension (usually JavaScript extensions for Chrome and Firefox) that interact with the second part, a binary extension that implements the functionality we need. It should be mentioned that we write 3 versions of binary extensions - for Windows, Linux and MacOS. The binary extension is supplied as part of the 1C:Enterprise platform and is located on the 1C application server. The first time it is called from the web client, it is downloaded to the client computer and installed in the browser.

When running in Safari, our extensions use NPAPI; when running in Internet Explorer, our extensions use ActiveX technology. Microsoft Edge does not yet support extensions, so the web client works with limitations in it.

Further development

One of the task groups for the web client development team is the further development of the functionality. The functionality of the web client should be identical to the functionality of the thin client, all new functionality is implemented simultaneously in both the thin client and the web client.

Other tasks are architecture development, refactoring, performance and reliability improvements. For example, one of the directions is further movement towards an asynchronous work model. Part of the functionality of the web client is currently built on a synchronous model of interaction with the server. The asynchronous model is now becoming more relevant in browsers (and not only in browsers), and this forces us to modify the web client by replacing synchronous calls with asynchronous ones (and refactoring the code accordingly). The gradual transition to an asynchronous model is explained by the need to support released solutions and gradually adapt them.

Source: habr.com

Add a comment