A strada per a verificazione di 4 milioni di linee di codice Python. Parte 1

Oghje avemu purtatu à a vostra attenzione a prima parte di a traduzzione di u materiale nantu à cumu si tratta Dropbox di u cuntrollu di tipu di codice Python.

A strada per a verificazione di 4 milioni di linee di codice Python. Parte 1

Dropbox scrive assai in Python. Hè una lingua chì usemu assai largamente, sia per i servizii di back-end sia per l'applicazioni client di desktop. Avemu ancu aduprà Go, TypeScript è Rust assai, ma Python hè a nostra lingua principale. In cunsiderà a nostra scala, è parlemu di milioni di linee di codice Python, hè risultatu chì u typing dinamicu di tali codice hà complicatu inutilmente a so intelligenza è hà cuminciatu à affettà seriamente a produtividade di u travagliu. Per mitigà stu prublema, avemu cuminciatu à transizione gradualmente u nostru codice à u cuntrollu di tipu staticu cù mypy. Questu hè probabilmente u sistema di cuntrollu di tipu standalone più populari per Python. Mypy hè un prughjettu open source, i so sviluppatori principali travaglianu in Dropbox.

Dropbox hè stata una di e prime cumpagnie à implementà a verificazione di tipu staticu in codice Python à questa scala. Mypy hè utilizatu in millaie di prughjetti oghje. Stu strumentu innumerevoli volte, cum'è dicenu, "pruvatu in battaglia". Avemu fattu una longa strada per ghjunghje à induve simu avà. In u caminu, ci sò parechje imprese senza successu è esperimenti falluti. Questu post copre a storia di a verificazione di u tipu staticu in Python, da i so principii rocciosi cum'è parte di u mo prughjettu di ricerca, finu à l'oghje, quandu a verificazione di u tipu è l'indicazione di tipu sò diventate cumune per innumerevoli sviluppatori chì scrivenu in Python. Sti miccanismi sò oghji sustinuti da parechji arnesi cum'è IDE è analizatori di codice.

Leghjite a seconda parte

Perchè u cuntrollu di tipu hè necessariu?

Se avete mai utilizatu Python tipatu dinamicamente, pudete avè una certa cunfusione per quessa chì ci hè stata una tale agitazione intornu à a tipografia statica è mypy ultimamente. O forse ti piace Python precisamente per via di a so digitazione dinamica, è ciò chì succede solu ti disturba. A chjave per u valore di a tipografia statica hè a scala di e suluzioni: u più grande u vostru prughjettu, u più appughjate versu u typing staticu, è in fine, più avete veramente bisognu.

Eppo supponi chì un certu prughjettu hà righjuntu a dimensione di decine di millaie di linii, è risulta chì parechji programatori sò travagliendu in questu. Fighjendu un prughjettu simili, basatu annantu à a nostra sperienza, pudemu dì chì capisce u so codice serà a chjave per mantene i sviluppatori pruduttivi. Senza annotazioni di tipu, pò esse difficiuli di capisce, per esempiu, chì argumenti per passà à una funzione, o chì tipi una funzione pò vultà. Eccu dumande tipiche chì sò spessu difficiuli di risponde senza aduprà annotazioni di tipu:

  • Pò sta funzione torna None?
  • Chì duverebbe esse stu argumentu? items?
  • Chì ghjè u tipu d'attributu id: int hè, str, o forse qualchì tipu persunalizatu?
  • Questu argumentu deve esse una lista? Hè pussibule di passà una tupla ?

Se guardate u seguente frammentu di codice annotatu è pruvate à risponde à e dumande simili, risulta chì questu hè u compitu più simplice:

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

  • read_metadata ùn torna None, postu chì u tipu di ritornu ùn hè micca Optional[…].
  • argumentu items hè una sequenza di linii. Ùn pò esse ripetutu in modu aleatoriu.
  • Attributu id hè una stringa di byte.

In un mondu ideale, unu s'aspittava chì tutte queste suttilità seranu descritte in a documentazione integrata (docstring). Ma l'esperienza dà assai esempi di u fattu chì una tale documentazione ùn hè spessu osservata in u codice cù quale avete da travaglià. Ancu s'è una tale documentazione hè presente in u codice, ùn si pò cuntà a so correttezza assoluta. Sta documentazione pò esse vaga, imprecisa è aperta à malintesi. In grandi squadre o grandi prughjetti, stu prublema pò diventà assai agutu.

