For noen år siden tok jeg en viktig avgjørelse i en SaaS-oppstart: hver kunde skulle ha sitt eget databaseskjema. Ingen tenant-data skulle ligge side om side med en annens. Ingen WHERE tenant_id = ? som siste forsvarslinje mot at feil kunde fikk se feil data.
Det var mer arbeid. Migreringer måtte kjøres per skjema. Verktøyene likte det dårlig. En kollega spurte, helt rimelig, om det ikke holdt med en kolonne.
I dag ville jeg antagelig valgt annerledes. Row Level Security i Postgres har modnet, og for lignende problemer bruker jeg det nå. Det gir samme garanti med langt mindre friksjon.
Men det er ikke poenget mitt.
Poenget er at spørsmålet ble stilt. Noen satt i et rom og sa høyt: hvordan skal vi garantere at kundedata er isolert, og hvem skal håndheve det. Databasen eller koden vår? Svaret jeg landet på var riktig for verktøyene vi hadde. Et annet svar hadde også vært forsvarlig. Det uforsvarlige hadde vært å aldri stille spørsmålet, og oppdage tre år senere at isolasjonen hviler på at ingen noen gang glemmer en WHERE-klausul.
Det er slike situasjoner jeg tenker på når folk snakker om vibe-koding.
Hva vibe-koding faktisk ga oss
La meg være tydelig på én ting først: vibe-koding er ikke en trussel mot faget. Det er en gave til en bestemt fase av det.
Terskelen for å lage noe som virker har falt gjennom gulvet. Prototyper som før tok to uker tar en ettermiddag. Folk som aldri har skrevet en linje kode får ideene sine ut i verden. Og for oss som har holdt på lenge er den kjedelige delen, plumbing, boilerplate, det femte CRUD-endepunktet denne uken, i ferd med å forsvinne. Det er bra. Det var aldri der verdien lå.
Jeg bruker agenter hver dag. Jeg vil ikke tilbake.
Så dette er ikke et argument for mindre AI. Det er et argument for mer dømmekraft rundt den.
Bruddet skjer ikke i koden
Når vibe-kodede systemer havarerer, er det sjelden fordi koden er dårlig. Koden er som regel helt grei. Den er lesbar, den følger konvensjoner, den har til og med tester.
Det som mangler er beslutningene.
Et sted underveis valgte agenten en database. Den valgte hvordan brukere og tilganger skulle modelleres. Den valgte om noe skulle være synkront eller ikke, om tilstand skulle bo i tjenesten eller utenfor, om denne integrasjonen skulle være et bibliotek eller ikke.
Ingen av disse ble diskutert. De ble ikke tatt som beslutninger i det hele tatt. De kom ut som plausibelt formulerte setninger i et svar, og siden alt fungerte, gikk man videre.
En gjennomgang av sju tidligfase vibe-kodede prosjekter fant nesten tusen sikkerhetsfunn, de fleste alvorlige. Det tallet er ubehagelig, men det er ikke det mest interessante. Det mest interessante eksempelet i den samme rapporten er dette: en tjeneste ble regenerert, og autentiseringen gikk fra tokens til cookies. Ikke fordi noen bestemte det. Den bare gjorde det. Autorisasjonen brøt sammen i alle avhengige tjenester.
Det er arkitekturdrift. Og det er umulig å oppdage i en kodegjennomgang som ser på én fil om gangen, fordi hver enkelt fil er helt fornuftig.
Ja, dette er spec-driven development
Svaret på dette har et navn allerede: spec-driven development. Skriv spesifikasjonen først, la den være sannhetskilden, generer koden fra den. Jeg jobber sånn, med OpenSpec.
Men slik SDD som regel beskrives, løser det halve problemet.
Spesifikasjonen beskriver hva systemet skal gjøre. Funksjonelle krav, brukerhistorier, akseptansekriterier. Alt det er nødvendig. Og en perfekt spesifikasjon av den typen beskytter deg ikke mot én eneste av beslutningene jeg listet opp over.
Du kan spesifisere «kunder skal ikke kunne se hverandres data» så presist du bare vil. Spesifikasjonen sier ingenting om hvorvidt den garantien skal ligge i databasen eller i applikasjonskoden. Det er en teknisk avveining med store konsekvenser, og den faller mellom stolene: for detaljert for produktspesifikasjonen, for grunnleggende til å overlates til den som genererer neste fil.
Guidet speccing
Det jeg mener med guided coding er egentlig én ting: spesifikasjonen må inneholde de tekniske valgene, ikke bare de funksjonelle.
Specen min gir harde krav. Ikke forslag. Ikke preferanser. Krav. Hvilken teknologi. Hvilken arkitektur. Hvordan data skal struktureres. Kodestil. At det skal skrives tester først. Rammene innenfor hvilke agenten har frihet, og grensene den ikke skal krysse uten at noen sier ifra.
Så skrives koden.
Og så, dette er den delen som faktisk betyr noe, leser jeg koden. Ikke for å finne skrivefeil. For å finne beslutningene. Og det jeg finner, guider jeg på:
«Fiks databasestrukturen, fordi denne relasjonen kommer til å bli et problem når volumet vokser.»
Og så flyter det tilbake i specen.
Det er hele mekanismen. Ikke et engangsdokument som skrives i starten og glemmes, men et levende artefakt som absorberer dømmekraft hver gang noen bruker den. Neste gang agenten genererer noe i det systemet, kjenner den til begrensningen — ikke fordi den husker samtalen, men fordi den står skrevet.
Det er forskjellen på å korrigere en agent og å lære opp et system.
De tre valgene som ikke lar seg gjøre om
Ikke alle beslutninger er verdt å bruke tid på. Det er nettopp derfor det fungerer å la agenten gjøre det meste. Men tre kategorier har en egenskap som skiller dem fra resten: de er dyre å angre.
Teknologivalg binder deg. Ikke «hvilket rammeverk er best», men: hva krever et helt team og et kvartal å komme seg ut av? En agent anbefaler det som er best representert i treningsdataene. Det er ikke det samme som det som passer denne kunden, dette teamet, dette driftsmiljøet, denne bemanningssituasjonen om to år.
Arkitekturvalg avgjør hva som kan endres senere. Grensene mellom delene. Hva som vet om hva. Hvor tilstanden bor. En agent optimaliserer for at neste prompt skal gi kode som kjører, ikke for at noen skal kunne bygge om en del av systemet om tre år uten å røre resten.
Datastruktur er den dyreste av dem alle. Kode kan skrives om på en ettermiddag; det er nettopp det agentene er gode til. En datamodell som ligger i produksjon med ekte kundedata i seg er en migrering, et vedlikeholdsvindu og en risiko. Hvis du bare tar med deg én ting herfra: la et menneske eie datamodellen.
Dette er ikke fem prosent av arbeidet. Det er kanskje én prosent. Men det er den prosenten som avgjør hva de neste to årene koster.
Hva slags ferdighet er dette egentlig?
Her er det ubehagelige spørsmålet: hvis agenten skriver koden, hva er det egentlig eksperten bidrar med?
Ikke syntaks. Ikke algoritmer. Ikke kjennskap til API-et. Den kan det bedre enn meg.
Det eksperten bidrar med er å vite hvilke spørsmål som må stilles før noe skrives. Å kjenne igjen et forslag som ser helt fornuftig ut, men som lukker en dør. Å ha sett hva som skjer tre år etter at en slik dør ble lukket.
Det er mønstergjenkjenning bygget på konsekvenser man selv har måttet leve med. Det er derfor det tar tid å bygge, og derfor det ikke kan promptes frem.
Da jeg valgte skjema per tenant, var det ikke fordi jeg hadde lest at det var beste praksis. Det var fordi jeg hadde sett hva som skjer når isolasjon hviler på at ingen noen gang glemmer noe. En agent i dag ville sannsynligvis foreslått tenant_id og en WHERE-klausul. Den ville fungert. Den ville bestått testene. Og den ville flyttet en garanti fra databasen, der den håndheves, til hodene til alle som noen gang skriver en spørring mot det systemet.
At jeg i dag ville valgt RLS i stedet, endrer ikke poenget. Det bekrefter det. Svaret er annerledes, men spørsmålet var det samme. Det er å stille spørsmålet som er faget.
Så
Vibe-koding er utmerket til å finne ut om noe er verdt å bygge. Guided coding handler om hva du gjør når svaret er ja.
Det som er igjen er dømmekraften. Å vite hva som skal bygges, hvordan, og hvilke av de valgene du ikke får gjort om.
Det er fortsatt den vanskelige delen. Det har det alltid vært.
Verktøykassa mi i dag: OpenSpec for spec-flyten, Superpowers for selve kodinga, Graphify for å gi agenten bedre kontekst på store kodebaser til en brøkdel av tokenbruken. Verktøyene kommer til å bli byttet ut. Mekanismen tror jeg blir stående.