Sobre el client web 1C

Una de les característiques agradables de la tecnologia 1C:Enterprise és que la solució d'aplicació, desenvolupada amb tecnologia de formularis gestionats, es pot llançar tant en un client prim (executable) per a Windows, Linux, MacOS X com com a client web per a 5 navegadors. Chrome, Internet Explorer, Firefox, Safari, Edge, i tot això sense canviar el codi font de l'aplicació. A més, externament, l'aplicació al client lleuger i al navegador funciona i sembla gairebé idèntica.
Troba 10 diferències (2 imatges sota el tall):

Finestra de client prim a Linux:

Sobre el client web 1C

La mateixa finestra al client web (al navegador Chrome):

Sobre el client web 1C

Per què vam fer un client web? Per dir-ho una mica patètic, el temps ens ha imposat una tasca així. Treballar per Internet ha estat durant molt de temps un requisit previ per a les aplicacions empresarials. En primer lloc, hem afegit la possibilitat de treballar a través d'Internet per al nostre client lleuger (alguns dels nostres competidors, per cert, es van aturar aquí; altres, per contra, van abandonar el client lleuger i es van limitar a implementar un client web). Vam decidir donar als nostres usuaris l'oportunitat de triar l'opció de client que més els convingui.

Sobre el client web 1C

L'addició de capacitats basades en web al client lleuger va ser un gran projecte amb un canvi complet en l'arquitectura client-servidor. Crear un client web és un projecte completament nou, començant de zero.

Declaració de problemes

Per tant, els requisits del projecte: el client web ha de fer el mateix que el client lleuger, és a dir:

  1. Mostra la interfície d'usuari
  2. Executeu codi de client escrit en llenguatge 1C

La interfície d'usuari a 1C es descriu en un editor visual, però de manera declarativa, sense disposició dels elements píxel a píxel; S'utilitzen unes tres dotzenes de tipus d'elements d'interfície: botons, camps d'entrada (text, numèric, data/hora), llistes, taules, gràfics, etc.

El codi de client en l'idioma 1C pot contenir trucades al servidor, treballar amb recursos locals (fitxers, etc.), impressió i molt més.

Tant el client prim (quan treballa a través del web) com el client web utilitzen el mateix conjunt de serveis web per comunicar-se amb el servidor d'aplicacions 1C. Les implementacions del client, per descomptat, són diferents: el client prim està escrit en C++, el client web està escrit en JavaScript.

Una mica d'història

El projecte de client web va començar l'any 2006, amb un equip de (de mitjana) 5 persones. En determinades etapes del projecte, els desenvolupadors es van implicar per implementar funcionalitats específiques (document de full de càlcul, diagrames, etc.); per regla general, aquests eren els mateixos desenvolupadors que feien aquesta funcionalitat al client lleuger. Aquells. els desenvolupadors van tornar a escriure components en JavaScript que havien creat prèviament en C++.

Des del principi, vam rebutjar la idea de qualsevol conversió automàtica (fins i tot parcial) del codi de client prim C++ en client web JavaScript a causa de les fortes diferències conceptuals entre els dos idiomes; el client web es va escriure en JavaScript des de zero.

En les primeres iteracions del projecte, el client web va convertir el codi del client en el llenguatge 1C integrat directament en JavaScript. El client prim actua de manera diferent: el codi del llenguatge 1C integrat es compila en bytecode i, a continuació, aquest bytecode s'interpreta al client. Posteriorment, el client web va començar a fer el mateix: en primer lloc, va augmentar el rendiment i, en segon lloc, va permetre unificar l'arquitectura dels clients prims i web.

La primera versió de la plataforma 1C:Enterprise amb suport de client web es va llançar el 2009. El client web en aquell moment suportava 2 navegadors: Internet Explorer i Firefox. Els plans originals incloïen suport per a Opera, però a causa de problemes insalvables en aquell moment amb els gestors de tancament de l'aplicació a Opera (no va ser possible fer un seguiment del 100% de certesa que l'aplicació es tancava, i en aquell moment dur a terme el procediment de desconnexió de el servidor d'aplicacions 1C) d'aquests plans va haver de ser abandonat.

Estructura del projecte

En total, la plataforma 1C:Enterprise té 4 projectes escrits en JavaScript:

  1. WebTools: biblioteques compartides utilitzades per altres projectes (també incloem Biblioteca de tancament de Google).
  2. Control Document amb format (implementat en JavaScript tant al client lleuger com al client web)
  3. Control Programador (implementat en JavaScript tant al client lleuger com al client web)
  4. Client web

L'estructura de cada projecte s'assembla a l'estructura dels projectes Java (o projectes .NET, el que estigui més proper); Tenim espais de noms i cada espai de noms es troba en una carpeta separada. Dins de la carpeta hi ha fitxers i classes d'espai de noms. Hi ha uns 1000 fitxers al projecte del client web.

