Una delle caratteristiche piacevoli della tecnologia 1C:Enterprise è che la soluzione applicativa, sviluppata con la tecnologia delle forme gestite, può essere eseguita sia nel client leggero (eseguibile) su Windows, Linux, MacOS X, sia come web client su 5 browser – Chrome, Internet Explorer, Firefox, Safari, Edge, e tutto ciò senza modificare il codice sorgente dell'applicazione. Inoltre, l'applicazione nel client leggero e nel browser funziona e appare praticamente identica.
Trova 10 differenze (sotto ci sono 2 immagini):
Finestra del client leggero su Linux:

La stessa finestra nel web client (nel browser Chrome):

Perché abbiamo creato il web client? Parlando in modo un po' retorico, questa esigenza ci è stata imposta dal tempo. Da tempo il lavoro tramite Internet è diventato un requisito necessario per le applicazioni aziendali. Inizialmente, abbiamo aggiunto la possibilità di lavorare tramite Internet per il nostro client leggero (alcuni dei nostri concorrenti, tra l'altro, si sono fermati a questo; altri, al contrario, hanno abbandonato il client leggero e si sono limitati all'implementazione del web client). Noi abbiamo deciso di dare ai nostri utenti la possibilità di scegliere la soluzione che meglio si adatta alle loro esigenze.

