- El enfoque HTML-first permitió que el formulario de solicitud de un servicio público funcionara incluso sin JavaScript, para que los usuarios pudieran completar la solicitud aun con dispositivos, navegadores o redes deficientes
- La app anterior en React fue retirada a los 3 días por quejas de los clientes; los problemas incluían spinners de carga, estado global en JavaScript, fallas de accesibilidad y un método de almacenamiento de imágenes que chocaba con el límite de 5 MB de
localStorage - La nueva implementación, basada en Astro, convirtió cada paso del formulario en una página separada y guardó en cada etapa los datos enviados y las cargas en una sesión de backend, evitando la pérdida de información ingresada
- La validación del formulario se resolvió con un web component que envolvía la validación HTML nativa del navegador, usando una estructura de mejora progresiva que, si fallaba, pasaba a la validación predeterminada del navegador y luego a la validación del API en el backend
- Tras el lanzamiento, la cantidad de personas que completaron el formulario se duplicó, y quedó claro que los usuarios que abandonaban por fallas de JavaScript no aparecían en los paquetes de analítica basados en JavaScript
Contexto del problema y el intento anterior fallido
- El cliente era una empresa de servicios públicos, y la solicitud del servicio podía hacerse mediante un antiguo formulario ASP del sitio web o a través de un proceso manual
- El proceso manual era más caro para la empresa, y al tratarse de un monopolio regulado, si la satisfacción del cliente caía por debajo del 96%, podía enfrentar multas de millones de libras
- Hubo dos intentos fallidos previos para resolver el problema, y en el más reciente contratistas de otro país construyeron una app en React
- La app en React fue retirada 3 días después de hacerse pública debido a las quejas de los clientes
- Esa app mezclaba spinners de carga con estado global en JavaScript y no cumplía con accesibilidad
- La carga de imágenes era una función clave del formulario, pero intentaron guardar las imágenes y todos los datos del formulario en
localStorage, que tiene un límite de 5 MB
Criterios definidos para hacerlo HTML-first
- El nuevo sitio se construyó con Astro y adoptó una arquitectura HTML-first
- JavaScript solo se usó dentro de web components y tuvo el papel de mejorar progresivamente un sitio que funcionaba correctamente incluso sin JavaScript
- Se aplicó el criterio de que un servicio público debe funcionar en todos los dispositivos posibles
- Se aplicó el criterio de que debe funcionar incluso con mala conectividad
- Se aplicó el criterio de que los datos ingresados en el formulario nunca deben desaparecer
- El caso de Terence Eden mostró que una página HTML simple de GOV.UK permitía leer información sobre ayudas de vivienda incluso en el navegador de una PlayStation Portable, que era lento y se quedaba sin memoria con frecuencia
- Las páginas de GOV.UK estaban escritas como HTML simple y liviano, y debían funcionar incluso en navegadores muy deficientes
Estructura del formulario y preservación de datos
- Cada sesión del formulario debía tener un ID único
- En todos los pasos del asistente del formulario, los datos enviados y los archivos cargados debían guardarse en el backend
- Debía ser posible completar el formulario sin JavaScript
- Debía ser posible completar el formulario incluso en navegadores web antiguos y de bajo rendimiento
- La accesibilidad debía cumplir con WCAG, y el equipo fijó como objetivo AA, no AAA
- JavaScript y CSS moderno debían usarse para mejorar la experiencia
- En la estructura final, cada paso del asistente del formulario se convirtió en una página separada, y al hacer clic en siguiente se enviaba el formulario
- Si el API consideraba válidos los datos, el navegador era redirigido al siguiente paso
- El envío del formulario y la redirección son un patrón antiguo de aplicaciones web, y gracias a Remix han vivido un pequeño resurgimiento moderno
- Este servicio no era una app que mostrara datos en tiempo real, sino un formulario grande, por lo que enviar 20 MB de JavaScript antes de renderizar era inapropiado
Validación del formulario y mejora progresiva
- La validación del formulario y el renderizado de errores suelen tratarse como un área en la que los equipos invierten varios meses-persona por culpa de las librerías de validación para React
- Los navegadores ya incluyen un sistema de validación, y puede aprovecharse con menos trabajo que mantener implementaciones imitadas de menor calidad en librerías separadas
- El web component HTML implementado era un elemento personalizado simple que envolvía HTML existente
- Este web component no usaba Shadow DOM y casi no renderizaba HTML desde JavaScript
- El componente envolvía el formulario HTML, tomaba la validación HTML y la mostraba en una forma moderna
- Bloqueaba los tooltips emergentes de validación HTML y colocaba los errores dentro de un elemento
aria-describedbyasociado al campo - Actualmente se recomienda usar
aria-errormessage - Cuando el estado pasaba a ser válido mientras se escribía, borraba la validación y la reevaluaba en
blury al enviar - Esta experiencia de usuario se entregaba en menos de 1 KB, y si fallaba, volvía a la validación predeterminada del navegador
- Si también fallaba la validación predeterminada del navegador, la validación la resolvía el API del backend
- Los problemas de validación se informaban en el momento más temprano que permitiera el navegador del usuario, y aun si algo fallaba siempre había un fallback con una experiencia aceptable
- Después se reescribió desde cero una nueva versión del web component para uso general, y su nombre es validation-enhancer
- El ejemplo de uso muestra que
validation-enhancerenvuelve un formulario HTML y aprovecha directamenteinput type="email",requiredyaria-errormessage
Email
Submit
Resultados del lanzamiento y conclusión
- Tras el lanzamiento, se duplicó la cantidad de personas que completaron el formulario
- Los responsables de analítica no sabían de dónde habían salido esos usuarios
- Los paquetes de analítica basados en JavaScript no ven a los usuarios que abandonan por fallas de JavaScript
- El enfoque de mantener sesiones en el backend y no perder nunca los datos del usuario dio resultado
- En un caso, un usuario completó el formulario un mes después de haberlo iniciado
- Después de terminar el contrato, la persona que tomó el relevo respondió que una estructura que siempre funciona incluso sin JavaScript le generaba más trabajo al equipo
- Excluir a usuarios de navegadores antiguos, usuarios con mala conectividad o usuarios de tecnologías de asistencia no es aceptable en un servicio público monopólico
- Hay que dejar atrás la inercia de seguir empujando enfoques ásperos e inmaduros que surgieron durante la fase de expansión de la industria del software
- Si construyes una aplicación web que funciona incluso en una PlayStation Portable con conexión 3G, funcionará para todos los usuarios, y puede seguir funcionando incluso dentro de 30 años
2 comentarios
Opiniones de Hacker News
Como alguien que no es desarrollador web, me da curiosidad por qué este enfoque implica más trabajo
El enfoque que describe el artículo se ve bastante simple: haces componentes estándar para formularios y pones un botón de envío debajo. Yo también hacía eso cuando armaba sitios personales hace mucho tiempo, y no era tan difícil. Tal vez es porque no conozco bien esta área, pero hacer un frontend llamativo parece mucho más difícil
No es porque sean tontos. Si les preguntas directamente “¿se puede hacer un sitio web sin React?”, obviamente responderán “sí”. Pero si les dices que hagan un sitio nuevo, por costumbre y por querer terminar el trabajo, arrancan sin pensarlo demasiado un proyecto nuevo de React
Algunos realmente no conocen otra forma. No tienen experiencia montando un servidor HTTP común que entregue HTML puro, ni creando formularios que validen y se envíen sin JavaScript. Esta gente no es la que escribe en HN, ni participa en discusiones en línea sobre herramientas o tecnologías nuevas, o incluso antiguas. Aprendieron apenas lo suficiente para conseguir trabajo en un bootcamp o en una sola materia universitaria de webapps, y después solo fueron aprendiendo la herramienta específica que pedía su empleador o que alguien del equipo elegía en cada momento
Como alguien mayor, me tomó un tiempo darme cuenta de esto, pero ahora lo entiendo. Dependiendo de su trayectoria profesional, algunas personas llegan a conocer las partes más simples de HTML, CSS y JavaScript puro después de haber conocido las partes complejas y específicas de frameworks de cada tecnología. Entonces, para ellos, no se siente como algo menos profesional, sino más bien como un conocimiento más críptico, avanzado o secundario
Decir “eso nos da muchísimo más trabajo” tampoco necesariamente es una afirmación errónea hecha a propósito. Si haces una tarea con herramientas que no te son familiares, es muy probable que de verdad sientas que implica mucho más trabajo, incluso si esas herramientas son menos complejas
La app era rápida y simple, pero también tuvo su costo. Estábamos más limitados para traer componentes de UI ricos directamente desde paquetes de npm, y ofrecer una buena experiencia de usuario requería mucho más trabajo. Todo tomaba más tiempo y, al final, la experiencia de usuario también fue peor. Sí nos importaba, pero a veces simplemente no alcanza el tiempo para cuidar todo hasta el final
La empresa fracasó y no creo que React la hubiera salvado. Pero sí puedo decir por experiencia propia que una obsesión moral con la “simplicidad” tampoco ayudó. Siempre hay tradeoffs
Alguien dice que ofreció una solución más simple y razonable que la que la mayoría habría imaginado, y la persona que recibió el traspaso no quedó satisfecha
¿Sabemos si la calidad del código entregado era alta? ¿Esa persona reaccionó al hecho de que “no es React”? ¿Podría haber existido una plantilla obligatoria en la empresa sobre cómo construir apps?
No lo sabemos
Ya no lo he escuchado tanto últimamente, pero la propuesta de HTML Triptych sigue siendo una de esas cosas que espero que algún día lleguen al navegador. La forma en que los formularios HTML conversan con endpoints REST es un buen patrón
La validación de apoyo al usuario se maneja con atributos de entrada, la validación real se hace del otro lado de la solicitud, y el flujo queda como GET /form => POST /thing => GET /thing/1. Si la funcionalidad de triptych se implementa, sería un patrón excelente
[0] https://triptychproject.org/
No me gustan para nada los sitios hechos con React, pero lo que no entiendo es si estos sitios no hacen lazy loading en absoluto
Incluso una aplicación grande de una sola página puede ser muy rápida si solo carga los componentes cuando hacen falta
Pasé de Angular1 -> Vue2 -> Svelte2 y terminé quedándome con web components puros sin shadow DOM; da gusto trabajar así y además es rápido
Hoy en día, la mayoría de las apps las hago simplemente con HTMX + Go + SQLite
Siento que es suficiente para la mayoría de los proyectos
Uno de mis sitios tiene muchas imágenes y maneja 10 TB de tráfico al mes. En ese caso, la configuración es la siguiente: 1. Uso S3 porque necesito un almacén de datos confiable 2. Pongo Cloudflare al frente y activo Tiered Cache. Así los POP prefieren obtener el contenido desde Cloudflare en vez del origen. Cacheo todo por 1 año tanto en el navegador como en Cloudflare, y configuré reglas para ignorar la política de caché del origen y los query strings, usando solo objetos inmutables que requieran revisión 3. Delante de eso pongo BunnyCDN
Cloudflare por sí solo no permite operar un sitio con muchas imágenes, así que de esta forma reduje muchísimo los costos. Según la política, no debería usarse principalmente para imágenes, sino para HTML, CSS, JavaScript y otro contenido del sitio
Si usara solo S3, el costo sería enorme
Pero últimamente he estado haciendo una app móvil. Las PWA tienen limitaciones. Como el sistema operativo puede recuperar el almacenamiento de IndexedDB, no se puede ofrecer dentro de la app un almacén de datos confiable sin registro ni intervención del backend
Al final no me quedó otra que pasarme a Flutter en Android, pero eso trajo otro tipo de dolor. A veces las actualizaciones de la app se tardan mucho en “revisión”, y eso desespera. Comparada con eso, la web app de la misma app se actualiza rapidísimo
Me pregunto por qué no existe un sistema operativo móvil que te deje crear apps con JavaScript, HTML y CSS, y además te dé almacenamiento estable sin tanto esfuerzo. Lo bueno de las PWA es que se pueden actualizar rápido
Viajar en el tiempo es la parte fácil; luego hay que evitar de algún modo la caída de Palm y que webOS termine olvidado como sistema operativo para smartphones
Si 2009 te queda muy lejos, también puedes apostar por Firefox OS en 2012
Bromas aparte, sí ha habido intentos de personas y empresas. Pero por mala suerte en el timing y por una serie de acontecimientos, esa realidad no pudo ocurrir en nuestra línea temporal
Se siente justo en ese punto óptimo donde no tiene cargas innecesarias como C, pero tampoco estorba y te deja enfocarte en la lógica de negocio como Java. No es como Rust
No sirve para todo. En particular, se extraña su falta de capacidad para construir abstracciones. Pero para apps de servidor con mucha lógica de negocio es excelente. No se siente como un lenguaje que quiera hacerlo todo, sino como uno especializado en ese terreno
También hice algunas librerías para abstraer las partes de SQL y de HTMX/web/OAuth. Ahora mis apps se parecen mucho entre sí, así que es fácil mover funcionalidades de una a otra
https://github.com/cattlecloud/webtools
https://github.com/cattlecloud/litesql
Como respuesta contraria está In Defence of the Single Page Application
https://williamkennedy.ninja/javascript/2022/05/03/in-defenc...
In Defence of the Single Page Application - https://news.ycombinator.com/item?id=31275178 - mayo de 2022, 32 comentarios
Este artículo está bien y es un gran ejemplo de tomar un problema y resolverlo con la tecnología adecuada y con el nivel de profundidad correcto. Ayuda muchísimo tener dominio total del conocimiento del negocio del cliente
Pero no me gusta ese encuadre de “HTML simple es mejor que React”. Porque exactamente la misma historia se puede contar también desde la perspectiva de un desarrollador de React
Podría extenderme eternamente sobre muchas cosas que aquí se pasan por encima, como la complejidad y las sutilezas del almacenamiento de sesiones en el servidor frente al almacenamiento en el navegador, pero sería demasiado largo
Lo que es simple en HTML también es simple en React
Literalmente es el mismo código. No hay nada que te impida usar en React la validación HTML nativa del navegador. Y el código que se vuelve complejo en React, por ejemplo una lógica de validación excesivamente complicada, también se vuelve complejo en Astro. Astro también tiene su propia forma de abordar cosas como la validación por esquemas y, para integrarlo en un sitio Astro, hay que integrar routers del cliente y demás, así que ahí también es muy fácil terminar con complejidad excesiva
Además, el punto de comparación probablemente sea un equipo externo offshore con conocimiento incompleto, y por la estructura del proyecto tienen incentivos para construir una solución lo más rápido posible, con la menor cantidad de tiempo posible y con la mayor complejidad posible
Ese último punto es sutil. No significa que la consultora lo haga a propósito, pero por la estructura de incentivos, la complejidad excesiva sí termina beneficiándoles, así que no tienen un incentivo directo para optar por la vía simple
En cualquier caso, una solución simple que ataque directamente el problema inmediato siempre es mejor, sin importar el stack que elijas
No es que yo tenga algo contra la validación de formularios en Astro; solo quería subrayar que hay más en esta conversación que “validación nativa HTML del navegador”
Es un gran texto, pero cada vez que leo algo inspirador así siempre me genera conflicto. La idea de un sitio simple donde todo tiene totalmente sentido, funciona bien, carga rápido y no depende de navegadores modernos me encanta
Pero luego pienso si no será porque no soy lo bastante inteligente como para entender React o la tecnología de moda del momento
Se siente como si hubiera un límite de comprensión que no puedo cruzar. Si me das un editor sencillo como Sublime y me dices que haga una página web, incluso con JavaScript, es un espacio en el que soy feliz. Si me das VSCode o Zed, plugins de Claude/Copilot/ChatGPT pegados por todos lados, y tutoriales de React, se me derrite el cerebro
Mantener las cosas simples no es algo malo; de hecho, muchas veces hace falta ser suficientemente inteligente como para no volverlas innecesariamente complejas
Embrace Extend Extinguish es real, y quienes se suben a eso bien podrían ser reemplazados por LLM que mientan más rápido y escupan código basura
Esto me recuerda a hace casi 15 años. Usábamos gestión de sesiones del backend en Grails y formularios HTML mejorados con CSS responsivo y “un poco” de JS
La diferencia con aquella época es que la tecnología de los navegadores no estaba tan avanzada como ahora. Había que preocuparse por varios navegadores, lidiar con IE7 e incluso IE6, lo cual era difícil, y hacía falta muchísimo QA. BrowserStack apareció después
Hay una razón por la que evolucionaron las bibliotecas de JavaScript. No existía npm, ni siquiera bower. Luego apareció Backbone.js y me gustó. AngularJS fue asombroso, después la siguiente versión de Angular trajo una gran ruptura de compatibilidad, y luego llegaron React, Polymer y otros
Hoy los navegadores nativos pueden hacer muchísimas cosas y el mejoramiento progresivo también es fácil. Pero no siempre fue así. En ese momento, decidir usar React era razonable por muchas razones, y aquí también podría haberlo sido
Hace más de 10 años construí apps así en GOV.UK para el Ministerio de Justicia. Hicimos nuestra propia biblioteca de asistentes de formularios para validar formularios largos por pasos y dividirlos en varias páginas, porque Ruby on Rails no lo soportaba de forma nativa
En ese tiempo era muy importante el principio de que todas las personas debían poder usar los servicios digitales sin importar desde qué entorno accedieran
Puedes cotejar la página de una aplicación multipágina y ese ID de sesión con cada ID de sesión, así que, si hace falta, el usuario incluso podría ingresarlo manualmente. Pero debería ser posible identificarlo con suficiente información, como la dirección IP, la fecha de carga, el navegador y el sistema operativo. Aun así, la sesión más precisa debería estar en el navegador, para que la cookie de una solicitud no se mezcle con la de otro solicitante, como un familiar que use una PlayStation Portable
Me pregunto qué tecnología usan para la app móvil. Supongo que no es una app móvil completa, sino que quizá usa una webview
Esto no es “convertimos una app de React en formularios HTML y mejoró el rendimiento”. Es “convertimos una mala página web en una buena página web y mejoró el rendimiento”
Echarle la culpa de esto a la tecnología que impulsa la experiencia en el navegador es una tontería. Puedes crear una gran experiencia de usuario con React, y también puedes hacer un sitio horrible con HTML puro
La mejora vino de un cambio de diseño, no de la tecnología
Pero sí, es cierto. El cambio del lado del usuario vino de corregir el diseño, no de la tecnología usada
Esto se parece mucho a un mal bullet point en un CV. Como cuando alguien dice “reescribí un sitio web con enfoque HTML-first y aumenté 100% el número de visitantes”, como si el resultado del negocio hubiera sido gracias al cambio de código. Si preguntas por ese punto, al final terminan admitiendo que rediseñaron todo el sitio para corregir problemas de diseño o agregar funciones, y que ese rediseño fue lo que impulsó el aumento de visitantes
JavaScript: The Good Parts de Douglas Crockford es ridículamente corto. React: The Good Parts sería todavía más corto
Curiosamente, el texto original describe un formulario tipo asistente multipágina, algo que casi no he visto en unos 10 años. Pero cada vez que veía algo así, por lo general era un sistema empresarial espantoso. La última vez que vi uno fue algo como un producto de Oracle para reportar gastos
El problema de esas cosas siempre es que son lentas a mitad del trabajo. Tienes que esperar varios segundos por cada botón. Y si tienes que volver uno o dos pasos atrás, es el doble de frustrante. Las aplicaciones de una sola página mal hechas tienden a ser lentas al inicio. Tardan en cargar, pero una vez cargadas, por lo general el rendimiento está bien
Opiniones en Lobste.rs
Hacer algo que realmente funcione bien para las personas obviamente requiere más trabajo. Pero al final eso también es el núcleo de todo el trabajo
Parece que lo que de verdad querían decir quienes venían después es que no conocen bien los fundamentos de la plataforma web
No significa que eso sea deseable, sino que así es la realidad actual
Da algo de tristeza la parte donde dicen que tomó tiempo explicarles a sus colegas lo de “enviar formularios y redirigir”. Es porque todos se acostumbraron a las apps web centradas en el cliente
El desarrollo web de verdad está en un estado lamentable ahora mismo, y hay mucho que volver a enseñar
No creo que haga falta un nivel de compatibilidad tan alto para justificar este enfoque. Como dice el artículo, al final del día solo es un formulario
Así que yo probablemente lo haría así en cualquier caso
Me gustaría trabajar haciendo sitios como el que describe el artículo. La restricción de una descarga muy pequeña que además tenga que funcionar en casi todos los navegadores y cuidar la accesibilidad suena como un reto bastante interesante
Me pregunto si hay empresas especializadas en esto, o si están contratando. Tal vez solo sea una persona mayor extrañando la vieja simplicidad
La funcionalidad está lo bastante bien aislada como para que sea muy fácil extraerla como una librería reutilizable, y todavía queda mucho por hacer. Dan ganas de poner esto como valor predeterminado de los frameworks web. Es un artículo realmente bueno
Un poco irónicamente, en Firefox por algún estilo ni siquiera podía ver o seleccionar el cuerpo completo del artículo, así que tuve que cambiar al modo lectura. Podía ver el título, las comillas rosas y los bloques de código, pero el resto no aparecía
Edit: viendo más abajo, probablemente sea un problema de mi entorno. Lo dejo por contexto
Sí pude leer bien el artículo en sí. Todos, ya seamos desarrolladores o usuarios finales, estamos pagando el costo de la “agilidad” de React. Más de una vez he pensado que ojalá pudiéramos usar otro stack en la empresa
También me impresionó la empatía del autor y cómo la incorporó en un diseño donde “todos ganan”. Tener ese nivel de cuidado al final sí da recompensa
Totalmente de acuerdo. Antes hice un blog con una cantidad extrema de JavaScript, y por culpa de las funciones basadas en JS casi hubo una rebelión
Todavía no he tenido tiempo de migrarlo a un enfoque HTML primero, pero por fuera lo dejé para que pareciera en su mayoría una página web HTML primero
En mis datos analíticos también vi resultados parecidos. La tasa de rebote bajó de 80% a cerca de 50%, y los nuevos visitantes de las publicaciones posteriores casi se duplicaron
Pensar en cuánta gente pudo haber evitado mi dominio para siempre por aquella implementación desastrosa hecha en JS da escalofríos. Si tienes una página web o un blog, este es uno de los consejos más importantes
Este enfoque también ayuda con el autorrelleno de formularios. Antes todo el formulario era dinámico y no tenía atributos para identificar cada parte, así que no se podía crear entrada automática
Me pareció una lástima que estuviera sobreingenierizado para verse bonito por encima de la funcionalidad, y por eso fue tan agradable leer este artículo sobre diseño centrado en el usuario
Si a esto le sumas streaming con SSE y una librería de morphing, también se pueden construir funciones dinámicas, en tiempo real y multijugador bastante geniales