Suporte de longo prazo para aplicativos JavaScript

Estamos publicando uma tradução do artigo, que descreve em detalhes o trabalho de longo prazo da equipe para criar e manter um grande portal de dados em JavaScript.


Em 2019, um artigo foi escrito sobre como manter grandes aplicativos JavaScript. Na continuação deste material, gostaríamos de compartilhar um projeto de cliente que minha equipe vem apoiando desde 2014.







Portal de dados da Organização para Cooperação e Desenvolvimento Econômico (OCDE)





Página inicial do portal



A Organização para a Cooperação e Desenvolvimento Econômico é um órgão intergovernamental que coleta dados e publica pesquisas em nome de seus Estados membros. O portal da organização contém informações de vários campos: economia, ecologia, educação, etc.



O portal de dados da OCDE é o principal repositório de dados estatísticos. Ajuda pesquisadores, jornalistas e formuladores de políticas a encontrar informações importantes e a visualizá-las rapidamente por meio de diagramas. O portal OECD também integra uma biblioteca com publicações OECD iLibrary e um recurso OECD.Stat onde todos os dados são armazenados.



A OCDE é financiada por estados membros, ou seja, contribuintes como você e eu. Um dos requisitos do projeto é usar tecnologias econômicas e confiáveis, pois manter o código é importante por muito tempo.



O portal de dados é uma colaboração entre a equipe da OCDE e desenvolvedores e designers externos. O design inicial e o protótipo foram criados por Moritz Stefaner e a equipe Raureif . E a 9elements desenvolveu a parte frontal e ainda a mantém.



Base de código JavaScript complexa



A parte mais difícil do frontend neste portal é o mecanismo de gráficos JavaScript. Ele contém dez tipos principais de gráficos com várias opções de configuração. Usando interfaces poderosas, os usuários podem consultar o banco de dados e criar diagramas para incorporação ou compartilhamento.







Começamos a trabalhar no portal de dados em 2014. Desde então, não foi muito reescrito, apenas novos recursos foram adicionados, pequenas melhorias e refatorações do código. Em dezembro de 2020, adicionamos vários novos recursos para o relatório OECD Economic Outlook , incluindo mais quatro tipos de gráfico. Também reorganizamos a base de código significativamente desta vez.



Neste artigo, vou mostrar como conseguimos manter o código por tanto tempo e melhorá-lo passo a passo. Também vou revelar o que não deu certo.



Tecnologia convencional enfadonha



O projeto começou em 2014 e foi quando escolhemos HTML simples, modelos XSLT, Sass para estilos de tabela e CoffeeScript como uma linguagem que compila com JavaScript. Escolhemos jQuery, D3, D3.chart e Backbone como bibliotecas JavaScript.



Em 2014, essas tecnologias eram as mais seguras e interoperáveis ​​de todas, escolher o CoffeeScript foi uma aposta arriscada. Graças ao CoffeeScript, fomos capazes de nos tornar mais produtivos e escrever um código confiável. Mas sabíamos que essa nova tecnologia poderia ser difícil.



Desde 2015 a equipe 9elementscomeçou a usar React para a maioria dos aplicativos da web em JavaScript. Pensamos em usar o React para uma nova versão do mecanismo de gráficos, mas nem todos conseguiram encontrar o momento certo. Como resultado, descobriu-se que manter a pilha de tecnologia original era a decisão certa.



A pilha de JavaScript que acabamos de descrever pode parecer desatualizada, mas, na verdade, a base de código resistiu ao teste do tempo. Um motivo: as tecnologias que escolhemos ainda são relevantes.



A influência destrutiva do tempo



Muitas bibliotecas JavaScript surgiram e desapareceram, mas jQuery ainda é a mais popular. É confiável, bem suportado e difundido. De acordo com o Web Almanac 2020 , o jQuery é usado por 83% de todos os sites. (Em comparação, React só foi encontrado em 4%.)



Claro, jQuery perdeu sua posição de liderança no tratamento de problemas complexos de DOM. Conforme mencionado, agora escolheríamos React ou Preact para criar esse portal de dados.



Segunda biblioteca, D3permanece o padrão para visualização de dados no navegador. Ela existe desde 2010 e ainda é a líder. Embora alguns dos principais lançamentos tenham mudado significativamente a estrutura e a API, o D3 ainda é uma excelente peça de engenharia.



A biblioteca Backbone não é tão popular, mas tem suas vantagens. Por exemplo, é relativamente simples: você pode ler o código-fonte em uma manhã e refazer as partes principais em um dia. Além disso, o Backbone ainda é compatível. É totalmente funcional, o que é especialmente importante.



