Impara Python in un weekend: Da zero a un progetto completo
Come possiamo imparare rapidamente un nuovo linguaggio di programmazione? In questo articolo, condivideremo la nostra esperienza di un weekend di apprendimento di Python costruendo un progetto completo.
Introduzione
Logto, in quanto servizio di identità, è essenziale fornire un'esperienza fluida attraverso vari linguaggi di programmazione e framework. Questo spesso comporta la creazione di Software Development Kit (SDK). Tuttavia, quando il linguaggio di programmazione non fa parte del nostro stack tecnologico e il nostro team non è familiare, creare un SDK robusto diventa una sfida.
Python ci ha posto questa sfida. Nonostante avessimo molti utenti Python, mancavamo di un SDK Python, una preoccupazione persistente. Determinato a risolvere questo problema, ho iniziato a colmare questa lacuna.
Anche se ho anni di esperienza nella programmazione, Python rimane relativamente inesplorato per me. Anche se avevo smanettato con Python 2 brevemente per script semplici anni fa, la mia conoscenza era obsoleta. Tuttavia, era ora di tuffarsi!
Giorno 1: Posa le fondamenta
Definisci l'obiettivo
Nella mia esperienza, l'approccio più efficace per apprendere un nuovo linguaggio di programmazione è costruire un progetto completo. Fortunatamente, il nostro obiettivo era chiaro: costruire un SDK Python di Logto per applicazioni web.
Piuttosto che gettarsi nel codice, scomponiamolo. Ecco la lista:
- Creare il client Logto per attività come il login, il logout, le informazioni dell'utente e la gestione dei token.
- Fornire un tutorial e un progetto di esempio per mostrare l'uso dell'SDK.
- Pubblicare l'SDK da qualche parte in modo che gli utenti possano installarlo facilmente.
Sembra che il compito 1 abbia più lavoro, quindi dobbiamo confermare l'ambito e continuare a scomporlo. Questo passaggio è cruciale per garantire i confini del progetto ed evitare l'espansione dell'ambito e l'over-engineering.
Il lavoro precedente del nostro team mi ha fatto risparmiare un sacco di tempo:
- Una convenzione SDK ha delineato la struttura e il design delle API degli SDK.
- Gli SDK esistenti per diversi linguaggi hanno fornito intuizioni sui modelli e i potenziali miglioramenti per Python.
Facendo riferimento a queste risorse, posso vedere un quadro chiaro di ciò che devo fare. Sebbene i dettagli specifici vadano oltre l'ambito di questo articolo, andiamo avanti.
Configura l'ambiente
Sto usando un Mac, quindi Python è già installato. Tuttavia, mi chiedevo se esistesse un modo migliore per gestire le versioni di Python (ho sentito parlare della complessità della compatibilità delle versioni), proprio come nvm
per Node.js. Rapidamente, ho trovato pyenv e ho iniziato direttamente a installarlo.
Il prossimo punto all'ordine del giorno: un gestore di pacchetti e dipendenze. Di solito sono accoppiati. Allora perché non pip
(il predefinito di Python)? Se dai un'occhiata al requirements.txt
, noterai che è solo una lista di pacchetti con versioni. Questo non è sufficiente per un SDK che potrebbe essere usato da altri progetti. Per esempio, potremmo aver bisogno di aggiungere alcuni pacchetti per lo sviluppo, ma non vogliamo includerli nell'SDK finale. Il requirements.txt
è troppo semplice per gestire questo.
Uno dei vantaggi di avere altri linguaggi di programmazione nello stack tecnologico è che puoi cercare l'equivalente Python. Quindi ho cercato "equivalente package.json Python" e ho trovato Poetry, un candidato eccellente:
- Funziona come gestore di pacchetti, gestore di dipendenze e gestore di ambienti virtuali.
- Ha un file
pyproject.toml
, simile apackage.json
in Node.js. - Utilizza un file di blocco per registrare versioni precise delle dipendenze.
Le CLI moderne spesso includono un comando init
progettato per nuovi progetti. Anche Poetry lo fa. Ho eseguito il comando e ha creato per me un file pyproject.toml
.
La prima linea di codice
Finalmente era arrivato il momento di scrivere il codice. Iniziare con il classico programma "Hello, World!" è sempre una buona scelta. Quando si impara un linguaggio di programmazione, gli IDE completi non sono sempre essenziali; un editor supportato da una comunità forte, come VS Code, è del tutto adeguato.
Dato che il nostro SDK si concentra su applicazioni web, ho iniziato con un semplice server web utilizzando il popolare framework Flask.
Sfruttando le capacità di Poetry, installare Flask può essere fatto facilmente eseguendo poetry add flask
. Poi, seguendo la guida rapida ufficiale di Flask, ho scritto un file 'hello.py' con il seguente frammento di codice:
Avviando il server tramite flask --app hello run
e navigando a http://localhost:5000 nel mio browser ho ottenuto il risultato desiderato. Ha funzionato!
Come principiante, non avevo fretta di scrivere più codice. Invece, ci sono molte informazioni da ricevere dal frammento di codice:
- Utilizza
from x import y
per importare un modulo o una classe. - Non ci sono punti e virgola per terminare le righe (oh no).
- Possiamo definire una nuova variabile inserendo un nome arbitrario e assegnandogli un valore.
- Creazione di un'istanza di una classe senza la parola chiave
new
. - Python supporta i decoratori, e
@app.route
funge da decoratore che registra una funzione come gestore di percorsi.- Il valore di ritorno della funzione è interpretato come corpo della risposta.
- Possiamo definire una funzione utilizzando la parola chiave
def
.
Come puoi vedere, se proviamo a capire ogni riga di codice invece di "farla semplicemente funzionare", possiamo imparare molto da essa. Nel frattempo, la documentazione ufficiale di Flask ha ulteriormente spiegato il frammento di codice in dettaglio.
Inizio del progetto
Ora è tempo di iniziare il progetto. Presto ho definito una classe LogtoClient
e ho cercato di aggiungere alcune proprietà e metodi per familiarizzare col linguaggio:
Successivamente, integra la classe con Flask:
Ha iniziato a sembrare un vero progetto. Ma sentivo che mancava qualcosa: un sistema di tipi.
Sistema di tipi
Dato che si tratta di un SDK, l'incorporazione di un sistema di tipi aiuterà gli utenti a comprendere l'API e a ridurre la possibilità di errori durante lo sviluppo.
Python ha introdotto type hints nella versione 3.5. Non è potente come TypeScript, ma è meglio di niente. Ho aggiunto alcuni suggerimenti di tipo alla classe LogtoClient
:
Ora sembra molto meglio. Ma la sfida è emersa quando si tratta di un tipo complesso come un oggetto con chiavi predefinite. Per esempio, dobbiamo definire una classe LogtoConfig
per rappresentare l'oggetto di configurazione:
Sembra ok, ma presto dovremo affrontare i problemi di codifica, decodifica e validazione dell'oggetto da JSON.
Dopo un po' di ricerca, ho scelto pydantic come soluzione. È una libreria di validazione dei dati che funziona con i suggerimenti di tipo. Supporta diverse funzionalità JSON senza seguire fastidiosi boilerplate code.
Quindi, la classe LogtoConfig
può essere riscritta così:
Mi ha anche insegnato l'ereditarietà delle classi in Python aggiungendo parentesi dopo il nome della classe.
Operazioni asincrone
All'interno dell'SDK Logto, dobbiamo fare richieste HTTP al server Logto. Se hai esperienza con JavaScript, l'espressione "callback hell" probabilmente suona familiare. È un problema comune quando si tratta di operazioni asincrone. I linguaggi moderni di programmazione presentano soluzioni simili come Promise
o coroutine
.
Fortunatamente, Python ha una soluzione integrata di async
e await
. Prima di usarli, assicurati della compatibilità con i framework più popolari. In Flask, ciò può essere fatto installando il pacchetto extra async
e usando async def
invece di def
:
Poi possiamo usare await
per attendere il risultato di un'operazione asincrona.
Richieste HTTP
Le richieste HTTP sono un argomento interessante. Quasi ogni linguaggio di programmazione ha una soluzione nativa, ma gli sviluppatori di solito usano una libreria di terze parti per comodità. Alcuni esempi:
- JavaScript:
XMLHttpRequest
vs.fetch
vs.axios
- Swift:
URLSession
vs.Alamofire
- Java:
HttpURLConnection
vs.OkHttp
Questo vale anche per Python. La mia decisione è stata di usare aiohttp, poiché supporta async
e await
, insieme alla sua popolarità.
La magia di Copilot
Prima di Copilot, ora ci avvicinavamo alla parte tediosa della scrittura della logica di business. Con l'aiuto della convenzione SDK e di altri SDK, posso scrivere i commenti descrittivi per ogni metodo prima di scrivere il codice.
Aggiunge maggiore leggibilità al codice e aiuta anche gli sviluppatori a comprendere l'API direttamente nell'IDE o nell'editor tramite l'intelligenza del codice.
Per esempio, consideriamo il metodo generateCodeChallenge
, i commenti possono essere scritti così:
Questo ha rappresentato un ottimo prompt per i modelli di linguaggio ampi (LLM): comprendere definizioni di metodi tramite commenti chiari. E Copilot non ha deluso:
Potrebbero essere necessari alcuni aggiustamenti, ma non importa. Ha già cambiato le regole del gioco.
Conclusione
Questo è praticamente il progresso raggiunto nel primo giorno. È stata una lunga giornata, ma con strumenti e tecnologie moderne, è stato molto meglio di quanto mi aspettassi.
Giorno 2: Alza il livello
Basandosi sul lavoro del primo giorno, la logica di business è stata completata rapidamente. Ma per un SDK, non è ancora sufficiente. Ecco i compiti per il secondo giorno:
- Aggiungere test unitari.
- Forzare la formattazione del codice.
- Verificare la compatibilità delle versioni di Python.
- Aggiungere l'integrazione continua.
- Pubblicare l'SDK.
Test unitari
I test unitari ci hanno salvato molte volte, quindi non li salterò. Ecco alcune considerazioni comuni quando si scrivono test unitari:
- Come organizzare ed eseguire i test?
- Come verificare il risultato?
- Come eseguire test asincroni? (Sembra una cosa semplice, ma occasionalmente causa problemi in alcuni linguaggi.)
- Come simulare le dipendenze? (Non tuffarti in questo argomento finché non è indispensabile, poiché può portare a vicoli ciechi.)
- Come generare report di copertura del codice?
Con queste domande in mente, ho scoperto che il modulo integrato unittest
non era sufficiente per alcuni casi. Così ho scelto pytest come framework di test. Supporta i test asincroni e sembra abbastanza maturo.
Il viaggio mi ha rivelato nuovi concetti interessanti come fixture
. Questo può anche migliorare la mentalità quando si scrive codice in altri linguaggi.
Formattazione del codice
Ogni linguaggio ha i suoi stili di formattazione del codice. Personalmente, una formattazione coerente può rendermi felice e a mio agio; è anche utile per la revisione del codice e la collaborazione.
Piuttosto che sfogliare la discussione sullo stile "migliore", ho deciso di scegliere un formatter opinato e attenervisi.
Black sembra una buona scelta. L'unica frustrazione è la dimensione delle tabulazioni non modificabile. Ma non è un grosso problema, ho deciso di adattarmi.
Compatibilità delle versioni di Python
In quanto SDK, dovrebbe essere compatibile con le versioni più diffuse di Python. Cercando "statistiche sull'uso delle versioni di Python", ho deciso di utilizzare Python 3.8 come versione minima.
Ora appare il vantaggio del gestore di ambienti. Posso facilmente cambiare versione di Python eseguendo pyenv local 3.8
e poetry env use 3.8
. Poi potrei eseguire i test per rivelare eventuali problemi di compatibilità.
Integrazione continua
L'integrazione continua garantisce la qualità di ogni modifica del codice. Poiché il nostro repository è ospitato su GitHub, GitHub Actions rappresentava la scelta naturale.
Il flusso di lavoro principale segue principi semplici:
- Configurare l'ambiente.
- Installare le dipendenze.
- Compilare il progetto (Non è necessario per Python comunque).
- Eseguire i test.
GitHub Actions ha una buona comunità, quindi bastano pochi minuti per costruire il flusso di lavoro.
Utilizzando strategie a matrice, possiamo eseguire il flusso di lavoro su diverse versioni di Python, persino su diversi sistemi operativi.
Pubblicazione dell'SDK
L'ultimo passaggio è pubblicare l'SDK. Per i pacchetti pubblici, questo può essere fatto generalmente inviandoli al registro dei pacchetti ufficiale per linguaggio specifico. Per esempio, npm per Node.js, PyPI per Python e CocoaPods per Swift.
Poetry è la mia stella polare. Basta eseguire poetry publish
per pubblicare il pacchetto su PyPI. È così semplice.
Pensieri finali
È stato un viaggio coinvolgente. Senza l'aiuto della comunità open-source, sarebbe stato molto più difficile. Applaudiamo tutti i contributori!
Ecco alcune conclusioni generali:
- Definisci esattamente l'obiettivo e scomponilo, quindi tieni sempre a mente l'obiettivo.
- Configura un ambiente di sviluppo stabile e riproducibile.
- Utilizza (buoni) strumenti il più possibile.
- Priorità alle soluzioni integrate o esistenti.
- Comprendi le convenzioni del linguaggio e ogni riga di codice che scrivi.
- Tuttavia, non fissarti sui dettagli.
- Usa Copilot per compiti chiari e descrittivi.
Puoi trovare il risultato finale in questo repository. Con la stessa strategia, ho anche costruito rapidamente il Logto PHP SDK. Non esitare a farci sapere se hai suggerimenti.
Spero che questo articolo sia utile per imparare un nuovo linguaggio di programmazione. Buon hacking!