Mensen van ACM: Russ Cox
Hoewel Go bekend staat om zijn eenvoud, snelheid en schaalbaarheid, heeft u aangegeven dat het hoofddoel bij het creëren van de taal was om uit te vinden hoe men effectief multicore netwerksystemen kan programmeren. Waarom was dit destijds een belangrijke uitdaging? En hoe is de ontwikkeling van cloud computing samengevallen met de groei van Go?
Het oorspronkelijke doel van Go was om een betere programmeeromgeving te bieden voor het soort software engineering dat rond 2007 bij Google werd gedaan. Die software bestond uit een enorme hoeveelheid code, een groot aantal engineers die samenwerkten en grote aantallen netwerkcomputers, elk met veel cores. Al deze vormen van schaalbaarheid werden slecht ondersteund door bestaande omgevingen, en we wilden iets beters bouwen om ons eigen werk te ondersteunen. Door vanaf nul te beginnen, konden we ook andere fundamenten heroverwegen, zoals afhankelijkheidsbeheer (dependency management), en kernaspecten van de implementatie herzien, zoals low-latency garbage collection.
Het is geen toeval dat Go goed is voor cloud computing, want dat is waar het voor is ontworpen. William Gibson zei ooit: "The future is here. It’s just not very evenly distributed." In 2007 bestond de toekomst van cloud computing al bij Google, en we hebben Go ontworpen om daar deel van uit te maken. Naarmate de toekomst van de cloud breder verspreid raakte, gebeurde dat ook met Go.
Kunt u enkele onverwachte inzichten delen uit uw tien jaar leidinggeven aan Go?
In software engineering lijken de meest fundamentele waarheden niet te veranderen. De context eromheen verandert wel, maar het lijkt erop dat we vooral veel tijd besteden aan het herinneren of herontdekken van zaken die we waren vergeten. Hier zijn er drie:
1. Eenvoud is de beste strategie voor schaalbaarheid
Wanneer engineers nadenken over hoe ze een complex probleem kunnen oplossen, is het voor de hand liggende antwoord het ontwerpen van een complexe oplossing—één met goede asymptotiek maar hoge vaste overheads. Als je in plaats daarvan zoekt naar manieren om het probleem te vereenvoudigen, leidt dat vaak tot eenvoudige oplossingen met lage overheads die net zo goed werken. Eenvoudigere oplossingen schalen beter en zijn gemakkelijker te onderhouden.
Een voorbeeld: build-systemen voor C++ en Java hebben veel problemen door cyclische afhankelijkheden tussen bibliotheken. Cycli creëren grote eenheden die in één keer verwerkt moeten worden, en er is veel werk gestoken in complexe oplossingen om dat te schalen. Voor Go hebben we cycli verboden. Als A B importeert, dan kan B A niet importeren, zelfs niet indirect. Door de package-graaf acyclisch te maken, worden builds en analyse-tools sneller en is het geheel gemakkelijker te begrijpen. De restrictie is soms irritant, maar de voordelen wegen ruimschoots op tegen het ongemak.
2. Software engineering is wat er gebeurt met programmeren wanneer je tijd en andere mensen toevoegt
Programmeren is wanneer je een probleem hebt om op te lossen, code schrijft, deze uitvoert, de bugs die je vindt oplost en klaar bent. Programmeren is op zichzelf al moeilijk. Maar wat als die code dag na dag, jarenlang moet blijven werken, zelfs terwijl je deze bijwerkt? Wat als veel andere programmeurs ook aan de code moeten werken? Dan heb je versiebeheersystemen, bugtrackers, tests, modulegrenzen, design patterns en meer nodig. Al dat komt kijken omdat je programmeren is veranderd in software engineering. Scholen kunnen programmeren onderwijzen, maar ze hebben niet de tijdshorizon om echte software engineering te doceren. Dat is iets wat je alleen door ervaring leert.
3. Tests zijn meer voor morgen dan voor vandaag
Tests die samen met onze code worden ingeleverd, zijn niet bedoeld om te bewijzen dat de code vandaag correct is. Ze zijn bedoeld om te kunnen controleren of het morgen, de dag daarna en volgend jaar nog steeds werkt, zelfs terwijl de code evolueert. Als we er alleen om gaven dat de code vandaag werkte, zouden we het handmatig kunnen testen tot we tevreden waren. En elke keer dat we die code opnieuw zouden bezoeken, zouden we heel zorgvuldig kunnen nadenken over de wijzigingen en handmatig testen wat beïnvloed zou kunnen worden. Deze strategie werkt, maar schaalt niet.
Als je geautomatiseerde tests hebt die je op elk moment opnieuw kunt draaien, en als die tests alle belangrijke gedragingen van je code controleren, dan kun je garanderen dat die gedragingen nooit breken, simpelweg door de tests uit te voeren! Je kunt een nieuwe compiler of een nieuwe versie van een afhankelijke bibliotheek evalueren. Je kunt gecompliceerde code refactoren of herschrijven. Je kunt gemakkelijker wijzigingen accepteren van engineers (of coding agents) die onbekend zijn met het systeem. Bijna alles aan software engineering wordt gemakkelijker in verhouding tot hoe goed je tests zijn.
Hoewel sommigen hebben voorspeld dat AI een fundamenteel nieuw paradigma in softwareontwikkeling zal inluiden, merkte u op dat "continuüm" een beter woord zou zijn om de impact van AI te beschrijven. Hoe ziet u deze komende transformatie voor zich?
Ik heb in een ACM ByteCast-aflevering gezegd dat als je de computers van nu vergelijkt met die die ik als kind in de jaren 80 had, ze in bijna elk opzicht kwalitatief verschillend zijn, maar dat die verandering stap voor stap is gebeurd. Ik verwacht dat de impact van AI zal zijn zoals de impact van alle andere veranderingen in computing: veel kleine stappen die over tijd optellen tot iets dat kwalitatief anders is, niet de enkele onbegrijpelijke sprong waar sommige mensen over hypen. Dat is een belangrijk onderscheid, want het betekent dat we, terwijl we die stappen zetten, nog tijd hebben om te beslissen waar AI goed voor is en waar niet, en hoe we het het beste kunnen gebruiken, zowel als software engineers als als samenleving.
Voor softwareontwikkeling geloof ik niet dat AI de fundamenten van software engineering ongeldig maakt. Integendeel, ik denk dat de fundamenten van software engineering ons kunnen helpen beter te begrijpen waar AI goed voor zal zijn en waar niet.
Een voorbeeld is het artikel uit 1985 van Peter Naur, "Programming as Theory Building". Naur spreekt over het belang van een coherente visie of theorie over hoe eisen uit de echte wereld worden vertaald naar het ontwerp en de structuur van het programma. Hij stelt dat het gebruik van een consistente theorie over een langere periode ervoor zorgt dat programma's eenvoudig blijven. Hij betoogt ook dat dit soort theorie nooit volledig kan worden opgeschreven of gecommuniceerd, omdat het belangrijkste aspect is hoe het omgaat met onvoorziene nieuwe eisen.
Peter Naur stelt dat de onderliggende theorie fundamenteel is voor het onderhoud van het programma:
"De dood van een programma vindt plaats wanneer het programmeursteam dat de theorie bezit, wordt ontbonden. Een dood programma kan blijven worden gebruikt voor uitvoering in een computer en nuttige resultaten produceren. De feitelijke staat van dood wordt zichtbaar wanneer eisen voor modificaties van het programma niet intelligent beantwoord kunnen worden."
Een implicatie hiervan is dat een programma niet erg goed zal werken als AI-agents met beperkt geheugen en zonder werkelijke persistente theorie herhaaldelijk wijzigingen aanbrengen in een codebase. AI-agents kunnen werkende code produceren, net zoals enthousiaste nieuwe engineers dat kunnen, maar al te vaak is het resultaat complexer dan nodig. Het mist coherentie en eenvoud omdat de theorie ontbreekt.
Als ander voorbeeld schetst het boek A Philosophy of Software Design (2018) van John Ousterhout het verschil tussen tactisch programmeren—wat betekent dat je je volledig richt op het vandaag werkend krijgen van iets—en strategisch programmeren—wat betekent dat je tijd investeert in het verbeteren van het ontwerp van het systeem om de nieuwe vereiste schoon op te lossen. Er zijn passende momenten voor beide, maar de gebruikelijke faalmodus is het resultaat van te veel tactisch werk en niet genoeg strategisch werk. Ousterhout introduceerde de term "tactical tornado" voor een programmeur die tonnen werkende, maar overdreven complexe code produceert die niet goed in het bestaande systeem past. Erger nog: een slechte manager ziet een tactical tornado vaak als de meest productieve programmeur van een team, en herkent niet de complexiteit en technische schuld die achterblijven voor de rest van het team om op te ruimen. Als we geen zorgvuldige managers zijn, kunnen AI-agents gemakkelijk de ultieme tactical tornadoes worden.
Terwijl we de komende jaren het gebruik van AI-coding agents verkennen, verwacht ik dat we andere fundamentele waarheden van software engineering opnieuw zullen moeten ontdekken: zaken die we al weten, maar die we momenteel proberen weg te wensen of weg te dromen.
Zal het kader dat universiteiten gebruiken om software engineering te onderwijzen moeten veranderen? Zo ja, hoe?
Absoluut. Scholen en universiteiten gebruiken artikelen, codeeropdrachten en tests als indirecte indicatoren voor de doelen die er echt toe doen, namelijk de beheersing van vaardigheden, kennis en nieuwe manieren van denken. Vroeger was het zo dat als je een basisbesturingssysteem kon coderen en draaien, dat een indirect bewijs was dat je de basis van hoe besturingssystemen werkten begreep.
Generatieve AI voegt een triviale nieuwe manier toe om het leren te vermijden, en dat hoeft niet eens het overduidelijke "schrijf mijn code voor mij" te zijn. Als je je eigen code schrijft, maar vervolgens altijd de AI vraagt om je bugs te vinden en op te lossen, omzeil je nog steeds de worsteling en het leerproces.
Ik denk niet dat iemand precies weet hoe het onderwijs moet veranderen. Het is verleidelijk om te zeggen dat we AI-coding agents moeten omarmen en ze moeten gebruiken om uit te breiden wat mogelijk is. Bijvoorbeeld, in plaats van één besturingssysteem in een klas te bouwen, zou je de AI kunnen vragen om er een paar heel verschillende te bouwen en je dan concentreren op het evalueren en vergelijken ervan. Dat lijkt een aantrekkelijk idee, maar ik ben niet overtuigd dat er genoeg inspanning wordt geleverd aan het echt leren over besturingssystemen, tegenover de inspanning die gaat naar hoe je de AI-agents effectief aanstuurt (prompting). Bovendien kun je die vergelijking ook zonder AI doen.
Uiteindelijk moeten we identificeren wat we daadwerkelijk willen onderwijzen, en misschien helpt AI ons wel om onbelangrijke details over te slaan die we voorheen niet konden. Maar voor de belangrijke details denk ik dat we fundamenteel moeten volhouden dat men direct met dat materiaal worstelt, anders vindt het leren niet plaats. Het heeft geen zin om een heftruck mee te nemen naar de sportschool.
Als onderdeel van uw vrijwilligerswerk bent u lid van de redactieraad van ACM Queue. Waarom is het magazine een belangrijke bron voor de software engineering community?
Ik denk dat het teruggaat naar het citaat van William Gibson. De nabije toekomst van software engineering en softwaresystemen is hier al, zowel in recent onderzoek als in recente praktische vooruitgang. Het doel van Queue is om die delen van de toekomst bekender te maken. We identificeren belangrijke onderwerpen en publiceren vervolgens diepgaande behandelingen door experts. Naarmate de tijd verstrijkt, lijkt die aanpak steeds minder gebruikelijk te worden, maar dat maakt het alleen maar waardevoller.
***
Over Russ Cox Russ Cox is een Distinguished Engineer bij Google. Hij was een leidende figuur in de ontwikkeling van de programmeertaal en omgeving Go, waarbij hij samenwerkte met co-createurs Robert Griesemer, Rob Pike en Ken Thompson, en ruim tien jaar lang optrad als technisch leider. Voor Go creëerde hij Google Code Search, die zoekopdrachten op basis van reguliere expressies over de open-source code ter wereld mogelijk maakte, en leidde tot de veelgebruikte RE2 regular expression bibliotheek. Hij maakt deel uit van de redactieraad van ACM Queue, een magazine voor praktiserende software engineers.
Mensen van ACM: Russ Cox
Hoewel Go bekend staat om zijn eenvoud, snelheid en schaalbaarheid, heeft u aangegeven dat het hoofddoel bij het creëren van de taal was om uit te vinden hoe men effectief multicore netwerksystemen kan programmeren. Waarom was dit destijds een belangrijke uitdaging? En hoe is de ontwikkeling van cloud computing samengevallen met de groei van Go?
Het oorspronkelijke doel van Go was om een betere programmeeromgeving te bieden voor het soort software engineering dat rond 2007 bij Google werd gedaan. Die software bestond uit een enorme hoeveelheid code, een groot aantal engineers die samenwerkten en grote aantallen netwerkcomputers, elk met veel cores. Al deze vormen van schaalbaarheid werden slecht ondersteund door bestaande omgevingen, en we wilden iets beters bouwen om ons eigen werk te ondersteunen. Door vanaf nul te beginnen, konden we ook andere fundamenten heroverwegen, zoals afhankelijkheidsbeheer (dependency management), en kernaspecten van de implementatie herzien, zoals low-latency garbage collection.
Het is geen toeval dat Go goed is voor cloud computing, want dat is waar het voor is ontworpen. William Gibson zei ooit: "The future is here. It’s just not very evenly distributed." In 2007 bestond de toekomst van cloud computing al bij Google, en we hebben Go ontworpen om daar deel van uit te maken. Naarmate de toekomst van de cloud breder verspreid raakte, gebeurde dat ook met Go.
Kunt u enkele onverwachte inzichten delen uit uw tien jaar leidinggeven aan Go?
In software engineering lijken de meest fundamentele waarheden niet te veranderen. De context eromheen verandert wel, maar het lijkt erop dat we vooral veel tijd besteden aan het herinneren of herontdekken van zaken die we waren vergeten. Hier zijn er drie:
1. Eenvoud is de beste strategie voor schaalbaarheid
Wanneer engineers nadenken over hoe ze een complex probleem kunnen oplossen, is het voor de hand liggende antwoord het ontwerpen van een complexe oplossing—één met goede asymptotiek maar hoge vaste overheads. Als je in plaats daarvan zoekt naar manieren om het probleem te vereenvoudigen, leidt dat vaak tot eenvoudige oplossingen met lage overheads die net zo goed werken. Eenvoudigere oplossingen schalen beter en zijn gemakkelijker te onderhouden.
Een voorbeeld: build-systemen voor C++ en Java hebben veel problemen door cyclische afhankelijkheden tussen bibliotheken. Cycli creëren grote eenheden die in één keer verwerkt moeten worden, en er is veel werk gestoken in complexe oplossingen om dat te schalen. Voor Go hebben we cycli verboden. Als A B importeert, dan kan B A niet importeren, zelfs niet indirect. Door de package-graaf acyclisch te maken, worden builds en analyse-tools sneller en is het geheel gemakkelijker te begrijpen. De restrictie is soms irritant, maar de voordelen wegen ruimschoots op tegen het ongemak.
2. Software engineering is wat er gebeurt met programmeren wanneer je tijd en andere mensen toevoegt
Programmeren is wanneer je een probleem hebt om op te lossen, code schrijft, deze uitvoert, de bugs die je vindt oplost en klaar bent. Programmeren is op zichzelf al moeilijk. Maar wat als die code dag na dag, jarenlang moet blijven werken, zelfs terwijl je deze bijwerkt? Wat als veel andere programmeurs ook aan de code moeten werken? Dan heb je versiebeheersystemen, bugtrackers, tests, modulegrenzen, design patterns en meer nodig. Al dat komt kijken omdat je programmeren is veranderd in software engineering. Scholen kunnen programmeren onderwijzen, maar ze hebben niet de tijdshorizon om echte software engineering te doceren. Dat is iets wat je alleen door ervaring leert.
3. Tests zijn meer voor morgen dan voor vandaag
Tests die samen met onze code worden ingeleverd, zijn niet bedoeld om te bewijzen dat de code vandaag correct is. Ze zijn bedoeld om te kunnen controleren of het morgen, de dag daarna en volgend jaar nog steeds werkt, zelfs terwijl de code evolueert. Als we er alleen om gaven dat de code vandaag werkte, zouden we het handmatig kunnen testen tot we tevreden waren. En elke keer dat we die code opnieuw zouden bezoeken, zouden we heel zorgvuldig kunnen nadenken over de wijzigingen en handmatig testen wat beïnvloed zou kunnen worden. Deze strategie werkt, maar schaalt niet.
Als je geautomatiseerde tests hebt die je op elk moment opnieuw kunt draaien, en als die tests alle belangrijke gedragingen van je code controleren, dan kun je garanderen dat die gedragingen nooit breken, simpelweg door de tests uit te voeren! Je kunt een nieuwe compiler of een nieuwe versie van een afhankelijke bibliotheek evalueren. Je kunt gecompliceerde code refactoren of herschrijven. Je kunt gemakkelijker wijzigingen accepteren van engineers (of coding agents) die onbekend zijn met het systeem. Bijna alles aan software engineering wordt gemakkelijker in verhouding tot hoe goed je tests zijn.
Hoewel sommigen hebben voorspeld dat AI een fundamenteel nieuw paradigma in softwareontwikkeling zal inluiden, merkte u op dat "continuüm" een beter woord zou zijn om de impact van AI te beschrijven. Hoe ziet u deze komende transformatie voor zich?
Ik heb in een ACM ByteCast-aflevering gezegd dat als je de computers van nu vergelijkt met die die ik als kind in de jaren 80 had, ze in bijna elk opzicht kwalitatief verschillend zijn, maar dat die verandering stap voor stap is gebeurd. Ik verwacht dat de impact van AI zal zijn zoals de impact van alle andere veranderingen in computing: veel kleine stappen die over tijd optellen tot iets dat kwalitatief anders is, niet de enkele onbegrijpelijke sprong waar sommige mensen over hypen. Dat is een belangrijk onderscheid, want het betekent dat we, terwijl we die stappen zetten, nog tijd hebben om te beslissen waar AI goed voor is en waar niet, en hoe we het het beste kunnen gebruiken, zowel als software engineers als als samenleving.
Voor softwareontwikkeling geloof ik niet dat AI de fundamenten van software engineering ongeldig maakt. Integendeel, ik denk dat de fundamenten van software engineering ons kunnen helpen beter te begrijpen waar AI goed voor zal zijn en waar niet.
Een voorbeeld is het artikel uit 1985 van Peter Naur, "Programming as Theory Building". Naur spreekt over het belang van een coherente visie of theorie over hoe eisen uit de echte wereld worden vertaald naar het ontwerp en de structuur van het programma. Hij stelt dat het gebruik van een consistente theorie over een langere periode ervoor zorgt dat programma's eenvoudig blijven. Hij betoogt ook dat dit soort theorie nooit volledig kan worden opgeschreven of gecommuniceerd, omdat het belangrijkste aspect is hoe het omgaat met onvoorziene nieuwe eisen.
Peter Naur stelt dat de onderliggende theorie fundamenteel is voor het onderhoud van het programma:
"De dood van een programma vindt plaats wanneer het programmeursteam dat de theorie bezit, wordt ontbonden. Een dood programma kan blijven worden gebruikt voor uitvoering in een computer en nuttige resultaten produceren. De feitelijke staat van dood wordt zichtbaar wanneer eisen voor modificaties van het programma niet intelligent beantwoord kunnen worden."
Een implicatie hiervan is dat een programma niet erg goed zal werken als AI-agents met beperkt geheugen en zonder werkelijke persistente theorie herhaaldelijk wijzigingen aanbrengen in een codebase. AI-agents kunnen werkende code produceren, net zoals enthousiaste nieuwe engineers dat kunnen, maar al te vaak is het resultaat complexer dan nodig. Het mist coherentie en eenvoud omdat de theorie ontbreekt.
Als ander voorbeeld schetst het boek A Philosophy of Software Design (2018) van John Ousterhout het verschil tussen tactisch programmeren—wat betekent dat je je volledig richt op het vandaag werkend krijgen van iets—en strategisch programmeren—wat betekent dat je tijd investeert in het verbeteren van het ontwerp van het systeem om de nieuwe vereiste schoon op te lossen. Er zijn passende momenten voor beide, maar de gebruikelijke faalmodus is het resultaat van te veel tactisch werk en niet genoeg strategisch werk. Ousterhout introduceerde de term "tactical tornado" voor een programmeur die tonnen werkende, maar overdreven complexe code produceert die niet goed in het bestaande systeem past. Erger nog: een slechte manager ziet een tactical tornado vaak als de meest productieve programmeur van een team, en herkent niet de complexiteit en technische schuld die achterblijven voor de rest van het team om op te ruimen. Als we geen zorgvuldige managers zijn, kunnen AI-agents gemakkelijk de ultieme tactical tornadoes worden.
Terwijl we de komende jaren het gebruik van AI-coding agents verkennen, verwacht ik dat we andere fundamentele waarheden van software engineering opnieuw zullen moeten ontdekken: zaken die we al weten, maar die we momenteel proberen weg te wensen of weg te dromen.
Zal het kader dat universiteiten gebruiken om software engineering te onderwijzen moeten veranderen? Zo ja, hoe?
Absoluut. Scholen en universiteiten gebruiken artikelen, codeeropdrachten en tests als indirecte indicatoren voor de doelen die er echt toe doen, namelijk de beheersing van vaardigheden, kennis en nieuwe manieren van denken. Vroeger was het zo dat als je een basisbesturingssysteem kon coderen en draaien, dat een indirect bewijs was dat je de basis van hoe besturingssystemen werkten begreep.
Generatieve AI voegt een triviale nieuwe manier toe om het leren te vermijden, en dat hoeft niet eens het overduidelijke "schrijf mijn code voor mij" te zijn. Als je je eigen code schrijft, maar vervolgens altijd de AI vraagt om je bugs te vinden en op te lossen, omzeil je nog steeds de worsteling en het leerproces.
Ik denk niet dat iemand precies weet hoe het onderwijs moet veranderen. Het is verleidelijk om te zeggen dat we AI-coding agents moeten omarmen en ze moeten gebruiken om uit te breiden wat mogelijk is. Bijvoorbeeld, in plaats van één besturingssysteem in een klas te bouwen, zou je de AI kunnen vragen om er een paar heel verschillende te bouwen en je dan concentreren op het evalueren en vergelijken ervan. Dat lijkt een aantrekkelijk idee, maar ik ben niet overtuigd dat er genoeg inspanning wordt geleverd aan het echt leren over besturingssystemen, tegenover de inspanning die gaat naar hoe je de AI-agents effectief aanstuurt (prompting). Bovendien kun je die vergelijking ook zonder AI doen.
Uiteindelijk moeten we identificeren wat we daadwerkelijk willen onderwijzen, en misschien helpt AI ons wel om onbelangrijke details over te slaan die we voorheen niet konden. Maar voor de belangrijke details denk ik dat we fundamenteel moeten volhouden dat men direct met dat materiaal worstelt, anders vindt het leren niet plaats. Het heeft geen zin om een heftruck mee te nemen naar de sportschool.
Als onderdeel van uw vrijwilligerswerk bent u lid van de redactieraad van ACM Queue. Waarom is het magazine een belangrijke bron voor de software engineering community?
Ik denk dat het teruggaat naar het citaat van William Gibson. De nabije toekomst van software engineering en softwaresystemen is hier al, zowel in recent onderzoek als in recente praktische vooruitgang. Het doel van Queue is om die delen van de toekomst bekender te maken. We identificeren belangrijke onderwerpen en publiceren vervolgens diepgaande behandelingen door experts. Naarmate de tijd verstrijkt, lijkt die aanpak steeds minder gebruikelijk te worden, maar dat maakt het alleen maar waardevoller.
***
Over Russ Cox Russ Cox is een Distinguished Engineer bij Google. Hij was een leidende figuur in de ontwikkeling van de programmeertaal en omgeving Go, waarbij hij samenwerkte met co-createurs Robert Griesemer, Rob Pike en Ken Thompson, en ruim tien jaar lang optrad als technisch leider. Voor Go creëerde hij Google Code Search, die zoekopdrachten op basis van reguliere expressies over de open-source code ter wereld mogelijk maakte, en leidde tot de veelgebruikte RE2 regular expression bibliotheek. Hij maakt deel uit van de redactieraad van ACM Queue, een magazine voor praktiserende software engineers.