Bij het bouwen van datapijplijnen merk je al snel hoe afhankelijk ze zijn van parameters, van bronpaden tot drempelwaarden tot kolomtoewijzingen en meer. Het begint meestal eenvoudig: je bent aan het prototypen in een notebook en probeert te voorkomen dat je te veel direct in je logica moet hardcoden door een paar basisparameters toe te voegen zoals omgeving, tabelnamen, verbindingsdetails, ... Later komen er wat filtervoorwaarden, misschien een beetje voorwaardelijke logica, of zelfs strategiepatronen als je van software engineering houdt.
Het duurt niet lang voordat je pijplijn lokaal of in dev draait en je parameters zijn verspreid over het notitieblok. Sommige instellingen zijn nog steeds hardcoded, andere zijn dubbel of inconsequent toegepast en nu ben je door het notitieblok aan het scrollen om een parameter te vinden die je wilt aanpassen om te testen.
Klinkt dat bekend?
Het probleem met hard-coding parameters en hoe ze op te lossen
In het begin lijkt het misschien onschuldig om deze parameters direct in je notebook of hoofdbestand te definiëren, zolang het natuurlijk geen gevoelige gegevens zijn. Maar naarmate je pijplijn complexer wordt of je meerdere omgevingen gaat ondersteunen (zoals ontwikkeling, staging en productie), is het hard coderen van parameters niet meer zo snel als het eerst was:
- Als de complexiteit van pijplijnen groeit, groeit het aantal parameters meestal mee. In plaats van een lange lijst met parameters te hebben (als ze niet verspreid zijn over je notebook natuurlijk), is het eenvoudiger om waarden te groeperen op basis van bijvoorbeeld de dataset die verwerkt moet worden door je pijplijn. Een dataklasse of pydantisch dataklasse object kan je configuratie mooi inkapselen en maakt toegang tot de attributen eenvoudig en leesbaar.
- Hard gecodeerde waarden zijn moeilijk te hergebruiken in verschillende omgevingen. Als je overschakelt van dev naar prod, heb je vaak verschillende referenties, bestandspaden of afstemparameters nodig. Hoewel je deze waarden afhankelijk van de omgeving voorwaardelijk kunt maken, weet je al dat het makkelijker is als je bijvoorbeeld een YAML-configuratiebestand per omgeving zou hebben.
Stap 1: Uw configuratie inkapselen in dataklassen
Wanneer u uw pijplijn notitieboek of bestand aanmaakt, begin dan met het aanmaken van een pydantic dataklasse waarin u uw pijplijnparameters inkapselt als attributen. Met deze dataklassen kunt u eenvoudig uw configuratieobject definiëren en attributen toevoegen tijdens uw ontwikkeling. Hieronder staat een voorbeeld van een eenvoudige dataklasse met objectinstantie en hoe je toegang kunt krijgen tot de configuratieattributen.
Nu heb je een gecentraliseerde plaats om je parameters op te slaan en te openen, eenvoudig toch? Dit maakt de volgende stap, het verplaatsen van je configuratiewaarden naar een apart configuratiebestand, veel eenvoudiger.
Stap 2: Parameters verplaatsen naar een speciaal (YAML) configuratiebestand
Om parameterbeheer te vereenvoudigen, is het het makkelijkst om je parameters te externaliseren in een apart configuratiebestand. Hierdoor kunt u het gedrag van uw pijplijn wijzigen zonder uw code aan te passen, waardoor deze schoner en beter aanpasbaar wordt.
Vermijd het plaatsen van geheimen zoals wachtwoorden of API-sleutels in je configuratiebestanden. Deze zouden in omgevingsvariabelen of een veilige geheime opslag moeten staan.
Hoewel JSON misschien een van de eerste formaten is waar je aan denkt voor een configuratiebestand, kun je YAML (YAML Ain't Markup Language) overwegen, omdat het een aantal interessante mogelijkheden biedt:
- Leesbaarder
- Ondersteuning voor opmerkingen, wat handig is voor collega's (en je toekomstige zelf)
- Flexibele structuur die gemakkelijk kan omgaan met geneste objecten, lijsten, meerregelige strings, ...
Multi-line strings zijn echt een onderschatte functie die geweldig kan zijn voor data-engineering. Neem een pijplijn die PySpark gebruikt waarbij dezelfde pijplijn kan worden gebruikt om verschillende datasets te verwerken. Stel nu dat je een filter wilt toepassen met SQL en voor sommige datasets heb je een vrij complex filter op meerdere kolommen. Met behulp van YAML kun je het SQL-statement mooi opmaken en gemakkelijk leesbaar maken, zoals hieronder te zien is. Hieronder staat een voorbeeld van een SQL-instructie uit een YAML-configuratie en hoe deze kan worden gebruikt in een PySpark-pijplijn voor een samenvoegvoorwaarde.
Stap 3: Uw configuraties valideren
Hoewel deze configuratiebestanden echt geweldig zijn, moeten ze wel geldig zijn. Helaas kan een kleine typefout of het verkeerde gegevenstype leiden tot subtiele bugs.
Als u bijvoorbeeld
functie inschakelen: "false".
in je configuratiebestand ziet er op het eerste gezicht prima uit, maar in Python evalueert een niet-lege tekenreeks (zelfs "false") naar True. Python is een dynamisch getypeerde taal en weet niet dat je een Bool wilde in plaats van een string. Als je invoertypes en -formaat niet valideert, kun je dus een onverwachte functie activeren en je pijplijn anders configureren dan bedoeld.
Dit is precies waarom we adviseren om de pydantic bibliotheek te gebruiken, omdat je hiermee een schema kunt definiëren en de configuratie kunt valideren nog voordat de pijplijn wordt uitgevoerd. Je validatie kan er zo complex en uitgebreid uitzien als je zelf wilt, dus bekijk zeker het pydantic pakket! Zoals je kunt zien, resulteert het veranderen van de waarde voor max_nb_files van 100 naar tien in een validatiefout om de geliefde vrijdagmiddag bug-hunt te voorkomen:
Het blokkeren van misconfiguraties voordat je pipeline wordt uitgevoerd, zorgt ervoor dat je precies weet wat je kunt verwachten van je PipelineConfig instantie. Je zou zelfs validatie van je configuraties kunnen toevoegen aan de deployment pijplijn om ervoor te zorgen dat alleen geldige configuraties worden uitgerold naar staging en, nog belangrijker, productie.
Laatste gedachten
Configuratiebeheer is verre van het meest sexy onderdeel van het bouwen van gegevenspijplijnen, maar toch is het er een die vroeg of laat opduikt. Zorg er in je volgende project voor dat je begint met het inkapselen van je configuratieparameters voor eenvoudige toegang. Als je POC eenmaal werkt, verplaats dan de configuratiewaarden naar speciale YAML-bestanden en valideer ze met pydantic, zodat je weet dat je pijplijn doet wat je bedoelde, zelfs als je collega's beginnen te rommelen in de configuraties!