Do ponto de vista tecnológico, apenas CoffeeScript não é uma tecnologia relevante na realidade atual. Essa linguagem foi desenvolvida devido a falhas óbvias no ECMAScript 5. Posteriormente, muitas ideias do CoffeeScript foram incorporadas aos padrões ECMAScript 6 (2015) e ECMAScript 7 (2016). De agora em diante, não temos motivos para usá-lo.



Escolhemos o CoffeeScript em 2014 por causa de sua filosofia "É apenas JavaScript". Ao contrário de outras linguagens compiladas com JavaScript, CoffeeScript é uma abstração direta. CoffeeScript compila em JavaScript puro sem surpresas.



A maioria das empresas hoje migrou suas bases de código do CoffeeScript para o JavaScript moderno. E nós fizemos o mesmo.



De CoffeeScript para TypeScript



Com essa ferramenta descafeinante , convertemos o código CoffeeScript para ECMAScript 6 (2015). Queríamos continuar a oferecer suporte aos mesmos navegadores, então agora estamos usando o compilador Babel para criar um ECMAScript 5 compatível com versões anteriores.



No geral, a transição ocorreu sem problemas, mas não queríamos parar por aí.



Em novos projetos, os desenvolvedores de 9elementos usam TypeScript. Na minha opinião, o TypeScript é a melhor coisa que aconteceu no mundo do JavaScript nos últimos anos. Como mencionei em meu artigo anterior, o TypeScript faz você pensar sobre os tipos e ensina a nomeá-los corretamente.



Para nosso portal de dados, íamos tirar proveito do TypeScript sem converter a base de código para TypeScript totalmente tipado.



TypeScript é um superconjunto de JavaScript. O compilador entende bem os arquivos .js. Portanto, gradualmente adicionamos anotações de tipo usando tecnologia de 20 anos atrás - JSDOC . Além disso, vários tipos (tipificações) foram escritos nos arquivos .ts para referenciá-los nas anotações JSDOC.



Portanto, a experiência de desenvolvimento no Visual Studio Code cresceu significativamente sem muito esforço. Embora não haja verificação de tipo estrita aqui, editar o código é tão conveniente quanto em um projeto TypeScript normal.



Combinando uma tecnologia entediante, mas robusta, com o compilador TypeScript mais recente, fomos capazes de adicionar novos recursos e refatorar o código com segurança e facilidade.



Documentação e comentários de código



Superficialmente, a codificação é uma conversa entre você e o computador: você diz ao computador o que ele precisa fazer.



Mas, na realidade, a codificação é uma conversa entre você e o leitor do código. É bem sabido que o código é escrito uma vez e lido repetidamente. Em primeiro lugar, você escreve o código para o seu futuro eu.



Adicionamos muitos comentários à base de código do portal e quase todos eles conseguiram provar seu valor nos últimos seis anos. Obviamente, o código deve ser estruturado de forma a ajudar os leitores a entendê-lo. Mas eu não acredito em códigos "autodescritivos" ou "autodocumentados".



Antes de mudar para o JSDOC, criamos anotações de tipo fáceis de ler, documentamos parâmetros de função e valores de retorno. Também documentamos tipos de dados básicos e estruturas complexas de objetos aninhados.



Esses comentários foram realmente úteis seis anos depois. Nós os traduzimos em JSDOC legível por máquina e declarações de tipo para o compilador TypeScript.



As coisas quebram - sempre tenha um conjunto de testes à mão



O projeto tem apenas alguns testes de unidade automatizados e mais de 50 (!) Páginas de teste que demonstram todas as páginas do portal, componentes, interfaces de consulta de dados, tipos de gráficos e configurações. Eles testam dados ao vivo, de teste e de simulação.



Essas páginas de teste fazem a mesma coisa que os testes automatizados: se corrigirmos um bug, primeiro adicionamos o script à página de teste correspondente. Se estamos desenvolvendo um novo recurso, ao mesmo tempo, criamos uma página de teste completa.





Página de teste



Antes do lançamento, verificamos manualmente todas as páginas de teste e as comparamos com a última, tanto visual quanto funcionalmente. Isso é demorado, mas permite que você encontre regressões rapidamente.



Não acho que um conjunto de testes automatizado seja mais eficiente. É quase impossível testar automaticamente as visualizações de dados interativos em um navegador. O teste de regressão visual é uma ferramenta valiosa, mas em nosso caso pode gerar muitos erros falsos.



