It paad nei typechecking 4 miljoen rigels fan Python-koade. Diel 1

Hjoed bringe wy jo oandacht it earste diel fan 'e oersetting fan it materiaal oer hoe't Dropbox omgiet mei typekontrôle fan Python-koade.

It paad nei typechecking 4 miljoen rigels fan Python-koade. Diel 1

Dropbox skriuwt in protte yn Python. It is in taal dy't wy ekstreem breed brûke, sawol foar back-end-tsjinsten as buroblêdkliïntapplikaasjes. Wy brûke ek in protte Go, TypeScript en Rust, mar Python is ús haadtaal. Sjoen ús skaal, en wy prate oer miljoenen rigels fan Python-koade, die bliken dat it dynamyske typen fan sa'n koade har begryp ûnnedich komplisearre en begon de arbeidsproduktiviteit serieus te beynfloedzjen. Om dit probleem te beheinen, binne wy ​​begon ús koade stadichoan oer te setten nei statyske typekontrôle mei mypy. Dit is wierskynlik it populêrste standalone type kontrôlesysteem foar Python. Mypy is in iepen boarne-projekt, har haadûntwikkelders wurkje yn Dropbox.

Dropbox wie ien fan 'e earste bedriuwen om statyske typekontrôle yn Python-koade op dizze skaal te ymplementearjen. Mypy wurdt dizze dagen brûkt yn tûzenen projekten. Dit ark ûntelbere kearen, sa't se sizze, "test yn 'e striid." Wy binne in lange wei kommen om te kommen wêr't wy no binne. Underweis wiene d'r in protte mislearre ûndernimmingen en mislearre eksperiminten. Dizze post behannelt de skiednis fan statyske typekontrôle yn Python, fan har rotsige begjin as ûnderdiel fan myn ûndersyksprojekt, oant hjoed de dei, doe't typekontrôle en type-oanwizings gewoan wurden binne foar ûntelbere ûntwikkelders dy't yn Python skriuwe. Dizze meganismen wurde no stipe troch in protte ark lykas IDE's en koade-analyzers.

Lês it twadde diel

Wêrom is type kontrôle nedich?

As jo ​​oait dynamysk typte Python hawwe brûkt, kinne jo miskien wat betizing hawwe oer wêrom't d'r de lêste tiid sa'n gedoe west hat om statysk typen en mypy. Of miskien fine jo Python krekt fanwegen syn dynamyske typen, en wat bart makket jo gewoan oerstjoer. De kaai foar de wearde fan statysk typen is de skaal fan 'e oplossingen: hoe grutter jo projekt, hoe mear jo nei statysk typen leanje, en op it lêst, hoe mear jo it echt nedich binne.

Stel dat in bepaald projekt hat berikt de grutte fan tsientûzenen rigels, en it die bliken dat ferskate programmeurs wurkje oan it. Sjoch nei in ferlykber projekt, basearre op ús ûnderfining, kinne wy ​​​​sizze dat it begripen fan har koade de kaai sil wêze om ûntwikkelders produktyf te hâlden. Sûnder type annotaasjes kin it lestich wêze om bygelyks út te finen hokker arguminten nei in funksje trochjaan moatte, of hokker typen in funksje weromkomme kin. Hjir binne typyske fragen dy't faak lestich binne te beantwurdzjen sûnder type annotaasjes te brûken:

  • Kin dizze funksje werom None?
  • Wat moat dit argumint wêze? items?
  • Wat is it type attribút id: int is it, str, of miskien wat oanpast type?
  • Moat dit argumint in list wêze? Is it mooglik om in tuple oan it trochjaan?

As jo ​​​​nei it folgjende type-oannotearre koadefragment sjogge en besykje ferlykbere fragen te beantwurdzjen, docht bliken dat dit de ienfâldichste taak is:

class Resource:
    id: bytes
    ...
    def read_metadata(self, 
                      items: Sequence[str]) -> Dict[str, MetadataItem]:
        ...

  • read_metadata komt net werom None, sûnt de return type is net Optional[…].
  • Argumint items is in folchoarder fan rigels. It kin net willekeurich iterearre wurde.
  • Attribút id is in string fan bytes.

Yn in ideale wrâld soe men ferwachtsje dat al sokke subtiliteiten beskreaun wurde yn 'e ynboude dokumintaasje (docstring). Mar ûnderfining jout in protte foarbylden fan it feit dat sokke dokumintaasje wurdt faak net waarnommen yn de koade dêr't jo moatte wurkje. Sels as sokke dokumintaasje oanwêzich is yn 'e koade, kin men net rekkenje op syn absolute korrektheid. Dizze dokumintaasje kin vague, ûnkrekt en iepen wêze foar misferstannen. Yn grutte teams of grutte projekten kin dit probleem ekstreem akuut wurde.

