Idempotència estructural: com saps que el harness ja està acabat
Un criteri concret per saber quan pots deixar d'afegir regles: si tornar a aplicar el pipeline no canvia res, has convergit. I es prova en dues línies.
·8 min de lectura
Tota conversa sobre governança de codi generat arriba al mateix carreró: quantes regles calen? Sense un criteri, la resposta acaba sent «les que s’ens acudeixin», que és com dir cap.
La tercera dimensió del marc de harness engineering —la Convergència— aporta un criteri que es pot executar en una terminal. Es diu idempotència estructural, i diu això:
Un harness ha convergit quan tornar a aplicar les seves regles no produeix cap canvi estructural.
Per què no pots escriure-ho tot d’entrada
Abans del criteri, la raó per la qual cal. La temptació de tot enginyer és seure un dia i escriure totes les regles. No funciona, i hi ha quatre motius que no depenen de la teva disciplina:
El domini coevoluciona. No pots escriure regles per a un subsistema que encara no existeix. Les convencions dels agents no es podien articular abans de tenir agents.
Les regles interactuen. Cada capa de restriccions en revela efectes d’interacció que abans no es veien. La regla d’ordenar imports i la de separar imports de tipus poden portar-se molt bé o desfer-se mútuament, i no ho saps fins que hi són totes dues.
Els patrons emergeixen. Els antipatrons arquitectònics són invisibles fins que el codi té prou mida. Fins a deu fitxers, tot sembla ordenat.
Escriure-ho tot no surt a compte. Predir cada patró futur té un cost que creix amb la complexitat del projecte i un rendiment que decreix.
Per tant el harness es construeix per capes: H₀ → H₁ → … → Hₙ, i cada capa fa visible el que l’anterior tapava. La pregunta no és com evitar-ho, és com saber que ja hi ets.
El criteri, sense matemàtiques
Formalment: sigui P la transformació que aplica totes les regles del harness i O una observació de l’estructura. El harness ha convergit quan O(P²(σ)) = O(P(σ)).
Traduït: executa el pipeline dues vegades seguides. Si la segona passada no canvia res, has convergit.
Hi ha dos detalls que fan que això sigui útil i no una trivialitat.
Què s’observa. L’observació no és el codi sencer: és la signatura estructural —ruta del fitxer, nom, col·locació al directori, exports, imports, ordre de les funcions—, i exclou deliberadament la lògica. Si observessis el codi sencer, cap canvi seria mai idempotent. Si no observessis res, tot ho seria. La signatura estructural és el punt intermedi que té sentit.
Amb una sola repetició n’hi ha prou. Un cop es compleix per a k=2, es compleix per a qualsevol k. No cal iterar fins a l’infinit ni deixar-ho corrent tota la nit: dues passades i ja ho saps.
Com es prova de veritat
La versió honesta, que corre a CI:
#!/usr/bin/env bash
# convergencia.sh — el harness canvia res la segona vegada?
set -euo pipefail
# Passada 1: aplicar tot el que transforma
npm run lint -- --fix
npm run format
git diff --quiet || git commit -am "harness: passada 1" --no-verify
# Passada 2: sobre el resultat de la primera
npm run lint -- --fix
npm run format
if ! git diff --quiet; then
echo "✕ El harness NO ha convergit. Canvis a la segona passada:"
git diff --stat
exit 1
fi
echo "✓ Idempotència estructural: cap canvi a la segona passada."
Si això falla, tens informació molt concreta: hi ha regles incompletes o que es contradiuen. I el git diff --stat t’assenyala exactament quins fitxers.
La correcció, i aquest matís és important: s’ajusten les regles P, no l’observació O. La sortida fàcil quan la prova falla és treure de l’observació allò que no convergeix. Això no arregla res: només amaga el conflicte.
Independència de camí
Una propietat germana, i la que fa que un harness sigui utilitzable en equip: l’ordre en què introdueixes les regles no ha de canviar el resultat final.
Codi Codi
│ │
regla A regla B
│ │
regla B regla A
│ │
▼ ▼
┌──────────────────────────────┐
│ la mateixa forma canònica │
└──────────────────────────────┘
Si es compleix, un equip pot instal·lar paquets de restriccions en qualsevol ordre sense pensar en efectes d’interacció. És exactament el que necessitava Toss per muntar el seu mercat de connectors: sense independència de camí, distribuir regles com a paquets instal·lables és impossible.
No és automàtic. Ho tens a favor perquè la majoria de regles de linter són predicats declaratius —diuen si una cosa és vàlida—, i els predicats no depenen de l’ordre. Ho tens en contra quan hi ha correccions automàtiques, que sí que són transformacions seqüencials i sí que poden barallar-se. La independència de camí és un objectiu d’enginyeria, no una garantia regalada.
Idempotència: la idea ja la coneixes
Si això et sona, és perquè és el mateix principi que ja fas servir en dos llocs.
| Domini | Què convergeix | Garantia |
|---|---|---|
| Terraform, Ansible | Estat de la infraestructura | Apliques n vegades, l’estat és el mateix |
| Integracions | Efecte d’una operació | Reintentes n vegades, l’efecte és un |
| Harness | Estructura del codi | Apliques n vegades, l’estructura és la mateixa |
I aquí hi ha la coincidència que fa gràcia: en Mitchell Hashimoto, creador de Terraform, ha arribat pel seu compte al mateix principi al nivell del codi, sense buscar-hi el paral·lelisme. Vint anys separant els dos descobriments. Quan la mateixa persona troba la mateixa idea en dos dominis diferents, normalment vol dir que la idea és de la casa, no del domini.
El bucle: buscar forats, no corregir errors
La convergència no és només una prova, és una manera de treballar. La formulació que més m’agrada és d’en Ben Shoemaker, parlant de quan llegeix codi generat:
«Fins i tot quan el llegeixo, generalment miro d’esbrinar quin és el forat del harness perquè no hagi de tornar a tractar aquest problema mai més.»
El canvi de pregunta és tot el mètode:
| Reacció habitual | Reacció convergent |
|---|---|
| «Aquest codi està malament» → el corregeixo | «Aquest codi està malament» → per què ho ha permès el harness? |
| Corregeixes una instància | Tanques una classe sencera |
| El problema torna | El problema no pot tornar |
En Hashimoto ho diu igual: «cada cop que trobes que un agent comet un error, dediques el temps a dissenyar una solució perquè l’agent no torni a cometre aquell error mai més».
Perquè això funcioni cal una cosa avorrida però decisiva: portar registre. Tres columnes en un fitxer de text —què vaig corregir, de quin tipus era, quina regla ho hauria evitat— i revisar-lo cada quinze dies. Sense el registre, corregeixes el mateix vuit vegades i no te n’adones, perquè cada vegada per separat és barata.
Els agents de neteja
Entre els punts d’imposició sempre s’hi cola deriva. La resposta d’OpenAI són agents de neteja recurrents que fan el que anomenen entropy management; a Thoughtworks en diuen «recollida d’escombraries», i és el mateix.
Un agent programat —setmanal, per exemple— amb una tasca acotada: buscar un tipus concret de deriva estructural i corregir-lo. No «millora el codi», que és una invitació al desastre, sinó «troba fitxers a serveis/ que exportin més d’una cosa i separa’ls».
Un avís per experiència: un agent de neteja sense una prova de convergència al davant és una màquina de fer soroll. Primer la porta de CI, després l’automatització que la satisfà.
Què costa això
Convergència no és correcció. Aquesta és la limitació seriosa i cal dir-la clara: la convergència estructural no garanteix res del comportament. Dos fitxers amb la mateixa signatura estructural poden tenir errors diferents. El harness et diu que la casa està ben ordenada, no que la instal·lació elèctrica funcioni.
El criteri es pot satisfer trivialment. Si l’observació és massa laxa, sempre convergeix i no vol dir res. La prova només val el que valgui la signatura estructural que hagis definit.
La prova s’ha de mantenir. Cada regla nova pot trencar la idempotència, i el dia que la trenca convé arreglar-ho, no desactivar la comprovació. Com totes les portes de CI, val el que valgui la disciplina de qui la manté verda.
El que t’has d’endur
- El criteri per parar existeix i s’executa: pipeline dues vegades,
git diffbuit. - Si la segona passada canvia coses, tens regles incompletes o en conflicte. Ajusta les regles, no la mesura.
- L’ordre d’introduir regles no hauria de canviar el resultat. Vigila les correccions automàtiques.
- Davant d’un error, busca el forat del harness, no la correcció puntual.
- Porta registre de les correccions. És el que converteix les anècdotes en regles.
- Estructural no vol dir correcte. Les proves segueixen sent la teva feina.
Amb les tres dimensions posades —context, restricció i convergència— queda la pregunta incòmoda: si el harness verifica l’estructura i les proves verifiquen el comportament, què queda per revisar a mà?