Parte II — El blog era la parte fácil
El artículo estaba firmado, al pie, «ASU Innovation». Estaba publicado en umbracolombia.com.
Nadie había decidido eso. El artículo existía dos veces —un nodo bajo cada sitio— porque el proceso que lo publicaba escribía en los dos, y cada escritura creaba un nodo. Los dos cuerpos eran idénticos: 6.455 caracteres, el mismo SHA-256. Y como la firma era una propiedad del sitio y no del autor, la copia colombiana salió con el nombre de la empresa española.
Después de la migración de versiones, el blog parecía lo que quedaba de trámite. Dos sitios, los dos escriben de Umbraco y de Sitecore, publique en los dos y listo. Esa frase esconde una pregunta que no habíamos hecho: ¿qué es exactamente lo que se publica dos veces?
Lo que creíamos: que sobraba un nodo
La reacción obvia fue borrar uno. Es lo que uno hace con un duplicado.
Y era razonable, salvo por dos cosas que en Umbraco no se pueden separar del árbol. La primera es que la URL de un nodo sale de dónde vive: los dominios se enlazan a la Home de cada sitio, así que un nodo bajo el Blog de ASU solo puede tener una URL de ASU. La segunda es que el tema sale del mismo lugar —se elige leyendo una propiedad en la raíz del sitio, es decir en un ancestro del nodo—, de modo que un nodo fuera de los dos árboles no tiene esa raíz que leer y se pinta con el tema por defecto, que implementa uno de los ocho bloques. La página no falla: sale casi vacía.
Borrar un duplicado, entonces, no deja un artículo compartido. Deja un artículo que solo existe en un sitio y desaparece del otro.
Lo que quedó: el cuerpo vive una vez
Lo que hicimos fue partir el artículo en dos cosas distintas, que hasta ese momento estaban pegadas por accidente.
El texto —el título, el cuerpo, la fecha, las categorías, las etiquetas, el autor— vive una sola vez, en una biblioteca fuera de los dos sitios. Y cada sitio que quiere mostrarlo tiene un nodo delgado que no tiene cuerpo: apunta al artículo, y aporta lo único que sí es propio del sitio, que es la URL, el idioma en que aparece allí y si esa copia es la canónica.
Hoy son 45 artículos en la biblioteca y 65 referencias repartidas: 20 artículos salen en los dos sitios, 23 solo en ASU, dos solo aquí —este entre ellos—. Sin la biblioteca serían 65 cuerpos, y cada corrección habría que hacerla en dos sitios y acordarse de los dos.
La firma dejó de ser un problema el mismo día, no porque la arregláramos, sino porque dejó de tener dónde equivocarse: el autor es un campo del artículo, y un artículo hay uno.
Lo que costó mover 20 artículos
Dos URLs publicadas devolvieron 404 en la primera ejecución, y las dos por la misma razón de fondo: en Umbraco el nombre de un nodo es la URL.
El primero fue tomar el nombre equivocado. Al crear la referencia le pusimos el nombre del artículo de la biblioteca, y resulta que el título en español de un sitio no era el título en español del otro. La referencia nació con un segmento distinto del que tenía la página que reemplazaba.
El segundo fue más sutil y más fácil de repetir: creamos la referencia antes de mandar el duplicado a la papelera. Con un hermano del mismo nombre delante, Umbraco desambigua solo y agrega « (1)» al final. Nadie ve un error. Simplemente la URL que estaba en Google dejó de existir.
Los dos se encontraron porque antes de mover nada guardamos la lista de las URLs publicadas y la volvimos a pedir después. No se encontraron mirando la página: las dos páginas rotas se veían bien, cada una en su sitio, hasta que uno pedía la dirección vieja.
El listado: dos intentos antes del que quedó
Con todos esos artículos, la página del blog los imprimía todos. Faltaba lo que un blog hace desde hace veinte años: buscar, filtrar por categoría, por etiqueta, por mes, y poder verlo como lista o como grilla.
El primer intento fue el barato: pintar todo y esconder con JavaScript lo que no coincide. Funciona hoy y se cae solo, porque «pintar todo» es justamente lo que no escala —la página se lleva el texto completo de todos ellos antes de que el lector haya pedido nada—. Se escribió, se midió contra el contenido real y se botó.
El segundo intento fue escribir nuestro propio endpoint. Escala bien y tiene un defecto que solo se ve al usarlo: el filtrado queda escrito dos veces, una en Razor para la primera pintada y otra en el endpoint para todo lo demás. Y esas dos se separan. Una ordena por una fecha y la otra por otra, o una quita los acentos y la otra no, y el lector ve la página reacomodarse sola la primera vez que toca un control.
Lo que quedó salió de leer el ensamblado en vez de la documentación: IApiContentQueryService —el servicio que usa por dentro el endpoint de la Delivery API— se puede inyectar. Es decir, el servidor puede correr exactamente la misma consulta que corre el navegador, contra los mismos manejadores de filtro. Una sola definición de qué significa «categoría umbraco».
De ahí salió gratis lo que más nos gusta del resultado: las facetas son enlaces normales, «ver más» es un enlace normal, la búsqueda es un formulario normal. El script los intercepta para que no cuesten una recarga; con el script bloqueado, navegan. Y un listado filtrado tiene URL, así que se puede compartir.
La parte que sí hubo que resolver es que la referencia es lo que el listado enlaza, y el artículo es donde están los datos. Se arregla en el índice: la referencia toma prestadas del artículo la fecha, el mes, las categorías, las etiquetas, el autor y el texto completo. Seis campos, cinco filtros y un orden.
Lo que me enseñó una medición a medio hacer
Con los filtros escritos, los probé contra el contenido real y varios devolvieron cero donde yo esperaba resultados. Con esos números delante la explicación se armó sola —siempre se arma sola— y me pasé un rato bueno buscando el defecto en mi propio código.
No había defecto. Había pedido una reconstrucción del índice y había empezado a preguntar antes de que terminara. Un índice a medio construir contesta con lo que lleva y no menciona que va por la mitad, así que yo estaba leyendo respuestas reales de una base incompleta como si fueran la verdad.
Lo aprovechable de ahí no es cuál era el filtro. Es que las respuestas malas eran coherentes entre sí, y la coherencia se siente exactamente igual que la verdad. Una hipótesis que encaja con todo lo que uno ve no es evidencia de nada si lo que uno ve viene de un sistema que todavía se está armando.
De eso salieron dos costumbres. La primera es operativa: cuando una comprobación depende de un proceso asíncrono, la comprobación empieza cuando el proceso termina, no cuando uno lo lanzó —y «terminar» hay que poder medirlo, no suponerlo—. La segunda es de método: antes de creerle a un número, verificar que la cosa que lo produce esté en el estado en que uno cree que está. Suena obvio escrito así. No lo es a las once de la noche con una explicación elegante en la cabeza.
Los fallos de un blog no fallan
Al mirar la página terminada aparecieron dos cosas que no había roto ese día y que llevaban meses ahí. Una hacía que buscar en un idioma encontrara artículos escritos en el otro. La otra, más vieja y peor, hacía que ninguna tarjeta del listado mostrara resumen —en ninguno de los dos sitios, desde que existía la biblioteca compartida—.
Las dos tienen la misma raíz, y no es un descuido concreto: en un CMS los valores por defecto son plausibles. Un texto sin llenar no se comporta como un hueco, se comporta como un texto vacío. Una propiedad que varía por idioma, leída sin decir cuál, no se queja: contesta en el idioma por defecto. Ninguna de las dos cosas es un error para el sistema, porque el sistema no sabe qué esperaba uno.
El resultado es que el fallo no interrumpe nada. Se ve como una decisión. Un listado sin resúmenes parece un listado que decidió no llevarlos, y una búsqueda que devuelve de más parece una búsqueda generosa. Por eso ninguna de las dos apareció en un log ni en una prueba de humo, y sí apareció mirando una captura y contando párrafos.
Lo que queda cojo
Lo que no quedó resuelto tiene todo la misma forma, y a estas alturas ya se reconoce: son estados en los que el blog se ve bien.
El índice se reconstruye en el despliegue, y si a alguien se le olvida, el listado no falla: se muestra sin filtrar. Eso es deliberado —un arranque en frío no debe tumbar el blog—, y el precio es que un despliegue a medias se ve correcto hasta que alguien hace clic en una categoría. Lo mismo pasa con los conteos de la barra lateral, que son del blog entero y no cambian al filtrar: es a propósito, y un lector puede leerlos igual como el resultado del filtro que acaba de aplicar. Y como las facetas de la referencia son prestadas, hay un manejador que las refresca cuando se publica el artículo; funciona, y es una pieza móvil más, de modo que si algún día deja de correr, el síntoma será otra vez un artículo que no sale en un filtro y una página que responde 200.
Cada fallo de este blog respondió 200. El artículo duplicado, 200. La firma equivocada, 200. La referencia sin resumen, 200. El índice a medias, 200 con las respuestas cambiadas. Ninguno se encontró leyendo un log. Todos se encontraron contando: URLs antes y después, resultados con filtro contra resultados sin filtro, tarjetas contra resúmenes. La suite del proyecto tiene 26 comprobaciones y no es que alguien se sentara a diseñarlas: cada una es un día como estos.