Soporte a largo plazo para aplicaciones JavaScript

Estamos publicando una traducción del artículo, que describe en detalle el trabajo a largo plazo del equipo para crear y mantener un gran portal de datos en JavaScript.


En 2019, se escribió un artículo sobre el mantenimiento de grandes aplicaciones JavaScript. Como continuación de este material, nos gustaría compartir un proyecto de cliente que mi equipo ha estado apoyando desde 2014.







Portal de datos de la Organización para la Cooperación y el Desarrollo Económicos (OCDE)





Página de inicio del portal



La Organización para la Cooperación y el Desarrollo Económicos es un organismo intergubernamental que recopila datos y publica investigaciones en nombre de sus estados miembros. El portal de la organización contiene información de diversos campos: economía, ecología, educación, etc.



El portal de datos de la OCDE es el principal repositorio de datos estadísticos. Ayuda a investigadores, periodistas y legisladores a encontrar información importante y visualizarla rápidamente mediante diagramas. El portal de la OCDE también integra una biblioteca con las publicaciones iLibrary de la OCDE y un recurso OECD.Stat donde se almacenan todos los datos.



La OCDE está financiada por los estados miembros, es decir, contribuyentes como usted y yo. Uno de los requisitos del proyecto es utilizar tecnologías rentables y fiables, ya que mantener el código es importante durante mucho tiempo.



El portal de datos es una colaboración entre el personal de la OCDE y desarrolladores y diseñadores externos. El diseño y el prototipo inicial fueron creados por Moritz Stefaner y el equipo de Raureif . Y 9elements desarrolló la parte frontal y aún la mantiene.



Base de código JavaScript compleja



La parte más difícil de la interfaz de este portal es el motor de gráficos JavaScript. Contiene diez tipos principales de gráficos con numerosas opciones de configuración. Mediante potentes interfaces, los usuarios pueden consultar la base de datos y crear diagramas para incorporarlos o compartirlos.







Comenzamos a trabajar en el portal de datos en 2014. Desde entonces, no se ha reescrito mucho, solo se han agregado nuevas características, pequeñas mejoras y refactorizaciones del código. En diciembre de 2020, agregamos varias características nuevas para el informe de Perspectivas económicas de la OCDE , incluidos cuatro tipos de gráficos más. También reorganizamos significativamente la base de código esta vez.



En este artículo, te mostraré cómo logramos mantener el código durante tanto tiempo y mejorarlo paso a paso. También revelaré lo que no funcionó.



Aburrida tecnología convencional



El proyecto comenzó en 2014 y fue entonces cuando elegimos HTML simple, plantillas XSLT, Sass para estilos de tabla y CoffeeScript como lenguaje que se compila con JavaScript. Elegimos jQuery, D3, D3.chart y Backbone como bibliotecas de JavaScript.



En 2014, estas tecnologías fueron las más seguras e interoperables, de todas, elegir CoffeeScript fue una apuesta arriesgada. Gracias a CoffeeScript, hemos podido ser más productivos y hemos escrito código confiable. Pero sabíamos que esta nueva tecnología podría ser difícil.



Desde 2015 el equipo de 9elementscomenzó a usar React para la mayoría de las aplicaciones web de JavaScript. Pensamos en usar React para una nueva versión del motor de gráficos, pero no todos pudieron encontrar el momento adecuado. Como resultado, resultó que apegarse a la pila de tecnología original fue la decisión correcta.



La pila de JavaScript que se acaba de describir puede parecer obsoleta, pero de hecho, la base de código ha resistido la prueba del tiempo. Una razón: las tecnologías que hemos elegido siguen siendo relevantes.



La influencia destructiva del tiempo



Muchas bibliotecas de JavaScript han ido y venido, pero jQuery sigue siendo la más popular. Es confiable, bien respaldado y generalizado. Según Web Almanac 2020 , jQuery es utilizado por el 83% de todos los sitios web. (En comparación, React solo se encontró al 4%).



Por supuesto, jQuery ha perdido su posición de liderazgo al abordar problemas complejos de DOM. Como se mencionó, ahora mismo elegiríamos React o Preact para crear dicho portal de datos.



Segunda biblioteca, D3sigue siendo el estándar para la visualización de datos en el navegador. Existe desde 2010 y sigue siendo líder. Aunque un par de versiones importantes han cambiado significativamente la estructura y la API, D3 sigue siendo una pieza de ingeniería sobresaliente.



La biblioteca Backbone no es tan popular, pero tiene sus ventajas. Por ejemplo, es relativamente simple: puede leer el código fuente en una mañana y rehacer las partes principales en un día. Además, Backbone sigue siendo compatible. Es completamente funcional, lo cual es especialmente importante.