Wylst Python útblinkt yn 'e iere as tuskenstadia fan projekten, kinne op in stuit suksesfolle projekten en bedriuwen dy't Python brûke de fitale fraach te krijen hawwe: "Moatte wy alles opnij skriuwe yn in statysk typte taal?".

Typekontrôlesystemen lykas mypy lossen it boppesteande probleem op troch de ûntwikkelder in formele taal te jaan foar it beskriuwen fan typen, en troch te kontrolearjen dat typedeklaraasjes oerienkomme mei de programma-ymplemintaasje (en, opsjoneel, troch te kontrolearjen op har bestean). Yn 't algemien kinne wy ​​​​sizze dat dizze systemen sa'n ding as soarchfâldich kontrolearre dokumintaasje ta ús beskikke.

It brûken fan sokke systemen hat oare foardielen, en se binne al hielendal net-triviale:

  • It type kontrôlesysteem kin wat lytse (en net sa lyts) flaters detektearje. In typysk foarbyld is as se ferjitte in wearde te ferwurkjen None of in oare spesjale betingst.
  • Koade refactoring is sterk ferienfâldige omdat it type kontrôle systeem is faak hiel akkuraat oer hokker koade moat wurde feroare. Tagelyk hoege wy net te hoopjen op 100% koadedekking mei tests, dy't yn alle gefallen meastentiids net helber binne. Wy hoege net te ferdjipjen yn 'e djipten fan' e stapelspoar om de oarsaak fan it probleem út te finen.
  • Sels op grutte projekten kin mypy faaks folslein type kontrôle dwaan yn in fraksje fan in sekonde. En de útfiering fan tests duorret meastentiids tsientallen sekonden of sels minuten. It type kontrôlesysteem jout de programmeur direkte feedback en lit him syn wurk rapper dwaan. Hy hoecht net mear kwetsbere en dreech te ûnderhâlden ienheidstests te skriuwen dy't echte entiteiten ferfange troch spots en patches gewoan om koade-testresultaten rapper te krijen.

IDE's en bewurkers lykas PyCharm of Visual Studio Code brûke de krêft fan type-annotaasjes om ûntwikkelders te foarsjen fan koadefoltôging, flatermarkearring en stipe foar gewoan brûkte taalkonstruksjes. En dit binne gewoan guon fan 'e foardielen fan typen. Foar guon programmeurs is dit alles it wichtichste argumint foar it typen. Dit is iets dat direkt nei ymplemintaasje profitearret. Dit gebrûksgefal foar typen fereasket gjin apart typekontrôlesysteem lykas mypy, hoewol it moat wurde opmurken dat mypy helpt by it hâlden fan typeannotaasjes yn oerienstimming mei koade.

Eftergrûn fan mypy

De skiednis fan mypy begon yn it Feriene Keninkryk, yn Cambridge, in pear jier foardat ik by Dropbox kaam. Ik bin, as ûnderdiel fan myn doktoraalûndersyk, belutsen west by de ferieniging fan statysk typearre en dynamyske talen. Ik waard ynspirearre troch in artikel oer inkrementeel typen troch Jeremy Siek en Walid Taha, en troch it Typed Racket-projekt. Ik besocht manieren te finen om deselde programmeartaal te brûken foar ferskate projekten - fan lytse skripts oant koadebases besteande út in protte miljoenen rigels. Tagelyk woe ik der foar soargje dat men yn in projekt fan elke skaal net te grutte kompromissen hoecht te meitsjen. In wichtich part fan dit alles wie it idee om stadichoan te ferpleatsen fan in net typearre prototypeprojekt nei in wiidweidich hifke statysk typearre klear produkt. Dizze ideeën wurde tsjintwurdich foar in grut part as fanselssprekkend nommen, mar yn 2010 wie it in probleem dat noch aktyf ûndersocht waard.

Myn oarspronklike wurk yn type kontrôle wie net rjochte op Python. Ynstee brûkte ik in lytse "selsmakke" taal Alore. Hjir is in foarbyld wêrmei jo kinne begripe wêr't wy it oer hawwe (type annotaasjes binne hjir opsjoneel):

def Fib(n as Int) as Int
  if n <= 1
    return n
  else
    return Fib(n - 1) + Fib(n - 2)
  end
end

It brûken fan in ferienfâldige memmetaal is in mienskiplike oanpak dy't brûkt wurdt yn wittenskiplik ûndersyk. Dit is sa, net yn 't minst om't jo fluch eksperiminten kinne útfiere, en ek troch it feit dat wat neat te meitsjen hat mei de stúdzje maklik negeare kin wurde. Programmatalen yn 'e echte wrâld binne de neiging om grutskalige ferskynsels te wêzen mei komplekse ymplemintaasjes, en dit fertraget eksperiminten. Alle resultaten basearre op in ferienfâldige taal lykje lykwols in bytsje fertocht, om't de ûndersiker by it krijen fan dizze resultaten mooglike ôfwagings dy't wichtich binne foar it praktyske gebrûk fan talen opoffere hawwe.

