Stien til at typetjekke 4 millioner linjer Python-kode. Del 3

Vi præsenterer for din opmærksomhed den tredje del af oversættelsen af ​​materiale om den vej, som Dropbox tog, da vi implementerede et typekontrolsystem for Python-kode.

Stien til at typetjekke 4 millioner linjer Python-kode. Del 3

→ Tidligere dele: først и sekund

Når 4 millioner linjer med maskinskrevet kode

En anden stor udfordring (og den næstmest almindelige bekymring blandt de adspurgte internt) var at øge mængden af ​​kode, der var dækket af typetjek i Dropbox. Vi har prøvet flere tilgange til at løse dette problem, fra naturligt at øge størrelsen af ​​den indtastede kodebase til at fokusere mypy-teamets indsats på statisk og dynamisk automatiseret typeslutning. I sidste ende så det ud til, at der ikke var nogen simpel vinderstrategi, men vi var i stand til at opnå hurtig vækst i mængden af ​​kommenteret kode ved at kombinere mange tilgange.

Som et resultat har vores største Python-lager (med backend-kode) næsten 4 millioner linjer med annoteret kode. Arbejdet med statisk kodetastning blev afsluttet på cirka tre år. Mypy understøtter nu forskellige typer kodedækningsrapporter, der gør det nemmere at overvåge skrivefremskridt. Vi kan især generere rapporter om kode med uklarheder i typer, som fx eksplicit brug af en type Any i annoteringer, der ikke kan verificeres, eller med ting som import af tredjepartsbiblioteker, der ikke har typeannoteringer. Som en del af et projekt for at forbedre nøjagtigheden af ​​typekontrol i Dropbox, bidrog vi til at forbedre typedefinitionerne (såkaldte stubfiler) for nogle populære open source-biblioteker i et centraliseret Python-lager maskinskrevne.