Desde un punto de vista tecnológico, solo CoffeeScript no es una tecnología relevante en las realidades actuales. Este lenguaje se desarrolló debido a fallas obvias en ECMAScript 5. Posteriormente, muchas ideas de CoffeeScript se incorporaron a los estándares ECMAScript 6 (2015) y ECMAScript 7 (2016). De ahora en adelante, no tenemos ninguna razón para usarlo.



Elegimos CoffeeScript en 2014 debido a su filosofía "Es solo JavaScript". A diferencia de otros lenguajes compilados con JavaScript, CoffeeScript es una abstracción sencilla. CoffeeScript se compila en JavaScript puro sin sorpresas.



Hoy en día, la mayoría de las empresas han migrado sus bases de código de CoffeeScript a JavaScript moderno. E hicimos lo mismo.



De CoffeeScript a TypeScript



Con esta herramienta de descafeinado , convertimos el código CoffeeScript a ECMAScript 6 (2015). Queríamos seguir admitiendo los mismos navegadores, por lo que ahora estamos usando el compilador de Babel para crear ECMAScript 5 compatible con versiones anteriores.



En general, la transición se realizó sin problemas, pero no queríamos detenernos allí.



En proyectos nuevos, los desarrolladores de 9elements usan TypeScript. En mi opinión, TypeScript es lo mejor que ha sucedido en el mundo de JavaScript en los últimos años. Como mencioné en mi artículo anterior, TypeScript te hace pensar en tipos y te enseña a nombrarlos correctamente.



Para nuestro portal de datos, íbamos a aprovechar TypeScript sin convertir la base de código a TypeScript completamente escrito.



TypeScript es un superconjunto de JavaScript. El compilador comprende bien los archivos .js. Por lo tanto, agregamos gradualmente anotaciones de tipo utilizando tecnología de hace 20 años: JSDOC . Además de esto, se escribieron varios tipos (mecanografía) en los archivos .ts para hacer referencia a ellos en las anotaciones JSDOC.



Por lo tanto, la experiencia de desarrollo en Visual Studio Code ha crecido significativamente sin mucho esfuerzo. Si bien aquí no hay una verificación de tipo estricta, editar el código es tan conveniente como en un proyecto normal de TypeScript.



Al combinar una tecnología bastante aburrida pero robusta con el último compilador de TypeScript, pudimos agregar nuevas funciones y refactorizar el código de manera segura y sencilla.



Comentarios de documentación y código



En la superficie, la codificación es una conversación entre usted y la computadora: usted le dice a la computadora lo que necesita hacer.



Pero, en realidad, la codificación es una conversación entre usted y el lector del código. Es bien sabido que el código se escribe una vez y se lee una y otra vez. En primer lugar, escribe código para su yo futuro.



Hemos agregado muchos comentarios al código base del portal, y casi todos ellos han logrado demostrar su valía durante los últimos seis años. Obviamente, el código debe estar estructurado de tal manera que ayude a los lectores a comprenderlo. Pero no creo en el código "autodescriptivo" o "autodocumentado".



Antes de pasar a JSDOC, hicimos anotaciones de tipo fáciles de leer, documentamos parámetros de función y valores de retorno. También hemos documentado tipos de datos básicos y estructuras complejas de objetos anidados.



Estos comentarios fueron realmente útiles seis años después. Los tradujimos a JSDOC legible por máquina y declaraciones de tipo para el compilador TypeScript.



Las cosas se rompen: siempre tenga a mano un conjunto de pruebas



El proyecto tiene solo unas pocas pruebas unitarias automatizadas y más de 50 (!) Páginas de prueba que demuestran todas las páginas del portal, componentes, interfaces de consulta de datos, tipos de gráficos y configuraciones. Prueban datos en vivo, de ensayo y simulados.



Estas páginas de prueba hacen lo mismo que las pruebas automatizadas: si arreglamos un error, primero agregamos el script a la página de prueba correspondiente. Si estamos desarrollando una nueva función, al mismo tiempo creamos una página de prueba completa.





Página de prueba



Antes del lanzamiento, verificamos manualmente todas las páginas de prueba y las comparamos con la última tanto visual como funcionalmente. Esto lleva mucho tiempo, pero le permite encontrar regresiones rápidamente.



No creo que una suite de pruebas automatizada sea más eficiente. Es casi imposible probar automáticamente visualizaciones de datos interactivas en un navegador. La prueba de regresión visual es una herramienta valiosa, pero en nuestro caso puede dar demasiados errores falsos.



