Het volledige Raku++-verhaal

Vraag een softwarebedrijf hoe ze weten dat een release beter is dan de vorige, en meestal krijg je een antwoord over proces — stand-ups, reviews, sprints. Dat is nuttig. Het is geen bewijs.

Bij Raku++, onze vanaf nul geschreven compiler voor de programmeertaal Raku, deden we het andere experiment: beslis vrijwel niets op basis van meningen. Kies meetlatten die je niet zelf in de hand hebt, meet er bij elke release tegenaan, publiceer de uitkomsten inclusief de uitkomsten die je slecht doen lijken, en laat de grafieken bepalen wat er als volgende wordt opgepakt.

Deze pagina beschrijft die methode, met de echte cijfers. Elke grafiek hieronder komt uit de live dashboards achter raku.online/spec — dezelfde data waar de engineers van het project zelf naar kijken.

1. Kies een meetlat die je niet zelf in de hand hebt

De verleiding bij een eigen testsuite is dat je de tests zelf schrijft én zelf bepaalt wanneer ze goed genoeg zijn. Dat is een spiegel, geen meting. Raku heeft toevallig een zeldzaam bezit: de specificatie is uitvoerbaar — zo'n 1.460 bestanden met draaiende tests, onderhouden door de gemeenschap van de taal zelf, volledig buiten onze invloed.

Dat werd vanaf dag één de belangrijkste meetlat. Niet "voelt dit als Raku" maar "hoeveel van andermans asserties slagen".

Roast-bestanden die volledig slagen, eerste commit tot v1.5.0
01753505257001852 jul9 jul16 jul22 jul62529 juleerste commitv1.5.0

Bron: het releasedashboard van het project. Een bestand telt alleen mee als elke assertie erin slaagt — de strengste van de drie beschikbare maten.

Dat is een bevredigende lijn, en tegelijk de minst interessante van deze pagina. Een stijgende grafiek is makkelijk te tekenen. Wat telt, is wat er gebeurt als de grafiek je iets vertelt wat je niet wilde horen.

2. Begrijp wat je getal doet als je beter wordt

Hier is hetzelfde project, dezelfde releases, gemeten als percentage van de tests die de suite declareert:

Dezelfde releases, als aandeel van alle gedeclareerde tests
78%82%86%90%v0.5.082,1%v0.7.180,4%v0.9.0v0.9.1v1.0.0v1.1.0v1.1.5v1.2.5v1.5.090,5%meer bestanden draaiden, dus het doel groeide

Bron: het releasedashboard van het project. 157.293 van de 191.546 bij v0.5.0; 196.395 van de 217.060 bij v1.5.0.

Het werk tussen die eerste twee releases hoorde bij het productiefste van het hele project. Het percentage ging omlaag.

De reden is structureel, en het loont om hem te begrijpen, want dezelfde valkuil bestaat in de meeste projecten. Als een testbestand vroeg crasht, worden de tests ná de crash nooit gedeclareerd. Los de crash op en het bestand komt verder — het declareert tientallen tests extra, waarvan de meeste nu falen. Je werd beter; je noemer groeide sneller.

Er zijn drie verdedigbare manieren om dat slagingspercentage te berekenen. Wij publiceren de strengste, altijd naast het cijfer per bestand, met de methodologie erbij opgeschreven. Het alternatief — stilletjes de definitie kiezen die de release van deze week het mooist doet uitkomen — is precies hoe meten in marketing verandert.

3. Weet hoeveel je getal wiebelt

Een getal zonder foutmarge nodigt uit tot overinterpretatie. Twee sweeps over een identieke codebase gaven ons 934, 939 en 943 overeenkomsten op dezelfde dataset. Er veranderde niets tussen de runs — de referentie-engine randomiseert de iteratievolgorde van hashes per proces, dus een handvol voorbeelden klapt beide kanten op.

De regel in dit project is dus: een beweging binnen de ruisband is geen resultaat. We legden de band vast en behandelen alles onder ongeveer ±5 op die maat als vlak.

