Veien til typesjekking av 4 millioner linjer med Python-kode. Del 3

Vi presenterer den tredje delen av oversettelsen av materialet om banen som Dropbox tok da vi implementerte et typekontrollsystem for Python-kode.

Veien til typesjekking av 4 millioner linjer med Python-kode. Del 3

→ Tidligere deler: første и andre

Når 4 millioner linjer med maskinskrevet kode

En annen stor utfordring (og den nest vanligste bekymringen blant de som ble spurt internt) var å øke mengden kode som dekkes av typesjekker i Dropbox. Vi har prøvd flere tilnærminger for å løse dette problemet, fra naturlig å øke størrelsen på den innskrevne kodebasen til å fokusere mypy-teamets innsats på statisk og dynamisk automatisert typeslutning. Til slutt virket det som om det ikke var noen enkel vinnerstrategi, men vi var i stand til å oppnå rask vekst i volumet av kommentert kode ved å kombinere mange tilnærminger.

Som et resultat har vårt største Python-lager (med backend-kode) nesten 4 millioner linjer med kommentert kode. Arbeidet med statisk kodeskriving ble fullført på cirka tre år. Mypy støtter nå ulike typer kodedekningsrapporter som gjør det enklere å overvåke skrivefremdriften. Spesielt kan vi generere rapporter om kode med uklarheter i typer, som for eksempel eksplisitt bruk av en type Any i merknader som ikke kan verifiseres, eller med ting som import av tredjepartsbiblioteker som ikke har typekommentarer. Som en del av et prosjekt for å forbedre nøyaktigheten av typesjekking i Dropbox, bidro vi til å forbedre typedefinisjonene (såkalte stubfiler) for noen populære åpen kildekode-biblioteker i et sentralisert Python-lager maskinskrevet.

Vi implementerte (og standardiserte i påfølgende PEP-er) nye funksjoner i typesystemet som tillater mer presise typer for noen spesifikke Python-mønstre. Et bemerkelsesverdig eksempel på dette er TypeDict, som gir typer for JSON-lignende ordbøker som har et fast sett med strengnøkler, hver med en verdi av sin egen type. Vi vil fortsette å utvide typesystemet. Vårt neste skritt vil sannsynligvis være å forbedre støtten for Pythons numeriske evner.

Veien til typesjekking av 4 millioner linjer med Python-kode. Del 3
Antall linjer med kommentert kode: server

Veien til typesjekking av 4 millioner linjer med Python-kode. Del 3
Antall linjer med kommentert kode: klient

Veien til typesjekking av 4 millioner linjer med Python-kode. Del 3
Totalt antall linjer med kommentert kode

Her er en oversikt over hovedtrekkene til tingene vi gjorde for å øke mengden annotert kode i Dropbox:

Annoteringsstrenghet. Vi økte gradvis kravene til strengheten ved å kommentere ny kode. Vi startet med linter-tips som foreslo å legge til merknader til filer som allerede hadde noen merknader. Vi krever nå typekommentarer i nye Python-filer og i de fleste eksisterende filer.

Skrive rapporter. Vi sender team ukentlig rapporter om nivået på å skrive inn koden deres og gir råd om hva som bør kommenteres først.

Popularisering av mypy. Vi snakker om mypy på arrangementer og snakker med team for å hjelpe dem i gang med typekommentarer.

Avstemninger. Vi gjennomfører periodiske brukerundersøkelser for å identifisere store problemer. Vi er klare til å gå ganske langt i å løse disse problemene (til og med å lage et nytt språk for å øke hastigheten på mypy!).

Opptreden. Vi har forbedret ytelsen til mypy betraktelig ved å bruke daemonen og mypyc. Dette ble gjort for å jevne ut ulempene som oppstår under merknadsprosessen, og for å kunne jobbe med store mengder kode.

Integrasjon med redaktører. Vi har bygget verktøy for å støtte kjøring av mypy i redigeringsprogrammer som er populære på Dropbox. Dette inkluderer PyCharm, Vim og VS Code. Dette forenklet i stor grad prosessen med å kommentere koden og sjekke funksjonaliteten. Denne typen handlinger er vanlige når man merker eksisterende kode.

Statisk analyse. Vi laget et verktøy for å utlede funksjonssignaturer ved å bruke statiske analyseverktøy. Dette verktøyet kan bare fungere i relativt enkle situasjoner, men det hjalp oss med å øke kodetypedekningen uten mye innsats.

Støtte for tredjepartsbiblioteker. Mange av prosjektene våre bruker SQLAlchemy-verktøysettet. Den utnytter de dynamiske egenskapene til Python som PEP 484-typer ikke er i stand til å modellere direkte. Vi, i samsvar med PEP 561, opprettet den tilsvarende stubbfilen og skrev en plugin for mypy (åpen kilde), som forbedrer SQLAlchemy-støtten.

Vanskeligheter vi møtte

Veien til 4 millioner linjer med maskinskrevet kode har ikke alltid vært lett for oss. På denne stien møtte vi mange jettegryter og gjorde flere feil. Dette er noen av problemene vi møtte. Vi håper at det å fortelle om dem vil hjelpe andre til å unngå lignende problemer.