Compatibilidad con versiones anteriores y posteriores



En 2014, se suponía que nuestro portal funcionaba con Internet Explorer 9. Ahora Internet Explorer no es tan importante, especialmente cuando se crea un motor dinámico para trazar en el navegador.



Sin embargo, decidimos mantener la compatibilidad con los navegadores más antiguos. El portal de datos es una plataforma internacional a la que visitan usuarios de todo el mundo. No todo el mundo tiene las últimas computadoras y navegadores nuevos.





Portal en Internet Explorer 9



Pudimos mantener un nivel básico de compatibilidad con el navegador mediante el uso de aburridas tecnologías estándar. Por supuesto, también hay algunas funciones web modernas, pero solo las activamos si el navegador lo admite. Aquí es donde nos ayuda el enfoque de mejora progresiva . (mejora progresiva). También usamos Babel y polyfills para hacer que las funciones modernas de JavaScript funcionen en navegadores más antiguos.



Tus abstracciones pueden morder



A lo largo de los años, no hemos estado limitados por la pila de tecnología. Más bien, sus propias abstracciones se interpusieron en el camino.



Dividimos la interfaz de usuario en partes visuales (vistas) y creamos una clase base similar a Backbone.View. (Hoy en día, todas las bibliotecas grandes de JavaScript usan el término "componente" en lugar de "vista" para partes de la interfaz de usuario). Usamos Backbone.Model para almacenar datos y estados. Funcionó muy bien, pero decidimos ceñirnos a nuestras propias mejores prácticas.



La idea detrás de dividir la visión del modelo Backbone es que este modelo es la única fuente de verdad. El DOM debería reflejar los datos del modelo. Todos los cambios también deben provenir del modelo. Los marcos modernos como React, Vue y Angular siguen la convención de que la IU es una "función de estado", lo que significa que la IU es definitivamente derivada del estado.



Violamos este principio y, a veces, hicimos del DOM la fuente de la verdad. Esto generó confusión con el código que consideraba al modelo como una fuente autorizada.



Gráficos orientados a objetos



Para los gráficos, adoptamos un enfoque diferente: creamos clases de gráficos que son diferentes de las descritas anteriormente.



El D3 en sí es funcional. Un gráfico generalmente se crea y actualiza con una función de renderizado que llama a otras funciones. Estos diagramas son una introducción a esta gran característica. Más estado está contenido en objetos específicos.



Esto hace que D3 sea expresivo y flexible. Pero el código D3 es difícil de leer porque hay pequeñas convenciones (convenciones que no están documentadas) para tratar con estructuras de gráficos.



Irene Ros y Mike Pennisi, desarrolladores de Bocoup, inventaron d3.chart, una pequeña biblioteca sobre D3 que representa la POO basada en clases. Su objetivo principal era estructurar y reutilizar el código de gráficos. Estos diagramas se componen de capas, cada una de las cuales renderiza y actualiza una parte específica del DOM usando D3. Además, se pueden adjuntar otros diagramas a los gráficos.



La regla general de OOP es "La composición prevalece sobre la herencia". Desafortunadamente, elegimos una extraña combinación de composición y herencia para el comportamiento del diagrama.



Necesitábamos usar funciones o clases simples en lugar de jerarquías de clases complejas. La gente todavía está envolviendo D3 en OOP basada en clases, pero ninguna solución basada en clases ha podido superar la estructura funcional de D3.



Resumamos



Desde que desarrollamos la parte de front-end del portal de datos en 2014, ha habido muchos enfoques interesantes para crear interfaces web basadas en JavaScript.



Ahora los componentes de la interfaz de usuario son declarativos, puede prescindir de renderizar plantillas HTML y actualizar el DOM manualmente. Simplemente actualiza el estado y el marco actualiza el DOM. Este flujo de datos unidireccional elimina toda una clase de errores.



Las tecnologías que elegimos en 2014 resistieron la prueba del tiempo o facilitaron el cambio a una pila diferente. Podría pensar que tuvimos suerte, pero deliberadamente hicimos una elección a favor de tecnologías duraderas.



En 9elements siempre intentamos utilizar tecnologías modernas, incluida la evaluación de tecnologías frontales experimentales que pueden no ser relevantes en 3-4 años. Desafortunadamente, muchos proyectos de JavaScript de código abierto pueden ser técnicamente progresivos, pero inestables.



Para cada proyecto, buscamos el equilibrio óptimo entre tecnologías sostenibles con riesgos mínimos y un stack innovador, que nos ayude a crear un producto de calidad.



All Articles