Despre clientul web 1C

Una dintre caracteristicile frumoase ale tehnologiei 1C:Enterprise este că soluția de aplicație, dezvoltată folosind tehnologia de formulare gestionate, poate fi lansată atât într-un client subțire (executable) pentru Windows, Linux, MacOS X, cât și ca client web pentru 5 browsere - Chrome, Internet Explorer, Firefox, Safari, Edge și toate acestea fără a schimba codul sursă al aplicației. Mai mult, extern aplicația din clientul subțire și din browser funcționează și arată aproape identic.
Găsiți 10 diferențe (2 imagini sub tăietură):

Fereastra client subțire pe Linux:

Despre clientul web 1C

Aceeași fereastră în clientul web (în browserul Chrome):

Despre clientul web 1C

De ce am făcut un client web? Pentru a spune oarecum patetic, timpul ne-a pus o astfel de sarcină. Lucrul pe Internet a fost mult timp o condiție prealabilă pentru aplicațiile de afaceri. În primul rând, am adăugat posibilitatea de a lucra prin internet pentru clientul nostru subțire (unii dintre concurenții noștri, de altfel, s-au oprit aici; alții, dimpotrivă, au abandonat clientul subțire și s-au limitat la implementarea unui client web). Am decis să oferim utilizatorilor noștri posibilitatea de a alege opțiunea client care li se potrivește cel mai bine.

Despre clientul web 1C

Adăugarea de capabilități bazate pe web la clientul subțire a fost un proiect mare, cu o schimbare completă în arhitectura client-server. Crearea unui client web este un proiect complet nou, pornind de la zero.

Declarație de problemă

Deci, cerințele proiectului: clientul web trebuie să facă la fel ca clientul subțire și anume:

  1. Afișează interfața utilizator
  2. Executați codul client scris în limbajul 1C

Interfața cu utilizatorul din 1C este descrisă într-un editor vizual, dar declarativ, fără aranjarea pixel-cu-pixel a elementelor; Sunt utilizate aproximativ trei duzini de tipuri de elemente de interfață - butoane, câmpuri de introducere (text, numeric, dată/oră), liste, tabele, grafice etc.

Codul client în limbajul 1C poate conține apeluri de server, lucru cu resurse locale (fișiere, etc.), imprimare și multe altele.

Atât clientul subțire (când lucrează prin web) cât și clientul web folosesc același set de servicii web pentru a comunica cu serverul de aplicații 1C. Implementările clientului, desigur, sunt diferite - clientul subțire este scris în C++, clientul web este scris în JavaScript.

Un pic de istorie

Proiectul de client web a început în 2006, cu o echipă de (în medie) 5 persoane. În anumite etape ale proiectului, dezvoltatorii au fost implicați pentru a implementa funcționalități specifice (document foaie de calcul, diagrame etc.); de regulă, aceștia au fost aceiași dezvoltatori care au făcut această funcționalitate în clientul subțire. Acestea. dezvoltatorii au rescris componentele în JavaScript pe care le creaseră anterior în C++.

De la bun început, am respins ideea oricărei conversii automate (chiar parțiale) a codului clientului subțire C++ în client web JavaScript din cauza diferențelor conceptuale puternice dintre cele două limbi; clientul web a fost scris de la zero în JavaScript.

În primele iterații ale proiectului, clientul web a convertit codul clientului în limbajul 1C încorporat direct în JavaScript. Clientul subțire acționează diferit - codul din limbajul 1C încorporat este compilat în bytecode, iar apoi acest bytecode este interpretat pe client. Ulterior, clientul web a început să facă același lucru - în primul rând, a oferit un câștig de performanță, iar în al doilea rând, a făcut posibilă unificarea arhitecturii clienților subțiri și web.

