Het pad naar het typechecken van 4 miljoen regels Python-code. Deel 3

We presenteren onder uw aandacht het derde deel van de vertaling van materiaal over het pad dat Dropbox heeft gevolgd bij het implementeren van een typecontrolesysteem voor Python-code.

Het pad naar het typechecken van 4 miljoen regels Python-code. Deel 3

→ Vorige delen: eerste и tweede

Bereik van 4 miljoen regels getypte code

Een andere grote uitdaging (en de op een na meest voorkomende zorg onder de intern ondervraagden) was het vergroten van de hoeveelheid code die onder typecontroles in Dropbox valt. We hebben verschillende benaderingen geprobeerd om dit probleem op te lossen, van het natuurlijk vergroten van de omvang van de getypte codebase tot het concentreren van de inspanningen van het mypy-team op statische en dynamische geautomatiseerde type-inferentie. Uiteindelijk leek het erop dat er geen eenvoudige winnende strategie bestond, maar dat we door een combinatie van vele benaderingen een snelle groei van het volume aan geannoteerde code konden realiseren.

Als gevolg hiervan beschikt onze grootste Python-repository (met backend-code) over bijna 4 miljoen regels geannoteerde code. Het werk aan het typen van statische codes werd in ongeveer drie jaar voltooid. Mypy ondersteunt nu verschillende soorten codedekkingsrapporten die het gemakkelijker maken om de voortgang van het typen te controleren. We kunnen met name rapporten genereren over code met onduidelijkheden in typen, zoals bijvoorbeeld expliciet gebruik van een type Any in annotaties die niet kunnen worden geverifieerd, of met zaken als het importeren van bibliotheken van derden die geen typeannotaties hebben. Als onderdeel van een project om de nauwkeurigheid van typecontrole in Dropbox te verbeteren, hebben we bijgedragen aan het verbeteren van de typedefinities (zogenaamde stub-bestanden) voor een aantal populaire open source-bibliotheken in een gecentraliseerde Python-repository getypt.