Manglende filer. Vi startet arbeidet med å sjekke bare en liten mengde filer. Alt som ikke er inkludert i disse filene, ble ikke sjekket. Filer ble lagt til skannelisten da de første merknadene dukket opp i dem. Hvis noe ble importert fra en modul utenfor verifiseringsomfanget, snakket vi om å jobbe med verdier som Any, som ikke ble testet i det hele tatt. Dette førte til et betydelig tap av skrivenøyaktighet, spesielt i de tidlige stadiene av migrasjonen. Denne tilnærmingen har fungert overraskende bra så langt, selv om en typisk situasjon er at å legge til filer i omfanget av gjennomgangen avslører problemer i andre deler av kodebasen. I verste fall, da to isolerte kodeområder ble slått sammen, der, uavhengig av hverandre, typer allerede var kontrollert, viste det seg at typene av disse områdene var inkompatible med hverandre. Dette førte til behovet for å gjøre mange endringer i merknadene. Når vi ser tilbake nå, innser vi at vi burde ha lagt til kjernebiblioteksmoduler til kontrollområdet for mypy-type tidligere. Dette vil gjøre arbeidet vårt mye mer forutsigbart.

Kommenterer gammel kode. Da vi startet, hadde vi omtrent 4 millioner linjer med eksisterende Python-kode. Det var tydelig at det ikke var en lett oppgave å kommentere all denne koden. Vi har laget et verktøy kalt PyAnnotate som kan samle inn typeinformasjon mens testene kjører og kan legge til typekommentarer til koden din basert på informasjonen som samles inn. Vi har imidlertid ikke lagt merke til en spesielt utbredt bruk av dette verktøyet. Innsamling av type informasjon gikk sakte, og automatisk genererte merknader krevde ofte mange manuelle redigeringer. Vi tenkte på å kjøre dette verktøyet automatisk hver gang vi gjennomgår kode, eller på å samle inn typeinformasjon basert på analyse av et lite volum av faktiske nettverksforespørsler, men bestemte oss for å ikke gjøre det fordi begge tilnærmingene var for risikabelt.

Som et resultat kan det bemerkes at det meste av koden ble manuelt kommentert av eierne. For å lede denne prosessen i riktig retning utarbeider vi rapporter om spesielt viktige moduler og funksjoner som må kommenteres. For eksempel er det viktig å gi typekommentarer for en bibliotekmodul som brukes hundrevis av steder. Men en gammel tjeneste som erstattes med en ny er ikke lenger så viktig å kommentere. Vi eksperimenterer også med å bruke statisk analyse for å generere typekommentarer for eldre kode.

Syklisk import. Ovenfor snakket jeg om syklisk import ("avhengighetsflokene"), hvis eksistens gjorde det vanskelig å øke hastigheten på mypy. Vi måtte også jobbe hardt for å få mypy til å støtte alle slags idiomer som er forårsaket av denne sykliske importen. Vi har nylig fullført et stort systemredesignprosjekt som løste de fleste av mypys problemer angående sirkulær import. Disse problemene stammet faktisk fra de aller første dagene av prosjektet, tilbake fra Alore, det pedagogiske språket som mypy-prosjektet opprinnelig var fokusert på. Alore-syntaks gjør det enkelt å løse problemer med sykliske importkommandoer. Moderne mypy har arvet noen begrensninger fra sin tidligere, enkle implementering (som passet utmerket for Alore). Python gjør det vanskelig å jobbe med sirkulær import, hovedsakelig fordi uttrykk er tvetydige. For eksempel kan en tilordningsoperasjon faktisk definere et typealias. Mypy er ikke alltid i stand til å oppdage ting som dette før det meste av importsløyfen er behandlet. Det var ingen slike uklarheter i Alore. Dårlige beslutninger tatt i de tidlige stadiene av systemutvikling kan gi en ubehagelig overraskelse for programmereren mange år senere.

Resultater: veien til 5 millioner linjer med kode og nye horisonter

Mypy-prosjektet har kommet langt – fra tidlige prototyper til et system som kontrollerer 4 millioner linjer med produksjonskodetyper. Etter hvert som mypy utviklet seg, ble Pythons typehint standardisert. I disse dager har et kraftig økosystem utviklet seg rundt å skrive Python-kode. Den har et sted for bibliotekstøtte, den inneholder hjelpeverktøy for IDE-er og redaktører, den har flere typekontrollsystemer, som hver har sine egne fordeler og ulemper.

Selv om typekontroll allerede er en selvfølge hos Dropbox, tror jeg at vi fortsatt er i begynnelsen av å skrive Python-kode. Jeg tror teknologier for typesjekking vil fortsette å utvikle seg og forbedres.

Hvis du ikke allerede har brukt typekontroll i ditt storskala Python-prosjekt, så vet at det nå er et veldig godt tidspunkt å begynne å gå over til statisk skriving. Jeg har snakket med de som har gjort en lignende overgang. Ingen av dem angret. Typekontroll gjør Python til et språk som er mye bedre egnet til å utvikle store prosjekter enn «vanlig Python».

Kjære lesere! Bruker du typekontroll i Python-prosjektene dine?

Veien til typesjekking av 4 millioner linjer med Python-kode. Del 3
Veien til typesjekking av 4 millioner linjer med Python-kode. Del 3

Kilde: www.habr.com

Legg til en kommentar