Français
  • python
  • programmation
  • apprentissage
  • sdk

Apprendre Python en un week-end : Du zéro à un projet complet

Comment pouvons-nous apprendre rapidement un nouveau langage de programmation ? Dans cet article, nous partagerons notre expérience d'un week-end à apprendre Python en construisant un projet complet.

Gao
Gao
Founder

Introduction

Logto, en tant que service d'identité, offrir une expérience fluide à travers divers langages de programmation et frameworks est essentiel. Cela implique souvent la création de Software Development Kits (SDKs). Cependant, lorsque le langage de programmation se situe en dehors de notre pile technologique et que notre équipe n'est pas familiarisée, créer un SDK robuste devient un défi.

Python nous a posé un tel défi. Bien que nous ayons de nombreux utilisateurs de Python, nous manquions d'un SDK Python, une préoccupation persistante. Déterminé à résoudre ce problème, j'ai commencé à combler ce manque.

Bien que j'aie des années d'expérience en programmation, Python reste un territoire relativement inexploré pour moi. Bien que j'aie joué brièvement avec Python 2 pour des scripts simples il y a des années, mes connaissances étaient obsolètes. Néanmoins, il était temps de plonger dedans!

Jour 1 : Poser les bases

Définir l'objectif

D'après mon expérience, la méthode la plus efficace pour apprendre un nouveau langage de programmation est de construire un projet complet. Heureusement, notre objectif était clair : construire un SDK Python Logto pour des applications web.

Plutôt que de se lancer dans le code, décomposons-le. Voici la liste :

  1. Créer le client Logto pour des tâches telles que la connexion, la déconnexion, les informations utilisateur et la gestion des tokens.
  2. Fournir un tutoriel et un projet exemple pour montrer l'utilisation du SDK.
  3. Publier le SDK quelque part afin que les utilisateurs puissent l'installer facilement.

On dirait que la tâche 1 représente le plus de travail, donc nous devons confirmer l'étendue et continuer à la décomposer. Cette étape est cruciale pour sécuriser les limites du projet et éviter la dérive des objectifs et la sur-ingénierie.

Le travail précédent de notre équipe m'a fait gagner beaucoup de temps :

  • Une convention SDK décrivait la structure et la conception de l'API des SDKs.
  • Les SDK existants pour différents langages ont fourni des idées sur les modèles et les améliorations possibles pour Python.

En référence à ces ressources, je peux voir une image claire de ce qu'il y a à faire. Bien que les détails sortent du cadre de cet article, avançons.

Configurer l'environnement