Vi implementerede (og standardiserede i efterfølgende PEP'er) nye funktioner i typesystemet, der tillader mere præcise typer for nogle specifikke Python-mønstre. Et bemærkelsesværdigt eksempel på dette er TypeDict, som giver typer til JSON-lignende ordbøger, der har et fast sæt strengnøgler, hver med en værdi af sin egen type. Vi vil fortsætte med at udvide typesystemet. Vores næste skridt vil sandsynligvis være at forbedre understøttelsen af ​​Pythons numeriske muligheder.

Stien til at typetjekke 4 millioner linjer Python-kode. Del 3
Antal linjer med annoteret kode: server

Stien til at typetjekke 4 millioner linjer Python-kode. Del 3
Antal linjer med annoteret kode: klient

Stien til at typetjekke 4 millioner linjer Python-kode. Del 3
Samlet antal linjer med kommenteret kode

Her er en oversigt over hovedfunktionerne i de ting, vi gjorde for at øge mængden af ​​kommenteret kode i Dropbox:

Anmærkningsstrenghed. Vi øgede gradvist kravene til strengheden ved at kommentere ny kode. Vi startede med linter tips, der foreslog at tilføje annoteringer til filer, der allerede havde nogle annoteringer. Vi kræver nu typeanmærkninger i nye Python-filer og i de fleste eksisterende filer.

Indtastning af rapporter. Vi sender teams ugentlige rapporter om niveauet for indtastning af deres kode og giver råd om, hvad der skal annoteres først.

Popularisering af mypy. Vi taler om mypy ved arrangementer og taler med teams for at hjælpe dem i gang med typeanmærkninger.

Afstemninger. Vi gennemfører periodiske brugerundersøgelser for at identificere store problemer. Vi er klar til at gå ret langt med at løse disse problemer (selv at skabe et nyt sprog for at fremskynde mypy!).

Ydeevne. Vi har forbedret mypys ydeevne betydeligt ved at bruge dæmonen og mypyc. Dette er gjort for at udjævne de gener, der opstår under annoteringsprocessen, og for at kunne arbejde med store mængder kode.

Integration med redaktører. Vi har bygget værktøjer til at understøtte at køre mypy i editorer, der er populære på Dropbox. Dette inkluderer PyCharm, Vim og VS Code. Dette forenklede i høj grad processen med at kommentere koden og kontrollere dens funktionalitet. Disse typer handlinger er almindelige, når man kommenterer eksisterende kode.

Statisk analyse. Vi skabte et værktøj til at udlede funktionssignaturer ved hjælp af statiske analyseværktøjer. Dette værktøj kan kun fungere i relativt simple situationer, men det hjalp os med at øge vores kodetypedækning uden stor indsats.

Support til tredjepartsbiblioteker. Mange af vores projekter bruger SQLAlchemy-værktøjssættet. Det udnytter de dynamiske muligheder i Python, som PEP 484-typer ikke er i stand til at modellere direkte. Vi, i overensstemmelse med PEP 561, oprettede den tilsvarende stub-fil og skrev et plugin til mypy (åben kildekode), som forbedrer SQLAlchemy-understøttelse.

Vanskeligheder vi stødte på

Vejen til 4 millioner linjer med indtastet kode har ikke altid været let for os. På denne sti stødte vi på mange huller og lavede flere fejl. Dette er nogle af de problemer, vi stødte på. Vi håber, at det at fortælle om dem vil hjælpe andre til at undgå lignende problemer.

Manglende filer. Vi startede vores arbejde med kun at kontrollere en lille mængde filer. Alt, der ikke var inkluderet i disse filer, blev ikke kontrolleret. Filer blev tilføjet til scanningslisten, da de første anmærkninger dukkede op i dem. Hvis noget blev importeret fra et modul placeret uden for verifikationsomfanget, så talte vi om at arbejde med værdier som Any, som slet ikke blev testet. Dette førte til et betydeligt tab af skrivenøjagtighed, især i de tidlige stadier af migration. Denne tilgang har fungeret overraskende godt indtil videre, selvom en typisk situation er, at tilføjelse af filer til omfanget af gennemgangen afslører problemer i andre dele af kodebasen. I værste fald, da to isolerede kodeområder blev slået sammen, hvor typer uafhængigt af hinanden allerede var kontrolleret, viste det sig, at typerne af disse områder var inkompatible med hinanden. Dette førte til behovet for at foretage mange ændringer i annoteringerne. Når vi ser tilbage nu, indser vi, at vi tidligere burde have tilføjet kernebiblioteksmoduler til mypys typekontrolområde. Det ville gøre vores arbejde meget mere forudsigeligt.

Annotering af gammel kode. Da vi startede, havde vi omkring 4 millioner linjer med eksisterende Python-kode. Det var tydeligt, at det ikke var en let opgave at kommentere al denne kode. Vi har oprettet et værktøj kaldet PyAnnotate, der kan indsamle typeoplysninger, efterhånden som test kører, og kan tilføje typeanmærkninger til din kode baseret på de indsamlede oplysninger. Vi har dog ikke bemærket en særlig udbredt anvendelse af dette værktøj. Indsamling af typeoplysninger var langsom, og automatisk genererede annoteringer krævede ofte mange manuelle redigeringer. Vi tænkte på at køre dette værktøj automatisk, hver gang vi gennemgår kode, eller indsamle typeoplysninger baseret på at analysere en lille mængde faktiske netværksanmodninger, men besluttede at lade være, fordi begge metoder var for risikabelt.

Som et resultat kan det bemærkes, at det meste af koden blev manuelt kommenteret af dens ejere. For at guide denne proces i den rigtige retning udarbejder vi rapporter om særligt vigtige moduler og funktioner, der skal kommenteres. For eksempel er det vigtigt at levere typeanmærkninger til et biblioteksmodul, der bruges hundredvis af steder. Men en gammel tjeneste, der bliver erstattet med en ny, er ikke længere så vigtig at kommentere. Vi eksperimenterer også med at bruge statisk analyse til at generere typeannoteringer til ældre kode.

Cyklisk import. Ovenfor talte jeg om cyklisk import ("afhængighedsvirvlerne"), hvis eksistens gjorde det vanskeligt at fremskynde mypy. Vi var også nødt til at arbejde hårdt for at få mypy til at understøtte alle former for idiomer, der er forårsaget af disse cykliske importer. Vi har for nylig afsluttet et stort systemredesign-projekt, der løste de fleste af mypys problemer vedrørende cirkulær import. Disse problemer stammede faktisk fra projektets meget tidlige dage, tilbage fra Alore, det undervisningssprog, som mypy-projektet oprindeligt var fokuseret på. Alore-syntaks gør det nemt at løse problemer med cykliske importkommandoer. Moderne mypy har arvet nogle begrænsninger fra sin tidlige, usofistikerede implementering (hvilket passede godt til Alore). Python gør det svært at arbejde med cirkulær import, primært fordi udtryk er tvetydige. For eksempel kan en tildelingsoperation faktisk definere et typealias. Mypy er ikke altid i stand til at opdage ting som dette, før det meste af importsløjfen er blevet behandlet. Der var ingen sådanne uklarheder i Alore. Dårlige beslutninger taget i de tidlige stadier af systemudvikling kan give en ubehagelig overraskelse for programmøren mange år senere.

Resultater: vejen til 5 millioner linjer kode og nye horisonter

Mypy-projektet er nået langt - fra tidlige prototyper til et system, der styrer 4 millioner linjer af produktionskodetyper. Efterhånden som mypy udviklede sig, blev Pythons typetip standardiseret. I disse dage har et kraftfuldt økosystem udviklet sig omkring at skrive Python-kode. Det har et sted til bibliotekssupport, det indeholder hjælpeværktøjer til IDE'er og redaktører, det har flere typekontrolsystemer, som hver har sine egne fordele og ulemper.

Selvom typekontrol allerede er en selvfølge hos Dropbox, tror jeg, vi stadig er i de tidlige dage med at skrive Python-kode. Jeg tror, ​​at typekontrolteknologier vil fortsætte med at udvikle sig og forbedres.

Hvis du ikke allerede har brugt typekontrol i dit storstilede Python-projekt, så ved, at det nu er et meget godt tidspunkt at begynde at gå over til statisk skrivning. Jeg har talt med dem, der har lavet en lignende overgang. Ingen af ​​dem fortrød det. Typekontrol gør Python til et sprog, der er meget bedre egnet til at udvikle store projekter end "almindelig Python."

Kære læsere! Bruger du typekontrol i dine Python-projekter?

Stien til at typetjekke 4 millioner linjer Python-kode. Del 3
Stien til at typetjekke 4 millioner linjer Python-kode. Del 3

Kilde: www.habr.com

Tilføj en kommentar