Uma das características agradáveis da tecnologia 1C:Enterprise é que a solução de aplicação desenvolvida com tecnologia de formulários gerenciados pode ser executada tanto no cliente leve (executável) em Windows, Linux, MacOS X, quanto como cliente web em 5 navegadores – Chrome, Internet Explorer, Firefox, Safari, Edge, tudo isso sem alteração do código-fonte do aplicativo. Além disso, visualmente, o aplicativo no cliente leve e no navegador funciona e se parece praticamente idêntico.
Encontre 10 diferenças (abaixo, 2 imagens):
Janela do cliente leve no Linux:

A mesma janela no cliente web (no navegador Chrome):

Por que fizemos o cliente web? Falando um pouco de forma grandiosa, essa tarefa foi imposta pelo tempo. Há muito tempo, o trabalho pela Internet se tornou um pré-requisito para aplicações empresariais. No início, adicionamos a capacidade de trabalhar pela Internet ao nosso cliente leve (alguns de nossos concorrentes, diga-se de passagem, pararam nisso; outros, por outro lado, abandonaram o cliente leve e se limitaram à implementação do cliente web). Nós decidimos dar aos nossos usuários a possibilidade de escolher a opção de cliente que mais se adequa a eles.

Adicionar a capacidade de trabalhar pela Internet para o cliente leve foi um grande projeto com uma mudança completa na arquitetura de interação cliente-servidor. A criação do cliente web, por outro lado, é um projeto totalmente novo, começando do zero.
Formulação do problema
Então, os requisitos para o projeto: o cliente web deve fazer o mesmo que o cliente leve, ou seja:
- Exibir a interface do usuário
- Executar código do cliente, escrito na linguagem 1C
A interface do usuário em 1C é descrita em um editor visual, mas de forma declarativa, sem organização pixel a pixel dos elementos; são utilizados cerca de trinta tipos de elementos de interface – botões, campos de entrada (textuais, numéricos, data/hora), listas, tabelas, gráficos etc.
O código do cliente na linguagem 1C pode conter chamadas de servidor, manipulação de recursos locais (arquivos etc.), impressão e muito mais.
Tanto o cliente leve (ao trabalhar pela web) quanto o cliente web utilizam o mesmo conjunto de serviços web para comunicação com o servidor de aplicações 1C. A implementação nos clientes, claro, é diferente – o cliente leve é escrito em C++, o cliente web – em JavaScript.
Um pouco de história
O projeto de criação do cliente web começou em 2006, com uma equipe média de 5 pessoas. Em algumas etapas do projeto, desenvolvedores foram envolvidos para implementar funcionalidades específicas (documentos tabulares, gráficos etc.); como regra, eram os mesmos desenvolvedores que haviam feito essa funcionalidade no cliente fino. Ou seja, os desenvolvedores reescreviam em JavaScript componentes que haviam sido criados anteriormente em C++.
Desde o início, rejeitamos a ideia de qualquer conversão automática (mesmo que parcial) de código C++ do cliente fino para JavaScript do cliente web, devido às fortes diferenças conceituais entre essas duas linguagens; o cliente web foi escrito em JavaScript do zero.
Nas primeiras iterações do projeto, o cliente web convertia o código do cliente na linguagem embutida 1C diretamente em JavaScript. O cliente fino opera de forma diferente — o código na linguagem embutida 1C é compilado em bytecode, que é então interpretado no cliente. Posteriormente, o cliente web também começou a fazer isso – primeiro, isso melhorou o desempenho e, em segundo lugar, permitiu unificar a arquitetura dos clientes fino e web.
A primeira versão da plataforma 1C:Enterprise com suporte ao cliente web foi lançada em 2009. Naquele momento, o cliente web suportava 2 navegadores – Internet Explorer e Firefox. Nos planos iniciais, havia suporte para Opera, mas devido a problemas insuperáveis na época com os manipuladores de fechamento do aplicativo no Opera (não era possível detectar com 100% de certeza que o aplicativo estava sendo fechado, e nesse momento realizar o procedimento de desconexão do servidor de aplicativos 1C), esses planos tiveram que ser abandonados.
Estrutura do projeto
No total, a plataforma 1C:Enterprise possui 4 projetos escritos em JavaScript:
- WebTools – bibliotecas gerais utilizadas pelos outros projetos (neste grupo, incluímos ).
- Elemento de controle (implementado em JavaScript tanto no cliente fino quanto no cliente web)
- Elemento de controle (implementado em JavaScript tanto no cliente fino quanto no cliente web)
- Cliente web
A estrutura de cada projeto se assemelha à estrutura de projetos Java (ou projetos .NET – conforme o que for mais familiar); temos namespaces, e cada namespace reside em uma pasta separada. Dentro da pasta, estão os arquivos e classes do namespace. No projeto do cliente web, há cerca de 1000 arquivos.
Estruturalmente, o cliente web é amplamente dividido nas seguintes subsistemas:
- Interface gerenciada do aplicativo cliente
- Interface geral do aplicativo (menus do sistema, painéis)
- Interface de formulários gerenciados, que inclui cerca de 30 elementos de controle (botões, diferentes tipos de campos de entrada – texto, numérico, data/hora e outros, tabelas, listas, gráficos etc.)
- Modelo de objeto disponível para desenvolvedores no cliente (mais de 400 tipos: modelo de objeto da interface gerenciada, configurações de layout de dados, formatação condicional, etc.)
- Interpretador de linguagem embutida 1C
- Extensões de navegador (usadas para funcionalidades não suportadas no JavaScript)
- Trabalho com criptografia
- Trabalhando com arquivos
- Tecnologia de componentes externos, permitindo seu uso tanto no cliente leve quanto no web-client
Características do desenvolvimento
Implementar tudo o que foi descrito acima em JavaScript é uma tarefa complexa. O web-client 1C pode ser um dos maiores aplicativos client-side escritos em JavaScript – cerca de 450.000 linhas. Utilizamos ativamente na codificação do web-client a abordagem orientada a objetos, que facilita o trabalho com um projeto tão grande.
Para minimizar o tamanho do código do cliente, inicialmente utilizamos nosso próprio ofuscador, e a partir da versão da plataforma 8.3.6 (outubro de 2014) começamos a usar . O efeito do uso em números – tamanho do framework do web-client após ofuscação:
- Nosso próprio ofuscador – 1556 kB
- Google Closure Compiler – 1073 kB
O uso do Google Closure Compiler nos ajudou a aumentar a performance do web-client em 30% em comparação com nosso próprio ofuscador. Além disso, houve uma redução de 15-25% (dependendo do navegador) no volume de memória consumido pelo aplicativo.
O Google Closure Compiler trabalha muito bem com código orientado a objetos, portanto sua eficiência para o web-client é máxima. O Closure Compiler faz várias coisas boas para nós:
- Verificação estática de tipos na fase de construção do projeto (assegurada pelo fato de cobrirmos o código com anotações JSDoc). O resultado é uma tipagem estática muito próxima da tipagem em C++. Isso ajuda a capturar uma porcentagem considerável de erros na fase de compilação do projeto.
- Redução do tamanho do código através da ofuscação
- Uma série de otimizações de código executado, como:
- substituições inline de funções. Chamar uma função em JavaScript é uma operação bastante cara, e as substituições inline de pequenos métodos que são frequentemente usados aceleram significativamente o código.
- Contagem de constantes na fase de compilação. Se uma expressão depende de uma constante, o valor real da constante será inserido nela.
Como ambiente de desenvolvimento do cliente da web, usamos o WebStorm.
Para a análise de código, usamos , onde integramos analisadores de código estáticos. Com a ajuda dos analisadores, monitoramos a degradação da qualidade do código-fonte em JavaScript e nos esforçamos para evitar isso.

