Saltar al contenido
Development

Vaciar un backlog: cinco arreglos pequeños en una sola versión

Por Victor Da Luz
astroaccessibilitydev-logastro-tools

La biblioteca de componentes de blog tenía cinco pendientes pequeños en el backlog, ninguno urgente, ninguno relacionado con los demás salvo por vivir en el mismo repositorio. Un arreglo de accesibilidad para una decoración muerta. Atributos de carga diferida faltantes. Un campo de esquema que se validaba pero nunca se renderizaba. Un campo de JSON-LD que no podía reflejar ediciones. Una definición de tipo silenciosamente desincronizada del esquema que describe.

Cada uno por separado apenas merece un párrafo. Juntos son una tarde decente de trabajo.

El arreglo de a11y que era una cuestión de intención, no de código

Las flechas deshabilitadas de primero/anterior/siguiente/último de Pagination se renderizaban como <span role="button" aria-disabled="true">. Ese es un olor real de a11y: un elemento no enfocable con role="button" se anuncia a un lector de pantalla como un control interactivo, pero un usuario de teclado nunca puede alcanzarlo para descubrir que está deshabilitado. El estado aria-disabled es invisible justo para la audiencia para la que existe.

El arreglo es casi vergonzosamente pequeño: quitar el role, quitar el aria-label, agregar aria-hidden="true". La parte interesante fue elegir cuál de dos opciones válidas tomar. La alternativa era convertirlo en un <a> o <button> real con semántica de deshabilitado apropiada. Se optó por el camino de la decoración porque una flecha de paginación deshabilitada no es contenido interactivo, no hay nada detrás que alcanzar. Marcarla como aria-hidden es más honesto que disfrazarla de control deshabilitado que nunca va a habilitarse en esta página.

Un campo de esquema que existía y no hacía nada

El paquete valida un objeto heroImageCredit, nombre del fotógrafo, fuente, información de licencia, específicamente para imágenes de fuentes que requieren atribución como Openverse. Lleva un tiempo en el esquema. Nunca se renderizó.

Eso es una brecha de cumplimiento disfrazada de detalle agradable. La atribución para imágenes de Openverse no es cortesía opcional, es un término de licencia. Un campo que se valida correctamente pero nunca llega a la página es peor que no tener el campo, porque parece que el requisito está cubierto cuando no lo está.

El arreglo fue un componente nuevo pequeño, HeroImageCredit, reutilizando la propia capa de i18n del paquete para las etiquetas “Photo:” y “via” en vez de escribirlas fijas en inglés, que es exactamente la clase de error recién corregido en otra parte del mismo paquete. Vale la pena recordar que la lección aplica a cada componente nuevo, no solo a los que ya existían.

El cambio de una línea con el test más interesante

buildBlogPostingSchema siempre fijaba el dateModified del JSON-LD al mismo valor que datePublished, sin condición. Una entrada editada nunca podía señalar “esto cambió” a quien leyera los datos estructurados. El arreglo: un campo opcional updatedDate, usado cuando está presente, con pubDate como respaldo en caso contrario.

El test existente para el comportamiento anterior llevaba un comentario dejado en una sesión previa, señalando que el comportamiento actual era conocido y que un pendiente específico del backlog lo cambiaría. Encontrar un test que ya sabía que estaba a punto de volverse incorrecto fue un momento pequeño y satisfactorio, prueba de que el pendiente del backlog había sido nombrado con honestidad desde el principio en vez de retocado después para sonar más inteligente.

El tipo que estaba estructuralmente bien y semánticamente mal

BlogPostData, la interfaz sobre la que operan los componentes, le faltaban campos que el esquema real producía (heroImageCredit, affiliates, y ahora updatedDate). Nada se rompió, porque el paquete usa tipado estructural y ningún componente leía todavía esos campos. Pero en el momento en que un componente quiso leer heroImageCredit, que, a partir de esta versión, uno lo hace, cada consumidor necesitaría un cast para sortear un tipo que mentía sobre lo que contenían los datos.

La sugerencia fue derivar el tipo directamente del esquema con z.infer<ReturnType<typeof blogSchema>>, que se ve más elegante. No se tomó ese camino: el archivo de esquema ya importa un tipo del archivo de tipos, y derivar el tipo de vuelta desde el esquema habría creado una importación circular. Tres líneas extra a mano en vez de un truco de infer fue la decisión aburrida pero correcta.

Un error que vale la pena dejar por escrito

A mitad de este lote se corrió prettier --write sobre un puñado de archivos sin comprobar si el repositorio tiene una configuración de prettier. No la tiene, y el estilo de comillas por defecto de prettier es comillas dobles mientras que cada línea del código existente acá usa comillas simples. El resultado fue un diff que cambió en silencio el estilo de comillas en cada línea sin tocar de cuatro archivos, junto con los cambios reales. Se detectó antes de confirmar el commit leyendo el diff en vez de confiar en la herramienta, se revirtió, y se reaplicaron los cambios a mano.

Formatear un archivo para el que no se escribió la configuración del formateador no es una operación segura ni neutral. Es una apuesta a que los valores por defecto de la herramienta coinciden con una convención que nadie codificó en ningún lado.

Qué se haría distinto

Agrupar arreglos pequeños y no relacionados por dónde caen, no por qué son. Los cinco tocaban el mismo paquete, así que una versión, una corrida de CI, una etiqueta tenía sentido. Si hubieran abarcado varios repositorios, se habrían mantenido separados en vez de forzar una versión compartida alrededor de arreglos que no necesitan salir juntos.

Lecturas relacionadas

Development

El error de i18n en aria-label que estaba escondido a plena vista

Una librería de componentes compartida lanzó una capa real de traducción al español, y dos aria-labels en inglés codificados de forma fija viajaron sin ser detectados durante meses de todas formas, porque estar 90% correcto es mejor camuflaje que estar 0% correcto.

Leer