Binnenkort gaan we Django, het webframework dat wij gebruiken, upgraden naar een nieuwe versie. Daar komt nogal wat voorbereiding bij kijken. We willen immers graag zeker weten dat alles goed blijft werken. Gelijk een interessante aanleiding om jou meer inzicht te geven waar een developer bij Antagonist zich zoal mee bezighoudt!
Het upgraden van Django is elke keer een unieke uitdaging. Dit keer veroorzaakte de gewenste upgrade problemen met onze testinfrastructuur. Daarom moesten we die eerst grondig onder handen nemen. Ruim vóór de daadwerkelijke upgrade, zodat we genoeg tijd hebben om eventuele problemen te ontdekken. Goed, laten we bij het begin beginnen.
Wat doet Mijn Antagonist precies?
Mijn Antagonist is ons administratieve beheersysteem. Het is geschreven in Python, evenals veel andere tools die wij intern gebruiken. Zowel klanten als medewerkers maken er gebruik van. Klanten gebruiken het vooral voor administratieve taken, zoals klantgegevens wijzigen of nieuwe bestellingen plaatsen. Medewerkers gebruiken het om onze klanten te ondersteunen.
Maar Mijn Antagonist is en doet nog zoveel meer. Het is dé hub die veel van onze automatisering mogelijk maakt, het kloppende hart van Antagonist. Zonder deze automatische processen zouden we het werk met ons kleine, hechte team niet aankunnen! Development is de spil in deze geoliede machine en is dan ook continue bezig met dit belangrijke systeem.
Automatisering
De kern van Mijn Antagonist is een takensysteem. Zoals de naam al verklapt, voert dit systeem op de achtergrond allerlei taken uit. Denk aan het verwerken van bestellingen, het opleveren van hostingpakketten en het beheren van domeinnamen. Daarnaast helpt het takensysteem ons met het automatiseren van allerlei aspecten van de bedrijfsvoering.
Bij Antagonist vinden wij de beleving van onze klant het allerbelangrijkst. We willen daarom dat klanten zo snel en gemakkelijk mogelijk hun zaken zelf kunnen regelen. Als dit niet lukt, dan staan we klaar om persoonlijke hulp te bieden. Automatisering is bijzonder belangrijk hierbij.
Door zoveel mogelijk aspecten van Antagonist te automatiseren, kunnen wij ons focussen op zaken die voor de klant écht van belang zijn. Bijvoorbeeld het verder verbeteren van onze service. Dit, om ervoor zorgen dat vragen niet alleen beantwoord worden, maar dat er ook met klanten wordt meegedacht en dat problemen voor de volle 100% worden opgelost.
Wat is Django?
Mijn Antagonist is gebouwd met behulp van Django. Het doel van Django is om allerlei repetitieve taken uit handen van de developer te nemen, zoals het verwerken van formulieren en communicatie met de database.
Django is een behoorlijk groot, complex project waar hard aan gewerkt wordt. Upgrades zijn daarom altijd uitdagend. Er verandert bij elke versie wel iets dat roet in het eten gooit, maar uiteindelijk wordt Mijn Antagonist er wel beter van. En die extra performance komt ons allen ten goede! Bij de vorige upgrade is Mijn Antagonist bijvoorbeeld 25% sneller geworden.
Django werkt, net als veel andere open source-projecten, met een LTS-systeem (Long Term Support). Dat betekent dat sommige versies extra lang ondersteund worden. Door altijd een ondersteunde LTS-versie te gebruiken, hoeven we niet elke keer zoveel tijd te investeren, terwijl we wel voorzien blijven van beveiligingsupdates.
Waarom is upgraden zo complex?
Daar zijn een aantal redenen voor. Ten eerste is Mijn Antagonist een project dat bijzonder omvangrijk is. We moeten zeker weten dat een upgrade goed gaat, voordat we deze doorvoeren. Als je zonder enige voorbereiding gaat upgraden, dan gaat dingen vaak op subtiele wijze kapot of functioneren ze niet langer naar behoren. Om dat te voorkomen, hebben we een uitgebreide testinfrastructuur. Daarover straks meer.
Een tweede reden is dat Django behoorlijk snel ontwikkeld wordt, met het gevolg dat er soms grote verschillen zitten tussen de versies. Ten derde is Django een framework met een sterke mening, dat heel fijn werkt als je dingen op de Django-manier doet. Maar inzichten veranderen in de loop der tijd en uiteraard zijn er ook technologische ontwikkelingen. Dit zorgt ervoor dat Django soms van mening verandert en dus ook dat wij Mijn Antagonist moeten ombouwen.
Waarom toch upgraden?
Maar als een upgrade zo lastig is, waarom dan alle moeite? Nou, op een gegeven moment wegen de voordelen zwaarder dan de nadelen. Beveiliging is natuurlijk een belangrijke reden. Er worden wel eens problemen ontdekt in Django en die worden dan alleen in de ondersteunde versies opgelost.
We kunnen die oplossing vaak zelf wel in oudere versies toepassen, backporten zoals dat heet, maar ook dat kost tijd. En die besteden we liever aan het optimaliseren van onze dienstverlening. Ten slotte willen we natuurlijk gebruikmaken van de nieuwste features die een nieuwe versie met zich meebrengt.
Testen, testen, testen
Voordat we live kunnen gaan met de nieuwe versie van Django, is het belangrijk om uitgebreid te testen. Sommige dingen worden met de hand getest, maar uiteraard voeren we de meeste tests in Antagonist-stijl uit. Lees: automatisch. Om dit te doen, maken we gebruik van Continuous Integration (CI). Kort gezegd, betekent CI dat we voortdurend automatisch testen of Mijn Antagonist nog naar behoren werkt.
Bij elke aanpassing die we doen, worden er een paar duizend tests automatisch uitgevoerd. Daarin worden verschillende aspecten van Mijn Antagonist volledig automatisch getest. Zo krijgen we bij elke aanpassing automatisch en snel feedback, voordat we de aanpassing online zetten.
De CI-omgeving voert verschillende soorten tests uit. Sommige tests zijn heel simpel, maar we hebben ook de wat meer ingewikkelde tests, die bijvoorbeeld automatisch een browser starten en controleren of een bepaalde pagina in Mijn Antagonist er wel correct uitziet.
Pytest
Voor het testen, maken we gebruik van een test-framework genaamd Pytest. Pytest is voor testen wat Django voor webdevelopment is. Het helpt ons om eenvoudig tests te schrijven en uit te voeren. Elke keer als tests worden uitgevoerd, wordt er een schone database aangemaakt. Op die manier weten wij zeker dat er geen troep van de vorige tests achterblijft.
Een test bestaat uit vier fasen. Als eerste worden er voorbereidingen getroffen. Zo heeft een test soms specifieke data nodig in de database. Daarna wordt de test uitgevoerd. Vervolgens wordt gecontroleerd of de test wel of niet geslaagd is. Als laatste worden de data die in stap één zijn aangemaakt weer uit de database verwijderd. Die laatste stap is belangrijk, want we willen dat elke test met een schone lei begint.
Databases bij het testen
Sommige van onze tests hebben een werkende database met data nodig. Stel dat je een test hebt die een pakket bestelt, dan moet dat pakkettype wel aanwezig zijn in de database. Om dit type tests te faciliteren, hebben we een dataset met alle data die nodig zijn om de tests uit te voeren.
Voorheen werd deze dataset voor het uitvoeren van de tests automatisch geladen. Op die manier wisten we zeker dat we de vereiste data beschikbaar hadden. In de nieuwe versie van Django is dit echter niet langer mogelijk. De data worden weggegooid na elke test om een schoon systeem achter te laten voor de volgende test.
Een oplossing is om voor elke test opnieuw de dataset te laden, maar dit gaat erg traag en daar houden we niet van. Daarnaast is het ook niet handig om in een test ervan uit te gaan dat je bepaalde data hebt. Door deze afhankelijkheden weg te halen, worden de tests een stuk algemener en gemakkelijker uit te voeren. Toch blijft het een feit dat sommige tests bepaalde data nodig hebben. Hoe gaan we daarmee om?
In plaats van altijd dezelfde dataset te laden, lossen we het probleem op door voor elke test enkel de data aan te maken die nodig zijn. Als een test bijvoorbeeld een pakket gaat bestellen, dan maken we een klant en het betreffende pakkettype aan. Verder hebben we niets nodig.
Op deze manier zorgen we ervoor dat de test zo snel mogelijk wordt uitgevoerd. Hierdoor hebben we ook een veel algemenere test gekregen. We kunnen dezelfde test nu ook gebruiken om andere producten te bestellen, zoals bijvoorbeeld een domeinnaam. Het enige wat wij hoeven te doen, is in de setup-fase andere producten aan maken.
Factory
Maar dan zitten we met een nieuw probleem: veel objecten in onze database zijn afhankelijk van elkaar. Om een product te bestellen, hebben we een bestelling nodig. Deze bestelling kan één of meerdere producten bevatten. Tevens heeft een bestelling nul of meerdere betalingen. We hebben ook nog een gebruiker nodig en het producttype.
We kunnen die elke keer met de hand aanmaken, maar dat is onhandig. De oplossing hiervoor is een zogenaamde factory. Een factory is in feite een soort recept om een object in de database aan te maken. Zo hebben we bijvoorbeeld een DomainFactory. Als een test een domein nodig heeft, maakt de DomainFactory het domein aan. Inclusief alles waar dat domein van afhankelijk is, zoals een gebruiker en een bestelling.
De afgelopen tijd hebben we alle tests aangepast, zodat deze voor alle data-factories zijn te gebruiken. Dat scheelt enorm. Op deze manier hebben we onze dataset niet langer nodig en kunnen we Django upgraden!
Join The A-Team!
We zijn de afgelopen tijd hard bezig geweest met het verbeteren van onze testinfrastructuur en met het treffen van voorbereidingen voor de Django-upgrade. Daarna zijn we natuurlijk niet klaar. We willen de komende tijd nog meer grote structurele aanpassingen maken, zodat we in de toekomst sneller nieuwe features kunnen maken waar jij en wij blij van worden 🙂
Wil jij ons daarbij helpen? Kom werken voor Antagonist! Wij beloven dat jij als developer een uitdagende baan krijgt bij één van de meest innovatieve hostingproviders van Nederland. Als je inhoudelijke vragen hebt over de functie, dan kun je natuurlijk altijd vrijblijvend contact met ons opnemen.
P.S. Wil je op de hoogte blijven van alle artikelen, updates, tips en trucs die verschijnen op ons blog? Dat kan! Rechts bovenin via RSS, e-mail, het liken op Facebook, het +1’en op Google+ of het volgen op Twitter.