Lerne Python an einem Wochenende: Von null zu einem vollständigen Projekt
Wie können wir schnell eine neue Programmiersprache erlernen? In diesem Artikel teilen wir unsere Wochenenderfahrung, Python zu lernen, indem wir ein vollständiges Projekt erstellen.
Einführung
Logto, als Identitätsdienst, sorgt für ein reibungsloses Erlebnis in verschiedenen Programmiersprachen und Frameworks. Dies beinhaltet oft die Erstellung von Software Development Kits (SDKs). Wenn die Programmiersprache jedoch außerhalb unseres Tech-Stacks liegt und unserem Team die Vertrautheit fehlt, wird es zu einer Herausforderung, ein robustes SDK zu erstellen.
Python stellte uns eine solche Herausforderung. Trotz zahlreicher Python-Nutzer fehlte uns ein Python SDK, was eine beständige Sorge darstellte. Entschlossen, dies anzugehen, begann ich, diese Lücke zu überbrücken.
Obwohl ich jahrelange Programmiererfahrung habe, bleibt Python für mich relativ unerschlossenes Terrain. Während ich vor Jahren kurzzeitig mit Python 2 für einfache Skripte experimentierte, war mein Wissen veraltet. Trotzdem war es an der Zeit, sich hineinzustürzen!
Tag 1: Grundlage legen
Ziel definieren
Meiner Erfahrung nach ist der effektivste Ansatz, eine neue Programmiersprache zu lernen, ein vollständiges Projekt zu bauen. Zum Glück war unser Ziel klar: Ein Logto Python SDK für Webanwendungen zu erstellen.
Anstatt direkt in den Code zu springen, lass uns das Ganze aufschlüsseln. Hier ist die Liste:
- Erstellen des Logto-Clients für Aufgaben wie Anmelden, Abmelden, Benutzerinformationen und Token-Management.
- Bereitstellung eines Tutorials und eines Beispielprojekts, um die Nutzung des SDKs zu demonstrieren.
- Veröffentlichung des SDKs irgendwo, damit die Benutzer es einfach installieren können.
Es sieht so aus, als ob Aufgabe 1 die meiste Arbeit erfordert, daher müssen wir den Umfang bestätigen und weiter aufschlüsseln. Dieser Schritt ist entscheidend, um den Projektrahmen zu sichern und Umfangserweiterungen und Überengineering zu vermeiden.
Vorherige Arbeiten unseres Teams haben mir eine Menge Zeit gespart:
- Eine SDK-Konvention skizzierte die Struktur und das API-Design von SDKs.
- Bestehende SDKs für verschiedene Sprachen lieferten Einblicke in Muster und potenzielle Verbesserungen für Python.
Anhand dieser Ressourcen kann ich ein klares Bild dessen sehen, was zu tun ist. Während die Details über den Rahmen dieses Artikels hinausgehen, machen wir jetzt weiter.
Die Umgebung einrichten
Ich benutze einen Mac, daher ist Python bereits installiert. Allerdings habe ich mich gefragt, ob es eine bessere Möglichkeit gibt, die Python-Versionen zu verwalten (ich habe von den Schmerzen der Versionskompatibilität gehört), genau wie nvm
für Node.js. Schnell fand ich pyenv und begann direkt mit der Installation.
Als nächstes auf der Tagesordnung: ein Paket- und Abhängigkeitsmanager. Normalerweise sind sie gekoppelt. Warum dann nicht pip
(das Python-Standardtool)? Wenn du dir die requirements.txt
ansiehst, wirst du feststellen, dass es sich nur um eine Liste von Paketen mit Versionen handelt. Das reicht für ein SDK, das möglicherweise von anderen Projekten verwendet wird, nicht aus. Zum Beispiel müssen wir möglicherweise einige Pakete für die Entwicklung hinzufügen, aber wir möchten sie nicht im endgültigen SDK enthalten. Die requirements.txt
ist zu einfach, um dies zu handhaben.
Einer der Vorteile, wenn du andere Programmiersprachen in deinem Tech-Stack hast, ist, dass du nach dem "Python-Äquivalent" suchen kannst. Also suchte ich nach "package.json Python-Äquivalent" und fand Poetry, einen großartigen Kandidaten:
- Es fungiert als Paketmanager, Abhängigkeitsmanager und als virtueller Umgebungsmanager.
- Es hat eine
pyproject.toml
-Datei, ähnlich wiepackage.json
in Node.js. - Es verwendet eine Sperrdatei, um genaue Abhängigkeitsversionen zu protokollieren.
Moderne CLIs umfassen oft einen init
-Befehl, der speziell für neue Projekte entwickelt wurde. So auch Poetry. Ich führte den Befehl aus und er erstellte eine pyproject.toml
-Datei für mich.
Die erste Codezeile
Endlich war der Moment gekommen, Code zu schreiben. Mit dem klassischen "Hello, World!" Programm zu beginnen, ist immer eine gute Wahl. Beim Erlernen einer Programmiersprache sind voll ausgestattete IDEs nicht immer erforderlich; ein von einer starken Community unterstützter Editor wie VS Code ist völlig ausreichend.
Da sich unser SDK auf Webanwendungen konzentriert, begann ich mit einem einfachen Webserver unter Verwendung des beliebten Frameworks Flask.
Dank der Fähigkeiten von Poetry kann Flask einfach installiert werden, indem man poetry add flask
ausführt. Dann, gemäß der offiziellen Schnellstartanleitung von Flask, schrieb ich eine 'hello.py'-Datei mit folgendem Codeabschnitt:
Das Starten des Servers mit flask --app hello run
und das Navigieren zu http://localhost:5000 in meinem Browser lieferte das gewünschte Ergebnis. Es funktionierte!
Als Anfänger habe ich es nicht eilig, mehr Code zu schreiben. Es gibt stattdessen eine Menge Informationen, die aus dem Codeabschnitt zu entnehmen sind:
- Verwende
from x import y
, um ein Modul oder eine Klasse zu importieren. - Kein Semikolon zum Beenden von Zeilen (oh nein).
- Wir können eine neue Variable definieren, indem wir einen beliebigen Namen eingeben und ihr einen Wert zuweisen.
- Erstellen einer Instanz einer Klasse ohne das
new
Schlüsselwort. - Python unterstützt Dekoratoren, und
@app.route
fungiert als Dekorator, der eine Funktion als Routen-Handler registriert.- Der Rückgabewert der Funktion wird als Antworttext interpretiert.
- Wir können eine Funktion mit dem
def
Schlüsselwort definieren.
Wie du sehen kannst, wenn wir versuchen, jede Zeile des Codes zu verstehen, anstatt es nur "zum Laufen zu bringen", können wir viel daraus lernen. In der Zwischenzeit erklärte die offizielle Dokumentation von Flask den Codeabschnitt im Detail.
Projektstart
Jetzt ist es an der Zeit, das Projekt zu starten. Kurz darauf definierte ich eine LogtoClient
-Klasse und versuchte, einige Eigenschaften und Methoden hinzuzufügen, um ein Gefühl für die Sprache zu bekommen:
Anschließend die Klasse in Flask integrieren:
Es begann sich wie ein echtes Projekt anzufühlen. Aber ich hatte das Gefühl, dass etwas fehlte: ein Typsystem.
Typsystem
Da es sich um ein SDK handelt, wird die Implementierung eines Typsystems den Benutzern helfen, die API zu verstehen und die Fehlerwahrscheinlichkeit bei der Entwicklung zu verringern.
Python führte Type Hints in Version 3.5 ein. Sie sind nicht so mächtig wie TypeScript, aber besser als nichts. Ich fügte der Klasse LogtoClient
einige Type Hints hinzu:
Sieht jetzt viel besser aus. Aber die Herausforderung warf sich auf, als es um komplexe Typen wie ein Objekt mit vordefinierten Schlüsseln ging. Zum Beispiel müssen wir eine LogtoConfig
-Klasse definieren, um das Konfigurationsobjekt darzustellen:
Sieht okay aus, aber bald müssen wir uns mit den Problemen der Codierung, Dekodierung und Validierung des Objekts aus JSON auseinandersetzen.
Nach einiger Recherche entschied ich mich für pydantic als Lösung. Es handelt sich um eine Datenvalidierungsbibliothek, die mit Type Hints funktioniert. Sie unterstützt verschiedene JSON-Funktionalitäten, ohne dass aufwendiger Boilerplate-Code erforderlich ist.
Daher kann die Klasse LogtoConfig
wie folgt umgeschrieben werden:
Es lehrte mich auch etwas über Klassenvererbung in Python, indem ich Klammern nach dem Klassennamen hinzufügte.
Asynchrone Operationen
Im Logto SDK müssen wir HTTP-Anfragen an den Logto-Server stellen. Wenn du Erfahrung mit JavaScript hast, mag der Begriff "Callback-Hölle" ein Begriff für dich sein. Es ist ein häufiges Problem, wenn man mit asynchronen Operationen arbeitet. Moderne Programmiersprachen bieten ähnliche Lösungen wie Promise
oder Coroutine
an.
Zum Glück hat Python eine eingebaute Lösung mit async
und await
. Bevor wir sie verwenden, stellen wir die Kompatibilität mit gängigen Frameworks sicher. In Flask kann dies durch die Installation des async
-Zusatzes und die Verwendung von async def
anstelle von def
erreicht werden:
Dann können wir await
verwenden, um das Ergebnis einer asynchronen Operation abzuwarten.
HTTP-Anfragen
HTTP-Anfragen sind ein interessantes Thema. Fast jede Programmiersprache hat eine native Lösung, aber Entwickler verwenden normalerweise eine Drittanbieterbibliothek aus Gründen der Benutzerfreundlichkeit. Einige Beispiele:
- JavaScript:
XMLHttpRequest
vs.fetch
vs.axios
- Swift:
URLSession
vs.Alamofire
- Java:
HttpURLConnection
vs.OkHttp
Das gilt auch für Python. Meine Entscheidung war, aiohttp zu verwenden, da es async
und await
unterstützt und ziemlich beliebt ist.
Die Magie von Copilot
Vor Copilot sollten wir jetzt zum mühsamen Teil des Schreibens von Geschäftslogik kommen. Mit Hilfe der SDK-Konvention und anderer SDKs kann ich die erklärenden Kommentare für jede Methode schreiben, bevor ich den Code schreibe.
Es erhöht die Lesbarkeit des Codes und hilft Entwicklern, die API direkt in der IDE oder im Editor durch Code-Intelligenz zu verstehen.
Betrachte zum Beispiel die Methode generateCodeChallenge
, die Kommentare können wie folgt geschrieben werden:
Dies stellte einen großartigen Hinweis für große Sprachmodelle (LLMs) dar: Definitionen von Methoden durch klare Kommentare zu verfassen. Und Copilot enttäuschte nicht:
Einige Anpassungen könnten erforderlich sein, aber das ist nicht wichtig. Es hat das Spiel bereits verändert.
Zusammenfassung
Das war so ziemlich der Fortschritt, den wir am ersten Tag erreicht haben. Es war ein langer Tag, aber mit modernen Werkzeugen und Technologien war es viel besser, als ich erwartet hatte.
Tag 2: Die Messlatte höher legen
Basierend auf den Arbeiten des ersten Tages wurden die Geschäftslogik schnell erledigt. Aber für ein SDK ist das noch nicht ausreichend. Hier sind die Aufgaben für den zweiten Tag:
- Unit-Tests hinzufügen.
- Codeformatierung erzwingen.
- Python-Versionskompatibilität überprüfen.
- Continuous Integration einrichten.
- Das SDK veröffentlichen.
Unit-Tests
Unit-Tests haben uns schon oft gerettet, also werde ich sie nicht überspringen. Hier sind allgemeine Überlegungen beim Schreiben von Unit-Tests:
- Wie organisiert und führt man die Tests aus?
- Wie wird das Ergebnis überprüft?
- Wie führt man asynchrone Tests aus? (Es klingt vielleicht einfach, aber es kann in einigen Sprachen Probleme verursachen.)
- Wie gibt man die Abhängigkeiten vor? (Tauchen Sie nicht in dieses Thema ein, bis es unverzichtbar wird, da es in Kaninchenlöcher führen kann.)
- Wie erstellt man Codeabdeckungsberichte?
Mit diesen Fragen im Hinterkopf stellte ich fest, dass das integrierte unittest
-Modul in einigen Fällen nicht ausreicht. Also entschied ich mich für pytest als Testframework. Es unterstützt asynchrone Tests und erscheint reif genug.
Die Reise offenbarte mir interessante neue Konzepte wie fixture
. Dies kann auch die Denkweise beim Schreiben von Code in anderen Sprachen bereichern.
Codeformatierung
Jede Programmiersprache hat ihre eigenen Codeformatierungsstile. Persönlich kann eine konsistente Formatierung mich glücklich und zufrieden machen; es ist auch hilfreich für den Code-Review und die Zusammenarbeit.
Anstatt das Argument des "besten" Stils zu durchsuchen, entschied ich mich für einen Meinungsstarken Formatierer und halte mich an ihn.
Black scheint eine gute Wahl zu sein. Die einzige Frustration ist die nicht-veränderbare Tab-Größe. Aber das ist kein großes Problem, ich entschied mich, mich anzupassen.
Python-Versionskompatibilität
Als SDK sollte es mit den gängigsten Python-Versionen kompatibel sein. Durch die Suche nach "Python Version Usage Statistics" entschied ich mich, Python 3.8 als Mindestversion festzulegen.
Die Tugend des Umgebungsmanagers zeigt sich jetzt. Ich kann die Python-Version einfach durch Ausführen von pyenv local 3.8
und poetry env use 3.8
umschalten. Dann könnte ich die Tests ausführen, um Kompatibilitätsprobleme aufzudecken.
Continuous Integration
Continuous Integration stellt die Qualität jeder Codeänderung sicher. Da unser Repository auf GitHub gehostet wird, bot sich GitHub Actions als natürliche Wahl an.
Der Kernablauf folgt einfachen Prinzipien:
- Die Umgebung einrichten.
- Abhängigkeiten installieren.
- Das Projekt bauen (Das ist bei Python nicht erforderlich).
- Die Tests ausführen.
GitHub Actions hat eine gute Community, daher dauert es nur ein paar Minuten, um den Workflow zu erstellen.
Durch die Verwendung von Matrixstrategien können wir den Workflow mit verschiedenen Python-Versionen und sogar auf verschiedenen Betriebssystemen ausführen lassen.
Das SDK veröffentlichen
Der letzte Schritt ist die Veröffentlichung des SDKs. Für öffentliche Pakete kann dies typischerweise durch die Übermittlung an das offizielle sprachspezifische Paketregister erfolgen. Zum Beispiel npm für Node.js, PyPI für Python, und CocoaPods für Swift.
Poetry ist mein Leitstern. Einfach poetry publish
ausführen, um das Paket an PyPI zu übermitteln. So einfach ist das.
Abschließende Gedanken
Es war eine spannende Reise. Ohne die Hilfe der Open-Source-Community wäre es wesentlich schwerer gewesen. Applaus an alle Mitwirkenden!
Hier sind einige allgemeine Erkenntnisse:
- Definiere das Ziel präzise und zerlege es, halte dir dann das Ziel immer vor Augen.
- Richte eine stabile und reproduzierbare Entwicklungsumgebung ein.
- Verwende (gute) Werkzeuge so viel wie möglich.
- Priorisiere integrierte oder bestehende Lösungen.
- Verstehe Sprachkonventionen und jede Zeile Code, die du schreibst.
- Fixiere dich jedoch nicht auf Details.
- Verwende Copilot für klare, beschreibende Aufgaben.
Du findest das Endergebnis in diesem Repository. Mit der gleichen Strategie habe ich auch schnell das Logto PHP SDK erstellt. Zögere nicht, uns zu kontaktieren, wenn du Vorschläge hast.
Ich hoffe, dieser Artikel ist hilfreich, um eine neue Programmiersprache zu lernen. Happy Hacking!