Hoe je plezier in programmeren kunt blijven houden in een wereld van LLM's

Er zijn aanzienlijke en terechte ethische zorgen over de geavanceerde LLM's (Large Language Models) van grote techbedrijven. Deze zijn uitvoerig besproken; ik ben me daarvan bewust en ben het ermee eens, maar dit bericht gaat daar niet over. Zie me asjeblieft niet aan voor een pro-LLM 'techbro'.

Daarnaast: aangezien mensen mijn teksten eerder hebben aangezien voor LLM-gegenereerd, wil ik vermelden dat dit 100% door een mens is geschreven, zonder enige AI-assistentie.

Zielen in de Grote Machine

Er is een geweldig boek met deze titel van Sean Mcmullen dat ik als tiener met plezier heb gelezen. Op het eerste gezicht beschrijft het het tegenovergestelde van onze huidige situatie: een enorme computer waarbij de individuele componenten mensen zijn die samenwerken om één rekenunit te vormen. LLM's daarentegen draaien op eigenlijke computers en doen alsof ze (super-)mensen zijn.

Bij nader inzien liggen het verhaal en de realiteit echter niet zo ver uit elkaar: onze rol in het proces van softwareproductie wordt langzaam gedegradeerd van actoren naar tandwielen in een machine. De 'spec-driven-dystopie' houdt in dat we simpelweg een specificatie aangereikt krijgen, deze in de LLM rammen, en huilen wanneer onze tokens opraken omdat een technofeodale heer besloot er minder uit te delen.

Als Haskell-programmeur geniet ik van het schrijven van Haskell. Ja, ik houd veel van het product dat we op het werk maken en ik houd van wat je kunt doen met mijn open-source bibliotheken, maar ik geniet vooral van het proces van het uitdrukken van mijn gedachten in deze taal. Ik ga ervan uit dat dit voor de meeste van jullie ook geldt, en dat dit in veel andere talen niet het geval is. Dit verklaart waarschijnlijk waarom liefhebbers van verschillende programmeertalen verschillende meningen hebben over hoe hoopvol of duister de LLM-ondersteunde toekomst is.

Wanneer ik code genereer, komt een groot deel van dat plezier in gevaar. Dus: doe het liever niet. Ik wil Haskell-programma's blijven schrijven (in ieder geval de leuke delen) en niet te veel gegenereerde code hoeven te lezen en reviewen. Tegelijkertijd wil ik die tokens inzetten voor zaken die mijn brein niet langzaam doen wegbranden.

Ik wil jullie een manier laten zien om plezier in programmeren te houden en tegelijkertijd matig productiever te worden met LLM's, in plaats van te lijken op iemand die veel productiever is terwijl je alle vreugde verliest.

Als je volledig LLM-onthoudend wilt zijn, is dat ook prima; dan weet je waarschijnlijk al wat je doet. Maar er kunnen redenen zijn waarom je dat niet wilt, bijvoorbeeld omdat je daadwerkelijk een productiviteitswinst moet realiseren, of omdat je niet achtergebleven wilt worden terwijl de rest van je team, je bedrijf of je industrie overstapt op intensief LLM-gebruik.

Blijf zelf code schrijven

Als je de controle over je codebase wilt behouden, moet je zelf code blijven schrijven. Als je alles laat genereren, verandert het in een LLM-woestenij waar alleen jouw coding-agents in kunnen overleven. Je moet dus blijven schrijven, anders gaat je codebase uiteindelijk verloren.

Een andere reden om zelf code te schrijven, is om een goede programmeur te blijven. Vaardigheden kunnen verloren gaan door een gebrek aan oefening. Hier is het risico bijzonder hoog, omdat de drempel om je programmeerwerk op te geven en aan een agent over te dragen erg laag is. Na slechts een paar weken waarin je niet meer zelf codeert en alles aan agents overlaat, zul je merken dat het moeilijk is om weer zelf aan de slag te gaan.

