Blog ·
Een datum in de toekomst is geen agenda
Vierentwintig live artikelen beweerden nog niet gepubliceerd te zijn. De oplossing was geen planner maar een build die zo'n datum voortaan weigert.
Door Provibr
Elk artikel op deze site draagt een publicatiedatum in zijn frontmatter. Hij staat onder de titel, hij gaat mee in de gestructureerde gegevens die een zoekmachine leest, en hij is de enige datum die de sitemap ooit afdrukt. Hij hoort een feit te zijn.
Een tijdlang waren er vierentwintig dat niet. Ze droegen datums verspreid over de zes dagen erna, omdat wie ze schreef een publicatieritme in gedachten had en dat in het bestand zette. Negen talen per stuk, dus tweehonderdzestien bestanden. Elk van die pagina's was live, doorzoekbaar en geïndexeerd, en elk van die pagina's vertelde een crawler in machineleesbare vorm dat hij gepubliceerd was op een dag die nog niet had plaatsgevonden.
Er stond niets op rood. De build was groen, de tests waren groen, de pagina's werden getoond. Het enige dat de tegenspraak kon zien was een machine die de pagina las, en machines dienen geen foutmeldingen in.
Wat de geschiedenis zei
Het eerste dat vastgesteld moest worden, was welke van de twee datums waar was. Dat is één commando: vraag git wanneer elk bestand voor het eerst is toegevoegd. Alle vierentwintig zijn op dezelfde dag toegevoegd, in drie commits, door drie rondes van hetzelfde nachtwerk. Er was geen uitrol over zes dagen. De spreiding was een bedoeling die was opgeschreven in een veld dat voor waarnemingen bestemd is.
Dat onderscheid is het hele artikel. Een veld dat vastlegt wat er gebeurd is kan niet óók uitdrukken wat je van plan bent, want een lezer kan de twee niet uit elkaar houden en een crawler evenmin.
Waarom we de planner niet gebouwd hebben
De voor de hand liggende reparatie is de datums waar maken door de site ze te laten respecteren: verberg een artikel tot zijn datum aanbreekt. Dat is hier om twee onafhankelijke redenen de verkeerde reparatie, en beide zijn het uitschrijven waard omdat de eerste makkelijk te missen is.
Deze site wordt statisch gegenereerd. Pagina's worden één keer gerenderd, tijdens de build, en als bestand geserveerd. Een poort op de datum wordt dus tijdens de build beoordeeld en daarna nooit meer. Er verschijnt niets om middernacht; er verschijnt iets wanneer iemand bouwt. Een datumpoort levert dus geen publicatieagenda op, maar een verzameling pagina's die ontbreken tot er toevallig een ongerelateerde uitrol draait.
De tweede reden is erger. Die tweehonderdzestien adressen waren al gecrawld. Ze verbergen tot hun genoemde datum aanbreekt betekent tot zes dagen lang een 404 serveren op pagina's die een zoekmachine al gezien en geïndexeerd heeft. Een 404 op een eerder geïndexeerd adres is geen "kom later terug" maar een verwijderingssignaal, en het herstel ervan kost veel meer dan de onwaarheid die je repareerde.
De datums zijn dus gecorrigeerd naar de dag waarop het werk werkelijk landde, waarbij alleen die regel in elk van de tweehonderdzestien bestanden geraakt is, en in plaats daarvan is de mogelijkheid om een toekomstige datum te schrijven weggehaald.
De poort staat bij de bron en heeft geen ontsnappingsklep
De contentbuild weigert nu elke frontmatterdatum die later ligt dan de dag waarop hij bouwt. Geen waarschuwing: een mislukte build met de bestandsnaam en beide datums in de melding.
Twee kleine beslissingen daarbinnen verdienen een naam. Hij vergelijkt met vandaag in de eigen tijdzone van het project en niet met UTC, want een artikel dat hier om half één 's nachts verschijnt draagt de lokale datum, en een vergelijking met UTC zou een bestand op zijn eigen publicatiedag afkeuren. En er is met opzet geen overschrijving: geen omgevingsvariabele, geen vlag. Een ontsnappingsklep op zo'n regel wordt één keer om een goede reden gebruikt en daarna permanent, en een agenda hoort in een takenlijst en niet in de frontmatter van een bestand dat al vastgelegd is.
Er staat een tweede poort verderop, in het register dat de gepubliceerde artikelen samenstelt, en die laat elk artikel weg waarvan de publicatiedatum nog in de toekomst ligt. Dat is een vangnet voor de wegen die niet langs de build gaan: een met de hand bewerkt bestand, een merge die twee generaties door elkaar haalt, een teruggezette backup. Hij poort alleen op de publicatiedatum en niet op de wijzigingsdatum, want een tikfout in een datumveld hoort geen al geïndexeerde pagina te laten verdwijnen.
En die tweede poort wordt één keer beoordeeld, bij het laden van de module tijdens de build. Dat staat in een commentaar ernaast, want een lezer die iets anders aanneemt schrijft uiteindelijk de planner waar deze paragraaf tegen pleit.
Een datum die je niet kunt afleiden kun je beter weglaten
Dezelfde ronde moest beslissen welke datum, als er al een is, bij de documentatiepagina's hoort, die helemaal geen frontmatter hebben. Er dienden zich drie kandidaten aan, en alle drie zijn onwaar.
| Kandidaat | Waarom hij fout is |
|---|---|
| De gitdatum van het paginabestand | Verandert bij een gewijzigde klassenaam, en verandert niet als de tekst naar een vertaalbestand verhuist |
| De gitdatum van de vertaalcatalogus | Eén bestand draagt duizenden losse teksten en verandert dus voortdurend om redenen die niets met deze pagina te maken hebben |
| De builddatum | Zegt elke dag dat elke pagina vandaag geschreven is |
De documentatiepagina's dragen dus geen publicatiedatum in hun gestructureerde gegevens. Niets is beter dan een aannemelijk getal, want een aannemelijk getal is het getal dat niemand controleert.
Dezelfde redenering gold al voor de sitemap. Vaste routes dragen helemaal geen wijzigingsdatum, en de reden is geen luiheid: hun inhoud is broncode en hun tekst woont in negen vertaalcatalogi, dus elke datum die we konden uitrekenen zou iets anders volgen dan wat de lezer ziet. Een zoekmachine die een "gewijzigde" pagina drie keer ophaalt en ongewijzigd aantreft, leert het veld te negeren, en dan is het veld erger dan afwezig voor de pagina's waar het wél echt is. Artikelen dragen er wél een, want die staat in de frontmatter naast de titel, waar wie het stuk herschrijft hem ook werkelijk ziet.
Na dit werk veranderde de dekking helemaal niet: de artikeladressen dragen een wijzigingsdatum, al het andere niets, precies zoals daarvoor. Wat wél veranderde is dat tweehonderdzestien van die datums in de toekomst lagen, en nu geen enkele meer.
Nog een tegenspraak, opgelost met identiteit
Bij het nalopen van de gestructureerde gegevens dook een kleinere versie van hetzelfde probleem op: op sommige pagina's waren de auteur en de uitgever twee losse entiteiten zonder verklaarde relatie. Letterlijk gelezen beweerden die pagina's dat het artikel geschreven was door de ene onderneming en uitgegeven door de andere. Beide wijzen nu naar dezelfde identiteit. Niemand zou geklaagd hebben, en het was nog steeds een bewering van ons die niet klopte.
Wat wij zouden opschrijven
- Zet nooit een bedoeling in een veld dat een waarneming vastlegt. Een lezer kan ze niet uit elkaar houden, en een machine evenmin.
- Toets de bewering aan de geschiedenis. Eén commando over de bestandsgeschiedenis besliste welke van twee datums de echte was, en het sprak alle vierentwintig bestanden tegen.
- Een datumpoort op een statisch gegenereerde site is geen agenda. Er verschijnt niets om middernacht; er verschijnt iets bij de volgende build.
- Verberg geen adressen die al geïndexeerd zijn. Een 404 op een gecrawlde pagina is een verwijderingssignaal, en de genezing kost meer dan de kwaal.
- Zet de poort waar de fout gemaakt wordt, laat de build falen, en bouw er geen omzeiling in. Zet een tweede poort verderop voor de wegen die de eerste overslaan.
- Laat een datum weg die je niet eerlijk kunt afleiden. Drie aannemelijke bronnen die alle drie fout zijn, betekent dat de eerlijke uitkomst niets is.
Voor de duidelijkheid over wat dit is: dit is huishoudwerk aan een publieke website, geen productfunctie, en het veranderde geen gedrag waarvoor iemand betaalt. Een deel ervan is onbewezen. De gestructureerde gegevens zijn tegen hun eigen schema gevalideerd en met de hand gelezen, niet door een echte crawler of een echte deelkaart. Niets hiervan is gemeten tegen de index van een zoekmachine, want die meting duurt weken en niemand hoort daarop te wachten voordat hij een onwaarheid weghaalt.
Uit het sitewerk aan Provibr. Wat het kost om zestienduizend teksten in negen talen kloppend te houden staat in zestienduizend sleutels, negen talen, en hoe een botsing van veldnummers in een protocol verborgen bleef staat in twee rondes, één veldnummer.