Code Slop i el deute tècnic generat per IA
Vaig acabar l'article anterior d'aquesta sèrie amb una pregunta: l'última vegada que vau aprovar alguna cosa, hauríeu pogut explicar per què estava bé? Aquest tracta del que passa quan la resposta és no, i no com a excepció, sinó com la manera habitual en què funciona un pipeline.
El code slop no és codi que es vegi òbviament dolent. El codi òbviament dolent es detecta. És codi que supera tots els punts de control que heu muntat, tots els tests que heu escrit, i que tot i així no és res que voldríeu haver de mantenir d'aquí a sis mesos.
Quin aspecte té realment el code slop
Compila. Passa els tests que se us va acudir escriure. Fa el que demanava el tiquet, tècnicament. I a més és la quarta manera lleugerament diferent de fer el mateix en aquesta base de codi, perquè l'agent no tenia manera de saber que les altres tres ja existien: va veure l'arxiu que li vau dir que edités, no el patró que ja estava establert dues carpetes més enllà.
El slop no és un bug. Un bug falla amb prou soroll perquè algú acabi notant-ho. El slop només afegeix massa: un helper duplicat, una abstracció que té un únic punt d'ús, gestió d'errors per a un cas que no es pot donar, un test que comprova que el mock s'ha comportat com el mock. Res d'això està malament. Tot això és ara una cosa que una persona ha de llegir, entendre i mantenir, per sempre, o fins que algú reuneixi el coratge d'esborrar-ho.
Per què supera tots els punts de control
Els punts de control de l'article anterior es van dissenyar per detectar errors: una sortida incorrecta, una lògica trencada, una especificació incomplerta. El slop no és un error. És codi correcte que no hauria d'existir, o codi correcte repetit tres vegades, o codi correcte que resol un problema que ningú té en realitat. Cap de les vostres comprovacions actuals busca això, perquè «és això correcte?» i «necessita aquesta base de codi això?» són preguntes diferents, i la majoria de les revisions, humanes o automàtiques, només fan la primera.
Un agent que optimitza per «que els tests passin» no té cap senyal que li digui que el helper que acaba d'escriure ja existeix com a formatDate dos arxius més enllà. No té cap senyal que li digui que la interfície que acaba d'introduir només s'implementarà una vegada, la que el mateix agent acaba de crear. No està sent gandul ni descurat. Està tenint èxit, exactament tal com se li va indicar, en un objectiu més estret que el que realment us importa.
Els tests que no ho detecten
Aquesta és la part que més em va costar acceptar: una bateria de tests en verd és prova que el codi fa el que comproven els tests. No és prova que el codi sigui la quantitat de codi adequada. Podeu escriure un test perfectament vàlid per a una classe que no hauria d'existir, una interfície amb una única implementació, una opció de configuració que ningú farà servir mai amb un valor diferent del predeterminat.
Les xifres de cobertura ho empitjoren, no ho milloren. Un percentatge de cobertura alt sobre codi innecessari només vol dir que heu provat a fons aquest codi innecessari. És una xifra real que mesura el que no toca, i això és més perillós que una xifra òbviament falsa: una xifra falsa es qüestiona, una xifra real que mesura l'eix equivocat es dona per bona.
Què busco ara de debò
La pregunta que em faig ja no és «funciona?»; això ja ho han respost els tests. És «ho hauria escrit jo així?» i, més en concret, «hi ha menys codi que faci la mateixa feina?». Algunes coses que treuen a la llum el slop de manera bastant fiable quan les busco:
- Cerqueu abans de refiar-vos d'una funció nova. Si un agent acaba d'escriure un helper, cerqueu primer alguna cosa semblant. Les utilitats reinventades són el que més trobo, i són invisibles tret que les busqueu expressament.
- Compteu els punts d'ús. Una interfície, un flag de configuració o una factory amb exactament una implementació o un únic punt d'ús és una decisió presa per a un futur que no ha arribat. Elimineu la cerimònia i quedeu-vos amb el concret.
- Llegiu el diff pensant contra què protegeix. La gestió d'errors i la validació per a estats que no es poden donar no són seguretat: són farciment que sembla seguretat, i és exactament el tipus de cosa que els revisors deixen passar perquè sembla responsable.
- Pregunteu-vos què passa si ho esborreu. Si treure un fragment de codi no canvia cap comportament observable, és que no es guanyava el lloc.
Res d'això és exòtic. És la mateixa disciplina de revisió que ja apliquen els bons enginyers al codi escrit per persones. La diferència és que un agent en genera deu vegades més volum en la mateixa tarda, així que les parts de la revisió que abans eren opcionals, les que us podíeu saltar perquè una persona no solia escriure tant codi innecessari d'una tirada, deixen de ser-ho.
Com pagar-lo abans que s'acumuli
La versió cara d'aquest problema no és el slop en si: és el slop que revisa un altre agent més endavant, que tracta la duplicació existent com a precedent i afegeix una cinquena versió del mateix helper al costat de les altres quatre. El deute que genera una persona a poc a poc es detecta a poc a poc, al mateix ritme que s'acumula. El deute que genera un agent de pressa pot avançar les persones que se suposa que el vigilen abans que ningú llegeixi el diff amb prou atenció per veure el patró.
La solució no és més punts de control; l'article anterior ja va explicar per què això surt malament. És fer que «aquesta base de codi ja fa això?» formi part del que se li indica a l'agent que comprovi abans d'escriure codi nou, en lloc d'una cosa que una persona reconstrueix després a partir d'un diff enorme. Surt més barat assenyalar-li a un agent el patró que ja existeix que netejar després el seu intent d'endevinar-lo.
Conclusió
Un pipeline que només comprova la correcció enviarà encantat a producció codi correcte que no hauria d'existir. El slop no és la fallada d'un procés trencat: és el resultat previsible d'un procés que mai es va fer la segona pregunta.
En el pròxim article d'aquesta sèrie veuré com mesurar de debò si una configuració d'agents millora amb el temps, en lloc de només semblar que millora: Evals: com sé de debò si el meu agent ha millorat — construir el bucle de retroalimentació que detecta les regressions que ni els punts de control ni els tests en verd detecten.
Fins llavors, la pregunta que val la pena fer-se sobre el vostre propi resultat no és:
Això funciona?
És:
És això el mínim de codi que podia fer-ho funcionar?
Si heu trobat una manera de detectar duplicació o abstracció innecessària abans que arribi a producció, m'agradaria saber com. No dubteu a escriure'm.