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

Vi presentiamo la terza parte della traduzione del materiale sul percorso compiuto dall'azienda Dropbox nell'implementazione di un sistema di verifica dei tipi per il codice Python.

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

→ Parti precedenti: il primo e seconda

Raggiungere 4 milioni di righe di codice tipizzato

Un'altra importante sfida (questo è stato il secondo problema più segnalato durante i sondaggi interni) era aumentare la quantità di codice in Dropbox coperto da controlli di tipo. Abbiamo sperimentato diversi approcci per affrontare questo problema, dalla crescita naturale della base di codice tipizzata alla concentrazione degli sforzi del team mypy su inferenze di tipo statiche e dinamiche automatizzate. Alla fine, è emerso che non esisteva una strategia vincente semplice, ma siamo riusciti a ottenere una rapida crescita del codice annotato, combinando numerosi approcci.

Di conseguenza, nel nostro più grande repository Python (con codice backend), il numero di righe di codice annotato ha raggiunto quasi 4 milioni. Il lavoro di tipizzazione statica del codice è stato svolto in circa tre anni. Mypy ora supporta diversi tipi di report sulla copertura del codice di tipo, che semplificano il monitoraggio del processo di tipizzazione. In particolare, possiamo generare report sul codice con incertezze nei tipi, come ad esempio l'uso esplicito di un tipo Any nelle annotazioni, che non possono essere verificate, o come l'importazione di librerie esterne 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 di tipo (i cosiddetti file stub) per alcune popolari librerie open source nel repository Python centralizzato typeshed.

Abbiamo implementato (e standardizzato nei successivi PEP) nuove funzionalità del sistema di tipi che consentono di utilizzare tipi più precisi per alcuni modelli specifici di Python. Un esempio notevole di ciò è TypeDict, che fornisce tipi per dizionari simili a JSON che hanno un insieme fisso di chiavi stabili, ciascuna delle quali ha un valore del proprio tipo. Continueremo a espandere il sistema di tipi. Probabilmente, il nostro prossimo passo sarà migliorare il supporto delle funzionalità di Python per lavorare con i 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: cliente

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

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

Rigidità dell'annotazione. Abbiamo gradualmente aumentato i requisiti di rigore per l'annotazione del nuovo codice. Abbiamo iniziato con i suggerimenti del linter, che raccomandavano di aggiungere annotazioni nei file che già contenevano alcune annotazioni. Ora richiediamo la presenza di annotazioni sui tipi nei nuovi file Python e nella maggior parte dei file esistenti.

Report sulla tipizzazione. Inviamo settimanalmente report ai team sul livello di tipizzazione del loro codice e forniamo suggerimenti su cosa dovrebbe essere annotato per primo.

Promozione di mypy. Parliamo di mypy in vari eventi e ci confrontiamo con i team, aiutandoli a iniziare ad utilizzare le annotazioni sui tipi.

Sondaggi. Eseguiamo sondaggi periodici tra gli utenti per identificare i principali problemi. Siamo pronti a spingerci abbastanza in là nella risoluzione di questi problemi (fino a creare un nuovo linguaggio per accelerare mypy!).

Prestazioni. Abbiamo notevolmente migliorato le prestazioni di mypy grazie all'uso di un demone e di mypyc. Questo è stato fatto per rendere più fluido il processo di annotazione e per poter lavorare con grandi volumi di codice.

Integrazione con gli editor. Abbiamo creato strumenti di supporto per eseguire mypy negli editor più popolari in Dropbox. Questi includono PyCharm, Vim e VS Code. Questo ha notevolmente semplificato il processo di annotazione del codice e di verifica del suo funzionamento. Azioni simili sono comuni quando si annota il codice esistente.

Analisi statica. Abbiamo creato uno strumento per generare le firme delle funzioni utilizzando strumenti di analisi statica. Questo strumento può funzionare solo in situazioni relativamente semplici, ma ci ha aiutato ad aumentare senza sforzo la copertura del codice con i tipi.

Supporto per librerie di terze parti. In molti dei nostri progetti utilizziamo il set di strumenti SQLAlchemy. Questo usa le capacità dinamiche di Python che i tipi PEP 484 non possono modellare direttamente. In conformità con il PEP 561, abbiamo creato un file stub corrispondente e scritto un plugin per mypy.open source), migliorando il supporto per SQLAlchemy.

Le difficoltà che abbiamo incontrato

Il percorso verso 4 milioni di righe di codice tipizzato non è sempre stato facile. Lungo questo cammino abbiamo incontrato molte insidie e commesso alcuni errori. Ecco alcuni dei problemi che abbiamo affrontato. Speriamo che raccontarli possa aiutare altri a evitare simili problematiche.

