CodePipeline and S3

Using CodePipeline and S3 to protect your software deploys in AWS

Det finns en viss stolthet hos utvecklare i att själv kämpa sig igenom en funktion, sitta uppe till klockan två på natten, felsöka något obegripligt problem med en SQLite-migrering och lägga upp en commit klockan tre med ett meddelande som ”fix: hopefully”. Förr trodde jag att det var så riktig utveckling såg ut.

Sedan byggde jag en AFK-factory och såg min kodbas växa - bokstavligen medan jag kokade te.

Här beskriver jag arbetsflödet jag använde för att bygga en mobil app för varvtidtagning och telemetrianalys - från det första specifikationsdokumentet till fungerande kod, nästan helt genom autonoma agenter, strukturerade tester och en metod som kallas vertikal uppdelning. Det är ingen magi. Det är ingenjörskonst. Men visst - det känns lite som fusk.

Steg noll: Planera på ett tydligt sätt och gör det sedan genomförbart

Innan jag skrev en enda rad kod ägnade jag tid åt att i ChatGPT utarbeta en ordentlig produktspecifikation. Inte någon vag önskelista, utan ett faktiskt strukturerat dokument: arkitekturbeslut, datamodeller, detaljerade beskrivningar screen-by-screen, API-beteende, specialfall. Den typ av dokument som man skulle ge till en ny teammedlem och förvänta sig att denne ska förstå systemet utifrån, för att sedan se smärtan i deras ögon när de inser att dokumentet är 28 sidor långt.

Detta är viktigt eftersom agenter inte är tankeläsare. En LLM som får uppdraget ”bygg en varvtidtagare åt mig” kommer att producera något. Det kanske till och med kompileras. Men det kommer inte att producera din produkt - den med din specifika datamodell, dina specifika UX-begränsningar, dina specifika protokollsärdrag (i det här fallet: att tolka binära telemetriramar från en datalogger via TCP, vilket innebär GPS kodad som ECEF-koordinater och ett keepalive-kommando som bokstavligen bara är ”kkk\x01”).

PDF-dokumentet blev källan till sanningen. Varje gång ett nytt ärende skapades för Sandcastle-agenten att implementera hade den det dokumentet som kontext. Agenten gissade inte på avsikten utan utförde en specifikation. Vad är Sandcastle? Vi kommer snart till det.

Lärdom: Kvaliteten på din plan är en kraftmultiplikator för allt nedströms. Om du är vag mot en agent får du vag kod. Om du är precis får du precis kod. Detta skiljer sig inte från att leda människor, men agenter protesterar inte eller ber om förtydliganden om du inte uttryckligen uppmanar dem att göra det. Så ansvaret för precisionen ligger på dig.

The Sandcastle: En autonom issue factory

Sandcastle är en autonom implementeringspipeline. Arbetsflödet ser ut så här:

• Ett GitHub-ärende skapas där en funktion eller en buggfix beskrivs – med tillräckligt mycket sammanhang för att avsikten ska vara entydig.

npm run sandcastle startar en Docker-miljö i en sandlåda.

• Agenten läser ärendet, läser kodbasen, planerar en implementering, skriver koden och öppnar en pull-request.

• Pull-requesten granskas av en granskningsagent och mergas.

Resultatet blir att varje ärende blir en separat enhet av autonomt arbete. Du kan lägga fem ärenden i kö, gå ut och springa en runda, komma tillbaka och ha fem ärenden kodade, testade, granskade och mergade. Det är din AFK-factory.

Är koden perfekt? Nej. Behöver den granskas? Absolut. Men här är grejen - granskningslagret är betydligt billigare än implementeringslagret. Att läsa en diff och avgöra om den är korrekt kräver en bråkdel av den ansträngning som krävs för att skriva koden från grunden. Du går från att vara författare till att vara redaktör, och det är en värdefull förändring.

Det som gör att Sandcastle fungerar bra här är kombinationen av en strikt specifikation, tydliga begränsningar för teknikstacken (strikt TypeScript, inga valfria bibliotek) och - inte minst - tester. Vilket tar oss vidare till den mer intressanta delen.

TDD är inte vad du tror att det är (om du gör det på fel sätt)

De flesta som påstår sig använda TDD gör i själva verket något jag skulle kalla ”test-decorated development”: de skriver koden, den fungerar, och sedan skriver de tester för att bekräfta att den fungerar. Detta fungerar bra som ett sätt att skapa en falsk trygghet. Det är inte TDD.

Riktig TDD går till på motsatt sätt: man skriver först ett test som misslyckas, och sedan skriver man kod för att få det att godkännas. Det misslyckade testet tvingar dig att fundera över vad du egentligen vill att koden ska göra – dess publika gränssnitt, dess beteende, dess gränsfall – innan du har bestämt dig för några implementeringsdetaljer.

Men det finns ett mer subtilt misstag som även äkta tillämpare av TDD gör, och det är skillnaden mellan horisontell uppdelning och vertikal uppdelning.

Horizontal kontra Vertical är en distinktion som faktiskt spelar roll

Horizontal slicing innebär att man skriver alla tester för ett lager innan man implementerar det. Skriv alla modelltester. Skriv sedan alla servicetester. Skriv sedan alla kontrollertester. Koppla sedan ihop dem. Det låter organiserat. Det ger skräp.

Här är anledningen: när du skriver tester för en komponent isolerat innan du vet hur de andra komponenterna faktiskt kommer att bete sig, gör du antaganden. Dessa antaganden bakas in i låtsasmodeller. Låtsasmodellerna ljuger. Testerna godkänns. Integrationen är trasig. Du har spenderat en vecka på en testpyramid som inte speglar verkligheten.

