Ir al contenido

Blog ·

Documentación escrita antes de la fusión

Dos frases de una página de documentación nueva eran falsas el día en que salió, porque otra rama entró antes. Qué detecta una guarda y qué solo un grep.

Por Provibr

Una página de documentación es un conjunto de afirmaciones sobre el código. Suena obvio hasta que uno se fija en que nada de la compilación comprueba ninguna de ellas. Las pruebas afirman cosas sobre el código. Las comprobaciones de tipos afirman cosas sobre el código. La prosa sobre el código afirma cosas sobre el código y la verifica una persona que la lee una vez, el día en que se escribió.

Escribimos dos páginas de documentación nuevas en una misma ronda: una para el editor de automatizaciones, unas 2930 palabras inglesas repartidas en ocho secciones, y otra para el panel de inicio, unas 909. Más una sección añadida a dos páginas que ya existían. Dos frases de la página de automatizaciones ya eran falsas cuando se publicó.

Nadie había escrito una falsedad. Ambas frases eran exactas frente a la rama sobre la que se escribieron.

La frase que era cierta cuando se escribió

La documentación de una función suele escribirse después de la función, lo que significa que se escribe mientras otras ramas siguen abiertas. La nuestra lo estaba. La página describía un nodo de aviso y decía, en esencia, que no envía correo. En la rama sobre la que se escribió eso era exactamente así: el nodo creaba una notificación en el panel y nada salía del edificio.

Una ronda paralela se fusionó antes y le dio al nodo una casilla de correo, apagada por omisión, una categoría de baja propia y una regla según la cual una ejecución de prueba nunca envía nada. Cada uno de esos hechos le interesa a quien lee. Ninguno estaba en la página, y lo que sí estaba en la página le decía ahora lo contrario.

La segunda frase describía cómo se conecta un plan a un flujo. Decía que el plan ejecuta el flujo que tiene detrás, de una época en que esa relación era uno a uno. La misma fusión la sustituyó por una unión: un plan puede colgar como mucho un flujo por momento, de entre tres momentos, y un flujo activado a mano o por webhook no puede colgar ahí en absoluto. «No se puede adjuntar» es mejor respuesta que «adjuntado y sin hacer nada en silencio», pero es una respuesta distinta, y la página seguía dando la antigua.

La reparación fue pequeña. Lo interesante es cómo se encontró, que fue porque alguien se puso a buscar a propósito, porque una ronda que toca un tema es el único momento en que alguien tiene un motivo para releer la prosa sobre ese tema.

Lo que una guarda puede detectar

Hay un segundo modo de fallo en esas mismas páginas y, a diferencia del primero, es mecanizable.

La página del panel de inicio tiene una tabla que enumera las tarjetas que se pueden añadir. Esas tarjetas tienen nombres, en nueve idiomas, y esos nombres ya existen: son las etiquetas del selector en el que la gente hace clic de verdad. Escribir una tabla de documentación significa escribirlos una segunda vez.

Salió mal de inmediato, en el primer borrador, en inglés:

En el selectorEn la página de documentación
Integration listConnections
Open ticketsTickets
Credit balanceCredit

Ninguno de ellos está mal como inglés. Los tres están mal como documentación, porque quien lee que debe añadir «Connections» buscará una tarjeta llamada Connections y encontrará una tarjeta llamada Integration list. La deriva es silenciosa por construcción: ambos textos están bien por separado, y nadie pone un manual al lado de un selector.

Así que la tabla toma ahora las mismas claves de catálogo que toma el selector, y una prueba exige que sean idénticas palabra por palabra en los nueve idiomas. La clave de documentación se deriva del identificador de la tarjeta en lugar de listarse a mano, para que la séptima tarjeta opcional que alguien añada el año que viene quede medida sin que nadie se acuerde de añadirla aquí. Es la misma forma que la guarda que corremos entre las dos copias de los mensajes de servidor en inglés, y existe por la misma razón: dos sitios que sostienen una verdad necesitan una prueba que lo diga, no una convención.

Los nombres de los botones de esa misma página se adivinaron en cinco de los nueve idiomas. Ahora salen también del catálogo. Y tres idiomas habían traducido la palabra Scripts, que es el nombre de una entrada de menú que no se traduce en el producto, así que la página le decía a quien lee en español, portugués y ucraniano que hiciera clic en algo que no existe con ese nombre.

Un token técnico no es una palabra

Los nombres de producto, los puertos, las rutas, los nombres de módulo y los códigos de estado van en un token monoespaciado y se quedan en inglés, aparezcan donde aparezcan, en todos los idiomas. Esa regla no es nueva. Lo nuevo fue que escribirla en estas páginas chocó con otras dos guardas a la vez.

Poner un elemento <code> literalmente dentro de un array de filas de tabla activa la regla de lint que quiere una clave en cada elemento JSX de un array, incluso aquí, donde el componente de tabla envuelve cada celda en su propio elemento con clave y esa clave no se lee nunca. Ponerle una clave activa una guarda distinta, que ve un hijo con clave junto a llamadas de traducción cuyas claves no puede resolver en ese fichero.