We hebben nieuwe functies van het typesysteem geïmplementeerd (en gestandaardiseerd in daaropvolgende PEP's) die nauwkeurigere typen voor sommige specifieke Python-patronen mogelijk maken. Een opmerkelijk voorbeeld hiervan is TypeDict, dat typen biedt voor JSON-achtige woordenboeken met een vaste set tekenreekssleutels, elk met een waarde van een eigen type. We zullen het typesysteem blijven uitbreiden. Onze volgende stap zal waarschijnlijk het verbeteren van de ondersteuning voor de numerieke mogelijkheden van Python zijn.

Het pad naar het typechecken van 4 miljoen regels Python-code. Deel 3
Aantal regels geannoteerde code: server

Het pad naar het typechecken van 4 miljoen regels Python-code. Deel 3
Aantal regels geannoteerde code: client

Het pad naar het typechecken van 4 miljoen regels Python-code. Deel 3
Totaal aantal regels geannoteerde code

Hier is een overzicht van de belangrijkste kenmerken van de dingen die we hebben gedaan om de hoeveelheid geannoteerde code in Dropbox te vergroten:

Annotatie nauwkeurigheid. We hebben geleidelijk de vereisten voor de nauwkeurigheid van het annoteren van nieuwe code verhoogd. We zijn begonnen met lintertips die suggereerden om annotaties toe te voegen aan bestanden die al enkele annotaties bevatten. We hebben nu typeannotaties nodig in nieuwe Python-bestanden en in de meeste bestaande bestanden.

Rapporten typen. We sturen teams wekelijks rapporten over het niveau van het typen van hun code en geven advies over wat als eerste moet worden geannoteerd.

Popularisering van mypy. We praten over mypy op evenementen en praten met teams om hen op weg te helpen met typeannotaties.

Opiniepeilingen. We voeren periodiek gebruikersonderzoeken uit om grote problemen te identificeren. We zijn bereid heel ver te gaan in het oplossen van deze problemen (zelfs door een nieuwe taal te creëren om mypy te versnellen!).

Prestatie. We hebben de prestaties van mypy aanzienlijk verbeterd door de daemon en mypyc te gebruiken. Dit is gedaan om de ongemakken die ontstaan ​​tijdens het annotatieproces weg te nemen en om met grote hoeveelheden code te kunnen werken.

Integratie met editors. We hebben tools ontwikkeld ter ondersteuning van het uitvoeren van mypy in editors die populair zijn op Dropbox. Dit omvat PyCharm, Vim en VS Code. Dit vereenvoudigde het proces van het annoteren van de code en het controleren van de functionaliteit ervan aanzienlijk. Dit soort acties komen vaak voor bij het annoteren van bestaande code.

Statische analyse. We hebben een tool gemaakt om functiesignaturen af ​​te leiden met behulp van statische analysetools. Deze tool werkt alleen in relatief eenvoudige situaties, maar heeft ons geholpen de dekking van codetypen zonder veel moeite te vergroten.

Ondersteuning voor bibliotheken van derden. Veel van onze projecten maken gebruik van de SQLAlchemy-toolkit. Het maakt gebruik van de dynamische mogelijkheden van Python die PEP 484-typen niet rechtstreeks kunnen modelleren. We hebben, in overeenstemming met PEP 561, het bijbehorende stub-bestand gemaakt en een plug-in voor mypy geschreven (open source), wat de ondersteuning voor SQLAlchemy verbetert.

Moeilijkheden die we tegenkwamen

Het pad naar 4 miljoen regels getypte code is voor ons niet altijd gemakkelijk geweest. Op dit pad kwamen we veel kuilen tegen en maakten we verschillende fouten. Dit zijn enkele van de problemen die we tegenkwamen. We hopen dat het vertellen ervan anderen zal helpen soortgelijke problemen te voorkomen.

Ontbrekende bestanden. We zijn ons werk begonnen met het controleren van slechts een klein aantal bestanden. Alles wat niet in deze bestanden was opgenomen, werd niet gecontroleerd. Bestanden werden aan de scanlijst toegevoegd toen de eerste annotaties erin verschenen. Als er iets werd geïmporteerd uit een module die zich buiten het verificatiebereik bevond, dan hadden we het over het werken met waarden als Any, die helemaal niet zijn getest. Dit leidde tot een aanzienlijk verlies aan typnauwkeurigheid, vooral in de vroege stadia van de migratie. Deze aanpak heeft tot nu toe verrassend goed gewerkt, hoewel een typische situatie is dat het toevoegen van bestanden aan de reikwijdte van de review problemen in andere delen van de codebase aan het licht brengt. In het ergste geval, toen twee geïsoleerde codegebieden werden samengevoegd, waarin typen onafhankelijk van elkaar al waren gecontroleerd, bleek dat de typen van deze gebieden niet met elkaar compatibel waren. Dit leidde tot de noodzaak om veel wijzigingen in de annotaties aan te brengen. Als we nu terugkijken, realiseren we ons dat we eerder kernbibliotheekmodules aan het typecontrolegebied van mypy hadden moeten toevoegen. Dit zou ons werk veel voorspelbaarder maken.

Annoteren van oude code. Toen we begonnen, hadden we ongeveer 4 miljoen regels bestaande Python-code. Het was duidelijk dat het annoteren van al deze code geen gemakkelijke taak was. We hebben een tool gemaakt met de naam PyAnnotate die type-informatie kan verzamelen terwijl tests worden uitgevoerd en type-annotaties aan uw code kan toevoegen op basis van de verzamelde informatie. We hebben echter geen bijzonder brede adoptie van deze tool opgemerkt. Het verzamelen van type-informatie verliep traag en automatisch gegenereerde annotaties vereisten vaak veel handmatige bewerkingen. We dachten erover om deze tool automatisch uit te voeren elke keer dat we code beoordelen, of om type-informatie te verzamelen op basis van het analyseren van een klein aantal daadwerkelijke netwerkverzoeken, maar besloten dit niet te doen omdat beide benaderingen te riskant waren.

Als gevolg hiervan kan worden opgemerkt dat het grootste deel van de code handmatig is geannoteerd door de eigenaren. Om dit proces in goede banen te leiden, stellen wij rapporten op over bijzonder belangrijke modules en functies die moeten worden geannoteerd. Het is bijvoorbeeld belangrijk om typeannotaties te geven voor een bibliotheekmodule die op honderden plaatsen wordt gebruikt. Maar een oude dienst die wordt vervangen door een nieuwe is niet meer zo belangrijk om te annoteren. We experimenteren ook met het gebruik van statische analyse om typeannotaties voor oudere code te genereren.

Cyclische import. Hierboven had ik het over cyclische importen (de ‘afhankelijkheidsknooppunten’), waarvan het bestaan ​​het moeilijk maakte om mypy te versnellen. We moesten ook hard werken om mypy allerlei idiomen te laten ondersteunen die door deze cyclische importen worden veroorzaakt. We hebben onlangs een groot systeemherontwerpproject voltooid waarmee de meeste problemen van mypy met betrekking tot circulaire import zijn opgelost. Deze problemen vloeiden eigenlijk voort uit de allereerste dagen van het project, terug uit Alore, de educatieve taal waar het mypy-project oorspronkelijk op gericht was. De Alore-syntaxis maakt het eenvoudig om problemen met cyclische importopdrachten op te lossen. Moderne mypy heeft enkele beperkingen geërfd van de eerdere, eenvoudige implementatie (die uitstekend bij Alore paste). Python maakt het werken met circulaire import lastig, vooral omdat uitdrukkingen dubbelzinnig zijn. Een toewijzingsbewerking kan bijvoorbeeld feitelijk een typealias definiëren. Mypy kan dit soort dingen niet altijd detecteren totdat het grootste deel van de importlus is verwerkt. Dergelijke dubbelzinnigheden bestonden niet in Alore. Slechte beslissingen die in de vroege stadia van de systeemontwikkeling worden genomen, kunnen vele jaren later voor een onaangename verrassing voor de programmeur zorgen.

Resultaten: het pad naar 5 miljoen regels code en nieuwe horizonten

Het mypy-project heeft een lange weg afgelegd: van vroege prototypes tot een systeem dat 4 miljoen regels productiecodetypes bestuurt. Naarmate mypy evolueerde, werden de typehints van Python gestandaardiseerd. Tegenwoordig heeft zich een krachtig ecosysteem ontwikkeld rond het typen van Python-code. Er is plaats voor bibliotheekondersteuning, het bevat hulpprogramma's voor IDE's en editors, het heeft verschillende typebesturingssystemen, die elk hun eigen voor- en nadelen hebben.

Hoewel typecontrole bij Dropbox al een vanzelfsprekendheid is, denk ik dat we ons nog in de begindagen bevinden van het typen van Python-code. Ik denk dat de technologieën voor typecontrole zullen blijven evolueren en verbeteren.

Als je typecontrole nog niet hebt gebruikt in je grootschalige Python-project, weet dan dat dit een goed moment is om over te stappen op statisch typen. Ik heb gesproken met mensen die een soortgelijke overstap hebben gemaakt. Geen van hen had er spijt van. Type checking maakt Python tot een taal die veel beter geschikt is voor het ontwikkelen van grote projecten dan ‘gewone Python’.

Beste lezers! Maakt u gebruik van typecontrole in uw Python-projecten?

Het pad naar het typechecken van 4 miljoen regels Python-code. Deel 3
Het pad naar het typechecken van 4 miljoen regels Python-code. Deel 3

Bron: www.habr.com

Voeg een reactie