J'utilise un Mac, donc Python est déjà installé. Cependant, je me demandais s'il y avait une meilleure façon de gérer les versions de Python (j'ai entendu parler de la douleur liée à la compatibilité des versions), tout comme nvm pour Node.js. Rapidement, j'ai trouvé pyenv et j'ai directement commencé à l'installer.

Ensuite au programme : un gestionnaire de paquets et de dépendances. D'habitude, ils sont couplés. Alors pourquoi pas pip (le gestionnaire par défaut de Python) ? Si vous jetez un œil au requirements.txt, vous verrez que c'est juste une liste de paquets avec des versions. Cela ne suffit pas pour un SDK qui pourrait être utilisé par d'autres projets. Par exemple, nous pourrions avoir besoin d'ajouter des paquets pour le développement, mais nous ne voulons pas les inclure dans le SDK final. Le requirements.txt est trop simple pour gérer cela.

L'un des avantages lorsque vous avez d'autres langages de programmation dans votre pile technologique est que vous pouvez rechercher l'"équivalent en Python". Alors j'ai cherché "équivalent de package.json en Python" et j'ai trouvé Poetry, un candidat de choix :

  • Il fonctionne comme gestionnaire de paquets, de dépendances et de virtual environment.
  • Il dispose d'un fichier pyproject.toml, semblable à package.json dans Node.js.
  • Il utilise un fichier de verrouillage pour consigner les versions de dépendances précises.

Les interfaces de ligne de commande modernes (CLIs) comprennent souvent une commande init adaptée aux nouveaux projets. Poetry aussi. J'ai lancé la commande et elle a créé un fichier pyproject.toml pour moi.

La première ligne de code

Enfin, le moment de coder était arrivé. Commencer par le classique programme "Hello, World!" est toujours un bon choix. Lors de l'apprentissage d'un langage de programmation, les IDE complets ne sont pas toujours indispensables; un éditeur soutenu par une forte communauté, tel que VS Code, est tout à fait adéquat.

Étant donné que notre SDK se concentre sur les applications web, j'ai commencé avec un serveur web simple en utilisant le framework populaire Flask.

En tirant parti des capacités de Poetry, l'installation de Flask peut être facilement effectuée en exécutant poetry add flask. Ensuite, en suivant le guide de démarrage rapide de Flask, j'ai composé un fichier 'hello.py' avec le snippet suivant :

Lancer le serveur via flask --app hello run et naviguer à http://localhost:5000 sur mon navigateur a donné le résultat souhaité. Ça a marché !

En tant que débutant, je n'étais pas pressé d'écrire plus de code. Au lieu de cela, il y a beaucoup d'informations à recueillir à partir du snippet de code :

  • Utiliser from x import y pour importer un module ou une classe.
  • Pas de point-virgule pour terminer les lignes (oh non).
  • On peut définir une nouvelle variable en entrant un nom arbitraire et en lui assignant une valeur.
  • Créer une instance d'une classe sans le mot-clé new.
  • Python prend en charge les décorateurs, et le @app.route sert de décorateur qui enregistre une fonction comme gestionnaire de route.
    • La valeur de retour de la fonction est interprétée comme le corps de la réponse.
  • On peut définir une fonction en utilisant le mot-clé def.

Comme vous pouvez le voir, si l'on essaye de comprendre chaque ligne de code au lieu de « juste le faire fonctionner », on peut en apprendre beaucoup. Pendant ce temps, la documentation officielle de Flask a expliqué en détails le snippet.

Lancement du projet

Il est maintenant temps de commencer le projet. J'ai rapidement défini une classe LogtoClient et essayé d'ajouter quelques propriétés et méthodes pour me familiariser avec le langage :

Ensuite, intégrez la classe avec Flask :

Il commençait à ressembler à un projet réel. Mais je sentais qu'il manquait quelque chose : un système de types.

Système de types

Étant un SDK, incorporer un système de types aidera les utilisateurs à comprendre l'API et à réduire le risque d'erreurs lors du développement.

Python a introduit les annotations de types dans la version 3.5. Ce n'est pas aussi puissant que TypeScript, mais c'est mieux que rien. J'ai ajouté quelques annotations de types à la classe LogtoClient :

Ça a l'air beaucoup mieux maintenant. Mais le défi surgit lorsqu'il s'agit de types complexes comme un objet avec des clés pré-définies. Par exemple, nous devons définir une classe LogtoConfig pour représenter l'objet de configuration :

Ça a l'air correct, mais bientôt nous allons devoir faire face aux problèmes de codage, décodage et validation de l'objet depuis JSON.

Après quelques recherches, j'ai choisi pydantic comme solution. C'est une bibliothèque de validation de données qui fonctionne avec les annotations de types. Elle prend en charge diverses fonctionnalités JSON sans suivre un code standard fastidieux.

Ainsi, la classe LogtoConfig peut être réécrite comme suit :

Cela m'a également enseigné l'héritage des classes en Python en ajoutant des parenthèses après le nom de la classe.

Opérations asynchrones

Dans le SDK Logto, nous devons faire des requêtes HTTP au serveur Logto. Si vous avez de l'expérience avec JavaScript, la phrase "enfer des callbacks" résonne probablement. C'est un problème courant lors de la gestion des opérations asynchrones. Les langages de programmation modernes présentent des solutions similaires comme Promise ou coroutine.

Heureusement, Python a une solution intégrée de async et await. Avant de les utiliser, assurez-vous de la compatibilité avec les frameworks populaires. Dans Flask, cela peut être fait en installant l'extension async et en utilisant async def à la place de def :

Ensuite, nous pouvons utiliser await pour attendre le résultat d'une opération asynchrone.

Requêtes HTTP

Les requêtes HTTP sont un sujet intéressant. Presque tous les langages de programmation ont une solution native, mais les développeurs utilisent généralement une bibliothèque tierce pour plus de facilité d'utilisation. Quelques exemples :

  • JavaScript : XMLHttpRequest vs. fetch vs. axios
  • Swift : URLSession vs. Alamofire
  • Java : HttpURLConnection vs. OkHttp

C'est également vrai pour Python. Ma décision a été d'utiliser aiohttp car il prend en charge async et await, couplé à sa popularité.

La magie de Copilot

Avant Copilot, nous devrions maintenant arriver à la partie fastidieuse de l'écriture de la logique métier. Avec l'aide de la convention du SDK et d'autres SDKs, je peux écrire les commentaires descriptifs pour chaque méthode avant d'écrire le code.

Cela ajoute plus de lisibilité au code, et aide également les développeurs à comprendre l'API directement dans l'IDE ou l'éditeur via l'intelligence du code.

Par exemple, considérez la méthode generateCodeChallenge, les commentaires peuvent être rédigés ainsi :

Cela a constitué une grande incitation pour les grands modèles de langage (LLM) : comprendre les définitions de méthodes via des commentaires clairs. Et Copilot n'a pas déçu :

Quelques ajustements pourraient être nécessaires, mais peu importe. Cela a déjà changé la donne.

Conclusion

C'est à peu près le progrès réalisé durant le premier jour. Ce fut une longue journée, mais avec les outils et technologies modernes, c'était bien mieux que je ne l'avais imaginé.

Jour 2 : Élever le niveau

Sur la base du travail du premier jour, la logique métier était réalisée rapidement. Mais pour un SDK, c'est encore insuffisant. Voici les tâches du second jour :

  • Ajouter des tests unitaires.
  • Imposer le formatage du code.
  • Vérifier la compatibilité des versions de Python.
  • Ajouter l'intégration continue.
  • Publier le SDK.

Tests unitaires

Les tests unitaires nous ont sauvé plusieurs fois, donc je ne passerai pas à côté. Voici les considérations courantes lors de l'écriture de tests unitaires :

  • Comment organiser et exécuter les tests ?
  • Comment vérifier le résultat ?
  • Comment exécuter des tests asynchrones ? (Cela peut sembler simple, mais cela pose parfois des problèmes dans certains langages.)
  • Comment simuler les dépendances ? (Ne pas creuser trop dans ce sujet avant que ce soit indispensable, car cela peut mener à des cavités de lapin.)
  • Comment générer des rapports de couverture de code ?

Avec ces questions en tête, j'ai trouvé que le module intégré unittest était insuffisant pour certains cas. J'ai donc choisi pytest en tant que framework de tests. Il prend en charge les tests asynchrones et semble suffisamment mature.

Le parcours m'a révélé de nouveaux concepts intéressants comme fixture. Cela peut également bénéficier à la mentalité lors de l'écriture de code dans d'autres langages.

Formatage du code

Chaque langage a son propre style de formatage du code. Personnellement, un formatage cohérent peut me rendre heureux et à l'aise ; c'est aussi utile pour la révision du code et la collaboration.

Plutôt que de parcourir les arguments du "meilleur" style, j'ai décidé de choisir un formateur d'opinions et m'y tenir.

Black semble être un bon choix. La seule frustration est la taille des tabulations non modifiable. Mais ce n'est pas un gros problème, j'ai décidé de m'y accommoder.

Compatibilité des versions de Python

Étant un SDK, il doit être compatible avec les versions prédominantes de Python. En recherchant "statistiques d'utilisation des versions de Python", j'ai décidé d'utiliser Python 3.8 comme version minimale.

La vertu du gestionnaire d'environnement apparait maintenant. Je peux facilement basculer la version de Python en exécutant pyenv local 3.8 et poetry env use 3.8. Je pouvais ensuite exécuter les tests pour révéler les problèmes de compatibilité.

Intégration continue

L'intégration continue garantit la qualité de chaque changement de code. Comme notre dépôt était hébergé sur GitHub, GitHub Actions était le choix naturel.

Le workflow de base suit des principes simples :

  • Configurer l'environnement.
  • Installer les dépendances.
  • Construire le projet (Pas besoin pour Python cependant).
  • Exécuter les tests.

GitHub Actions dispose d'une bonne communauté, donc il ne faut que quelques minutes pour construire le workflow.

En utilisant des stratégies de matrice, nous pouvons exécuter le workflow sur différentes versions de Python, même sur différents systèmes d'exploitation.

Publier le SDK

La dernière étape est de publier le SDK. Pour les paquets publics, cela peut être fait en les soumettant au registre officiel propre au langage. Par exemple, npm pour Node.js, PyPI pour Python, et CocoaPods pour Swift.

Poetry est mon étoile guide. Il suffit de lancer poetry publish pour publier le paquet sur PyPI. C'est aussi simple que ça.

Réflexions finales

Ce fut une aventure captivante. Sans l'aide de la communauté open-source, cela aurait été beaucoup plus difficile. Applaudissons tous les contributeurs !

Voici quelques leçons générales à retenir :

  • Définissez précisément l'objectif et décomposez-le, puis gardez toujours l'objectif en tête.
  • Configurez un environnement de développement stable et reproductible.
  • Utilisez (de bons) outils autant que possible.
  • Priorisez les solutions intégrées ou existantes.
  • Comprenez les conventions du langage et chaque ligne de code que vous écrivez.
    • Cependant, ne vous attardez pas sur les détails.
  • Utilisez Copilot pour des tâches claires et descriptives.

Vous pouvez trouver le résultat final dans ce dépôt. Avec la même stratégie, j'ai également rapidement construit le SDK PHP Logto. N'hésitez pas à nous faire savoir si vous avez des suggestions.

J'espère que cet article sera utile pour apprendre un nouveau langage de programmation. Bon hacking !