Mentre Python eccelle in i primi fasi o intermedi di prughjetti, in un certu puntu i prughjetti di successu è l'imprese chì utilizanu Python ponu affruntà a quistione vitale: "Avemu duvemu riscrive tuttu in una lingua di tipografia statica?".

I sistemi di verificazione di u tipu cum'è mypy risolve u prublema di sopra fornendu à u sviluppatore una lingua formale per a descrizzione di i tipi, è verificandu chì e dichjarazioni di tipu currispondenu à l'implementazione di u prugramma (è, eventualmente, cuntrollà per a so esistenza). In generale, pudemu dì chì questi sistemi mettenu à a nostra dispusizione qualcosa cum'è una documentazione currettamente verificata.

L'usu di tali sistemi hà altri vantaghji, è sò digià cumplettamente micca trivial:

  • U sistema di cuntrollu di u tipu pò detectà qualchi errori chjuchi (è micca cusì chjuchi). Un esempiu tipicu hè quandu si scurdanu di processà un valore None o qualchì altra cundizione speciale.
  • Code refactoring hè assai simplificatu perchè u sistema di cuntrollu di tipu hè spessu assai precisa circa ciò chì codice deve esse cambiatu. À u listessu tempu, ùn avemu micca bisognu di sperà per una cobertura di codice 100% cù testi, chì, in ogni casu, ùn hè di solitu micca fattibile. Ùn avemu bisognu di sfondate in a prufundità di a traccia di stack per scopre a causa di u prublema.
  • Ancu in i grandi prughjetti, mypy pò spessu fà un cuntrollu di tipu cumpletu in una frazzioni di seconda. È l'esekzione di e teste generalmente dura decine di seconde o ancu minuti. U sistema di cuntrollu di tipu dà à u prugrammatore un feedback istantaneu è li permette di fà u so travagliu più veloce. Ùn ci hè più bisognu di scrive testi fragili è difficiuli di mantene e teste di unità chì rimpiazzanu entità reali cù mocks è patches solu per ottene risultati di teste di codice più veloce.

L'IDE è l'editori cum'è PyCharm o Visual Studio Code utilizanu a putenza di l'annotazioni di tipu per furnisce i sviluppatori cù u cumpletu di u codice, l'evidenziazione di l'errore è u supportu per e custruzzioni di lingua cumuni. È questi sò solu alcuni di i benefici di scrive. Per certi programatori, tuttu questu hè l'argumentu principale in favore di typing. Questu hè qualcosa chì benefiziu immediatamente dopu l'implementazione. Stu casu d'usu per i tipi ùn hà micca bisognu di un sistema di cuntrollu di tipu separatu cum'è mypy, ancu s'ellu si deve esse nutatu chì mypy aiuta à mantene l'annotazioni di tipu coherente cù u codice.

U fondu di mypy

A storia di mypy hà cuminciatu in u Regnu Unitu, in Cambridge, uni pochi d'anni prima di unisce à Dropbox. Sò participatu, cum'è parte di a mo ricerca di duttore, in l'unificazione di lingue statiche è dinamiche. Eru inspiratu da un articulu nantu à a tipografia incrementale da Jeremy Siek è Walid Taha, è da u prughjettu Typed Racket. Aghju pruvatu à truvà manere di utilizà a stessa lingua di prugrammazione per parechji prughjetti - da picculi scripts à basi di codice custituiti da parechji milioni di linii. À u listessu tempu, aghju vulsutu assicurà chì in un prughjettu di ogni scala, ùn averebbe micca bisognu di cumprumessi troppu grande. Una parte impurtante di tuttu questu era l'idea di passà gradualmente da un prughjettu di prototipu senza tipu à un pruduttu finitu testatu in modu staticu. In questi ghjorni, sti idee sò largamente pigliate per scontate, ma in u 2010 era un prublema chì era sempre esse attivamente esploratu.

