- Meetlatten in gebruikVier, allemaal extern
- Checks per sweep217.060 + 1.451 + 833
- Opnieuw gemetenBij elke release
- Release-poortenVijf, automatisch
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".
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:
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:
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.
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.
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:
- Meet tegen iets externs — een standaard, een referentie-implementatie, de acceptatiedata van de klant zelf
- Publiceer het minst flatteuze verdedigbare cijfer, en schrijf op hoe het berekend wordt
- Bepaal de ruisband vóórdat je bewegingen als vooruitgang leest
- Houd een correctheidsfix ook als die de score verlaagt, en zeg waarom het getal bewoog
- Maak van elk gesloten defect een blijvende regressietest — inmiddels 149 stuks
- Zet automatische poorten op de metrieken, zodat niets afhangt van iemand die eraan denkt te kijken
- Leg de mislukte experimenten vast, zodat niemand er een week aan verspilt om ze te herontdekken
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.
De dashboards achter deze grafieken zijn openbaar: de specificatie en haar conformiteitsdata, en de meetdocumentatie van het project op GitHub.