Wat we volgen Schaal Hoe ruisig Wat als echt telt
Specificatietests die slagen 217.060 ±20 tests, ±1 bestand Een benoemde fix, zonder regressies
Documentatievoorbeelden die matchen 1.451 ±5, iteratievolgorde Een beweging buiten de band
Operatorchecks die matchen 833 Deterministisch Elke verandering
Benchmarkkernels 9 Enkele % per run Beste van zes, tegen een vastgelegde basislijn

4. Vergelijk met een referentie, voorbeeld voor voorbeeld

Een specificatiesuite test features geïsoleerd. Ze zegt niets over de vraag of je product zich gedraagt zoals de documentatie gebruikers belooft. Dus bouwden we een tweede meetlat: neem elk uitvoerbaar voorbeeld uit de officiële documentatie van de taal — 1.451 stuks — draai elk op onze engine en op de volwassen referentie-implementatie, en vergelijk de uitvoer byte voor byte.

Dat levert meer op dan geslaagd/gezakt. Elk voorbeeld belandt in een van meerdere bakjes, en juist die bakjes zijn het nuttige deel:

Elk uitvoerbaar voorbeeld uit de officiële documentatie, per uitkomst
596471176v1.1.025 jul835237164112v1.2.027 jul853211159119v1.2.027 jul943120157123v1.5.029 julbeide engines volgen de docsRaku++ wijkt afalle drie verschillende docs zijn verouderdde referentie-engine wijkt afniet headless uitvoerbaar

Bron: de conformiteitssweep achter raku.online/spec, vier regeneraties tussen 25 en 29 juli 2026. 1.451 voorbeelden per sweep.

Lees de rode band: dat is onze defectenlijst, en die daalde van 471 naar 120 in vier regeneraties. Elk daarvan was een echt verschil in gedrag dat iemand moest vinden, doorgronden en dichten.

Maar kijk naar de lichtblauwe band, die juist groeide — van 104 naar 123. Dat zijn voorbeelden waarin onze engine en de referentie-implementatie het met elkáár eens zijn en allebei van de documentatie afwijken. Met andere woorden: de documentatie is verouderd. Meten tegen twee onafhankelijke referenties tegelijk verandert "wij hebben een bug" in "wij hebben een bug, zij hebben een bug, of de docs kloppen niet" — en die drie uit elkaar houden is het grootste deel van het werk.

5. Ga daarna fijner, operator voor operator

Vergelijkingen op voorbeeldniveau vinden clusters, maar geen oorzaken. Dus gaat dezelfde behandeling een niveau dieper: 833 losse expressies over 121 operatoren, elk op beide engines geëvalueerd en gedift.

De operatormatrix, voor en na één releasecyclus
833 expressies over 121 operatoren, op beide engines gedraaid678 eens7227 jul · v1.2.0708 eens3029 jul · v1.5.0afwijkingen: 72 naar 30 in één releasecyclus

Bron: de operator-gedragsmatrix achter raku.online/spec. „Beide verwerpen” betekent dat geen van beide engines de expressie accepteert — overeenstemming van een andere soort.

Dertig afwijkingen over, van tweeënzeventig, in één releasecyclus. En juist die steile daling laat zien waarom fijnmazig meten loont: verschillende van die correcties waren telkens één grondoorzaak die vijftien rijen tegelijk opruimde. Eén parserbug zorgde ervoor dat een term als functieaanroep werd gelezen, waardoor elke operator die erop kon volgen brak. Zoiets vind je niet door symptomen op te lossen — je vindt het doordat je een tabel hebt waarin vijftien schijnbaar losstaande rijen tegelijk groen worden.

6. Houd het getal in de gaten dat wegloopt

Correctheidsmetrieken krijgen aandacht omdat ze op de roadmap staan. Performance is anders: die verslechtert stilletjes, één redelijk ogende wijziging per keer, en niemand merkt het omdat geen enkele commit de schuldige is.

Hier is een benchmarkkernel over de releases van het project. Lager is beter.

Een benchmarkkernel over de releases, in milliseconden
0 ms600 ms1200 ms1800 ms1693,5v0.5.0768,6v0.7.1v0.9.0v0.9.1v1.0.0v1.2.6903,3v1.5.0744,1v1.5.1sloop stilletjes de verkeerde kant oplager is beter

