Nešto se tiho izvrnulo u softverskom inženjerstvu u poslednje dve godine. Tokom najvećeg dela istorije struke kod je bio artefakt, a specifikacija potrošna skela oko njega — dokument napisan jednom, preleten dvaput i napušten do trećeg sprinta. Sada AI agenti pišu sve veći deo koda i ekonomija se preokrenula. Kod je postao jeftin za proizvodnju i jeftin za regenerisanje. Ono što je retko jeste precizan iskaz o tome šta kod mora da radi. Specifikacija više nije skela. Ona je inženjerski artefakt.
Timovi koji je tako tretiraju dobijaju od agenata polugu koja se akumulira: predaju dobro definisan posao, verifikuju rezultat mehanički i merguju sa sigurnošću. Timovi koji je tako ne tretiraju dobijaju novu vrstu tehničkog duga — kod koji izgleda uverljivo, koji niko nije tražio, generisan brže nego što iko stiže da ga pregleda. Razlika između njih nije u modelu ni u alatima. Razlika je u tome da li je specifikacija ugovor.
Prompt nije specifikacija
Najčešći promašaj je tretirati chat prozor kao specifikaciju. Prompt je uvod u razgovor: opisuje nameru u prozi, granične slučajeve prepušta dobroj volji čitaoca i nestaje u scrollback baferu čim je poslat. Niko ne može da ga revidira, uporedi u diff-u ili da pokaže na njega tri nedelje kasnije, kada se ponašanje ospori. Agent kome date prompt radi ono što radi izvođač kome ste posao objasnili u hodniku: svaku rupu popunjava sopstvenim pretpostavkama, samouvereno.
Specifikacija je drugačiji objekat. Živi u repozitorijumu, pored koda koji uređuje. Verzionisana je, pa vidite šta je dogovoreno i kada se promenilo. Može se revidirati, pa kolega može da ospori zahtev umesto implementacije. I proverljiva je — to je ključno svojstvo — što znači da za svaki isporučen posao postoji mehanički način da se pita: zadovoljava li ovo specifikaciju, da ili ne? Onog trenutka kada to pitanje traži ličnu procenu, imate prozu, a ne ugovor.
Šta specifikaciju čini ugovorom
Četiri sastojka razdvajaju ugovor od želje. Kriterijumi prihvatanjadolaze prvi: uočljive, binarne tvrdnje o ponašanju. “Brzo” je želja; “p95 ispod 200 ms pri 50 zahteva u sekundi” je kriterijum. “Obrađuje loš ulaz” je želja; “odbija neispravan payload sa statusom 422 i mašinski čitljivim kodom greške” je kriterijum. Ako ne možete da odlučite prolazi ili pada iz perspektive izvan implementacije, prepisujte dok ne budete mogli.
Razrađeni primeri dolaze drugi i rade više posla od svakog drugog odeljka. Konkretni parovi ulaz-izlaz — uključujući i ružne: prazna lista, duplo slanje, granični slučaj sa vremenskom zonom, korisnik koji nalepi emodži u polje za iznos. Primeri su mesto na kome skrivene pretpostavke izlaze na videlo. Oni su, ne slučajno, i test slučajevi koji čekaju da budu prepisani.
Invarijante dolaze treće: svojstva koja moraju da važe bez obzira na to kojim putem implementacija krene. Saldo nikada ne ide u minus. Svaki prelaz stanja se loguje. Brisanja su meka. Nema poziva ka procesoru plaćanja bez idempotency ključa. Invarijante su zaštitna ograda koja preživljava refaktorisanje — što je dvostruko važno kada refaktoriše agent koji nije bio na sastanku na kome je pravilo objašnjeno.
Ne-ciljevidolaze poslednji i najviše se zanemaruju. Agent retko otkazuje tako što uradi premalo; obično uradi previše — izmisli opcije konfiguracije, doda keširanje koje niko nije tražio, “popravi” susedni kod. Kratak spisak onoga što ova izmena ne sme da dodirne i koje probleme ne sme da rešava najjeftinija je kontrola obima koju ćete ikada napisati.
Agent svaku rupu u specifikaciji popunjava sopstvenim pretpostavkama — samouvereno. Ugovor postoji zato da rupe vredne popunjavanja ni ne postoje.
Ugovori traže sprovođenje
Ugovor koji niko ne sprovodi je dekoracija. Sloj sprovođenja je ono što od spec-driven developmenta pravi inženjersku praksu, a ne dokumentacionu naviku, i ima tri dela. Prvo, testovi kao izvršni oblik ugovora. Kriterijumi prihvatanja i razrađeni primeri se prepisuju u test suite pre nego što agent napiše implementaciju. Suite je specifikacija kompajlirana u nešto što mašina može da proveri; agentov posao je da ga natera da prođe, bez slabljenja. Čuvajte i same testove u reviziji — agent koji izmeni assertion da bi test prošao jednostrano je iznova pregovarao ugovor.
Drugo, tipizirane granice. Šeme, tipovi i API ugovori prikivaju svaki interfejs koji agentov kod dodiruje. Stroga šema na granici pretvara čitavu klasu uverljivih ali pogrešnih izlaza u greške kompajliranja i pad validacije — povratnu informaciju koju agent dobija za sekunde, unutar petlje, umesto da mu je recenzent isporuči danima kasnije. Što je granica stroža, to je manje prostora da samouvereno smeće procuri kroz nju.
Treće, kapije revizije koje porede diff sa ugovorom. Ljudska revizija ne nestaje; menja metu. Pregledati izlaz agenta liniju po liniju, agentovom brzinom, unapred je izgubljena igra — prosto ima više koda nego pažnje. Uporediti diff sa ugovorom je izvodljivo: zadovoljava li izmena svaki kriterijum prihvatanja, poštuje li svaku invarijantu, ostaje li unutar ne-ciljeva? Sve u diff-u što ugovor ne objašnjava je prvo pitanje revizije, a ne bonus.
Tri načina na koja ovo pođe naopako
Maglovita specifikacija, samouvereno smeće.Tim napiše tri stavke, agent proizvede osamsto linija, a jaz između namere i ponašanja se otkrije u produkciji. Znak prepoznavanja su revizije koje počinju sa “nisam na to mislio” — rečenica koja optužuje specifikaciju, a ne agenta. Rešenje je dosadno: više primera, oštriji kriterijumi, napisani pre generisanja, a ne posle.
Preterana specifikacija, nikakva poluga. Suprotan jarak. Ako specifikacija diktira implementaciju — fajl po fajl, funkciju po funkciju — napisali ste kod dvaput, jednom na srpskom i jednom na jeziku na kome se izvršava, a agent je sveden na daktilografa. Specifikujte ponašanje na granici i invarijante unutar nje; implementaciju prepustite onome ko je piše. Ako specifikovanje zadatka traje duže od njegovog obavljanja, tom zadatku agent nije ni bio potreban.
Razilaženje specifikacije i stvarnosti. Najtiši način otkazivanja. Ugovor je rekao jedno, produkcija se razvila u nešto drugo i posle tri meseca sitnih pregovaranja usput specifikacija opisuje sistem koji više ne postoji. Razilaženje je neizbežno; nezabeleženo razilaženje je izbor. Pravilo koje ga sprečava staje u jednu rečenicu: promene ponašanja prvo sleću kao promene specifikacije, u istom pull request-u, ili ne sleću.
Workflow, s kraja na kraj
U praksi to izgleda kao kratka petlja. Napišite ugovor — kriterijume, primere, invarijante, ne-ciljeve — i dajte ga na reviziju ljudima koji će živeti sa tim ponašanjem; tu je neslaganje jeftino. Prepišite proverljive delove u testove koji padaju. Predajte ugovor agentu i pustite ga da radi prema suite-u koji pada, iterirajući dok mehaničke provere — testovi, tipovi, šeme, linteri — ne prođu, i to bez izmena samih provera. Tek onda uporedite diff sa ugovorom, a ne sa sopstvenim strpljenjem: kriterijumi ispunjeni, invarijante održane, ništa izvan ne-ciljeva. Merge beleži ugovor i njegovo ispunjenje u jednoj atomskoj celini, a sledeći zadatak kreće sa poštene osnove.
Petlja ima efekat drugog reda koji timove iznenadi: ugovori čine rad agenata paralelizovanim. Dva agenta nad jednim maglovitim briefom se sudaraju; pet agenata nad pet ugovora, sa tipiziranim granicama među njima, merguju čisto, jer svaki ugovor kaže šta njegov deo mora da radi i gde se završava. Isto svojstvo koje specifikaciju čini proverljivom čini je i sastavljivom — a tako mali seniorski tim nadgleda količinu istovremene implementacije za koju je pre pet godina bilo potrebno celo odeljenje.
Još jedno mehaničko pravilo drži petlju poštenom: provere se izvršavaju u CI-ju, a ne na agentovu reč. Agent koji javlja “svi testovi prolaze” iznosi tvrdnju; zeleni pipeline nad neizmenjenim test suite-om je činjenica. Ugovor, njegovi testovi i pipeline zajedno čine neutralnog arbitra kome je svejedno da li je kod napisao čovek koji ima loš dan ili model koji ima samouveren — i baš ta ravnodušnost je ono što izlaz čini vrednim poverenja.
Timovi koji ovo usvoje otkriju da se usko grlo pomerilo. Retka veština više nije proizvodnja koda — nego precizno odlučivanje šta kod treba da radi i proverljivo izražavanje toga. To je oduvek bio težak deo softvera; agenti nisu stvorili taj problem, samo su uklonili mesto na kome se krio.
Kada se isplati — a kada je samo režija
Spec-driven development nije besplatan, i pretvaranje da jeste ubija usvajanje. Ugovor se isplati kada je posao značajan i kada je cena greške stvarna: sistemi koji pomeraju novac, dodiruju podatke o klijentima, sede na granicama između timova ili će ih održavati ljudi — i agenti — koji nisu bili prisutni kada su odluke donete. Najbrže se isplati baš tamo gde je izlaz agenta najteže pregledati okom.
Režija je za spike-ove, prototipove i jednokratne skripte — kod čija je cela svrha da bude bačen čim odgovori na pitanje. Napišite rečenicu namere, pustite agenta, zadržite nauk i obrišite kod. Disciplina je znati u kom ste režimu i biti pošten onog trenutka kada prototip počne tiho da postaje sistem. Taj trenutak — a ne rewrite šest meseci kasnije — jeste kada se ugovor piše.
Industriji su bile potrebne dve decenije da nauči da testovi nisu birokratija, nego ono što vam dozvoljava da se krećete brzo bez lomljenja onoga što je važno. Specifikacije sada prolaze isti put, iz istog razloga. Kada se marginalni trošak pisanja koda približi nuli, vrednost se koncentriše u iskazu o tome šta kod mora da radi — a timovi koji taj iskaz pišu kao ugovor su oni kod kojih se rad agenata zaista akumulira.