Estructuralment, el client web es divideix en gran mesura en els següents subsistemes:

  • Interfície d'aplicació client gestionada
    • Interfície general d'aplicació (menús del sistema, panells)
    • Interfície de formularis gestionats, que inclou, entre altres coses, uns 30 controls (botons, diversos tipus de camps d'entrada: text, numèrics, data/hora, etc., taules, llistes, gràfics, etc.)

  • Model d'objectes disponible per als desenvolupadors al client (més de 400 tipus en total: model d'objectes d'interfície gestionada, configuració de disseny de dades, estil condicional, etc.)
  • Intèrpret del llenguatge 1C integrat
  • Extensions del navegador (utilitzades per a funcions no compatibles amb JavaScript)
    • Treballant amb criptografia
    • Treballar amb fitxers
    • Tecnologia de components externs, que permet utilitzar-los tant en clients lleugers com web

Característiques de desenvolupament

Implementar tot l'anterior a JavaScript no és fàcil. Potser el client web 1C és una de les aplicacions més grans del costat del client escrites en JavaScript: unes 450.000 línies. Utilitzem activament un enfocament orientat a objectes al codi del client web, que simplifica el treball amb un projecte tan gran.

Per minimitzar la mida del codi del client, primer vam utilitzar el nostre propi ofuscador i, a partir de la versió de la plataforma 8.3.6 (octubre de 2014), vam començar a utilitzar Compilador de tancament de Google. L'efecte de l'ús en números: la mida del marc del client web després de l'ofuscament:

  • Ofuscador propi – 1556 kb
  • Compilador de tancament de Google - 1073 kb

L'ús de Google Closure Compiler ens va ajudar a millorar el rendiment del client web en un 30% en comparació amb el nostre propi ofuscador. A més, la quantitat de memòria consumida per l'aplicació ha disminuït entre un 15 i un 25% (segons el navegador).

Google Closure Compiler funciona molt bé amb codi orientat a objectes, de manera que la seva eficiència per al client web és la més alta possible. Closure Compiler fa algunes coses bones per nosaltres:

  • Comprovació de tipus estàtic en l'etapa de construcció del projecte (assegura que cobrim el codi amb anotacions JSDoc). El resultat és una mecanografia estàtica, molt propera al nivell d'escriure en C++. Això ajuda a detectar un percentatge bastant gran d'errors en l'etapa de compilació del projecte.
  • Reducció de la mida del codi mitjançant l'ofuscament
  • Una sèrie d'optimitzacions del codi executat, per exemple, com ara:
    • substitucions de funcions en línia. Cridar una funció en JavaScript és una operació bastant cara, i les substitucions en línia de mètodes petits utilitzats amb freqüència acceleren significativament el codi.
    • Comptant constants en temps de compilació. Si una expressió depèn d'una constant, el valor real de la constant s'hi substituirà

Utilitzem WebStorm com a entorn de desenvolupament de client web.

Per a l'anàlisi del codi fem servir SonarQube, on integrem analitzadors de codi estàtic. Mitjançant analitzadors, controlem la degradació de la qualitat del codi font de JavaScript i intentem evitar-ho.

Sobre el client web 1C

Quins problemes hem resolt/estem resolent?

Durant la implementació del projecte, ens hem trobat amb una sèrie de problemes interessants que hem hagut de resoldre.

Intercanviar dades amb el servidor i entre finestres

Hi ha situacions en què l'ofuscament del codi font pot interferir amb el funcionament del sistema. El codi extern al codi executable del client web, a causa de la ofuscació, pot tenir noms de funció i paràmetres diferents dels que espera el nostre codi executable. El codi extern per a nosaltres és:

  • Codi procedent del servidor en forma d'estructures de dades
  • Codi per a una altra finestra d'aplicació

Per evitar l'ofuscament en interactuar amb el servidor, utilitzem l'etiqueta @expose:

/**
 * @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;
}

I per evitar l'ofuscament en interactuar amb altres finestres, utilitzem les anomenades interfícies exportades (interfícies en què s'exporten tots els mètodes).

/**
 * Экспортируемый интерфейс контрола 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 (){}

Vam utilitzar Virtual DOM abans que es convertís en corrent)

Com tots els desenvolupadors que tracten amb interfícies d'usuari web complexes, ràpidament ens vam adonar que el DOM no és adequat per treballar amb interfícies d'usuari dinàmiques. Gairebé immediatament, es va implementar un anàleg de Virtual DOM per optimitzar el treball amb la IU. Durant el processament d'esdeveniments, tots els canvis DOM s'emmagatzemen a la memòria i, només quan s'han completat totes les operacions, els canvis acumulats s'apliquen a l'arbre DOM.

Optimització del client web

Perquè el nostre client web funcioni més ràpid, intentem utilitzar al màxim les capacitats estàndard del navegador (CSS, etc.). Així, el panell d'ordres del formulari (situat a gairebé totes les formes de l'aplicació) es representa exclusivament mitjançant eines del navegador, utilitzant un disseny dinàmic basat en CSS.

Sobre el client web 1C

Proves

Per a proves funcionals i de rendiment, utilitzem una eina propietària (escrita en Java i C++), així com un conjunt de proves construïdes a sobre de Seleni.

La nostra eina és universal: us permet provar gairebé qualsevol programa amb finestra i, per tant, és adequada per provar tant un client lleuger com un client web. L'eina registra les accions de l'usuari que va llançar la solució d'aplicació 1C en un fitxer d'script. Al mateix temps, s'enregistren imatges de l'àrea de treball de la pantalla —estàndards—. En supervisar les noves versions del client web, els scripts es reprodueixen sense la participació de l'usuari. En els casos en què la captura de pantalla no coincideix amb la de referència en cap pas, la prova es considera fallida, després del qual un especialista en qualitat realitza una investigació per determinar si es tracta d'un error o d'un canvi previst en el comportament del sistema. En cas de comportament planificat, les normes es substitueixen automàticament per unes de noves.

L'eina també mesura el rendiment de l'aplicació amb una precisió de fins a 25 mil·lisegons. En alguns casos, fem un bucle de parts de l'script (per exemple, repetint l'entrada de l'ordre diverses vegades) per analitzar la degradació del temps d'execució al llarg del temps. Els resultats de totes les mesures es registren en un registre per a l'anàlisi.

Sobre el client web 1C
La nostra eina de prova i aplicació en prova

La nostra eina i Selenium es complementen; per exemple, si algun botó d'una de les pantalles ha canviat la seva ubicació, pot ser que Selenium no el rastregi, però la nostra eina ho notarà, perquè fa una comparació píxel per píxel de la captura de pantalla amb l'estàndard. L'eina també és capaç de fer un seguiment dels problemes amb el processament de l'entrada des del teclat o el ratolí, ja que això és exactament el que reprodueix.

Les proves d'ambdues eines (la nostra i Selenium) executen escenaris de treball típics de les nostres solucions d'aplicació. Les proves es llancen automàticament després de la creació diària de la plataforma 1C:Enterprise. Si els scripts són més lents (en comparació amb la versió anterior), investiguem i resolem la causa de la desacceleració. El nostre criteri és senzill: la nova construcció no hauria de funcionar més lenta que l'anterior.

Els desenvolupadors utilitzen diferents eines per investigar incidents de desacceleració; utilitzat principalment Edició Dynatrace AJAX empresa productora DynaTrace. S'enregistren els registres de l'execució de l'operació problemàtica a les versions anteriors i noves, i després s'analitzen els registres. Al mateix temps, és possible que el temps d'execució d'operacions individuals (en mil·lisegons) no sigui un factor decisiu: processos de servei com la recollida d'escombraries s'inicien periòdicament al navegador, poden superposar-se al temps d'execució de funcions i distorsionar la imatge. Els paràmetres més rellevants en aquest cas serien el nombre d'instruccions JavaScript executades, el nombre d'operacions atòmiques al DOM, etc. Si el nombre d'instruccions/operacions del mateix script ha augmentat en una versió nova, això gairebé sempre significa una caiguda del rendiment que cal corregir.

A més, un dels motius de la caiguda del rendiment pot ser que Google Closure Compiler per algun motiu no ha pogut realitzar la substitució en línia de la funció (per exemple, perquè la funció és recursiva o virtual). En aquest cas, intentem corregir la situació reescrivint el codi font.

Extensions del navegador

Quan una solució d'aplicació necessita una funcionalitat que no està disponible a JavaScript, fem servir les extensions del navegador:

  • per treballar amb fitxers
  • per treballar amb criptografia
  • treballar amb components externs

Les nostres extensions consten de dues parts. La primera part és el que s'anomena extensió del navegador (generalment extensions per a Chrome i Firefox escrites en JavaScript), que interactuen amb la segona part: una extensió binària que implementa la funcionalitat que necessitem. Cal esmentar que escrivim 3 versions d'extensions binàries: per a Windows, Linux i MacOS. L'extensió binària es subministra com a part de la plataforma 1C:Enterprise i es troba al servidor d'aplicacions 1C. Quan es truca per primera vegada des d'un client web, es baixa a l'ordinador client i s'instal·la al navegador.

Quan s'executen a Safari, les nostres extensions utilitzen NPAPI; quan s'executen a Internet Explorer, utilitzen la tecnologia ActiveX. microsoft Edge encara no admet extensions, de manera que el client web que hi ha funciona amb restriccions.

Desenvolupament posterior

Una de les tasques de l'equip de desenvolupament del client web és el desenvolupament posterior de la funcionalitat. La funcionalitat del client web ha de ser idèntica a la funcionalitat del client lleuger; tota la funcionalitat nova s'implementa simultàniament tant en el client lleuger com en el client web.

Altres tasques inclouen desenvolupar l'arquitectura, refactoritzar, millorar el rendiment i la fiabilitat. Per exemple, una de les direccions és un major moviment cap a un model de treball asíncron. Algunes de les funcionalitats del client web es construeixen actualment sobre un model d'interacció sincrònic amb el servidor. El model asíncron és ara cada cop més rellevant als navegadors (i no només als navegadors), i això ens obliga a modificar el client web substituint les trucades síncrones per altres de asíncrones (i refactoritzant el codi en conseqüència). La transició gradual a un model asíncron s'explica per la necessitat de donar suport a les solucions llançades i la seva adaptació gradual.

Font: www.habr.com

Afegeix comentari