L'aggiunta della possibilità di lavorare tramite Internet per il client leggero è stato un grande progetto con un completo cambio di architettura dell'interazione client-server. La creazione del web client è stata, invece, un progetto completamente nuovo, iniziato da zero.
Definizione del compito
Pertanto, i requisiti per il progetto: il web client deve fare le stesse cose del client leggero, vale a dire:
- Visualizzare l'interfaccia utente
- Eseguire codice client scritto nel linguaggio 1C
L'interfaccia utente in 1C è descritta in un editor visivo, ma in modo dichiarativo, senza il posizionamento pixel-to-pixel degli elementi; vengono utilizzati circa trenta tipi di elementi dell'interfaccia – pulsanti, campi di input (testo, numerico, data/ora), elenchi, tabelle, grafici, ecc.
Il codice client nel linguaggio 1C può includere chiamate al server, lavoro con risorse locali (file, ecc.), stampa e molto altro.
Sia il client leggero (quando si lavora tramite web) che il web client utilizzano lo stesso insieme di servizi web per comunicare con il server delle applicazioni 1C. L'implementazione nei client, ovviamente, è diversa: il client leggero è scritto in C++, il web client – in JavaScript.
Un po' di storia
Il progetto di creazione del client web è iniziato nel 2006, con il coinvolgimento di una squadra di 5 persone in media. In fasi specifiche del progetto sono stati coinvolti sviluppatori per implementare funzionalità specifiche (documenti tabellari, diagrammi, ecc.); in genere, si trattava degli stessi sviluppatori che avevano realizzato quelle funzionalità nel client leggero. Cioè, gli sviluppatori hanno riscritto componenti in JavaScript che erano stati creati precedentemente in C++.
Sin dall'inizio, abbiamo scartato l'idea di una qualsiasi conversione automatica (anche parziale) del codice C++ del client leggero in JavaScript per il client web, a causa delle forti differenze concettuali tra questi due linguaggi; il client web è stato scritto in JavaScript da zero.
Nelle prime iterazioni del progetto, il client web convertiva il codice del client in linguaggio integrato 1C direttamente in JavaScript. Il client leggero opera in modo diverso: il codice in linguaggio integrato 1C viene compilato in bytecode e poi questo bytecode viene interpretato sul client. Successivamente, anche il client web ha fatto lo stesso – in primo luogo, questo ha portato a un guadagno di prestazioni, in secondo luogo ha permesso di unificare l'architettura del client leggero e del client web.
La prima versione della piattaforma 1C:Enterprise con supporto per il client web è stata rilasciata nel 2009. A quel tempo, il client web supportava 2 browser: Internet Explorer e Firefox. Nei piani iniziali era prevista la supporto per Opera, ma a causa di problemi insormontabili con i gestori di chiusura dell'applicazione in Opera (non era possibile tracciare con il 100% di certezza che l'applicazione stesse chiudendo e in quel momento effettuare la procedura di disconnessione dal server delle applicazioni 1C) si è dovuto rinunciare a tali piani.
Struttura del progetto
In totale, nella piattaforma 1C:Enterprise ci sono 4 progetti scritti in JavaScript:
- WebTools – librerie comuni utilizzate dagli altri progetti (includiamo qui anche ).
- Controllo dell'elemento (realizzato in JavaScript sia nel client leggero che nel client web)
- Controllo dell'elemento (realizzato in JavaScript sia nel client leggero che nel client web)
- Client web
La struttura di ciascun progetto ricorda la struttura dei progetti Java (o dei progetti .NET – a chi sta più a cuore); abbiamo namespace, e ciascun namespace si trova in una cartella separata. All'interno della cartella ci sono file e classi del namespace. Nel progetto del client web ci sono circa 1000 file.
Strutturalmente, il client web è essenzialmente diviso nelle seguenti sottosistemi:
- Interfaccia controllata dell'applicazione client
- Interfaccia generale dell'applicazione (menu di sistema, pannelli)
- Interfaccia di moduli gestiti, che include, tra l'altro, circa 30 elementi di controllo (pulsanti, vari tipi di campi di input – testuali, numerici, data/ora, ecc., tabelle, elenchi, grafici, ecc.)
- Modello ad oggetti disponibile per gli sviluppatori lato client (oltre 400 tipi: modello ad oggetti dell'interfaccia gestita, impostazioni di layout dati, formattazione condizionale, ecc.)
- Interpretatore del linguaggio integrato 1C
- Estensioni del browser (utilizzate per funzionalità non supportate in JavaScript)
- Lavorare con la crittografia
- Gestione dei file
- Tecnologia dei componenti esterni, che consente di utilizzarli sia nel client leggero che nel web client
Caratteristiche dello sviluppo
L'implementazione di tutto quanto sopra in JavaScript è un compito complesso. È possibile che il web client 1C sia una delle più grandi applicazioni client-side scritte in JavaScript, con circa 450.000 righe. Utilizziamo attivamente nell codice del web client un approccio orientato agli oggetti, che semplifica il lavoro con un progetto di tali dimensioni.
Per ridurre la dimensione del codice client, inizialmente abbiamo utilizzato il nostro obfuscator, e a partire dalla versione della piattaforma 8.3.6 (ottobre 2014) abbiamo iniziato a utilizzare . L'effetto dell'uso in cifre – dimensione del framework del web client dopo obfuscazione:
- Proprio obfuscator – 1556 kB
- Google Closure Compiler – 1073 kB
L'utilizzo di Google Closure Compiler ci ha aiutato a migliorare le prestazioni del web client del 30% rispetto al nostro obfuscator. Inoltre, il consumo di memoria dell'applicazione è diminuito del 15-25% (a seconda del browser).
Google Closure Compiler funziona molto bene con codice orientato agli oggetti, quindi la sua efficacia per il web client è massima. Closure Compiler fa per noi diverse ottime cose:
- Controllo statico dei tipi durante la fase di compilazione del progetto (garantito dal fatto che copriamo il codice con annotazioni JSDoc). Ne risulta una tipizzazione statica molto vicina al livello di tipizzazione in C++. Questo aiuta a catturare una percentuale significativa di errori nella fase di compilazione del progetto.
- Riduzione della dimensione del codice tramite obfuscazione
- Una serie di ottimizzazioni del codice eseguito, ad esempio, come:
- sostituzioni inline delle funzioni. Chiamare una funzione in JavaScript è un'operazione piuttosto costosa e le sostituzioni inline di metodi brevi e frequentemente utilizzati accelerano notevolmente l'esecuzione del codice.
- Conteggio delle costanti in fase di compilazione. Se l'espressione dipende da una costante, verrà inserito il valore effettivo della costante
Come ambiente di sviluppo per il web client utilizziamo WebStorm.
Per l'analisi del codice utilizziamo , in cui integriamo analizzatori statici del codice. Attraverso gli analizzatori monitoriamo il degrado della qualità del codice sorgente in JavaScript e cerchiamo di evitarlo.

Quali problemi abbiamo risolto/risolviamo
Durante l'implementazione del progetto ci siamo imbattuti in una serie di problemi interessanti che abbiamo dovuto risolvere.
Scambio di dati con il server e tra finestre
Esistono situazioni in cui l’oscuramento del codice sorgente può ostacolare il funzionamento del sistema. Il codice esterno rispetto al codice eseguibile del web client, a causa dell’oscuramento, può avere nomi di funzioni e parametri diversi da quelli attesi dal nostro codice eseguibile. Il codice esterno per noi è:
- Codice ricevuto dal server sotto forma di strutture dati
- Codice di un'altra finestra dell'applicazione
Per evitare l’oscuramento durante l'interazione con il server utilizziamo il tag @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;
}E per evitare l’oscuramento durante l'interazione con altre finestre utilizziamo i cosiddetti interfacce esportabili (interfacce in cui tutti i metodi sono esportabili).
/**
* Экспортируемый интерфейс контрола 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 (){}Abbiamo utilizzato il Virtual DOM prima che diventasse mainstream)
Come tutti gli sviluppatori che si occupano di complessi UI web, abbiamo capito rapidamente che il DOM è poco adatto per lavorare con interfacce utente dinamiche. Praticamente subito è stato implementato un analogo del Virtual DOM per ottimizzare il lavoro con l'UI. Durante il processo di gestione dell'evento, tutte le modifiche al DOM vengono memorizzate in memoria e, solo al termine di tutte le operazioni, le modifiche accumulate vengono applicate all'albero DOM.
Ottimizzazione del funzionamento del web client
Per rendere il nostro web client più veloce, cerchiamo di sfruttare al massimo le capacità native del browser (CSS e simili). Così, la barra comandi del modulo (posizionata praticamente in ogni modulo dell'applicazione) viene disegnata utilizzando esclusivamente le funzionalità del browser, con layout dinamico basato su CSS.

Test
Per i test funzionali e i test delle prestazioni utilizziamo uno strumento di nostra produzione (scritto in Java e C++), oltre a un insieme di test basati su .
Il nostro strumento è universale: consente di testare praticamente qualsiasi programma per finestre, rendendolo adatto per testare sia il client aziendale che il client web. Lo strumento registra le azioni dell’utente che avvia l’applicazione ‘1C’ in un file di script. Contemporaneamente, viene effettuata la registrazione delle immagini dell'area di lavoro dello schermo - i riferimenti. Durante il controllo delle nuove versioni del client web, gli script vengono eseguiti senza l'intervento dell'utente. In caso di incongruenza tra lo screenshot e il riferimento in uno qualsiasi dei passaggi, il test viene considerato fallito; successivamente, uno specialista della qualità esegue un'indagine per determinare se si tratta di un errore o di un cambiamento pianificato nel comportamento del sistema. In caso di comportamento pianificato, i riferimenti vengono automaticamente sostituiti con nuovi.
Lo strumento misura anche le prestazioni delle applicazioni con un'accuratezza di 25 millisecondi. In alcuni casi, cicliamo parti dello script (ad esempio, ripetendo più volte l'inserimento di un ordine) per analizzare il degrado del tempo di esecuzione nel tempo. I risultati di tutte le misurazioni vengono registrati in un log per analisi.

Il nostro strumento di test e l'applicazione testata
Il nostro strumento e Selenium si integrano a vicenda; ad esempio, se un pulsante su uno degli schermi cambia posizione, Selenium potrebbe non rilevarlo, ma il nostro strumento lo noterà, poiché esegue un confronto pixel per pixel tra lo screenshot e il riferimento. Inoltre, lo strumento è in grado di rilevare problemi con l'elaborazione degli input da tastiera o mouse, in quanto è proprio questo che riproduce.
I test su entrambi gli strumenti (il nostro e Selenium) eseguono scenari di lavoro standard dalle nostre soluzioni applicative. I test vengono avviati automaticamente dopo la compilazione giornaliera della piattaforma ‘1C:Enterprise’. In caso di rallentamenti negli scenari (rispetto alla compilazione precedente), conduciamo un'indagine e risolviamo la causa del rallentamento. Il nostro criterio è semplice: la nuova compilazione deve funzionare non più lentamente della precedente.
Per indagare sugli incidenti di rallentamento, gli sviluppatori utilizzano diversi strumenti; nella maggior parte dei casi viene utilizzato produzione della società . Viene registrata l'esecuzione dei log dell'operazione problematica sia sulla precedente che sulla nuova versione, dopodiché i log vengono analizzati. In questo caso, il tempo di esecuzione delle singole operazioni (in millisecondi) potrebbe non essere un fattore decisivo: nel browser vengono eseguiti periodicamente processi di servizio come la pulizia della memoria, che possono sovrapporsi al tempo di esecuzione delle funzioni e distorcere l'immagine. Parametri più rilevanti in questo caso sono il numero di istruzioni JavaScript eseguite, il numero di operazioni atomiche sul DOM, ecc. Se il numero di istruzioni/operazioni nello stesso scenario nella nuova versione è aumentato, questo significa quasi sempre un rallentamento delle prestazioni che deve essere corretto.
Un'altra causa del calo delle prestazioni può essere che Google Closure Compiler non è riuscito per qualche motivo a effettuare la sostituzione inline della funzione (ad esempio perché la funzione è ricorsiva o virtuale). In questo caso cerchiamo di risolvere il problema riscrivendo il codice sorgente.
Estensioni del browser
Quando una soluzione applicativa necessita di funzionalità non disponibili in JavaScript, utilizziamo estensioni del browser:
- per la gestione dei file
- per la gestione della crittografia
- lavoro con
Le nostre estensioni sono composte da due parti. La prima parte è ciò che viene chiamato estensione del browser (di solito estensioni scritte in JavaScript per Chrome e Firefox), che interagiscono con la seconda parte - un'estensione binaria che implementa la funzionalità di cui abbiamo bisogno. Vale la pena menzionare che scriviamo 3 versioni di estensioni binarie - per Windows, Linux e MacOS. L'estensione binaria viene fornita con la piattaforma 1C:Enterprise e si trova sul server delle applicazioni 1C. Al primo avvio dal client web, viene caricata sul computer client e installata nel browser.
Quando si lavora in Safari, le nostre estensioni utilizzano NPAPI, mentre in Internet Explorer utilizzano la tecnologia ActiveX. ancora non supporta le estensioni, quindi il client web funziona con limitazioni.
Sviluppo futuro
Uno dei gruppi di compiti per il team di sviluppo del client web è l'ulteriore sviluppo delle funzionalità. Le funzionalità del client web devono essere identiche a quelle del client leggero; tutte le nuove funzionalità vengono implementate contemporaneamente sia nel client leggero che nel client web.
Altri compiti includono lo sviluppo dell'architettura, il refactoring, l'aumento delle prestazioni e dell'affidabilità. Ad esempio, una delle direzioni è continuare a spostarsi verso un modello di lavoro asincrono. Una parte delle funzionalità del client web è attualmente costruita su un modello di interazione sincrona con il server. Il modello asincrono sta diventando ora più attuale nei browser (e non solo nei browser), e ciò ci costringe a modificare il client web sostituendo le chiamate sincrone con chiamate asincrone (e un corrispondente refactoring del codice). La transizione graduale verso un modello asincrono è spiegata dalla necessità di supportare le soluzioni rilasciate e di adattarle progressivamente.
Fonte: habr.com
