Cumplimiento en el ecosistema de frameworks de JavaScript
En nuestra entrada de blog de introducción, explicamos cómo aprendimos mucho mientras compilamos y usamos frameworks y herramientas para desarrollar y mantener aplicaciones web a gran escala, como la Búsqueda de Google, Maps, Fotos, etcétera. Protegiendo a los desarrolladores de escribir código que pueda afectar negativamente la experiencia del usuario, demostramos que los frameworks pueden desempeñar un papel clave en el cambio de resultados para el rendimiento y la calidad de las aplicaciones.
En Google, usamos el término "Cumplimiento" para describir esta metodología, y en este artículo, se explica cómo planeamos hacer que este concepto sea de código abierto para el ecosistema del framework de JavaScript.
¿Qué es el cumplimiento?
En Google, la Conformidad fue una evolución. Los equipos se basaban en un pequeño conjunto de mantenedores con mucha experiencia que realizaban revisiones de código exhaustivas y marcaban elementos que afectaban la calidad y la capacidad de mantenimiento de la app más allá de los problemas de corrección. Para escalar esto a equipos crecientes de desarrolladores de apps, se desarrolló un sistema de cumplimiento para codificar las prácticas recomendadas de una manera automatizada y ejecutable. Esto garantizó un nivel alto y constante de calidad de la app y capacidad de mantenimiento de la base de código, independientemente de la cantidad de colaboradores de código.
El cumplimiento es un sistema que garantiza que los desarrolladores sigan el camino correcto, genera confianza y garantiza resultados predecibles. Hace que los equipos sean más productivos y se vuelve fundamental para la escalabilidad, a medida que los equipos crecen y se desarrollan más funciones de forma simultánea. Permite que los desarrolladores se enfoquen en compilar funciones del producto, lo que los libera de los detalles y el panorama cambiante en varias áreas, como el rendimiento, la accesibilidad, la seguridad, etcétera. Cualquier persona puede inhabilitar la Conformidad en cualquier momento, y debe ser personalizable en la medida en que los equipos tengan la opción de aplicar lo que decidan comprometerse.
El cumplimiento se basa en valores predeterminados sólidos y en proporcionar reglas prácticas que se pueden aplicar en el momento de la creación. Esto se desglosa en los siguientes 3 principios.
1. Valores predeterminados sólidos
Un aspecto fundamental de la conformidad es garantizar que las herramientas que usan los desarrolladores tengan parámetros predeterminados sólidos. Esto significa que las soluciones no solo están integradas en los frameworks, sino que los patrones de diseño de estos facilitan hacer lo correcto y dificultan seguir los antipatrones. El framework ayuda a los desarrolladores con el diseño de aplicaciones y la estructura de código.
Para mejorar el rendimiento de carga, se debe optimizar cada recurso (fuentes, CSS, JavaScript, imágenes, etcétera). Este es un desafío complejo que implica recortar bytes, reducir los viajes de ida y vuelta y separar lo que se necesita para la primera renderización, la preparación visual y la interacción del usuario. Por ejemplo, extraer CSS crítico y establecer la prioridad en imágenes importantes.
2. Reglas prácticas
Incluso con las optimizaciones básicas implementadas, los desarrolladores aún deben tomar decisiones. Hay un abanico de posibilidades para las optimizaciones en cuanto a la cantidad de entradas del desarrollador que se necesitan:
- Valores predeterminados que no requieren entradas del desarrollador, como la incorporación de CSS crítico.
- Requiere la habilitación del desarrollador. Por ejemplo, usar un componente de imagen proporcionado por el framework para ajustar el tamaño y la escala de las imágenes.
- Requiere la personalización y la habilitación del desarrollador. Por ejemplo, etiquetar imágenes importantes para que se carguen antes.
- No es una función específica, sino elementos que aún requieren la decisión del desarrollador. Por ejemplo, evitar fuentes o secuencias de comandos síncronas que retrasan la renderización anticipada.
Las optimizaciones que requieren que los desarrolladores tomen decisiones representan un riesgo para el rendimiento de la aplicación. A medida que se agregan funciones y tu equipo se expande, incluso los desarrolladores más experimentados no pueden seguir el ritmo de las prácticas recomendadas que cambian constantemente, ni es la mejor forma de aprovechar su tiempo. En el caso del cumplimiento, las reglas prácticas adecuadas son tan importantes como los valores predeterminados sólidos para garantizar que la aplicación siga cumpliendo con un cierto estándar, incluso cuando los desarrolladores sigan realizando cambios.
3. Hora de autoría
Es importante detectar y evitar los problemas de rendimiento desde el principio del ciclo de vida de desarrollo. El tiempo de autoría, antes de que se confirme el código, es ideal para detectar y abordar los problemas. Cuanto más tarde se detecte un problema en el ciclo de vida de desarrollo, más difícil y costoso será abordarlo. Si bien esto se aplica a los problemas de exactitud, también es cierto para los problemas de rendimiento, ya que muchos de estos problemas no se abordarán de forma retroactiva una vez que se confirmen en la base de código.
Actualmente, la mayoría de los comentarios sobre el rendimiento se realizan fuera del flujo de trabajo a través de la documentación, auditorías únicas o se muestran demasiado tarde a través de la regresión de métricas después de la implementación en producción. Queremos llevar esto al momento de la creación.
Cumplimiento en los frameworks
Para mantener un nivel alto de experiencia del usuario en el rendimiento de carga, se deben responder las siguientes preguntas:
- ¿Qué constituye una carga óptima y cuáles son los problemas comunes que podrían afectarla de manera negativa?
- ¿Qué soluciones se pueden incorporar sin necesidad de aportes de los desarrolladores?
- ¿Cómo podemos asegurarnos de que el desarrollador use estas soluciones y las aproveche de manera óptima?
- ¿Qué otras opciones podría elegir el desarrollador que afecten el rendimiento de carga?
- ¿Cuáles son los patrones de código que pueden informarnos sobre estas opciones (pasos 3 y 4 anteriores) al principio del proceso de creación?
- ¿Qué reglas podemos formular para evaluar estos patrones de código? ¿Cómo se pueden mostrar al desarrollador en el momento de la creación y, al mismo tiempo, integrarse sin problemas en su flujo de trabajo?
Para llevar el modelo de Conformance que tenemos internamente en Google a los frameworks de código abierto, nuestro equipo experimentó mucho en Next.js y nos complace compartir nuestra visión y nuestros planes refinados. Nos dimos cuenta de que el mejor conjunto de reglas que pueden evaluar los patrones de código deberá ser una combinación de análisis de código estático y verificaciones dinámicas. Estas reglas pueden abarcar varias plataformas, incluidas las siguientes:
- ESLint
- TypeScript
- Verificaciones dinámicas en el servidor de desarrollo del usuario (después de la creación del DOM)
- Agrupador de módulos (webpack)
- Herramientas de CSS (aún en fase exploratoria)
Si aprovechamos la posibilidad de proporcionar reglas a través de diferentes herramientas, podemos asegurarnos de que sean coherentes, pero también abarquen cualquier problema de experiencia del usuario que afecte directamente el rendimiento de la carga. Además, estas reglas también se pueden mostrar a los desarrolladores en diferentes momentos:
- Durante el desarrollo local en el servidor de desarrollo, el navegador y el IDE del usuario mostrarán advertencias que les indicarán a los desarrolladores que realicen pequeños cambios en el código.
- En el tiempo de compilación, los problemas no resueltos se volverán a mostrar en la terminal del usuario.
En pocas palabras, los equipos elegirán los resultados que les interesan, como las Métricas web esenciales o el rendimiento de carga, y habilitarán los conjuntos de reglas relevantes para que los sigan todos los colaboradores de código.
Si bien esto funciona muy bien para proyectos nuevos, no es fácil actualizar bases de código grandes para que cumplan con conjuntos de reglas completos. En Google, tenemos un sistema extenso para inhabilitar la opción en diferentes niveles, como líneas individuales de código fuente, directorios completos, bases de código heredadas o partes de la app que no están en desarrollo activo. Estamos explorando de forma activa estrategias eficaces para llevar esto a los equipos que usan frameworks de código abierto.
Cumplimiento en Next.js
ESLint es muy utilizado entre los desarrolladores de JavaScript. Más del 50% de las aplicaciones de Next.js usan ESLint en alguna parte de su flujo de trabajo de compilación. Next.js v11 introdujo la compatibilidad con ESLint lista para usar, que incluye un complemento personalizado y una configuración que se puede compartir para facilitar la detección de problemas comunes específicos del framework durante el desarrollo y el tiempo de compilación. Esto puede ayudar a los desarrolladores a corregir problemas importantes durante el tiempo de creación. Algunos ejemplos son cuando se usa o no un componente de una manera que podría perjudicar el rendimiento, como en No hay vínculo HTML para la página. O bien, si una fuente, un hoja de estilo o una secuencia de comandos pueden afectar negativamente la carga de recursos en una página. Por ejemplo, No synchronous script.
Además de ESLint, la comprobación de tipos integrada en desarrollo y producción es compatible con Next.js desde la versión 9 con compatibilidad con TypeScript. Varios componentes que proporciona el framework (Image, Script, Link) se compilaron como una extensión de los elementos HTML (<img>
, <script>
, <a>
) para proporcionar a los desarrolladores un enfoque de alto rendimiento para agregar contenido a una página web. La verificación de tipos admite el uso adecuado de estas funciones, ya que garantiza que las propiedades y las opciones asignadas estén dentro del alcance aceptable de los valores y tipos admitidos. Consulta Ancho y alto de la imagen obligatorios para ver un ejemplo.
Cómo mostrar errores con notificaciones y superposiciones
Como se mencionó anteriormente, las reglas de cumplimiento se pueden mostrar en varias áreas. Actualmente, se están explorando las notificaciones emergentes y las superposiciones como una forma de mostrar errores directamente en el navegador dentro del entorno de desarrollo local del usuario.
Muchas de las herramientas de verificación de errores y auditoría que usan los desarrolladores (Lighthouse, pestaña de problemas de Herramientas para desarrolladores de Chrome) son pasivas y requieren algún tipo de interacción del usuario para recuperar información. Es más probable que los desarrolladores actúen cuando los errores aparecen directamente en sus herramientas existentes y cuando proporcionan acciones concretas y específicas que se deben tomar para solucionar el problema.
Cumplimiento en otros frameworks
Primero, se explora la conformidad en Next.js con el objetivo de expandirse a otros frameworks (Nuxt, Angular, etcétera). ESLint y TypeScript ya se usan en muchos frameworks de muchas formas diferentes, pero se está explorando de forma activa el concepto de un sistema de tiempo de ejecución cohesivo a nivel del navegador.
Conclusión
El cumplimiento codifica las prácticas recomendadas en conjuntos de reglas que los desarrolladores pueden implementar como patrones de código simples. El equipo de Aurora se enfocó en el rendimiento de la carga, pero otras prácticas recomendadas, como la accesibilidad y la seguridad, son igualmente aplicables.
Seguir las reglas de Conformance debería generar resultados predecibles, y lograr un nivel alto de experiencia del usuario puede convertirse en un efecto secundario de la compilación en tu pila de tecnología. El cumplimiento hace que los equipos sean productivos y garantiza un nivel de alta calidad para la aplicación, incluso a medida que los equipos y las bases de código crecen con el tiempo.