Myn typekontrôler foar Alore like tige kânsryk, mar ik woe it útprobearje troch te eksperimintearjen mei echte koade, dy't, jo soene sizze, net yn Alore skreaun wie. Gelokkich foar my wie de Alore-taal foar in grut part basearre op deselde ideeën as Python. It wie maklik genôch om de typechecker opnij te meitsjen sadat it koe wurkje mei de syntaksis en semantyk fan Python. Dit liet ús besykje te typen kontrolearjen yn iepen boarne Python-koade. Derneist haw ik in transpiler skreaun om koade te konvertearjen skreaun yn Alore nei Python-koade en brûkte it om myn typechecker-koade oer te setten. No hie ik in type kontrôlesysteem skreaun yn Python dat in subset fan Python stipe, in soarte fan dy taal! (Bepaalde arsjitektoanyske besluten dy't sin makken foar Alore wiene min geskikt foar Python, en dit is noch te merken yn dielen fan 'e mypy-koadebase.)

Yn feite koe de taal dy't troch myn typesysteem stipe wurdt op dit punt net hielendal Python wurde neamd: it wie in fariant fan Python fanwegen guon beheiningen fan 'e Python 3-type annotaasjesyntaksis.

It like op in mingsel fan Java en Python:

int fib(int n):
    if n <= 1:
        return n
    else:
        return fib(n - 1) + fib(n - 2)

Ien fan myn ideeën op 'e tiid wie om type-annotaasjes te brûken om prestaasjes te ferbetterjen troch dit soarte Python te kompilearjen nei C, of ​​miskien JVM-bytekoade. Ik kaam op it poadium fan it skriuwen fan in kompilerprototype, mar ik liet dit idee ferlitte, om't typekontrôle sels frij nuttich útseach.

Ik einige mei it presintearjen fan myn projekt by PyCon 2013 yn Santa Clara. Dêr haw ik it ek oer hân mei Guido van Rossum, de woldiedige Python-diktator foar it libben. Hy oertsjûge my om myn eigen syntaksis te fallen en te hâlden mei de standert Python 3-syntaksis. Python 3 stipet funksje-annotaasjes, dus myn foarbyld koe wurde opnij skreaun lykas hjirûnder werjûn, wat resulteart yn in normaal Python-programma:

def fib(n: int) -> int:
    if n <= 1:
        return n
    else:
        return fib(n - 1) + fib(n - 2)

Ik moast wat kompromissen meitsje (alearst wol ik opmerke dat ik om dizze reden myn eigen syntaksis útfûn). Benammen Python 3.3, de meast resinte ferzje fan de taal op it stuit, stipe gjin fariabele annotaasjes. Ik bepraat mei Guido fia e-mail ferskate mooglikheden foar syntaktyske ûntwerp fan sokke annotaasjes. Wy besletten om type opmerkings te brûken foar fariabelen. Dit tsjinne it beëage doel, mar wie wat omslachtig (Python 3.6 joech ús in moaiere syntaksis):

products = []  # type: List[str]  # Eww

Type opmerkings kamen ek handich om Python 2 te stypjen, dy't gjin ynboude stipe hat foar type annotaasjes:

f fib(n):
    # type: (int) -> int
    if n <= 1:
        return n
    else:
        return fib(n - 1) + fib(n - 2)

It die bliken dat dizze (en oare) ôfwikselingen net echt útmakken - de foardielen fan statysk typen betsjutte dat brûkers al gau minder-as-perfekte syntaksis ferjitte. Sûnt gjin spesjale syntaktyske konstruksjes waarden brûkt yn 'e type-kontrolearre Python-koade, besteande Python-ark en koadeferwurkingsprosessen bleaunen normaal te wurkjen, wêrtroch it folle makliker waard foar ûntwikkelders om it nije ark te learen.

Guido oertsjûge my ek om mei te dwaan oan Dropbox neidat ik myn proefskrift foltôge. Dit is wêr't it meast nijsgjirrige diel fan it mypy-ferhaal begjint.

Oanhâlde wurde ...

Dear readers! As jo ​​​​Python brûke, fertel ús dan asjebleaft oer de skaal fan projekten dy't jo yn dizze taal ûntwikkelje.

It paad nei typechecking 4 miljoen rigels fan Python-koade. Diel 1
It paad nei typechecking 4 miljoen rigels fan Python-koade. Diel 1

Boarne: www.habr.com

Add a comment