LLM's zijn veel slechter in het produceren van goede, menselijk leesbare code dan wordt geadverteerd. Ze zijn redelijk goed in het produceren van code waar ze later zelf uitsluitend aan werken. Maar je hebt waarschijnlijk al de wanhoop ervaren van het kijken naar een volledig gegenereerd bestand waarin ergens een bug moet zitten, terwijl je als mens niet in staat lijkt deze te vinden omdat het landschap simpelweg te vreemd is.

Hoe behaal je dan productiviteitswinst als je de agents niet het coderen laat doen? Door ze bijna alles anders te laten doen. Vooral het saaie werk dat voor jou een hinderlijk klusje is. Idealiter taken die niet te moeilijk zijn om correct uit te voeren en gemakkelijk te controleren.

Planning

Sinds het begin van de computergeschiedenis worden computers gebruikt als boekhoudinstrument. Gebruik LLM's op die manier. Onder andere is het een administratie-tool die je in natuurlijke taal kunt aanspreken in plaats van via een formele interface. Zet een lang geschreven gesprek tussen domeinexperts om in uitvoerbare todo-lijsten. Test iets, noteer de resultaten en laat de AI deze organiseren in een plan om de defecten te herstellen.

Gebruik tools zoals een todo-app, of nog beter, markdown-bestanden met frontmatter om planningsitems correct bij te houden. LLM's kunnen een enorme context hebben, maar als deze te vol is, kunnen ze stilletjes informatie verliezen.

Laat de AI echter geen cruciale beslissingen nemen. Laat het je om input vragen. Als je de vraag niet begrijpt, is het de fout van de LLM dat hij niet de relevante context heeft gegeven (of je bent uitgeput en hebt een pauze nodig). Als je steeds terugkeert naar dezelfde problemen, stap dan even weg van het scherm en denk er zelf over na; kom pas terug als je een duidelijk beeld hebt van wat je wilt.

Onderzoek doen

Wanneer je een onderzoekstaak aan een agent geeft, is het verleidelijk om toe te kijken hoe hij query's uitvoert en "nadenkt", om een andere agent in een ander project te starten, of om koffie te zetten. Van deze drie is koffie zetten de beste optie. De nóg betere optie is: doe parallel zelf onderzoek met een goede oude zoekmachine. Weet in ieder geval globaal alles wat de agent zal weten.

Laat de AI niet zomaar iets onderzoeken, accepteer de resultaten niet als feiten en plan daar niet vanuit verder. Dit leidt tot gênante technische schulden.

Het doel van een agent die onderzoek doet, is niet dat hij alle relevante kennis aan jou presenteert of een betere beslissing neemt dan jij zou kunnen. Het doel is dat je niet zelf "Let Me Google That For You" hoeft te doen. Je moet het domein dat je modelleert net zo goed begrijpen als de agent, idealiter zelfs beter.

Laat je agents hun onderzoeksresultaten ergens opschrijven, met links naar de gebruikte bronnen. Wanneer de agent later terugkomt met een vreemd voorstel, vraag hem dan wat het onderzoek zegt en welke bron dat bevestigt. In 50% van de gevallen zal de AI zijn eigen fout ontdekken. In de andere 50% lees je het zelf en ben je in staat om zelf een goede beslissing te nemen.

Jij bent de programmeur

Dit is de game changer.

De typische coding-harnesses lokken je in de val van "eerst plannen, dan de agent laten coderen". Weiger dit. Plan samen, maar codeer daarna zelf. Vertel de LLM dat hij je codebase moet onderzoeken, laat hem de huidige todo noemen en alle plekken opzoeken die je moet bewerken, laat hem potentiële valkuilen noemen en herinner hem aan relevante achtergrondinformatie.

Ik werk met deze workflow en het is erg leuk. Ik geniet van mijn werk, soms zelfs meer dan vóór de komst van LLM's. Ik heb altijd een duidelijke todo, ik hoef me geen zorgen te maken over het algemene plan en ik kan me focussen. Ik ben snel klaar met de todo omdat deze goed is gepland. Het is als 'agile', maar dan zonder alle irritante processen.

