Il percorso per la verifica dei tipi di 4 milioni di righe di codice Python. Parte 3

Presentiamo la terza parte della traduzione del materiale sul percorso intrapreso dall'azienda Dropbox nell'implementare un sistema di verifica dei tipi di codice Python.

Il percorso per la verifica dei tipi di 4 milioni di righe di codice Python. Parte 3

→ Parti precedenti: prima e seconda

Raggiungere 4 milioni di righe di codice tipizzato

Un'altra importante sfida (questa era la seconda preoccupazione più comune emersa nei sondaggi interni) era aumentare il volume di codice in Dropbox coperto da verifiche sui tipi. Abbiamo provato diversi approcci per affrontare questa sfida, dalla crescita naturale della base di codice tipizzata alla focalizzazione degli sforzi del team mypy sulla deduzione statica e dinamica dei tipi. Alla fine, è emerso che non esiste una semplice strategia vincente, ma siamo riusciti a ottenere una rapida crescita del volume di codice annotato, combinando diversi approcci.

Come risultato, nel nostro più grande repository Python (con codice backend), il numero di righe di codice annotato ha raggiunto quasi 4 milioni. Il lavoro sulla tipizzazione statica del codice è stato svolto in circa tre anni. Mypy ora supporta diversi tipi di report sulla copertura del codice da parte dei tipi, facilitando il monitoraggio del progresso della tipizzazione. In particolare, possiamo generare report sul codice con incertezze nei tipi, come ad esempio l'uso esplicito del tipo Any nelle annotazioni, che non possono essere verificate, o come quelle riguardanti l'importazione di librerie di terze parti, che non hanno annotazioni di tipo. Nell'ambito del progetto per migliorare la precisione della verifica dei tipi in Dropbox, abbiamo contribuito a migliorare le definizioni dei tipi (i cosiddetti file stub) per alcune librerie open source popolari nel repository Python centralizzato typeshed.

Abbiamo implementato (e standardizzato nei successivi PEP) nuove funzionalità del sistema dei tipi, che consentono l'uso di tipi più precisi per alcuni schemi specifici di Python. Un esempio notevole di questo è TypeDict, che fornisce tipi per dizionari simili a JSON con un insieme fisso di chiavi stringa, ognuna delle quali ha un proprio tipo di valore. Continueremo a espandere il sistema di tipi. Probabilmente, il nostro prossimo passo sarà migliorare il supporto delle funzionalità di Python per la gestione dei numeri.

Il percorso per la verifica dei tipi di 4 milioni di righe di codice Python. Parte 3
Numero di righe di codice annotato: server

Il percorso per la verifica dei tipi di 4 milioni di righe di codice Python. Parte 3
Numero di righe di codice annotato: client

Il percorso per la verifica dei tipi di 4 milioni di righe di codice Python. Parte 3
Totale delle righe di codice annotato

Ecco una panoramica delle principali caratteristiche delle azioni che abbiamo intrapreso per aumentare il volume di codice annotato in Dropbox:

Rigorosità dell'annotazione. Abbiamo gradualmente aumentato i requisiti per la rigorosità dell'annotazione del nuovo codice. Abbiamo iniziato con suggerimenti del linter, che raccomandava di aggiungere annotazioni nei file già annotati. Ora richiediamo annotazioni di tipo in nuovi file Python e nella maggior parte dei file esistenti.

Rapporti di tipizzazione. Inviamo settimanalmente rapporti ai team riguardo al livello di tipizzazione del loro codice e forniamo suggerimenti su cosa sia meglio annotare per primo.

Promozione di mypy. Parliamo di mypy in diversi eventi e collaboriamo con i team per aiutarli a iniziare a usare le annotazioni dei tipi.

Sondaggi. Conduciamo sondaggi periodici tra gli utenti per identificare i principali problemi. Siamo pronti ad andare fino in fondo per risolvere queste questioni (fino a creare un nuovo linguaggio per accelerare mypy!).

Prestazioni. Abbiamo notevolmente migliorato le prestazioni di mypy grazie all'uso del demone e di mypyc. Questo è stato fatto per alleviare le difficoltà durante il processo di annotazione e per consentire di lavorare con grandi volumi di codice.

Integrazione con gli editor. Abbiamo sviluppato strumenti per supportare l'esecuzione di mypy negli editor più popolari in Dropbox. Questi includono PyCharm, Vim e VS Code. Ciò ha semplificato notevolmente il processo di annotazione del codice e di verifica della sua funzionalità. Queste azioni sono tipicamente necessarie quando si annota codice esistente.

Analisi statica. Abbiamo creato uno strumento per l'estrazione delle firme delle funzioni utilizzando metodologie di analisi statica. Questo strumento può funzionare solo in situazioni relativamente semplici, ma ci ha aiutato a incrementare senza sforzi significativi la copertura del codice con i tipi.

Supporto per librerie di terze parti. In molti dei nostri progetti utilizziamo il framework SQLAlchemy. Esso sfrutta le capacità dinamiche di Python, che i tipi definiti da PEP 484 non sono in grado di modellare direttamente. Abbiamo creato un file stub corrispondente e scritto un plugin per mypy (open source), che migliora il supporto per SQLAlchemy.

Le difficoltà che abbiamo incontrato

Il percorso verso 4 milioni di righe di codice tipizzato non è stato sempre facile. Lungo la strada abbiamo incontrato diversi ostacoli e commesso vari errori. Ecco alcuni dei problemi che abbiamo affrontato. Speriamo che la nostra esperienza aiuti altri a evitare simili problematiche.