Prima versiune a platformei 1C:Enterprise cu suport pentru client web a fost lansată în 2009. Clientul web la acel moment suporta 2 browsere - Internet Explorer și Firefox. Planurile inițiale includeau suport pentru Opera, dar din cauza unor probleme insurmontabile la acea vreme cu manipulatorii de închidere a aplicației din Opera (nu a fost posibil să urmărim cu certitudine 100% că aplicația se închidea, iar în acel moment să se efectueze procedura de deconectare de la serverul de aplicații 1C) din aceste planuri a trebuit să fie abandonat.

Structura proiectului

În total, platforma 1C:Enterprise are 4 proiecte scrise în JavaScript:

  1. WebTools – biblioteci partajate utilizate de alte proiecte (includem și Biblioteca de închidere Google).
  2. Element de control FormattedDocument (implementat în JavaScript atât în ​​clientul subțire, cât și în clientul web)
  3. Element de control Programator (implementat în JavaScript atât în ​​clientul subțire, cât și în clientul web)
  4. Client web

Structura fiecărui proiect seamănă cu structura proiectelor Java (sau proiecte .NET - oricare dintre acestea este mai apropiată); Avem spații de nume și fiecare spațiu de nume este într-un folder separat. În interiorul folderului există fișiere și clase de spații de nume. Există aproximativ 1000 de fișiere în proiectul client web.

Din punct de vedere structural, clientul web este în mare parte împărțit în următoarele subsisteme:

  • Interfață de aplicație client gestionată
    • Interfață generală a aplicației (meniuri de sistem, panouri)
    • Interfață de formulare gestionate, incluzând, printre altele, aproximativ 30 de controale (butoane, diverse tipuri de câmpuri de introducere - text, numerice, dată/oră etc., tabele, liste, grafice etc.)

  • Model de obiect disponibil pentru dezvoltatori pe client (peste 400 de tipuri în total: model de obiect de interfață gestionată, setări de aspect de date, stil condiționat etc.)
  • Interpret al limbajului 1C încorporat
  • Extensii de browser (utilizate pentru funcționalități care nu sunt acceptate în JavaScript)
    • Lucrul cu criptografie
    • Lucrul cu fișiere
    • Tehnologia componentelor externe, permițându-le să fie utilizate atât în ​​clienții subțiri, cât și în clienții web

Caracteristici de dezvoltare

Implementarea tuturor celor de mai sus în JavaScript nu este ușoară. Poate că clientul web 1C este una dintre cele mai mari aplicații la nivelul clientului scrise în JavaScript - aproximativ 450.000 de linii. Utilizăm în mod activ o abordare orientată pe obiect în codul clientului web, ceea ce simplifică lucrul cu un proiect atât de mare.

Pentru a minimiza dimensiunea codului clientului, am folosit mai întâi propriul nostru obfuscator, iar începând cu versiunea platformei 8.3.6 (octombrie 2014) am început să folosim Compilatorul de închidere Google. Efectul utilizării în numere – dimensiunea cadrului clientului web după ofuscare:

  • Obfuscator propriu – 1556 kb
  • Compilator de închidere Google – 1073 kb

Utilizarea Google Closure Compiler ne-a ajutat să îmbunătățim performanța clientului web cu 30% în comparație cu propriul nostru obfuscator. În plus, cantitatea de memorie consumată de aplicație a scăzut cu 15-25% (în funcție de browser).

Google Closure Compiler funcționează foarte bine cu codul orientat pe obiecte, astfel încât eficiența acestuia pentru clientul web este cât mai mare posibil. Closure Compiler face câteva lucruri bune pentru noi:

  • Verificarea tipului static la etapa de construire a proiectului (se asigură că acoperim codul cu adnotări JSDoc). Rezultatul este tastarea statică, foarte apropiată ca nivel de tastarea în C++. Acest lucru ajută la identificarea unui procent destul de mare de erori în etapa de compilare a proiectului.
  • Reducerea dimensiunii codului prin ofuscare
  • O serie de optimizări ale codului executat, de exemplu, cum ar fi:
    • substituții de funcție în linie. Apelarea unei funcții în JavaScript este o operație destul de costisitoare, iar substituțiile inline ale metodelor mici utilizate frecvent accelerează semnificativ codul.
    • Numărarea constantelor în timpul compilării. Dacă o expresie depinde de o constantă, valoarea actuală a constantei va fi substituită în ea