Zorg dat de agents zich aanpassen aan jouw manier van werken, niet andersom. Misschien ben je een ervaren programmeur die al weet hoe hij het beste kan werken. Laat de agents al het incidentele werk om je heen doen waar je minder van geniet.

Deze workflow heeft meerdere voordelen:

  • Je blijft doen waar je van geniet. Als je van programmeren houdt, doe het dan.
  • Je weet altijd in welke staat je codebase verkeert. Ben je verrast door vreemde gegenereerde zaken tijdens 'vibe coding' sessies? Heb je LLM-slop moeten herschrijven? Ben je het overzicht verloren in een sessie? Op deze manier hoeft dat nooit meer te gebeuren.
  • Je ontdekt een slecht plan vroegtijdig. Een agent-coder zou kunnen doorgaan met iets wat jij direct herkent als een slecht idee.
  • Je blijft je vaardigheden aanscherpen. Je blijft een goede programmeur, of verbetert zelfs.

Zeldzame gevallen waarin een coding agent nuttig is

Ideaal voor opschoning, kleine taken, routineklusjes en refactorings met een laag risico. Heb je FIXME's in je code laten staan (misschien expres om tijd en energie te besparen)? Heb je de drie interessante gevallen geschreven en de zeven vergelijkbare saaie gevallen overgeslagen? Heb je een reorganisatie van een module in gedachten en wil je deze benchmarken? Moet een niet-onderhouden bibliotheek worden vervangen door een betere? Dat zijn valide use-cases. Iets ingewikkelds vanaf de grond opbouwen is dat waarschijnlijk niet.

Soms is de tijd op maar wil je dat iets af is, en zijn de resterende todo's in je plan overduidelijk risicovrij. Het is oké om tegen je supervisor-agent te zeggen: "Ik ben afwezig, maak dit af". Met een beetje geluk kom je de volgende ochtend terug bij een voltooide feature. Maar het is belangrijk om het meeste codeerwerk zelf te doen.

Er zijn hier enkele valkuilen:

  • Stel, je hebt die drie interessante gevallen geschreven en vertelt de agent de overige zeven af te maken omdat het overduidelijke aanpassingen zijn. De kans is groot dat je eigenlijk een abstractie moet toepassen. Misschien gebruik je onbedoeld een 'lens' of een andere 'optic'? Misschien is dit een instantie van een populaire type class zoals Traversable? LLM's staan erom bekend dit niet te herkennen en in plaats daarvan enorme stukken code te kopiëren. Jij als mens streeft naar beter leesbare en redelijke code.
  • Hetzelfde geldt voor het "noemen van potentiële valkuilen". Ja, LLM's kunnen erg goed zijn in het doorlopen van de hele callchain om te zorgen dat alle plekken die je moet aanpassen in de todo staan. Maar in plaats van te vertrouwen op de AI om al deze koppelingen te vinden, zou je moeten overwegen of je codebase slecht is georganiseerd, waardoor je in de eerste plaats een LLM nodig hebt voor code-onderzoek.

De reviewcyclus

