Pređi na sadržaj

Intent-driven development: kada kod prestaje da bude ono što čuvate

Strahinja Polovina · Inženjering9 min čitanja

Pitajte bilo koji tim šta bi zgrabio iz zgrade u plamenu i sedamdeset godina biste dobijali isti odgovor: izvorni kod. Izgubiti ga značilo je izgubiti sve odluke koje je kompanija nakupila, hiljade sitnih procena zbog kojih sistem pristaje uz posao. Taj odgovor se tiho menja. Kada agenti umeju da regenerišu ispravnu implementaciju iz preciznog iskaza o tome šta sistem mora da radi, kod prestaje da bude porodično srebro, a iskaz to postaje. Praksu koja iz toga sledi zovemo intent-driven development: disciplinu u kojoj namera, a ne kod, postaje artefakt koji tim piše, pregleda, verzioniše i poseduje.

Tvrdnja iz naslova traži ogradu, i to odmah. “Pisanje koda postaje opcija” ne znači da niko ne čita kod, ni da generisani kod nije važan, ni da je inženjerska veština postala višak. Znači nešto uže i zanimljivije: za sve širu klasu poslova ručno kucanje implementacije je danas izbor, a ne nužnost, pa tim treba svesno da odluči gde taj izbor i dalje pravi, umesto da ga po navici pravi svuda.

Namera nije utisak

Reč “namera” poziva na zloupotrebu, jer zvuči kao nešto što se zadovoljava izjavom o misiji i kolažem slika na zidu. U praksi je namera koja može da vodi razvoj skup proverljivih tvrdnji o ponašanju, tvrdnji nad kojima mašina ili kolega mogu da provere sistem i odgovore prolazi ili pada. “Kupcima treba da kupovina prolazi glatko” je osećaj. “Kupac koji se vraća završava kupovinu u tri koraka; neuspela naplata čuva korpu i objašnjava grešku na jeziku kupca; dvostruka naplata nije moguća ni kada se dugme za potvrdu klikne dvaput” jeste namera. Razlika je u proverljivosti, i tu je cela razlika.

Namera se slaže u tri sloja. Na vrhu je namera proizvoda: koji ishod sistem postoji da proizvede, za koga i mereno čime. Ispod nje žive invarijante sistema, svojstva koja moraju da važe bez obzira na implementaciju: novac se ne gubi, revizijski trag se samo dopisuje, lični podaci ostaju unutar granice, brisanja su povratna. Na dnu su testovi prihvatanja i evali, izvršni oblik i jedini sloj koji pipeline zaista može da pokrene. Svaki sloj opravdava onaj ispod sebe, a svaki niži čini onaj iznad proverljivim. Tim koji održava sva tri može da preda implementaciju agentu onako kako investitor predaje gradnju izvođaču: po projektu, a ne po pridevima.

Ako vam to zvuči kao bliski rođak pisanja ugovora za AI agente, i jeste. Spec-driven development je disciplina na nivou zadatka: jedan posao, jedan ugovor, jedna petlja verifikacije. Intent-driven development je ono što kodna baza postane kada se ta disciplina nagomila, kada nakupljeni ugovori, invarijante i evali postanu stvarni opis sistema, a svaka konkretna implementacija samo njegova trenutna kompilacija.

Kod postaje izvedena stvar

Praktična posledica je pomak u tome šta uopšte znači “izvor”. U kompajliranom jeziku niko ne krpi binarni fajl, nego menja izvor i radi rebuild. Intent-driven timovi počinju isto tako da tretiraju implementacioni kod: kada ponašanje mora da se promeni, prva izmena sleće u sloj namere, kao nov test prihvatanja, promenjena invarijanta ili izoštrena tvrdnja o proizvodu, a implementacija se zatim regeneriše ili prerađuje dok tu izmenu ne zadovolji. Kod i dalje ostaje čitljiv, pregledan i noseći. Menja mu se status: on je izveden, a raspravlja se o onome iz čega je izveden.

Zbog toga i pregled menja metu. Čitati tri hiljade generisanih linija brzinom čitanja jeste gluma, jer onaj ko pregleda odobrava ono što ne može da drži u glavi. Pregledati diff namere je izvodljivo: koje novo ponašanje je obećano, koje invarijante su dirnute, prikivaju li novi testovi zaista to obećanje i ima li u diffu implementacije ičega što namera ne objašnjava. Pažnja senior inženjera pomera se nivo naviše, sa pitanja “da li je ova petlja ispravna” na pitanje “da li je ovo pravo obećanje i da li se sprovodi”. To nije degradacija inženjerske procene, nego njena primena tamo gde se sada najviše isplati.

Kod je izveden, namera je izvor. Timovi koji raspravljaju o izvoru isporučuju brže od onih koji raspravljaju o kompilaciji.

Gde ručno pisan kod i dalje pobeđuje

