Hoe Instagram miljoenen lijnen Python-code onder controle houdt

Instagram Server, de back-end van de populaire smartphone-app die miljoenen mensen gebruiken om foto’s te delen, draait nagenoeg volledig op Python. Het zijn miljoenen lijnen code, waar voortdurend aan wordt toegevoegd. Die gigantische codebase onder controle houden, is een hele uitdaging. Recent lichtte Instagram welke technieken het daarvoor gebruikt.

Instagram heeft een tipje van de sluier opgelicht en onthult hoe het enkele pijnpunten omzeilt bij het gebruik van de programmeertaal.

“Het is heel moeilijk om deze massieve monolithische codebase, die groeit aan een tempo van honderden commits per dag, te behoeden van complete chaos”, vertelt Instagram-ontwikkelaar Benjamin Woodruff. “We willen van Instagram een plek maken waar al onze ontwikkelaars productief kunnen zijn en snel nuttige functies kunnen toevoegen.”

Python uitgeperst

“Het is redelijk om te stellen dat we Python voorbij zijn vooropgesteld doel gebruiken. Het werkt geweldig voor kleinere teams met kleinere codebases”, zegt ontwikkelaar Carl Meyer. “We zouden eigenlijk moeten overschakelen naar een minder dynamische taal, maar we zijn met de grootte van de codebase voorbij het punt waar dat nog haalbaar is.”

We zouden eigenlijk moeten overschakelen naar een minder dynamische taal.

Bovendien vindt het ontwikkelteam van Instagram het ook gewoon leuk om met Python te werken. Het sociale netwerk probeert zijn app daarom te verbeteren op een manier die de voordelen van Python vergroot en de obstakels van de taal voor productiviteit in grootschalige projecten vermindert. Zo wordt onder meer de statische type-checker Pyre gebruikt om de servercodebase te analyseren en helpt LibCST bij het analyseren van Python-code.

Strikte modules

Instagram heeft daarnaast iets geïntroduceerd dat het ‘strikte modules’ noemt. Voorlopig zijn de strikte modules nog experimenteel en worden ze nog maar net in productie uitgerold.

Strikte modules zijn een nieuw Python-moduletype, dat wordt geïmplementeerd door gebruik te maken van veel van de low-level uitbreidingsmechanismen die al door Python worden geboden. Een aangepaste modulelader ontleedt de code met behulp van de AST-module, voert een abstracte interpretatie uit op de geladen code om deze te analyseren, past verschillende transformaties toe op de AST en compileert de gewijzigde AST vervolgens terug in Python-bytecode met behulp van de ingebouwde compileerfunctie.

Rem op snelle iteraties

Meyer ziet de programmeertaal Python als een briljant iets voor snelle iteratie. Je kunt namelijk wijzigingen aanbrengen en het resultaat zien, zonder de code te hoeven compileren. Al wordt dat volgens hem met een paar miljoen regels code en een rommelige dependency graph inmiddels enigszins “zuur”.

Zo duurt het ongeveer een minuut voordat Instagram Server start, wat zich vertaalt in een kritieke vertraging bij het testen van nieuwe functies. In die tijd kan de ontwikkelaar worden afgeleid door een andere taak, waardoor de voorgaande dus niet voltooid wordt. Ondanks dat Python de ontwikkeltijd in principe versnelt, zijn er volgens Meyer uitdagingen bij het gebruik op de schaal van Instagram.

Hoe klein de wijziging ook is, we moeten elke keer opnieuw beginnen.

“Omdat imports willekeurige bijwerkingen kunnen hebben, is er geen veilige manier om onze server stapsgewijs opnieuw te laden in Python. Hoe klein de wijziging ook is, we moeten elke keer opnieuw beginnen, al die modules importeren, klassen en functies opnieuw creëren, reguliere expressies hercompileren, enzovoorts. Doorgaans is 99 procent van de code niet gewijzigd sinds de vorige keer dat we de server opnieuw hebben geladen. Desondanks moeten we toch al dat trage werk opnieuw uitvoeren”, aldus Meyer.

Verspilde compute

In het geval van Instagram schaadt dat niet alleen de productiviteit van ontwikkelaars, maar veroorzaakt het ook een “aanzienlijke hoeveelheid verspilde compute in productie, omdat Instagram de site continu implementeert en opnieuw laadt op productieservers”, aldus Meyer. Hij ziet de ontwikkelde ‘strikte modules’ dan ook als het antwoord van Instagram op de zwakke punten van Python bij gebruik in grootschalige productieomgevingen.

Meyer: ”Strikte modules leggen enkele beperkingen op wat er op module-topniveau kan gebeuren. Alle code op moduleniveau moet zuiver zijn. Dit is statistisch geverifieerd tijdens het compileren via de abstracte interpreter. Dat betekent dat strikte modules neveneffecten-vrij zijn bij import: slechte interacties van bijwerkingen bij import zijn zo niet langer mogelijk.”