Vertical slicing innebär att man tar ett beteende som är synligt för användaren och implementerar hela stacken för att få det att fungera - ett test i taget, från det publika gränssnittet och inåt. Inte ”testa all parsningslogik” utan ”testa att när en enhet ansluter och skickar en telemetriram, registrerar sessionen ett varv.” Ett beteende. Hela stacken. Fungerande och testat.

Det konkreta resultatet är att du alltid har fungerande programvara. Efter den första vertical slicen har du en funktion som fungerar från början till slut. Efter den andra har du två. Du hamnar aldrig i en situation där du har ett vackert testat datalager som inte går att använda eftersom tjänstelagret inte är klart ännu.

För agentdriven utveckling är vertical slicing inte valfritt – det är bärande. När du ger en agent ett ärende måste denne producera en fungerande, testad vertical slice. Om instruktionen är ”implementera sessionsparsningslagret” får du en hög med kod som kanske eller kanske inte integreras korrekt. Om instruktionen är ”implementera: när en session synkroniseras från en enhet ska den kunna sökas fram från sessionsskärmen” får du kod som antingen fungerar från början till slut eller misslyckas i ett integrationstest som talar om exakt varför.

Testerna blir ett avtal mellan problembeskrivningen och implementeringen. Om agentens kod klarar testerna är beteendet korrekt. Om inte är testresultatet återkopplingsslingan.

Hantera agenter som en tech-lead, inte som en barnvakt

Här krävs ett nytt sätt att tänka. När man arbetar med mänskliga utvecklare har man samtal, kodgranskningar och ett förtroende som byggs upp över tid. När man arbetar med agenter har man:

Specifikationen (det fasta sammanhanget)

Ärendet (den specifika uppgiften)

Testerna (acceptanskriterierna)

Pull-requesten (leveransen)

Din uppgift som person i denna process är inte att skriva kod. Det är att se till att dessa fyra saker hänger ihop. Om en agent producerar dålig kod är diagnosen nästan alltid en av följande: specifikationen var tvetydig, problemet var otillräckligt specificerat eller så fanns det inga tester för att upptäcka avvikelsen.

Detta stämmer ganska bra överens med att leda juniora utvecklare, förutom att agenterna är snabbare, aldrig trötta, inte behöver kontext om ”kultur” och inte heller kommer att säga till dig när problembeskrivningen är motsägelsefull (om du inte bygger in den återkopplingsslingan). Felmönstren är olika men styrningen är likadan: skräp in, skräp ut.

En sak som hjälper enormt är att hålla problemen små och fristående. Ett problem som lyder ”implementera enhetsanslutning och datasynkronisering samt sessionsskärmen” kommer att resultera i en omfattande, svårgranskad PR som troligen innehåller subtila interaktionsfel. Tre små problem ger tre granskningsbara PR:er som sammanställs på ett överskådligt sätt.

The Toolchain, för den nyfikne

Appen i sig är ett React Native-projekt med ett Turborepo-monorepo, TypeScript i strikt läge genomgående, Drizzle ORM över SQLite, NativeWind för styling och React Query för datasynkronisering. Testerna körs med Vitest. Sandcastle-agenten kör Claude.

Valet av teknikstack är inte godtyckligt - det är en del av det som gör agentdriven utveckling hanterbar. TypeScript strict mode innebär att typsystemet fångar upp hela klasser av integrationsfel före körning. En välstrukturerad ORM innebär att agenten kan resonera kring datamodeller utan att läsa rå SQL. Ett konsekvent stylingsystem innebär att UI-komponenter inte avviker över tid.

Poängen är: dina verktyg är inte separata från ditt arbetsflöde. De formar vad agenter kan och inte kan göra på ett tillförlitligt sätt. Ett projekt utan typsäkerhet, utan tester och utan tydligt arkitekturmönster är svårt att utöka manuellt. Med en agent är det snudd på omöjligt.

Vad detta arbetsflöde inte är

Det här är inte ”vibe coding”. ”Vibe coding” innebär ”skriv en inloggningsskärm åt mig” -> godkänn vad som än kommer ut -> lansera det. Det resulterar i demoversioner, inte färdiga produkter.

Det här arbetsflödet liknar snarare en mycket bestämd tech lead som skriver detaljerade specifikationer, testar varje PR och har ett team av extremt snabba utvecklare som aldrig sover. Det mänskliga omdömet koncentreras till specifikations- och granskningsfaserna medan det tidskrävande mekaniska arbetet sker autonomt.

Det ersätter inte heller förståelsen för din kodbas. Du måste veta tillräckligt för att skriva en bra specifikation, utvärdera en PR och upptäcka när en agent har tagit en genväg som kommer att orsaka problem senare. Loopen kräver fortfarande en människa med domänkunskap. Det är bara det att människan arbetar på en högre abstraktionsnivå.

Slutsats: Den här kodfabriken är i full drift medan du sover

Kombinationen av en välskriven specifikation, självständig problembaserad implementering, vertikal TDD och en enhetlig toolchain ger upphov till något som nästan känns orättvist: en kodbas som växer stegvis, alltid är testad och som kräver att du ägnar större delen av din tid åt att tänka istället för att skriva.

Kräver det mer förberedelser i början? Ja. Tar det tid att skriva specifikationsdokumentet? Absolut. Men den sammantagna vinsten på den investeringen visar sig varje gång du lägger in en issue, startar en sandcastle-körning, går och gör något annat och kommer tillbaka till en PR som fungerar.

Det är AFK-fabriken. Varsågod!

Författaren, Marcus Wendel, iär senior mjukvaruutvecklare på adesso Sweden – med en tydlig preferens för all modern teknik och särskilt AI-native och AI-assisterad utveckling.