Poštenje oko granice čuva ovo od pretvaranja u ideologiju. Neki kod i dalje treba pisati rukom, a kategorije su uvek iste. Vrelo jezgro, dakle mehanizam za cene, algoritam za uparivanje ili model rizika, gde svaka grana otelotvoruje poslovnu odluku i gde je razumevanje tog koda samo po sebi vrednost. Nov algoritamski rad, gde nameru nije moguće iskazati preciznije od implementacije, jer je otkrivanje implementacije upravo taj posao. Granice kritične po bezbednost (autentikacija, kriptografija, iniciranje plaćanja), gde dubina pregleda znači više od brzine izrade i gde želite ljudski potpis na svakoj liniji. I sam sloj namere: testovi, invarijante, evali i šeme zaslužuju ljudsko autorstvo upravo zato što se sve ostalo proverava prema njima.

Korisno pitanje za bilo koji posao nije da li agent to ume da napiše, jer sve češće ume, nego šta gubimo ako to ne napiše čovek. Tamo gde je odgovor “ništa, pod uslovom da se namera sprovodi”, generisanje je racionalan podrazumevani izbor. Tamo gde je odgovor “razumevanje onoga od čega zarađujemo”, kucajte sami.

Kako ovo truli

Trulež namere je prvi način da stvar pođe naopako. Sloj namere je izvor istine samo dok se održava kao izvorni kod. Čim tim počne da krpi ponašanje direktno, hotfiksom ovde i brzom ručnom izmenom onde, a da promenu ne vrati u testove i invarijante, namera počinje da opisuje sistem koji više ne postoji. Onda sledeća regeneracija, verno kompajlirana iz zastarele namere, obriše i te nedokumentovane ispravke. Pravilo koje to sprečava isto je ono koje drži šeme poštenim: promene ponašanja prvo sleću kao promene namere, u istom pull requestu, ili ne sleću.

Regenerisanje bez ponovne verifikacije je drugi. Regeneracija nije idempotentna: dva prolaza nad istom namerom daju različit kod sa različitim uzgrednim ponašanjem, a sve što sloj namere ne prikiva slobodno je da se promeni. Timovi se opeku kada pretpostave da jučerašnji zeleni pipeline jemči za današnju regeneraciju. Ne jemči. Svaka regeneracija je nova implementacija i traži pun prolaz verifikacije: testove, evale i provere invarijanti, i to svaki put. Ako je to preskupo da se pokreće posle svake regeneracije, rešenje je učiniti verifikaciju jeftinijom, a ne ređom.

Tretirati generisani kod kao potrošni kada je noseći jeste treći i najsuptilniji. Tim usvoji da je kod samo ono što izađe iz builda i prestane da ga čita: nema pregleda, nema profilisanja, nema operativne bliskosti. Onda incident stigne u dva ujutru, a ljudi na dežurstvu debaguju sistem koji niko nikada nije pročitao, vođeni samo namerom koju je trebalo da zadovolji. To što je nešto izvedeno ne znači da sme da se ignoriše. Produkcijski kod traži operativno vlasništvo bez obzira na to ko ga je otkucao; sloj namere vam govori šta sistem treba da radi, ali se odgovor na incident i dalje odvija u onome što sistem zaista radi. Timovi koji ovo dobro rešavaju imenuju vlasnika za svaku generisanu komponentu isto kao i za ručno pisanu, nekoga ko ju je pročitao, profilisao i ume da se probije kroz nju pod pritiskom.

Kako ovo uvesti bez revolucije

Ništa od ovoga ne traži revoluciju, a timovi koji je pokušaju obično proizvedu manifest i nijednu promenu. Put koji radi je inkrementalan. Počnite tako što ćete nameru učiniti eksplicitnom za sistem koji već imate: zapišite invarijante za koje verujete da važe, pretvorite nepisano znanje u testove prihvatanja i budite pošteni tamo gde se testovi i sistem ne slažu. Taj korak se isplati čak i ako nijedan agent nikada ne dodirne kodnu bazu, jer je to prosto dokumentacija i pokrivenost testovima koju ste ionako dugovali sami sebi.

Zatim izaberite jednu ograničenu, dobro shvaćenu komponentu i kroz nju provucite punu petlju: namera napisana i pregledana, implementacija generisana prema njoj, verifikacija mehanička, ljudski pregled usmeren na diff namere. Merite pošteno vreme ciklusa, stopu defekata i utrošak na pregled, i to u odnosu na ručno pisanu osnovu. Širite se duž granica na kojima petlja pobeđuje, a kucajte i dalje tamo gde ne pobeđuje. Za nekoliko kvartala kodna baza se sama razvrsta u ručno pisano jezgro sa generisanom periferijom, a oskudna seniorska pažnja skupi se na sloju na kome se najviše akumulira: na preciznom i proverljivom odlučivanju o tome šta softver mora da radi.

Industrija je ovde već bila. Niko ne žali za ručnim pisanjem asemblera; sposobnost smo zadržali, a naviku odbacili, jer je izvor na višem nivou uz pouzdan kompajler prosto bio bolja pogodba. Namera plus agenti plus verifikacija uobličavaju se u istu takvu pogodbu, samo jedan nivo više. Pisanje koda postaje opcija, a posao postaje znati tačno šta kod mora da radi i umeti to dokazati.

Modernizujete način na koji vaš tim gradi softver?

Pomažemo timovima da usvoje inženjering ere agenata bez rušenja onoga što već radi. Dijagnostički poziv je besplatan.