Administración de la complejidad

Mantener una aplicación web simple puede ser sorprendentemente complicado. En este módulo, aprenderás cómo funcionan las APIs web con los subprocesos y cómo puedes usarlas para patrones comunes de AWP, como la administración del estado.

Simplicidad y complejidad

En su charla Simple Made Easy, Rich Hickey habla sobre las cualidades de los elementos simples frente a los complejos. Según describe, las cosas simples se centran en lo siguiente:

“Un rol, una tarea, un concepto o una dimensión”.

Sin embargo, enfatiza que la simplicidad no se trata de lo siguiente:

“Tener una instancia o realizar una operación”.

Que algo sea simple o no tiene que ver con lo interconectado que está.

La complejidad proviene de encuadrar, entrelazar o, según el término de Rich, combinar las cosas. Para calcular la complejidad, puedes contar la cantidad de roles, tareas, conceptos o dimensiones que algo administra.

La simplicidad es esencial en el desarrollo de software porque el código simple es más fácil de entender y mantener. La simplicidad también es necesaria para las aplicaciones web porque puede ayudar a que nuestra aplicación sea rápida y accesible en todos los contextos posibles.

Administración de la complejidad de las AWP

Todo el código JavaScript que escribimos para la Web afecta al subproceso principal en algún momento. Sin embargo, el subproceso principal tiene mucha complejidad lista para usar sobre la que no puedes controlar, como desarrollador.

Este es el subproceso principal:

  • Es responsable de dibujar la página, que en sí es un proceso complejo de varios pasos que implica calcular estilos, actualizar y componer capas, y pintar en pantalla.
  • Es responsable de escuchar y reaccionar a eventos, incluidos eventos como el desplazamiento.
  • Responsable de cargar y descargar la página.
  • Administrar medios, identidad y seguridad Eso es todo antes de que cualquier código que escribas pueda ejecutarse en ese subproceso, por ejemplo:
  • Manipulación del DOM
  • Acceder a APIs sensibles, como las capacidades del dispositivo o el contenido multimedia, la seguridad o la identidad

Como Surma dijo en su charla de Chrome Dev Summit 2019, el tema principal está sobrecargado y pagado de menos.

Sin embargo, la mayor parte del código de la aplicación también reside en el subproceso principal.

Todo ese código aumenta la complejidad del subproceso principal. El subproceso principal es el único que el navegador puede usar para diseñar y renderizar contenido en la pantalla. Por lo tanto, cuando tu código requiere cada vez más capacidad de procesamiento para completarse, debemos ejecutarlo rápidamente, porque cada segundo que lleva realizar la lógica de la aplicación es un segundo en que el navegador no puede responder a las entradas del usuario ni volver a dibujar la página.

Cuando las interacciones no se conectan a la entrada, cuando los marcos disminuyen o cuando tarda demasiado en usar un sitio, los usuarios se frustran, sienten que la aplicación no funciona y su confianza en ella disminuye.

pero la mala noticia es que Agregar complejidad al hilo principal es una forma casi segura de dificultar el cumplimiento de estos objetivos. pero la buena noticia es que, Porque lo que debe hacer el subproceso principal es claro: se puede usar como guía para ayudar a reducir la dependencia de él para el resto de tu aplicación.

Separaciones de problemas

Las aplicaciones web realizan muchos tipos diferentes de trabajos, pero, en términos generales, puedes dividirlo en trabajo que toca directamente la IU y trabajo que no. El trabajo de la IU es aquel que:

  • Toca directamente el DOM.
  • Usa APIs que tocan las capacidades del dispositivo, por ejemplo, notificaciones o acceso al sistema de archivos.
  • Toca la identidad, por ejemplo, las cookies del usuario y el almacenamiento local o de sesión.
  • Administra contenido multimedia, como imágenes, audio o video.
  • Tiene implicaciones de seguridad que requerirían la intervención del usuario para su aprobación, como la API de serie web.

El trabajo que no es de IU puede incluir lo siguiente:

  • Puros cálculos.
  • Acceso a los datos (recuperación, IndexedDB, etcétera).
  • Criptomonedas.
  • Mensajes.
  • Creación de BLOB o transmisión, o manipulación.

El trabajo que no es de IU suele estar restringido por el trabajo de la IU: un usuario hace clic en un botón que activa una solicitud de red para una API que muestra resultados analizados que luego se usan para actualizar el DOM. Cuando se escribe código, se suele tener en cuenta esta experiencia de extremo a extremo, pero no suele ocurrir dónde se encuentra cada parte de ese flujo. Los límites entre el trabajo con la IU y el trabajo que no corresponde a la IU son tan importantes como las experiencias de extremo a extremo, ya que son el primer lugar en el que puedes reducir la complejidad del subproceso principal.