File mancanti. Abbiamo iniziato il lavoro controllando solo un piccolo volume di file. Tutto ciò che non rientrava in questo numero di file non è stato verificato. I file venivano aggiunti all'elenco di controllo quando venivano annotate per la prima volta. Se qualcosa veniva importato da un modulo situato al di fuori dell'area di controllo, si trattava di lavorare con valori di tipo Any, che non sono mai stati controllati. Ciò ha portato a una significativa perdita di accuratezza nel tipo, specialmente nelle prime fasi della migrazione. Questo approccio ha comunque funzionato sorprendentemente bene, sebbene fosse tipica la situazione in cui l'aggiunta di file nell'area di controllo rivelava problemi in altre parti della base di codice. Nella situazione peggiore, quando due aree di codice isolate, in cui i tipi erano già stati verificati in modo indipendente, venivano unite, si scopriva che i tipi di queste aree erano incompatibili tra loro. Questo ha comportato la necessità di apportare numerose modifiche alle annotazioni. Ora, guardando indietro, comprendiamo che avremmo dovuto includere il modulo di libreria di base nell'area di controllo dei tipi mypy il prima possibile. Questo avrebbe reso il nostro lavoro molto più prevedibile.

Annotazione del vecchio codice. Quando abbiamo iniziato a lavorare, avevamo circa 4 milioni di righe di codice Python già esistente. Era chiaro che annotare tutto questo codice era un compito non facile. Abbiamo creato uno strumento chiamato PyAnnotate, che può raccogliere informazioni sui tipi durante l'esecuzione dei test e aggiungere al codice annotazioni di tipo basate sui dati raccolti. Tuttavia, non abbiamo notato un'adozione particolarmente ampia di questo strumento. La raccolta delle informazioni sui tipi era lenta, e le annotazioni generate automaticamente richiedevano spesso molte modifiche manuali. Abbiamo pensato di eseguire automaticamente questo strumento ad ogni controllo del codice, o di raccogliere informazioni sui tipi basate sull'analisi di un certo volume di richieste di rete reali, ma abbiamo deciso di non farlo, poiché entrambi questi approcci erano troppo rischiosi.

In conclusione, si può notare che la maggior parte del codice è stata annotata manualmente dai suoi proprietari. Noi, per orientare questo processo nella giusta direzione, prepariamo report sui moduli e sulle funzionalità particolarmente importanti da annotare. Ad esempio, è fondamentale fornire annotazioni sui tipi per un modulo di libreria utilizzato in centinaia di punti. Tuttavia, per un vecchio servizio che viene sostituito da uno nuovo, annotare non è così importante. Inoltre, stiamo sperimentando l'uso dell'analisi statica per generare annotazioni dei tipi per codice obsoleto.

Importazioni cicliche. Ho già parlato delle importazioni cicliche (dei "nodi di dipendenza"), la cui esistenza ha complicato il potenziamento di mypy. Inoltre, abbiamo dovuto lavorare duramente per fornire a mypy supporto per tutti i tipi di idiomi, che sono stati causati da queste importazioni cicliche. Di recente abbiamo completato un grande progetto di redesign del sistema, che ha risolto la maggior parte dei problemi di mypy riguardanti le importazioni cicliche. Questi problemi, infatti, risalivano ai primi giorni del progetto, all'epoca di Alore, il linguaggio didattico su cui era inizialmente basato il progetto mypy. La sintassi di Alore consente di gestire facilmente i problemi delle importazioni cicliche. L'attuale mypy ha ereditato alcune limitazioni dalla sua prima implementazione semplice (che andava bene per Alore). Python complica il lavoro con le importazioni cicliche principalmente a causa dell'ambiguità delle espressioni. Ad esempio, durante un'operazione di assegnazione di valori, potrebbe effettivamente essere definito un alias di tipo. Mypy non è sempre in grado di rilevare tali situazioni finché gran parte del ciclo di importazione non è stata elaborata. In Alore non c'erano ambiguità di questo tipo. Decisioni sbagliate prese nelle prime fasi dello sviluppo del sistema possono riservare brutte sorprese ai programmatori molti anni dopo.

Risultati: un cammino verso 5 milioni di righe di codice e nuovi orizzonti

Il progetto mypy ha fatto molta strada: da prototipi iniziali a un sistema che controlla i tipi di codice di produzione per un totale di 4 milioni di righe. Durante lo sviluppo, mypy ha standardizzato le annotazioni di tipo in Python. Oggi, attorno alla tipizzazione del codice Python, si è sviluppato un ecosistema robusto. Questo ecosistema include supporto per librerie, strumenti per IDE e editor, e diverse sistemi di controllo dei tipi, ognuna con i propri vantaggi e svantaggi.

Sebbene il controllo dei tipi sia ormai considerato una prassi consolidata in Dropbox, sono convinto che siamo ancora all'alba della tipizzazione del codice Python. Credo che le tecnologie di controllo dei tipi continueranno a evolversi e migliorare.

Se non hai ancora utilizzato i controlli dei tipi nel tuo progetto Python su larga scala, è proprio il momento giusto per iniziare la transizione verso la tipizzazione statica. Ho parlato con persone che hanno effettuato questa transizione. Nessuno di loro se n'è pentito. Il controllo dei tipi trasforma Python in un linguaggio decisamente più adatto allo sviluppo di grandi progetti rispetto al "normale Python".

Gentili lettori! Utilizzi il controllo dei tipi nei tuoi progetti Python?

Il percorso per la verifica dei tipi di 4 milioni di righe di codice Python. Parte 3
Il percorso per la verifica dei tipi di 4 milioni di righe di codice Python. Parte 3

Fonte: habr.com

Acquista hosting affidabile per siti web con protezione DDoS, VPS VDS server 🔥 Acquista hosting affidabile per siti web con protezione DDoS, VPS VDS server | ProHoster