Folosim WebStorm ca mediu de dezvoltare a clientului web.

Pentru analiza codului folosim soundQube, unde integrăm analizoare de cod statice. Folosind analizoare, monitorizăm degradarea calității codului sursă JavaScript și încercăm să o prevenim.

Despre clientul web 1C

Ce probleme am rezolvat/rezolvam?

Pe parcursul implementării proiectului, am întâlnit o serie de probleme interesante pe care a trebuit să le rezolvăm.

Schimbați date cu serverul și între ferestre

Există situații în care înfundarea codului sursă poate interfera cu funcționarea sistemului. Codul extern codului executabil al clientului web, din cauza ofuscarii, poate avea nume de funcții și parametri care diferă de cele la care se așteaptă codul nostru executabil. Codul extern pentru noi este:

  • Cod care vine de la server sub formă de structuri de date
  • Cod pentru o altă fereastră de aplicație

Pentru a evita înfundarea atunci când interacționăm cu serverul, folosim eticheta @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 pentru a evita ofuscarea atunci când interacționăm cu alte ferestre, folosim așa-numitele interfețe exportate (interfețe în care sunt exportate toate metodele).

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

Am folosit Virtual DOM înainte de a deveni mainstream)

La fel ca toți dezvoltatorii care se ocupă de interfețe web complexe, am realizat rapid că DOM-ul nu este potrivit pentru a lucra cu interfețe de utilizator dinamice. Aproape imediat, a fost implementat un analog al Virtual DOM pentru a optimiza lucrul cu UI. În timpul procesării evenimentului, toate modificările DOM sunt stocate în memorie și, numai când toate operațiunile sunt finalizate, modificările acumulate sunt aplicate arborelui DOM.

Optimizarea clientului web

Pentru ca clientul nostru web să funcționeze mai rapid, încercăm să folosim la maximum capabilitățile standard ale browserului (CSS, etc.). Astfel, panoul de comandă al formularului (situat pe aproape fiecare formă a aplicației) este redat exclusiv folosind instrumente de browser, folosind un aspect dinamic bazat pe CSS.

Despre clientul web 1C

Testarea

Pentru testarea funcțională și a performanței, folosim un instrument proprietar (scris în Java și C++), precum și o suită de teste construită pe deasupra Seleniu.

Instrumentul nostru este universal - vă permite să testați aproape orice program cu ferestre și, prin urmare, este potrivit pentru testarea atât a unui client subțire, cât și a unui client web. Instrumentul înregistrează acțiunile utilizatorului care a lansat soluția de aplicație 1C într-un fișier script. În același timp, sunt înregistrate imagini ale zonei de lucru a ecranului - standarde. La monitorizarea noilor versiuni ale clientului web, scripturile sunt redate fără participarea utilizatorului. În cazurile în care captura de ecran nu se potrivește cu cea de referință la niciun pas, testul este considerat eșuat, după care un specialist în calitate efectuează o investigație pentru a determina dacă aceasta este o eroare sau o schimbare planificată a comportamentului sistemului. În cazul unui comportament planificat, standardele sunt înlocuite automat cu altele noi.

Instrumentul măsoară, de asemenea, performanța aplicației cu o precizie de până la 25 de milisecunde. În unele cazuri, buclă părți ale scriptului (de exemplu, repetând intrarea comenzii de mai multe ori) pentru a analiza degradarea timpului de execuție în timp. Rezultatele tuturor măsurătorilor sunt înregistrate într-un jurnal pentru analiză.

Despre clientul web 1C
Instrumentul nostru de testare și aplicația în curs de testare

Instrumentul nostru și Selenium se completează reciproc; de exemplu, dacă un buton de pe unul dintre ecrane și-a schimbat locația, Selenium poate să nu urmărească acest lucru, dar instrumentul nostru va observa, deoarece face o comparație pixel cu pixel a capturii de ecran cu standardul. Instrumentul este, de asemenea, capabil să urmărească problemele cu procesarea intrărilor de la tastatură sau mouse, deoarece acesta este exact ceea ce reproduce.