Compatibilidade com versões anteriores e posteriores



Em 2014, nosso portal deveria funcionar com o Internet Explorer 9. Agora o Internet Explorer não é tão importante, especialmente ao criar um mecanismo dinâmico para plotagem no navegador.



No entanto, decidimos manter a compatibilidade com navegadores mais antigos. O portal de dados é uma plataforma internacional onde usuários de todo o mundo visitam. Nem todo mundo tem os computadores mais recentes e novos navegadores.





Portal no Internet Explorer 9



Conseguimos manter um nível básico de suporte ao navegador usando tecnologias padrão enfadonhas. Obviamente, também existem alguns recursos da Web modernos, mas só os ativamos se o navegador for compatível. É aqui que a abordagem de Aprimoramento Progressivo nos ajuda. (melhora progressiva). Também usamos Babel e polyfills para fazer as funções JavaScript modernas funcionarem em navegadores mais antigos.



Suas abstrações podem morder



Ao longo dos anos, não fomos limitados pela pilha de tecnologia. Em vez disso, suas próprias abstrações atrapalharam.



Dividimos a interface do usuário em partes visuais (visualizações) e criamos uma classe base semelhante a Backbone.View. (Hoje, todas as grandes bibliotecas JavaScript usam o termo "componente" em vez de "visualização" para partes da interface do usuário.) Usamos Backbone.Model para armazenar dados e estado. Funcionou muito bem, mas decidimos seguir nossas próprias práticas recomendadas.



A ideia por trás da divisão da visão do modelo do Backbone é que esse modelo é a única fonte de verdade. O DOM deve apenas refletir os dados do modelo. Todas as mudanças também devem vir do modelo. Estruturas modernas como React, Vue e Angular seguem a convenção de que a UI é uma "função de estado", o que significa que a UI é definitivamente derivada do estado.



Violamos esse princípio e às vezes transformamos o DOM na fonte da verdade. Isso levou à confusão com o código que via o modelo como uma fonte confiável.



Gráficos orientados a objetos



Para gráficos, adotamos uma abordagem diferente: criamos classes de gráficos diferentes das descritas acima.



O próprio D3 é funcional. Um gráfico geralmente é criado e atualizado com uma função de renderização que chama outras funções. Esses diagramas são introdutórios a esse ótimo recurso. Mais estado está contido em objetos específicos.



Isso torna o D3 expressivo e flexível. Mas o código D3 é difícil de ler porque existem pequenas convenções (convenções que não são documentadas) para lidar com estruturas de gráficos.



Irene Ros e Mike Pennisi, desenvolvedores da Bocoup, inventaram o d3.chart, uma pequena biblioteca no topo do D3 que representa OOP baseado em classes. Seu principal objetivo era estruturar e reutilizar o código de gráficos. Esses diagramas são compostos de camadas, cada uma das quais renderiza e atualiza uma parte específica do DOM usando D3. Além disso, outros diagramas podem ser anexados a gráficos.



A regra geral de OOP é "A composição prevalece sobre a herança." Infelizmente, escolhemos uma estranha combinação de composição e herança para o comportamento do diagrama.



Precisávamos usar funções ou classes simples em vez de hierarquias de classes complexas. As pessoas ainda estão envolvendo D3 em OOP baseado em classe, mas nenhuma solução baseada em classe foi capaz de superar a estrutura funcional do D3.



Vamos resumir



Desde que desenvolvemos a parte do front-end do portal de dados em 2014, houve muitas abordagens interessantes para construir interfaces da web baseadas em JavaScript.



Agora os componentes da IU são declarativos, você pode fazer sem renderizar modelos HTML e atualizar o DOM manualmente. Você apenas atualiza o estado e a estrutura atualiza o DOM. Esse fluxo de dados unidirecional elimina toda uma classe de bugs.



As tecnologias que escolhemos em 2014 resistiram ao teste do tempo ou facilitaram a mudança para uma pilha diferente. Você pode pensar que tivemos sorte, mas deliberadamente escolhemos tecnologias duráveis.



Na 9elements, sempre tentamos usar tecnologias modernas, incluindo a avaliação de tecnologias front-end experimentais que podem não ser relevantes em 3-4 anos. Infelizmente, muitos projetos JavaScript de código aberto podem ser tecnicamente progressivos, mas instáveis.



Para cada projeto, procuramos o equilíbrio ideal entre tecnologias sustentáveis ​​com riscos mínimos e uma pilha inovadora, que nos ajuda a criar um produto de qualidade.



All Articles