U mo travagliu originale in a verificazione di tipu ùn era micca destinatu à Python. Invece, aghju utilizatu una piccula lingua "casa". Alore. Eccu un esempiu chì vi permetterà di capisce ciò chì parlemu (l'annotazioni di tipu sò opzionali quì):

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

Utilizà una lingua nativa simplificata hè un accostu cumuni utilizatu in a ricerca scientifica. Questu hè cusì, micca menu perchè permette di fà rapidamente esperimenti, è ancu per u fattu chì ciò chì ùn hà nunda di fà cù a ricerca pò esse facilmente ignoratu. I linguaggi di prugrammazione di u mondu reale tendenu à esse fenomeni à grande scala cù implementazioni cumplessi, è questu rallenta l'esperimentazione. In ogni casu, ogni risultatu basatu annantu à una lingua simplificata pare un pocu suspettuosa, postu chì in l'ottenimentu di sti risultati, l'investigatore pò avè sacrificatu cunsiderazioni impurtanti per l'usu praticu di e lingue.

U mo verificatore di tipu per Alore pareva assai prumessu, ma vulia pruvà cù l'esperimentu cù u codice veru, chì, pudete dì, ùn era micca scrittu in Alore. Fortunatamente per mè, a lingua Alore era largamente basatu annantu à e stesse idee di Python. Era abbastanza faciule per cambià u tipu di verificatore per pudè travaglià cù a sintassi è a semantica di Python. Questu ci hà permessu di pruvà a verificazione di tipu in u codice Python open source. Inoltre, aghju scrittu un transpiler per cunvertisce u codice scrittu in Alore à u codice Python è l'aghju utilizatu per traduce u mo codice di verificatore. Avà aghju avutu un sistema di cuntrollu di tipu scrittu in Python chì supportava un sottumessu di Python, un tipu di quella lingua! (Cercate decisioni architettoniche chì avianu sensu per Alore eranu pocu adattati per Python, è questu hè sempre noti in parti di u codice mypy).

In fatti, a lingua supportata da u mo sistema di tipu ùn pudia micca esse chjamatu Python à questu puntu: era una variante di Python per via di alcune limitazioni di a sintassi di annotazione di tipu Python 3.

Sembrava una mistura di Java è Python:

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

Una di e mo idee à l'epica era di utilizà annotazioni di tipu per migliurà u rendiment cumpilendu stu tipu di Python à C, o forse JVM bytecode. Aghju ghjuntu à u stadiu di scrive un prototipu di compilatore, ma aghju abbandunatu sta idea, postu chì a verificazione di u tipu pareva assai utile.

Aghju finitu per presentà u mo prughjettu à PyCon 2013 in Santa Clara. Aghju ancu parlatu di questu cù Guido van Rossum, u dittatore benevolente di Python per a vita. Ellu m'hà cunvintu di abbandunà a mo propria sintassi è stà cù a sintassi standard di Python 3. Python 3 soporta l'annotazioni di funzioni, cusì u mo esempiu puderia esse riscritto cum'è mostra quì sottu, risultatu in un prugramma Python normale:

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

Aviu avutu à fà qualchì cumprumissu (prima di tuttu, vogliu nutà chì aghju inventatu a mo sintassi per questu propiu). In particulare, Python 3.3, a versione più recente di a lingua in quellu tempu, ùn sustene micca l'annotazione variabile. Aghju discututu cù Guido per e-mail diverse pussibulità per u disignu sintatticu di tali annotazioni. Avemu decisu d'utilizà cumenti di tipu per variàbili. Questu hà servitu u scopu previstu, ma era un pocu ingombrante (Python 3.6 ci hà datu una sintassi più bella):

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

I cumenti di tipu sò stati ancu utili per supportà Python 2, chì ùn hà micca supportu integratu per annotazioni di tipu:

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

Risultava chì questi (è altri) scambii ùn importavanu micca veramente - i benefici di a tipografia statica significavanu chì l'utilizatori si scurdavanu prestu di sintassi menu di perfetta. Siccomu nisuna custruzzione sintattica speciale hè stata aduprata in u codice Python verificatu di tipu, l'arnesi Python esistenti è i prucessi di trasfurmazioni di codice cuntinueghjanu à travaglià nurmale, facendu assai più faciule per i sviluppatori per amparà u novu strumentu.

Guido m'hà ancu cunvintu à unisce à Dropbox dopu avè finitu a mo tesi di graduatu. Hè quì chì a parte più interessante di a storia mypy principia.

Per esse continuatu ...

Beni, lettori! Se aduprate Python, per piacè diteci di a scala di prughjetti chì sviluppate in questa lingua.

A strada per a verificazione di 4 milioni di linee di codice Python. Parte 1
A strada per a verificazione di 4 milioni di linee di codice Python. Parte 1

Source: www.habr.com

Add a comment