File mancanti. Abbiamo iniziato a lavorare controllando solo un piccolo numero di file. Tutto ciò che non era incluso in questo numero non veniva controllato. I file venivano aggiunti alla lista di controllo quando comparivano le prime annotazioni. Se si importava da un modulo situato al di fuori dell'area di controllo, si trattava di lavorare con valori di tipo Any, che non venivano affatto controllati. Questo ha portato a una significativa perdita di accuratezza nella tipizzazione, specialmente nelle prime fasi della migrazione. Questo approccio ha funzionato sorprendentemente bene, anche se la situazione tipica era che l'aggiunta di file all'area di controllo rivelava problemi in altre parti della base di codice. Nel peggior dei casi, quando si univano due aree di codice isolate, in cui i tipi erano già stati controllati in modo indipendente, si scopriva che i tipi di queste aree erano incompatibili tra loro. Questo richiedeva modifiche significative nelle annotazioni. Ora, guardando indietro, ci rendiamo conto che avremmo dovuto aggiungere il modulo di base delle librerie all'area di controllo dei tipi mypy il prima possibile. Questo avrebbe reso il nostro lavoro molto più prevedibile.

Annotazione del codice vecchio. Quando abbiamo iniziato a lavorare, avevamo circa 4 milioni di righe di codice Python già esistente. Era chiaro che annotare tutto questo codice sarebbe stata un'impresa non facile. Abbiamo creato uno strumento chiamato PyAnnotate, che può raccogliere informazioni sui tipi durante l'esecuzione dei test e aggiungere annotazioni di tipo al codice, in base alle informazioni raccolte. Tuttavia, non abbiamo notato una diffusione particolarmente ampia di questo strumento. La raccolta delle informazioni sui tipi era lenta e le annotazioni generate automaticamente richiedevano spesso molte correzioni manuali. Abbiamo pensato di eseguire automaticamente questo strumento ad ogni revisione del codice o di raccogliere informazioni sui tipi, basandoci sull'analisi di un certo volume di richieste reali, ma abbiamo deciso di non farlo, poiché ciascuno di questi approcci era troppo rischioso.

In definitiva, si può osservare che la maggior parte del codice è stata annotata manualmente dai suoi proprietari. Per indirizzare questo processo nella giusta direzione, prepariamo report su moduli e funzioni particolarmente importanti da annotare. Ad esempio, è importante fornire annotazioni di tipo per il modulo di libreria utilizzato in centinaia di posti. D'altra parte, non è così importante annotare un vecchio servizio che viene sostituito da uno nuovo. Inoltre, stiamo sperimentando l'uso dell'analisi statica per generare annotazioni di tipo per il codice vecchio.

Importazioni cicliche. Ho parlato in precedenza delle importazioni cicliche (dei "nodi di dipendenze"), la cui esistenza ha complicato l'accelerazione di mypy. Inoltre, abbiamo dovuto lavorare intensamente per fornire a mypy supporto per tutti i tipi di idiomi, la cui origine è dovuta a queste importazioni cicliche. Recentemente abbiamo completato un grande progetto di redesign del sistema, che ha risolto la maggior parte dei problemi di mypy relativi alle importazioni cicliche. Questi problemi, in effetti, risalivano ai tempi molto precoci del progetto, sin dai tempi di Alore, il linguaggio educativo a cui il progetto mypy era inizialmente rivolto. La sintassi di Alore consente di risolvere facilmente i problemi delle catene cicliche di importazione. L'attuale mypy ha ereditato alcune limitazioni dalla sua prima implementazione semplice (che era perfettamente adeguata per Alore). Python complica la gestione delle importazioni cicliche principalmente a causa dell'ambiguità delle espressioni. Ad esempio, durante un'operazione di assegnazione, un alias di tipo può effettivamente essere determinato. Mypy non sempre è in grado di rilevare tali cose fino a quando gran parte del ciclo di importazione non è stata elaborata. In Alore non c'erano ambiguità di questo tipo. Decisioni sbagliate prese nelle fasi iniziali dello sviluppo del sistema possono riservare sorprese sgradevoli ai programmatori anche molti anni dopo.

Conclusioni: la strada verso 5 milioni di righe di codice e nuovi orizzonti

Il progetto mypy ha fatto molta strada — dai primi prototipi, fino a un sistema che controlla i tipi del codice di produzione per un totale di 4 milioni di righe. Durante lo sviluppo, mypy ha standardizzato le annotazioni di tipo in Python. Oggi, intorno alla tipizzazione del codice Python è emerso un potente ecosistema. Vi è spazio per il supporto delle librerie, strumenti per IDE e editor, e diversi sistemi di controllo dei tipi, ognuno con i propri vantaggi e svantaggi.

Sebbene il controllo dei tipi sia già considerato in Dropbox come qualcosa di scontato, sono sicuro che stiamo ancora vivendo all'alba della tipizzazione del codice Python. Penso che le tecnologie di controllo dei tipi continueranno a evolversi e migliorarsi.

Se non hai ancora utilizzato i controlli dei tipi nel tuo progetto Python su larga scala, sappi che ora è un momento molto appropriato per iniziare la transizione alla tipizzazione statica. Ho parlato con chi ha effettuato questa transizione. Nessuno di loro si è mai pentito. Il controllo dei tipi trasforma Python in un linguaggio molto più adatto rispetto al "classico Python" per lo sviluppo di grandi progetti.

Gentili lettori! Utilizzi i controlli 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