Bron: het benchmarkharnas van het project, bij elke release opnieuw gemeten. Beste van zes runs op één machine, inclusief procesopstart.

De eerste daling is bewust werk — een verbetering van 2,2×. Kijk daarna naar het gestippelde stuk: over zes releases kroop het getal van 769 ms terug omhoog naar 903 ms. Niemand leverde met opzet een performanceregressie op. Niemand keek er ook naar, want er stond niets op wacht.

Wat het oploste was geen heldendaad maar rekenwerk: profileren, de kandidaten rangschikken op gemeten kosten, en de lijst afwerken. Vijf kandidaten kwamen uit een profiel. Drie werden doorgevoerd. Eén werd gebouwd, gemeten, 2,5% trager bevonden en teruggedraaid. Eén werd geschat op een plafond van 4% voor de riskantste wijziging op de lijst en bewust nooit geprobeerd. Het resultaat was 744 ms — sneller dan het getal ooit was geweest.

En dan het belangrijkste: een vastgelegde basislijn wordt nu bij elke release opnieuw gemeten en laat de build falen als hij wegzakt. Dezelfde afdrijving kan geen tweede keer gebeuren, want een getal waar niemand een poort op zet, is een getal dat wegloopt.

Wat we werkelijk met de cijfers doen

De grafieken zijn het zichtbare deel. De gewoonten erachter maken ze pas iets waard:

Niets hiervan is specifiek voor compilers. Vervang "latency op het 99e percentiel", "orders die tot op de cent aansluiten" of "documenten die de nieuwe pipeline identiek classificeert aan de oude" en de methode blijft dezelfde: een externe meetlat, een bekende ruisband, een opnieuw gegenereerde grafiek, en een poort.

Waar dit past

Onze pagina over methodologieën gaat over hoe we projecten draaien — het ritme, de communicatie, de oplevering. Deze pagina is de andere helft: hoe we weten dat wat we opleveren daadwerkelijk beter is dan wat er was.

Als jouw project een getal heeft dat ertoe doet — een snelheidsbudget, een correctheidslat, een migratie die identieke uitvoer moet geven — dan is dat werk waar we graag aan beginnen, en zo zouden we het aanpakken.

Lees het volledige Raku++-verhaal

De dashboards achter deze grafieken zijn openbaar: de specificatie en haar conformiteitsdata, en de meetdocumentatie van het project op GitHub.

Een getal dat ertoe doet?

Vertel ons wat er moet bewegen — wij vertellen je hoe we het zouden meten.

Neem contact op

Meer in Softwareontwikkeling

Raku++ — een Raku-compiler

Onze vanaf nul geschreven, open-source implementatie van de programmeertaal Raku in C++ — native executables, een optimizer, een WebAssembly-build voor de browser en geen dependencies.

raku.online — een Raku-playground

Een Raku-playground die volledig in de browser draait — schrijf, draai en deel Raku-code, zonder installatie en zonder server erachter, plus een kant-en-klare widget om uitvoerbare editors op elke site in te sluiten.

Raku++ bouwen — het engineeringverhaal

Hoe we vanuit een lege map in minder dan een maand een compiler voor een omvangrijke programmeertaal schreven — de projecten eromheen, de vier meetlatten waaraan we het aftoetsten, en het snelheidswerk dat de opstarttijd op twee milliseconden bracht.

Backend-ontwikkeling

Robuuste backend-systemen voor complexe bedrijfslogica, dataverwerking en integratie

Frontend-ontwikkeling

Intuïtieve en responsieve interfaces voor een naadloze gebruikerservaring

Mobiele ontwikkeling

Mobile-first oplossingen op maat voor iOS- en Android-apparaten

Dataopslag en -beheer

Je data efficiënt en veilig beheren

DevOps en systeembeheer

Stroomlijn de ontwikkel- en deployprocessen

Datatransformatie en processtromen

Ontwerp en beheer dataworkflows voor naadloze integratie en datagedreven beslissingen

Hardware-integratie

Maatwerk hardware-integratie voor IoT- en embedded-toepassingen

Methodologieën

Het juiste proces voor het project — en een oplevering gestuurd door meten, waarbij releases worden afgeschermd door cijfers in plaats van meningen