Joel Spolskys programvarusanningar gäller fortfarande när AI snabbt kan skriva kod. Lär dig hur tester, rekrytering och enkelhet håller fokus på korrekthet.

AI kan producera kod som ser fungerande ut på några minuter. Det ändrar tempot i ett projekt, men inte vad som krävs för att mjukvara ska lyckas. Lektionerna i Joel Spolskys “programvarusanningar” handlade aldrig om skrivhastighet. De handlade om omdöme, återkopplingsloopar och att undvika självförvållad komplexitet.
Det som har förändrats är kostnaden för att skapa kod. Du kan be om tre angreppssätt, fem varianter eller en full omskrivning och få något tillbaka direkt. Det som inte har förändrats är kostnaden för att välja rätt angreppssätt, kontrollera det och leva med det i månader. Tid som sparas på skrivandet flyttar ofta till att bestämma vad du menade, validera kantfall och se till att dagens snabba vinst inte blir morgondagens underhållsskatt.
Korrekthet, säkerhet och underhållbarhet kräver fortfarande tid eftersom de bygger på bevis, inte på förtroende. Ett inloggningsflöde är inte klart när det kompilerar. Det är klart när det konsekvent avvisar ogiltiga indata, hanterar udda tillstånd och inte läcker data. AI kan låta säker men missa en avgörande detalj, som en behörighetskontroll på en endpoint eller en race condition vid uppdatering av betalning.
AI är som starkast när du behandlar det som en snabb maskin för utkast. Det glänser i boilerplate, repetitiva mönster, snabba refaktorer och när du vill utforska alternativ att jämföra sida vid sida. Använt rätt, komprimerar det fasen med "tomt papper".
AI gör mest skada när du ger vaga mål och accepterar utdata som de är. Samma felmönster återkommer: dolda antaganden (outtalade affärsregler), otestade vägar (felhantering, retryer, tomma tillstånd), självsäkra misstag (plausibel kod som är subtilt fel) och "smart" lösningar som är svåra att förklara senare.
Om kod är billig blir det nya knappa resurserna förtroende. Dessa sanningar skyddar det förtroendet: med användare, med kollegor och med ditt framtida jag.
När AI kan generera en funktion på minuter är det frestande att se testning som den långsamma delen du måste eliminera. Spolskys poäng gäller fortfarande: den långsamma delen är där sanningen finns. Kod är lätt att producera. Korrekt beteende är det inte.
En nyttig förskjutning är att behandla tester som krav du kan köra. Om du inte kan beskriva förväntat beteende på ett kontrollerbart sätt är du inte klar med tänkandet. I AI-assisterat arbete spelar detta större, inte mindre roll, eftersom modellen kan producera något som är nästan rätt men ändå fel.
Börja testa det som skulle göra mest skada om det gick sönder. För de flesta produkter är det kärnflöden (signup, checkout, spara, export), behörigheter (vem kan visa, redigera, ta bort) och dataintegritet (inga duplicerade poster, korrekta totalsummor, säkra migreringar). Täck sedan de kanter som brukar orsaka nattliga incidenter: tomma indata, långa texter, tidszoner, retryer och fladdriga externa gränser som betalningar, e-post och filuppladdningar.
AI är bra på att föreslå testfall, men det kan inte veta vad du faktiskt lovade användarna. Använd det som en brainstorming-partner: be om saknade kantfall, missbruksscenarier och kombinationer av behörigheter. Gör sedan det mänskliga jobbet: matcha täckningen mot dina verkliga regler och ta bort tester som bara "testar implementationen" istället för beteendet.
Gör fel meningsfulla. Ett misslyckande test ska berätta vad som gick sönder, inte skicka dig på en skattjakt. Håll tester små, namnge dem som meningar och gör felmeddelanden specifika.
Säg att du bygger en enkel "team notes"-app med AI-hjälp. CRUD-skärmar dyker upp snabbt. Korrekthetsrisken är inte UI:t. Den är åtkomstkontroll och dataregler: en användare ska inte se en annan teams anteckningar, redigeringar får inte skriva över nyare ändringar och radering av en anteckning får inte lämna föräldralösa bilagor. Tester som låser dessa regler kommer att kännas som flaskhalsen, men de är också ditt säkerhetsnät.
När testning är flaskhalsen tvingar det till klarhet. Den klarheten är vad som hindrar snabb kod från att bli snabba buggar.
En av de mest hållbara sanningarna är att enkel kod vinner över smart kod. AI gör det frestande att acceptera prydliga abstraktioner eftersom de dyker upp polerade och snabba. Kostnaden visar sig senare: fler ställen där buggar kan gömma sig, fler filer att skanna och fler "vad gör det här egentligen?"-ögonblick.
När kod är billig är det komplexitet du betalar för. En liten, tråkig design är lättare att testa, lättare att ändra och lättare att förklara. Det spelar ännu större roll när första utkastet kom från en modell som kan låta säker men vara subtilt fel.
En praktisk regel är att hålla funktioner, komponenter och moduler små nog att en kollega kan granska dem på minuter, inte timmar. Om en React-komponent behöver flera custom hooks, en lokal tillståndsmaskin och ett generellt "smart renderer"-lager, pausa och fråga om ni löser ett verkligt problem eller bara accepterar arkitektur för att AI erbjöd det.
Några "enkelhetstester" hjälper dig att stå emot:
Prompter spelar roll här. Om du ber om "bästa arkitekturen" får du ofta en överbyggd lösning. Be istället om begränsningar som driver mot färre rörliga delar. Till exempel: använd det enklaste tillvägagångssättet med färst filer; undvik nya abstraktioner om de inte tar bort upprepning i tre eller fler ställen; föredra explicit kod framför generiska hjälpare.
Ett konkret exempel: du ber AI lägga till rollbaserad åtkomst till en admin-sida. Den smarta versionen introducerar ett behörighetsramverk, dekoratörer och ett konfigurations-DSL. Den enkla versionen kontrollerar användarroll i ett ställe, gate:ar routes på ett ställe och loggar nekad åtkomst. Den enkla versionen är lättare att granska, lättare att testa och svårare att misstolka.
Om du bygger i ett chattbaserat verktyg som Koder.ai gör enkelhet även snapshots och rollback mer värdefulla. Små, uppenbara ändringar är lättare att jämföra, behålla eller återställa.
När kod är lätt att producera blir den knappa färdigheten att välja vad som ska existera och säkerställa att det är korrekt. Det gamla rådet att "anställ bra programmerare" gäller fortfarande, men jobbet skiftar. Du anställer inte någon för att skriva snabbare. Du anställer någon för att bedöma, förfina och försvara produkten.
De mest värdefulla personerna i AI-assisterad utveckling delar ofta fyra egenskaper: omdöme (vad som är viktigt), smak (hur bra ser det ut), felsökningsförmåga (hitta verklig orsak) och kommunikation (göra kompromisser tydliga). De kan ta en AI-skriven funktion som "nästan fungerar" och göra den till något du kan lita på.
Istället för att be om en perfekt lösning från start, ge kandidater ett AI-genererat pull request (eller en inklistrad diff) med några realistiska problem: otydliga namn, ett dolt kantfall, saknade tester och ett litet säkerhetsfel.
Be dem förklara vad koden försöker göra i vanligt språk, hitta de mest riskfyllda delarna, föreslå åtgärder och lägga till (eller skissera) tester som skulle fånga regressioner. Om du vill ha en stark signal, be också hur de skulle ändra instruktionerna så nästa AI-försök blir bättre.
Det visar hur de tänker under verkliga förhållanden: ofullständig kod, begränsad tid och behovet att prioritera.
AI låter ofta säker. Bra anställda är bekväma med att säga nej. De kan säga nej till en funktion som ökar komplexiteten, nej till en ändring som försvagar säkerheten och nej till att deploya utan bevis.
En konkret signal är hur de svarar på "Skulle du merga detta?" Starka kandidater svarar inte med en magkänsla. De ger ett beslut och en kort lista över nödvändiga ändringar.
Exempel: du ber om en "snabb" access-control-uppdatering och AI föreslår att strö ut kontroller i handlers. En stark kandidat avvisar det tillvägagångssättet och föreslår ett tydligt auktoriseringslager plus tester för admin- och icke-adminvägar.
Till sist, bygg delade standarder så teamet redigerar AI-utdata på samma sätt. Håll det enkelt: en definition of done, konsekventa granskningsförväntningar och en testbaslinje.
När AI kan generera mycket kod på minuter är det frestande att hoppa över tänkandet och bara iterera. Det funkar för demoer. Det fallerar när du behöver korrekthet, förutsägbarhet och färre överraskningar.
En bra prompt är oftast en kort spec i förklädnad. Innan du ber om kod, omvandla det vaga målet till några acceptanskriterier och uttryckliga icke-mål. Det hindrar AI (och ditt team) från att tyst expandera scope.
Håll specen liten men specifik. Du skriver inte en roman. Du sätter gränser för:
Definiera "klart" innan generering, inte efter. "Klart" bör vara mer än "det kompilerar" eller "UI:t ser rätt ut." Inkludera testförväntningar, bakåtkompatibilitet och vad som övervakas efter release.
Exempel: du vill "lägga till lösenordsåterställning." En tydligare spec kan säga: användare begär återställning via e-post; länkar går ut efter 15 minuter; samma meddelande visas oavsett om e-posten finns; rate limit per IP; logga försök utan att spara tokens i klartext. Icke-mål: ingen redesign av inloggningssidan. Nu har din prompt skyddsräcken och granskningar blir enklare.
Håll en lätt change log över beslut. Ett stycke per beslut räcker. Notera varför du valde ett tillvägagångssätt och varför du avvisade alternativ. När någon frågar "varför är det så här?" två veckor senare har du ett svar.
Den största förändringen med AI är att producera kod är enkelt. Det svåra är att bestämma vad koden ska göra och bevisa att den gör det.
Börja med att skriva målet och begränsningarna i vanligt språk. Ta med vad som aldrig får hända, vad som kan vara långsamt och vad som är utanför scope. En bra begränsning är testbar: "Ingen användare ska se en annan användares data" eller "Totalsummor måste stämma med finansexporten till öret."
Innan du ber om kod, be om en enkel design och avvägningar. Du vill att AI ska visa sitt resonemang i en form du kan bedöma: vad det kommer lagra, vad det validerar och vad det loggar. Om det föreslår något smart, tryck tillbaka och begär den enklaste versionen som fortfarande uppfyller begränsningarna.
En upprepbar loop kan se ut så här:
Här är ett litet scenario: du lägger till "refund status" på en order-skärm. AI kan generera UI snabbt, men korrektheten bor i kantfallen. Vad händer vid delvis återbetalning? Vad händer om betalningsleverantören försöker om och om igen via webhook? Skriv de fallen först, implementera en skiva (databasfält + validering) och verifiera med tester innan du går vidare.
Om du använder Koder.ai passar funktioner som planeringsläge, snapshots och rollback naturligt in i denna loop: planera först, generera i skivor och spara en säker återställningspunkt för varje meningsfull ändring.
När kodgenerering är snabb är det lätt att se kod som arbetsprodukten. Det är den inte. Arbetsprodukten är beteende: appen gör rätt även när saker går fel.
AI låter ofta säker, även när den gissar. Felet är att hoppa över tråkiga steg: köra tester, kontrollera kantfall och validera verkliga indata.
En enkel vana hjälper: innan du accepterar en ändring, fråga "Hur vet vi att det här är korrekt?" Om svaret är "det ser rätt ut" spelar du högst sannolikt på chans.
AI gillar att lägga till extras: caching, retryer, fler inställningar, fler endpoints, ett finare UI. Vissa idéer är bra, men de ökar risken. Många buggar kommer från "trevligt att ha"-funktioner som ingen bad om.
Håll en hård gräns: lös problemet du satte upp, och sluta sedan. Om ett förslag är värdefullt, fånga det som en separat uppgift med egna tester.
En stor AI-genererad commit kan dölja ett dussin orelaterade beslut. Granskning blir en gummistämpel för att ingen kan hålla allt i huvudet.
Behandla chattutdata som ett utkast. Dela upp det i små ändringar du kan läsa, köra och återställa. Snapshots och rollback hjälper bara om du tar dem vid vettiga tidpunkter.
Några enkla begränsningar förebygger det mesta: en feature per change set, en migration per change set, en riskfylld area åt gången (auth, betalningar, dataradering), tester uppdaterade i samma ändring och en klar "hur verifiera"-notis.
AI kan reproducera mönster från träningen eller föreslå beroenden du inte förstår. Även om licensen är ok är den större risken säkerhet: hårdkodade hemligheter, svag tokenhantering eller osäkra fil- och query-operationer.
Om du inte kan förklara vad ett kodstycke gör, skicka inte det i produktion. Be om en enklare version eller skriv om det själv.
Många "det fungerade på min maskin"-buggar är egentligen data- och skala-problem. AI kan skapa schemabytanden utan att tänka på befintliga rader, stora tabeller eller driftstopp.
Ett realistiskt exempel: modellen lägger till en ny NOT NULL-kolumn i en PostgreSQL-tabell och backfyllar i en långsam loop. I produktion kan det låsa tabellen och bryta appen. Tänk alltid på vad som händer med en miljon rader, ett långsamt nätverk eller ett misslyckat deploy mitt i processen.
Föreställ dig en liten intern begäranstracker: folk skickar in förfrågningar, chefer godkänner eller avvisar och ekonomi markerar som betalda. Det låter enkelt, och med AI-hjälp kan du generera skärmar och endpoints snabbt. Det som bromsar dig är samma gamla sanning: reglerna, inte skrivandet.
Börja med att skriva ner det minsta som måste vara korrekt. Om du inte kan förklara det med vanligt språk kan du inte testa det.
En tajt första-version definition ser ofta ut så här: fält (title, requester, department, amount, reason, status, timestamps); roller (requester, approver, finance, admin); statusar (draft, submitted, approved, rejected, paid). Beskriv sedan de övergångar som räknas: bara en approver kan gå från submitted till approved eller rejected; bara finance kan gå från approved till paid.
Använd AI i kontrollerad ordning så du kan fånga misstag tidigt:
De mest värdefulla testen är inte "sidan laddar." De är behörighetskontroller och tillståndsövergångar. Bevisa till exempel att en requester inte kan godkänna sin egen förfrågan, en approver inte kan markera något som betalt, avvisade förfrågningar inte kan betalas och (om det är regeln) att belopp inte kan ändras efter inskick.
Det som tar längst tid är att tydliggöra kantfall. Kan en approver ändra sig efter att ha avvisat? Vad händer om två approvers klickar approve samtidigt? Vad gör du om finance behöver delbetala? AI kan generera kod för vilket svar du än väljer, men det kan inte välja åt dig. Korrektheten kommer av att fatta de besluten och sedan tvinga koden att följa dem.
AI kan producera mycket kod snabbt, men sista milen är fortfarande mänskligt arbete: bevisa att det gör vad du menade och att det misslyckas på ett säkert sätt när det inte gör det.
Innan du börjar bocka av, välj den minsta definitionen av "klart" som betyder något. För en liten funktion kan det vara en happy path, två felvägar och en snabb läsbarhetsgenomgång. För betalningar eller auth, höj ribban.
Anta att AI lägger till "bulk invite users" i en admin-skärm. Happy path fungerar, men verklig risk är kantfall: dubblettposter, partiella fel och rate limits. En stabil release-beslut kan vara ett automatiserat test för dubbletter, en manuell kontroll för partiella felmeddelanden och en rollback-plan.
När kod är billig flyttas risken till beslutskvaliteten: vad du bad om, vad du accepterade och vad du skickade. Det snabbaste sättet att göra dessa sanningar lönsamma i AI-assisterat arbete är att lägga in skyddsräcken som hindrar "nästan rätt"-ändringar från att smita igenom.
Börja med en en-sidig spec för nästa funktion. Håll den enkel: vem den är för, vad den ska göra, vad den inte ska göra och några acceptanstester skrivna på vardagsspråk. Dessa acceptanstester blir din ankare när AI föreslår en frestande genväg.
En skyddssats som skalar utan mycket process-överhead:
Prompter är en del av er process nu. Kom överens om en husstil: vilka bibliotek som är tillåtna, hur fel hanteras, vad "klart" betyder och vilka tester som måste passera. Om en prompt inte kan återanvändas av en annan kollega är den troligen för vag.
Om du föredrar ett chatt-först-sätt att bygga webb, backend och mobila appar är Koder.ai (koder.ai) ett exempel på en vibe-coding-plattform där planeringsläge, snapshots och export av källkod kan stödja dessa skyddsräcken. Verktyget kan snabba upp utkast, men det är disciplinen som håller människor ansvariga för korrekthet.
Behandla AI-resultat som ett snabbt utkast, inte en färdig funktion. Börja med 3–5 pass/fail-acceptanskriterier, generera sedan en liten del i taget (en endpoint, en skärm, en migration) och verifiera med tester och feltestsökningar innan du går vidare.
För att tester visar vad koden faktiskt gör. AI kan producera plausibel logik som missar en viktig regel (behörigheter, retryer, kantfall). Tester omvandlar förväntningar till något du kan köra, upprepa och lita på.
Börja med det som skulle skada mest om det gick sönder:
Lägg på mer täckning när de högskadebeteenden är låsta.
Be om den enklaste lösningen med tydliga begränsningar och ta bort extra lager om de inte "betalar hyra". En bra regel: introducera inte en ny abstraktion om den inte tar bort upprepning på 3+ platser eller gör korrektheten enklare att bevisa.
Skriv en kort spec: inputs, outputs, fel, begränsningar och icke-mål. Ta med konkreta exempel (sample requests/responses, kantfall). Definiera sedan “klart” i förväg: vilka tester krävs, hur bakåtkompatibilitet ska bevaras och en snabb notis om hur man verifierar.
Dela upp ändringen så att varje del går att granska på några minuter:
Det här gör granskningen verklig istället för en snabb acceptans.
Lita inte på självsäkerhet—lita på bevis. Kör tester, mata in dåliga inputs och verifiera behörighetsgränser. Leta också efter vanliga AI-fällor: saknade auth-kontroller, osäkra queries, svag tokenhantering och tyst felhantering.
Föredra explicita transitions-endpoints över en generisk "uppdatera vad som helst"-rutt. Exempel: submit, approve, reject, pay istället för en generell update-route. Skriv sedan tester som säkerställer vem som får göra varje transition och vilka som är förbjudna.
Ge kandidater ett AI-genererat diff med verkliga problem: otydliga namn, saknat test, ett kantfall och en liten säkerhetsbrist. Be dem förklara avsikten, hitta de högst riskabla delarna, föreslå åtgärder och skissera vilka tester de skulle lägga till.
Använd verktygsfunktioner för en disciplinerad loop: planera först, generera i små bitar, snapshot innan riskfyllda ändringar och återställ om verifiering misslyckas. I ett chattbaserat verktyg som Koder.ai passar planeringsläge, snapshots och rollback naturligt in i denna process—särskilt när ändringar rör auth, betalningar eller migreringar.