Testele pe ambele instrumente (al nostru și Selenium) rulează scenarii de lucru tipice din soluțiile noastre de aplicație. Testele sunt lansate automat după construirea zilnică a platformei 1C:Enterprise. Dacă scripturile sunt mai lente (comparativ cu versiunea anterioară), investigăm și rezolvăm cauza încetinirii. Criteriul nostru este simplu - noua versiune nu ar trebui să funcționeze mai lent decât cea anterioară.

Dezvoltatorii folosesc diferite instrumente pentru a investiga incidentele de încetinire; folosit în principal Dynatrace AJAX Edition companie de productie DynaTrace. Se înregistrează jurnalele de execuție a operațiunii problematice pe build-urile anterioare și noi, apoi sunt analizate jurnalele. În același timp, timpul de execuție a operațiunilor individuale (în milisecunde) poate să nu fie un factor decisiv - procesele de servicii precum colectarea gunoiului sunt lansate periodic în browser, se pot suprapune cu timpul de execuție a funcțiilor și pot distorsiona imaginea. Parametrii mai relevanți în acest caz ar fi numărul de instrucțiuni JavaScript executate, numărul de operații atomice pe DOM etc. Dacă numărul de instrucțiuni/operații din același script a crescut într-o versiune nouă, aceasta înseamnă aproape întotdeauna o scădere a performanței care trebuie corectată.

De asemenea, unul dintre motivele scăderii performanței poate fi faptul că Google Closure Compiler nu a putut, dintr-un anumit motiv, să efectueze înlocuirea în linie a funcției (de exemplu, deoarece funcția este recursivă sau virtuală). În acest caz, încercăm să corectăm situația prin rescrierea codului sursă.

Extensii de browser

Când o soluție de aplicație are nevoie de funcționalități care nu sunt disponibile în JavaScript, folosim extensii de browser:

Extensiile noastre constau din două părți. Prima parte este ceea ce se numește extensie de browser (de obicei extensii pentru Chrome și Firefox scrise în JavaScript), care interacționează cu a doua parte - o extensie binară care implementează funcționalitatea de care avem nevoie. De menționat că scriem 3 versiuni de extensii binare - pentru Windows, Linux și MacOS. Extensia binară este furnizată ca parte a platformei 1C:Enterprise și se află pe serverul de aplicații 1C. Când este apelat pentru prima dată de la un client web, acesta este descărcat pe computerul client și instalat în browser.

Când rulează în Safari, extensiile noastre folosesc NPAPI; când rulează în Internet Explorer, folosesc tehnologia ActiveX. Microsoft Edge nu acceptă încă extensii, așa că clientul web din acesta funcționează cu restricții.

Dezvoltare ulterioară

Una dintre sarcinile echipei de dezvoltare a clientului web este dezvoltarea în continuare a funcționalității. Funcționalitatea clientului web ar trebui să fie identică cu funcționalitatea clientului subțire; toate funcționalitățile noi sunt implementate simultan atât în ​​clientul subțire, cât și în clientul web.

Alte sarcini includ dezvoltarea arhitecturii, refactorizarea, îmbunătățirea performanței și a fiabilității. De exemplu, una dintre direcții este deplasarea în continuare către un model de lucru asincron. Unele dintre funcționalitățile clientului web sunt construite în prezent pe un model sincron de interacțiune cu serverul. Modelul asincron devine acum din ce în ce mai relevant în browsere (și nu numai în browsere), iar acest lucru ne obligă să modificăm clientul web prin înlocuirea apelurilor sincrone cu cele asincrone (și refactorizarea codului în consecință). Trecerea treptată la un model asincron se explică prin necesitatea de a sprijini soluțiile lansate și adaptarea treptată a acestora.

Sursa: www.habr.com

Adauga un comentariu