Quais problemas resolvemos
Durante a implementação do projeto, encontramos uma série de tarefas interessantes que tivemos que resolver.
Troca de dados com o servidor e entre janelas
Existem situações em que a ofuscação do código-fonte pode prejudicar o funcionamento do sistema. O código externo em relação ao código executável do cliente da web, devido à ofuscação, pode ter nomes de funções e parâmetros que diferem daqueles que nosso código executável espera. O código externo para nós é:
- O código vindo do servidor na forma de estruturas de dados
- O código de outra janela do aplicativo
Para evitar ofuscação ao interagir com o servidor, usamos a 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 para evitar ofuscação ao interagir com outras janelas, usamos os chamados interfaces exportáveis (interfaces cujos todos os métodos são exportáveis).
/**
* Экспортируемый интерфейс контрола 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 (){}Usamos Virtual DOM antes de se tornar mainstream)
Assim como todos os desenvolvedores que lidam com uma complexa UI da Web, percebemos rapidamente que o DOM não é adequado para trabalhar com interfaces de usuário dinâmicas. Praticamente imediatamente, um análogo do Virtual DOM foi implementado para otimizar o trabalho com a UI. Durante o processamento de eventos, todas as mudanças no DOM são armazenadas na memória e, somente após a conclusão de todas as operações, as mudanças acumuladas são aplicadas à árvore DOM.
Otimização do funcionamento do cliente da web
Para que nosso cliente da web funcione mais rápido, tentamos ao máximo usar os recursos nativos do navegador (CSS, etc.). Assim, a barra de comando do formulário (localizada praticamente em cada formulário do aplicativo) é renderizada exclusivamente com os recursos do navegador, com uma formatação dinâmica baseada em CSS.

Testes
Para testes funcionais e de desempenho, usamos uma ferramenta desenvolvida internamente (escrita em Java e C++), além de um conjunto de testes baseados em .
Nossa ferramenta é versátil - ela permite testar praticamente qualquer programa de janela, portanto é adequada para testar tanto clientes leves quanto clientes web. A ferramenta grava as ações do usuário que iniciou a solução aplicada '1C' em um arquivo de script. Ao mesmo tempo, as imagens da área de trabalho da tela são gravadas - padrões. Ao controlar novas versões do cliente web, os scripts são executados sem a participação do usuário. Nos casos de discrepância entre a captura de tela e o padrão em qualquer etapa, o teste é considerado falhado, após o que um especialista em qualidade realiza uma investigação - se é um erro ou uma mudança planejada no comportamento do sistema. Em caso de comportamento planejado, os padrões são automaticamente substituídos por novos.
A ferramenta também mede o desempenho dos aplicativos com precisão de 25 milissegundos. Em alguns casos, fazemos um loop em partes do script (por exemplo, repetindo várias vezes a entrada do pedido) para analisar a degradação do tempo de execução ao longo do tempo. Os resultados de todas as medições são registrados em um log para análise.

Nossa ferramenta de teste e o aplicativo testado
Nossa ferramenta e o Selenium se complementam; por exemplo, se algum botão em uma das telas mudou de posição - o Selenium pode não rastrear isso, mas nossa ferramenta notará, pois realiza uma comparação pixel a pixel da captura de tela com o padrão. Além disso, a ferramenta é capaz de detectar problemas com o manuseio de entradas do teclado ou mouse, já que é isso que ela reproduz.
Os testes em ambas as ferramentas (a nossa e o Selenium) executam cenários típicos de trabalho de nossas soluções aplicadas. Os testes são executados automaticamente após a compilação diária da plataforma '1C:Enterprise'. Em caso de lentidão nos scripts (em comparação com a compilação anterior), realizamos uma investigação e removemos a causa da lentidão. Nosso critério é simples - a nova compilação deve funcionar não mais devagar que a anterior.
Para investigar incidentes de lentidão, os desenvolvedores usam diferentes ferramentas; predominantemente é utilizado da empresa . É feito o registro dos logs da execução da operação problemática nas versões anterior e nova, e então os logs são analisados. O tempo de execução de operações individuais (em milissegundos) pode não ser um fator decisivo – no navegador, processos de serviço como a limpeza de memória são periodicamente iniciados e podem interferir no tempo de execução das funções, distorcendo a imagem. Parâmetros mais relevantes nesse caso serão a quantidade de instruções JavaScript executadas, o número de operações atômicas no DOM, etc. Se a quantidade de instruções/operações no mesmo cenário na nova versão aumentou – isso quase sempre significa uma queda no desempenho, que precisa ser corrigida.
Além disso, uma das razões para a queda no desempenho pode ser que o Google Closure Compiler não conseguiu, por algum motivo, realizar a substituição inline da função (por exemplo, porque a função é recursiva ou virtual). Nesse caso, tentamos corrigir a situação reescrevendo o código-fonte.
Extensões de navegador
Quando a solução de aplicativo necessita de funcionalidades que não estão disponíveis em JavaScript, usamos extensões de navegador:
- para trabalhar com arquivos
- para trabalhar com criptografia
- trabalho com
Nossas extensões consistem em duas partes. A primeira parte é o que chamamos de extensão do navegador (geralmente, extensões escritas em JavaScript para Chrome e Firefox), que interage com a segunda parte – uma extensão binária, que implementa a funcionalidade necessária. Vale mencionar que escrevemos 3 versões de extensões binárias – para Windows, Linux e MacOS. A extensão binária é fornecida como parte da plataforma 1C:Enterprise e está localizada no servidor de aplicativos 1C. Na primeira chamada do cliente web, ela é carregada no computador do cliente e instalada no navegador.
Ao trabalhar no Safari, nossas extensões utilizam NPAPI; ao trabalhar no Internet Explorer, utilizam a tecnologia ActiveX. ainda não suporta extensões, portanto, o cliente web nele funciona com limitações.
Desenvolvimento futuro
Um dos grupos de tarefas para a equipe de desenvolvimento do cliente web é a continuidade do desenvolvimento das funcionalidades. As funcionalidades do cliente web devem ser idênticas às do cliente leve, e toda nova funcionalidade é implementada simultaneamente tanto no cliente leve quanto no cliente web.
Outras tarefas incluem o desenvolvimento da arquitetura, refatoração, aumento de desempenho e confiabilidade. Por exemplo, uma das direções é seguir em direção a um modelo de trabalho assíncrono. Atualmente, parte das funcionalidades do cliente web é construída com um modelo de interação síncrona com o servidor. O modelo assíncrono está se tornando mais relevante nos navegadores (e não apenas nos navegadores), o que nos leva a modificar o cliente web substituindo chamadas síncronas por assíncronas (e fazendo as correspondentes refatorações no código). A transição gradual para o modelo assíncrono é explicada pela necessidade de suporte às soluções lançadas e a sua adaptação gradual.
Fonte: habr.com