Enfócate en una sola tarea

Una de las formas más sencillas de simplificar el código es dividir las funciones para que cada una se enfoque en una sola tarea. Las tareas se pueden determinar a partir de los límites identificados a través de la experiencia de extremo a extremo:

  • Primero, responde a las entradas del usuario. Este es el trabajo de la IU.
  • Luego, realiza una solicitud a la API. Este trabajo no es de IU.
  • A continuación, analiza la solicitud a la API. De nuevo, esto no es un trabajo relacionado con la IU.
  • A continuación, determina los cambios en el DOM. Esto puede ser trabajo de la IU o, si usas algo como una implementación de DOM virtual, es posible que no sea trabajo de la IU.
  • Por último, realiza los cambios en el DOM. Este es el trabajo de la IU.

Los primeros límites claros se encuentran entre el trabajo de la IU y el trabajo que no lo hace. Además, hay que realizar juicios: ¿realizar y analizar una solicitud a la API es una o dos tareas? Si los cambios del DOM no corresponden a la IU, ¿se incluyen en el trabajo de la API? ¿Está en la misma conversación? ¿Estás en otra conversación? El nivel adecuado de separación aquí es clave para simplificar tu base de código y poder mover con éxito partes de ella fuera del subproceso principal.

Componibilidad

Para dividir los flujos de trabajo grandes de extremo a extremo en partes más pequeñas, debes pensar en la componibilidad de tu base de código. Toma señales de la programación funcional, considera lo siguiente:

  • Categorizar los tipos de trabajo que realiza tu aplicación.
  • Compilación de interfaces de entrada y salida comunes para ellos

Por ejemplo, todas las tareas de recuperación de API toman el extremo de la API y muestran un array de objetos estándar, y todas las funciones de procesamiento de datos toman y muestran un array de objetos estándar.

JavaScript tiene un algoritmo de clonación estructurado diseñado para copiar objetos JavaScript complejos. Los trabajadores web lo usan cuando envían mensajes, mientras que IndexedDB lo usa para almacenar objetos. Elegir interfaces que puedas usar con el algoritmo de clonación estructurada hará que sean aún más flexibles de ejecución.

Con esto en mente, puedes crear una biblioteca de funciones de componibilidad categorizando tu código y creando interfaces de E/S comunes para esas categorías. El código de componibilidad es un sello distintivo de las bases de código simples: piezas intercambiables y con acoplamiento bajo que pueden ubicarse una al lado de la otra y compilarse unas sobre otras, a diferencia del código complejo que está profundamente interconectado y, por lo tanto, no puede separarse fácilmente. Y, en la Web, el código componible puede marcar la diferencia entre trabajar en exceso o no en el subproceso principal.

Con el código componible a mano, es hora de quitarlo del subproceso principal.

Cómo usar trabajadores web para reducir la complejidad

Los trabajadores web, una función web a menudo poco utilizada pero ampliamente disponible, te permiten quitar el trabajo del subproceso principal.

Los trabajadores web permiten que una AWP ejecute (algo) JavaScript fuera del subproceso principal.

Hay tres tipos de trabajadores.

Los trabajadores dedicados, lo que se considera más comúnmente cuando se describen los trabajadores web, se pueden usar con una sola secuencia de comandos en una única instancia en ejecución de una AWP. Siempre que sea posible, el trabajo que no interactúe directamente con el DOM se debe mover a un trabajador web para mejorar el rendimiento.

Los trabajadores compartidos son similares a los trabajadores dedicados, excepto que varias secuencias de comandos pueden compartirlos en varias ventanas abiertas. Esto proporciona los beneficios de un trabajador dedicado, pero con un estado compartido y un contexto interno entre las ventanas y las secuencias de comandos.

Por ejemplo, un trabajador compartido podría administrar el acceso y las transacciones de la IndexedDB de una AWP y transmitir resultados de las transacciones en todas las secuencias de comandos de llamada para permitirle reaccionar a los cambios.

El último trabajador web es uno que se aborda en profundidad en este curso: los service worker, que actúan como proxy para las solicitudes de red y se comparten entre todas las instancias de una AWP.

Pruébalo

¡Es hora de codificar! Compila una AWP desde cero según todo lo que aprendiste en este módulo.

Recursos