La escapatoria fue una función de una línea que devuelve el elemento. Para la regla de lint es una llamada a función y no un elemento de array; para la otra guarda no es una clave. La salida dibujada es idéntica byte a byte. Es una cosa pequeña, y es la clase de cosa pequeña que se resuelve con un comentario de desactivación cuando nadie escribe por qué discrepaban las dos reglas.

Capturas que parecían correctas

La medición de estas páginas incluía capturas por ancla: desplazarse a cada sección, fotografiarla, mirarla.

Nueve de ellas mostraban la cabecera de la página.

El comando de navegador que captura una región más allá de la ventana calcula su recorte desde lo alto del documento, no desde la posición de desplazamiento actual. Al desplazarse a un ancla ocho pantallas más abajo y pedir una región en las coordenadas que informa el elemento, se fotografía lo alto de la página, con exactamente el tamaño correcto, en un fichero con el nombre correcto. Cada una de esas capturas era una imagen de aspecto verosímil de la cosa equivocada.

Sumar el desplazamiento actual lo arregló. La forma general es una con la que nos seguimos encontrando: una medición que falla produciendo una salida de aspecto normal es peor que una que se rompe, porque lo que se rompe se investiga ese mismo día.

La parte a la que no llega ninguna guarda

Los nombres de las tarjetas eran mecanizables porque ambos lados son cadenas de un mismo repositorio. Las dos frases obsoletas no lo eran, y merece la pena ser preciso sobre por qué, porque es tentador creer que todo problema de documentación tiene una prueba esperando a ser escrita.

Una frase que dice que un nodo no envía correo es una afirmación sobre un comportamiento repartido en cuatro ficheros, un valor por omisión, una casilla y una lista de categorías. No hay expresión con la que compararla. El único mecanismo que la detectaría es una prueba que dibuje el comportamiento y lea la frase, es decir, una prueba que hay que escribir por frase, y que escribe alguien que ya sabe que la frase está mal.

Lo que hicimos en su lugar fue más barato y merece nombrarse como práctica: cuando se hizo la corrección, se buscó en todo el subárbol de documentación cualquier otra afirmación sobre correo y cualquier otra afirmación sobre un flujo por plan. No había un tercer sitio. Eso es un resultado, no una formalidad. Sin ello, la ronda habría arreglado dos frases y habría dejado a quien lee con la creencia razonable de que la página estaba revisada.

La misma disciplina ya existe en otro punto de este proyecto para otro par: nuestros artículos largos pueden quedarse obsoletos frente a la lista de qué integraciones están en producción, y nada se pone rojo cuando ocurre. Dos artículos pasaron una vez seis semanas diciendo que dos hipervisores estaban en la hoja de ruta mientras ambos ya estaban en producción. La regla que salió de aquello es la misma: si una ronda cambia el estado de algo, se busca su nombre en la prosa con grep.

Lo que dejaríamos por escrito

  1. La prosa sobre el código es una afirmación sin probar. Nada de la compilación la lee. Eso está bien, mientras todo el mundo lo sepa y nadie dé por hecho que una ejecución verde dice algo del párrafo.
  2. La documentación se escribe frente a una rama, no frente a main. Si hay otras rondas abiertas, la página es una instantánea de un estado que puede no llegar nunca. Reléala después de la fusión, no antes.
  3. Un nombre que existe en el producto se lee, no se reescribe. Tres de seis nombres de tarjeta se desviaron en el primer borrador. En nueve idiomas eso es una clase de error, no un accidente.
  4. Derive la clave de documentación del identificador. Así la tarjeta siguiente queda cubierta sin que nadie recuerde esta regla.
  5. Una palabra adivinada en un idioma que no se lee es invisible. Cinco idiomas tenían nombres de botón adivinados y nada estaba rojo.
  6. Traducir un nombre de producto es una instrucción rota. Si el menú dice Scripts en todos los idiomas, el manual dice Scripts en todos los idiomas.
  7. Cuando dos reglas de lint discrepan, escriba a cuál obedeció y por qué. La alternativa es un comentario de desactivación que nadie puede evaluar después.
  8. Una medición que produce una salida verosímil al fallar no se pondrá en duda. Fotografíe algo reconocible, y mire las fotos.

Para que quede claro qué es esto: ambas páginas están en producción en nueve idiomas, las dos frases obsoletas se corrigieron en los nueve, y la guarda de nombres de tarjeta está en la suite y se demostró roja antes de demostrarse verde. Las afirmaciones de las páginas salen de leer el código y no de ejecutarlo; el ejemplo de curl de la página de automatizaciones no se ha lanzado contra un endpoint real; y cada traducción ha tenido una lectora, no dos.

Del trabajo de plataforma en Provibr. Las tarjetas a las que se refieren esos nombres están en un acceso directo es una referencia, no un derecho, y lo que cuesta mantener honestos nueve catálogos está en dieciséis mil claves y nueve idiomas.

Empiece con un host y un agente

Cree una cuenta, instale el agente con un solo comando y conecte su primer host de Proxmox. El periodo de prueba dura 14 días y no pide ningún dato de pago.