Je herinnert je misschien hoe AI-gegenereerde afbeeldingen plotseling veel realistischer werden door de komst van generative adversarial networks (GAN's). Kort gezegd heb je één model (de "generator") die een afbeelding maakt, en een ander (de "discriminator") die vertelt hoe goed dit is gelukt. Samen kunnen ze veel betere resultaten produceren dan de generator alleen.

Als je dit idee toepast op LLM-ondersteund coderen, krijg je een geautomatiseerde reviewcyclus. Accepteer en lees geen enkel artefact dat door een LLM is geproduceerd zonder een geautomatiseerde reviewcyclus. Dit geldt direct voor code (in die gevallen waarin je het toch laat genereren), maar in het bijzonder ook voor planning. Wanneer een agent iets codeert, is de klus niet klaar bij de overdracht; de klus is pas gedaan (en geschikt voor menselijke ogen) wanneer een reviewer-agent geen bevindingen meer heeft.

Hetzelfde geldt voor plannen. Het is erg vermoeiend om logische gaten in een plan te spotten (bijv. een functie refactoren in todo 2 die pas gepland staat om geschreven te worden in todo 7), dus voeg een review-agent toe die dat doet.

Ik heb het verrassend nuttig gevonden om mijn eigen code te laten reviewen. Soms wijst het op kleine details of dringt het aan op uitgebreidere documentatie (Haddocks), maar vaak genoeg vindt het een echte bug of een weglating, waardoor ik gefocust blijf op de eigenlijke todo. Ik raad aan om reviewcycli aan je eigen werk toe te voegen, al begrijp ik volledig als je liever geen review van een LLM over je code leest. Een manier om dit te omzeilen is door de AI te vertellen om kleine resterende bevindingen zelf te herstellen.

De grensverleggende modellen (The Frontier)

Je benut de mogelijkheden van de meest geavanceerde 'frontier models' volledig onderbezet.

Ja, dat is een logisch gevolg van mijn standpunt. Maar er zijn meerdere redenen waarom het een slecht idee is om te vertrouwen op de functies van frontier-modellen:

  1. Milieukosten. (Hoewel dit bericht dit onderwerp niet zou raken.) Frontier-modellen verbruiken een enorme hoeveelheid energie. Dit is tot op zekere hoogte een gissing, aangezien LLM-bedrijven niet erg transparant zijn over hoe hun gadgets werken.
  2. Vertrouwen. Het is moeilijk om vertrouwen op te bouwen in iets dat pretendeert veel slimmer te zijn dan jijzelf. Uiteindelijk ben jij verantwoordelijk voor de code die je produceert, niet je machine. Iemand anders de schuld geven van je code is iets wat slechte managers doen met hun werknemers; het is belachelijk om dat met een machine te doen. Gebruik LLM's dus op een manier waarop je verantwoordelijkheid kunt nemen voor de resultaten. Dit werkt alleen als je jezelf een integraal onderdeel van het proces maakt.
  3. Tokens. De meest geavanceerde modellen verbruiken de meeste tokens, dus er is geen zekerheid of je je taken in een bepaalde sessie ermee kunt voltooien. Alles wat je met een kleiner model kunt doen, is een veiligere keuze.
  4. Onafhankelijkheid. Wanneer je workflow geen frontier-modellen nodig heeft, heb je de kans om deze uiteindelijk te vervangen door open weight of open-source modellen, waardoor je niet langer afhankelijk bent van technofeodale heren.

Uiteindelijk doe je complex werk. Op sommige aspecten kunnen LLM's hetzelfde of misschien zelfs iets beter presteren. Maar dat is bij lange na niet genoeg om voor hen te buigen, gezien al hun nadelen. LLM's zouden vele malen beter moeten zijn dan een menselijke ontwikkelaar, minder middelen moeten verbruiken, betrouwbaarder moeten zijn in complexe real-world situaties, minstens zo goed uitgelijnd (aligned) moeten zijn en op een bepaalde manier verantwoording moeten kunnen afleggen voor hun resultaten, om menselijke ontwikkelaars in hun kernactiviteit te kunnen vervangen.

Geen tokens meer over?

Misschien heb je ervaren dat je werk tot stilstand kwam omdat je tokens op waren. Dat is irritant. Je workflow is nu gebouwd rond een tool waar je plotseling geen toegang meer toe hebt. In het extreme geval kun je helemaal niets meer doen.

Als dit een paar keer gebeurt, heb je misschien het gevoel gehad dat je bent verraden. En dat klopt. Hoeveel tokens je hebt in een bepaalde sessie bij een specifiek abonnement is een ondoorzichtig getal naar het goeddunken van een grote techno-feodale heer. Het is niet zoals een product dat je koopt op een eerlijke markt en vervolgens op een planbare manier gebruikt.

Je moet stoppen met de uitputting van je tokens te zien als "te weinig hebben gekocht", en het gaan behandelen als wat het is: een storing in de dienstverlening (service outage). Je LLM-bedrijf heeft je de belofte verkocht dat je de LLM kon gebruiken, en ze houden zich daar niet aan. Het maximum aantal tokens in je sessie kan veranderen zonder dat je het weet of erop invloed kunt uitoefenen, dus je kunt er eigenlijk niet op plannen.

Natuurlijk is besparen op tokens essentieel. Evalueer je agent-setups, je gebruik, je context-groottes en je vaardigheden om tokens te besparen. Maar zelfs als je dat doet, en zelfs als je een duurder abonnement hebt, is het mogelijk niet genoeg.

In plaats van het als "jouw fout" te zien wanneer je tokens op zijn, zie het als een technisch defect waar je op voorbereid moet zijn. Wie veel in een trein of vliegtuig heeft gewerkt, weet dat je voorbereid moet zijn op het feit dat je niet altijd internet hebt. Download en cache grote assets vooraf. Zorg dat je altijd werk hebt dat je offline kunt doen.

Voor LLM-ondersteund werk betekent dit dat je de AI tastbare artefacten moet laten produceren voor alles waar je aan werkt. Het belangrijkste: als je je aanpast aan de workflow voor menselijke programmeurs die ik heb geschetst, zorg er dan voor dat je altijd een geplande lijst met todo's hebt waar je aan kunt werken. Geniet van het wegwerken ervan, en wanneer je agent weer beschikbaar is, laat hem dan de schoonmaak doen.

LLM-wartaal

Tekst geproduceerd door een LLM verschilt van menselijke tekst. Het wordt vooral slecht wanneer de LLM eigenlijk niet weet waar hij over praat. Behandel LLM-wartaal als potentieel schadelijk voor je psychische gezondheid. Consumeer er niet te veel van. Blijf met mensen praten over je code, vooral over grotere visies en interessante aspecten. Lees LLM-artefacten pas nadat geautomatiseerde review-agents de scherpe randjes eraf hebben gehaald.

Wanneer je hoofd begint te tollen, neem dan een pauze. Ja, zelfs als er momenteel geen agent op de achtergrond draait en "waarde produceert". Je mentale gezondheid is belangrijker dan je werkoutput.

Je medemensen

Programmeren is grotendeels een sociale onderneming. In een bedrijf of een open-source project sturen we elkaar pull requests (PR's), schrijven we issues en commit-berichten. Dit is een vorm van communicatie. Zelfs als je de enige bent in je project, schrijft je vroegere zelf issues, commit-berichten en PR's voor je toekomstige zelf. Communicatie tussen mensen is de pijler van softwareontwikkeling.

Zorg dat je mensen altijd "mens-eerst" benadert. Stuur niet een volledig gegenereerde PR naar iemand. Ik heb dit per ongeluk gedaan; de ontvanger was terecht klaar mee. Ik zorg ervoor dat ik deze fout niet herhaal.

Agents zullen je graag aanbieden om een volledige PR-body te schrijven in grammaticaal correcte taal, met alle details erin. Dit is geen communicatie. Het is een tool-output. Behandel dergelijke teksten hetzelfde als benchmarkcijfers of debug-traces: voeg ze toe aan je handgeschreven PR-body, eventueel in een <details> blok, zodat mensen zelf kunnen beslissen of ze het willen lezen of niet. Je zult merken dat ze dat vaker niet doen.

Mijn reis

Met deze aanpak ben ik productiever dan zonder LLM-assistentie. Het is moeilijk om precies te zeggen, misschien twee keer zo snel? Dit is minder dan veel 'vibe coders' zullen claimen, maar dat is oké. Ik zie mezelf als een tuinman die milde, organische meststoffen gebruikt, terwijl vibe coders hun velden overspoelen met industriële chemicaliën. Ik geloof dat mijn manier op de lange termijn duurzamer is.

Ik hou van het programmeren in Haskell, en er mijn brood mee verdienen is mijn droombaan. De afgelopen maand was ik bang dat deze droom verleden tijd was. Maar alles wat ik hier heb beschreven, is wat ik heb geleerd om deze activiteit leuk te houden. Het lijkt te werken.