• python
  • programowanie
  • nauka
  • sdk

Naucz się Pythona w weekend: Od zera do pełnego projektu

Jak szybko możemy nauczyć się nowego języka programowania? W tym artykule podzielimy się naszym weekendowym doświadczeniem z nauką Pythona poprzez budowanie pełnego projektu.

Gao
Gao
Founder

Wprowadzenie

Logto, jako usługa tożsamości, zapewniającą płynne doświadczenie we wszelkich językach programowania i frameworkach, jest kluczowe. Często wymaga to tworzenia Software Development Kitów (SDK). Jednak kiedy dany język programowania nie znajduje się w naszym stosie technologicznym, a nasz zespół nie ma z nim doświadczenia, stworzenie solidnego SDK staje się wyzwaniem.

Python stanowił dla nas takie wyzwanie. Pomimo posiadania wielu użytkowników Pythona, brakowało nam SDK dla Pythona, co było stałym problemem. Zdeterminowany, aby to rozwiązać, zacząłem wypełniać ten brak.

Chociaż mam wieloletnie doświadczenie w programowaniu, Python wciąż jest dla mnie stosunkowo nieznanym terytorium. Chociaż bawiłem się Pythonem 2 przez krótki czas, aby napisać proste skrypty lata temu, moja wiedza była przestarzała. Niemniej jednak, nadszedł czas, aby zanurzyć się!

Dzień 1: Połóż fundamenty

Określ cel

Z mojego doświadczenia wynika, że najskuteczniejszym podejściem do nauki nowego języka programowania jest zbudowanie pełnego projektu. Na szczęście nasz cel był prosty: stworzyć SDK Pythona dla aplikacji webowych dla Logto.

Zamiast od razu rzucić się do kodowania, podzielmy to na kroki. Oto lista:

  1. Utwórz klienta Logto do zadań takich jak logowanie, wylogowywanie, zarządzanie informacjami o użytkowniku i tokenami.
  2. Zapewnij samouczek i przykład projektu pokazujący, jak używać SDK.
  3. Opublikuj SDK w odpowiednim miejscu, aby użytkownicy mogli je łatwo zainstalować.

Wygląda na to, że zadanie 1 wymaga najwięcej pracy, więc musimy potwierdzić zakres i kontynuować jego rozbicie. Ten krok jest kluczowy, aby zabezpieczyć granice projektu i uniknąć rozszerzania zakresu oraz nadmiernego inżynierowania.

Poprzednia praca naszego zespołu zaoszczędziła mi mnóstwo czasu:

  • Konwencja SDK określiła strukturę i projekt API SDK.
  • Istniejące SDK dla różnych języków dostarczyły wglądu w wzorce i potencjalne ulepszenia dla Pythona.

Odniesienie się do tych zasobów dało mi jasny obraz tego, co należy zrobić. Chociaż szczegóły wykraczają poza zakres tego artykułu, przejdźmy dalej.

Konfiguracja środowiska

Używam Maca, więc Python jest już zainstalowany. Zastanawiałem się jednak, czy jest lepszy sposób zarządzania wersjami Pythona (słyszałem o problemach z kompatybilnością wersji), podobnie jak nvm dla Node.js. Szybko znalazłem pyenv i od razu zabrałem się do instalacji.

Następnym punktem programu był menedżer pakietów i zależności. Zazwyczaj są one połączone. Dlaczego więc nie skorzystać z pip (domyślnego dla Pythona)? Jeśli spojrzysz na requirements.txt, zobaczysz, że to tylko lista pakietów z wersjami. To nie wystarczy dla SDK, który może być używany przez inne projekty. Na przykład, możemy potrzebować dodać kilka pakietów do rozwoju, ale nie chcemy ich uwzględniać w finalnym SDK. requirements.txt jest zbyt prosty, aby to obsłużyć.

Jedną z korzyści wynikających z posiadania innych języków programowania w swoim stosie technologicznym jest możliwość wyszukania „odpowiednika w Pythonie”. Więc wpisałem „odpowiednik package.json dla Pythona” i znalazłem Poetry, doskonałego kandydata:

  • Działa jako menedżer pakietów, menedżer zależności i menedżer środowiska wirtualnego.
  • Ma plik pyproject.toml, podobny do package.json w Node.js.
  • Używa pliku lock do zapisywania dokładnych wersji zależności.

Nowoczesne CLI często zawierają polecenie init przeznaczone dla nowych projektów. Podobnie jest z Poetry. Uruchomiłem polecenie i utworzyło ono dla mnie plik pyproject.toml.

Pierwsza linia kodu

W końcu nadszedł czas na napisanie kodu. Rozpoczęcie od klasycznego programu „Hello, World!” to zawsze dobry wybór. Kiedy uczysz się języka programowania, pełnowartościowe IDE nie zawsze są niezbędne; wystarczy edytor wspierany przez silną społeczność, taki jak VS Code.

Biorąc pod uwagę, że nasze SDK koncentruje się na aplikacjach webowych, rozpocząłem od prostego serwera webowego z użyciem popularnego frameworka Flask.

Wykorzystując możliwości Poetry, instalacja Flask może być łatwo dokonana za pomocą polecenia poetry add flask. Następnie, postępując zgodnie z oficjalnym przewodnikiem szybkiego startu Flask, napisałem plik 'hello.py' z następującym fragmentem kodu:

Uruchomienie serwera poprzez flask --app hello run i przejście do http://localhost:5000 w mojej przeglądarce dało pożądany wynik. Zadziałało!

Jako początkujący, nie spieszyłem się z pisaniem więcej kodu. Zamiast tego jest mnóstwo informacji do uzyskania z tego fragmentu kodu:

  • Użyj from x import y, aby zaimportować moduł lub klasę.
  • Brak średnika do zakończenia linii (o nie).
  • Możemy zdefiniować nową zmienną, wpisując dowolną nazwę i przypisując jej wartość.
  • Tworzenie instancji klasy bez użycia słowa kluczowego new.
  • Python obsługuje dekoratory, a @app.route działa jako dekorator rejestrujący funkcję jako obsługujący trasę.
    • Zwrócona przez funkcję wartość jest interpretowana jako treść odpowiedzi.
  • Możemy zdefiniować funkcję przy użyciu słowa kluczowego def.

Jak widać, jeśli spróbujemy zrozumieć każdą linię kodu zamiast „po prostu sprawić, żeby działało”, możemy się wiele z niej nauczyć. Tymczasem oficjalna dokumentacja Flask szczegółowo wyjaśniała ten fragment.

Rozpoczęcie projektu

Nadszedł czas, aby rozpocząć projekt. Wkrótce zdefiniowałem klasę LogtoClient i spróbowałem dodać kilka właściwości oraz metod, aby lepiej poznać język:

Następnie zintegrowałem klasę z Flaskiem:

Zaczęło to przypominać prawdziwy projekt. Jednak czegoś mi brakowało: systemu typów.

System typów

Jako SDK, wprowadzenie systemu typów pomoże użytkownikom zrozumieć API i zmniejszy ryzyko błędów podczas tworzenia oprogramowania.

Python wprowadził wskazówki typów w wersji 3.5. Nie są one tak potężne jak w TypeScript, ale lepsze to niż nic. Dodałem kilka wskazówek typów do klasy LogtoClient:

Wygląda to znacznie lepiej. Jednak napotkałem problem, gdy doszło do bardziej złożonych typów, jak obiekt o z góry ustalonych kluczach. Na przykład, musimy zdefiniować klasę LogtoConfig, aby reprezentowała obiekt konfiguracji:

To wygląda okej, ale szybko napotkamy problemy z kodowaniem, dekodowaniem i walidacją obiektu z JSON-a.

Po pewnych badaniach zdecydowałem się na pydantic jako rozwiązanie. Jest to biblioteka do walidacji danych, która współpracuje ze wskazówkami dotyczącymi typów. Obsługuje różne funkcjonalności JSON bez uciążliwego kodu szablonowego.

Dzięki temu klasa LogtoConfig może zostać przepisana jako:

Nauczyło mnie to również, jak działa dziedziczenie klas w Pythonie poprzez dodanie nawiasów po nazwie klasy.

Operacje asynchroniczne

W SDK Logto musimy wykonywać zapytania HTTP do serwera Logto. Jeśli masz doświadczenie z JavaScriptem, fraza „piekło callbacków” prawdopodobnie brzmi ci znajomo. Jest to często spotykany problem przy pracy z operacjami asynchronicznymi. Współczesne języki programowania przedstawiają podobne rozwiązania, takie jak Promise lub coroutine.

Na szczęście Python ma wbudowane rozwiązanie async i await. Zanim ich użyjesz, upewnij się, że są kompatybilne z popularnymi frameworkami. W Flasku można to zrobić, instalując dodatkowy pakiet async i używając async def zamiast def:

Następnie możemy użyć await, aby poczekać na wynik operacji asynchronicznej.

Zapytania HTTP

Zapytania HTTP to ciekawy temat. Prawie każdy język programowania ma rozwiązanie natywne, ale deweloperzy zazwyczaj korzystają z biblioteki zewnętrznej dla ułatwienia użycia. Oto kilka przykładów:

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

Podobnie jest z Pythonem. Moim wyborem było użycie aiohttp, ponieważ obsługuje async i await, a także jest popularny.

Magia Copilota

Przed Copilotem, teraz powinniśmy zajmować się żmudną częścią pisania logiki biznesowej. Dzięki pomocy konwencji SDK i innym SDK mogłem napisać opisowe komentarze dla każdej metody przed napisaniem kodu.

Zwiększa to czytelność kodu i pomaga deweloperom zrozumieć API bezpośrednio w IDE lub edytorze poprzez inteligencję kodu.

Na przykład, rozważmy metodę generateCodeChallenge, komentarze mogą wyglądać tak:

To doskonała podpowiedź dla Large Language Models (LLM): tworzenie definicji metod poprzez jasne komentarze. Copilot nie zawiódł:

Możliwe, że pewne poprawki będą potrzebne, ale to nie problem. Copilot z pewnością zmienił zasady gry.

Podsumowanie

W zasadzie tyle osiągnąłem pierwszego dnia. To był długi dzień, ale dzięki nowoczesnym narzędziom i technologiom było to znacznie lepsze, niż się spodziewałem.

Dzień 2: Podnieś poprzeczkę

Na podstawie pracy z pierwszego dnia, logika biznesowa była tworzona szybko. Jednak dla SDK to wciąż za mało. Oto zadania na drugi dzień:

  • Dodaj testy jednostkowe.
  • Wymuś formatowanie kodu.
  • Sprawdź zgodność z wersjami Pythona.
  • Dodaj ciągłą integrację.
  • Opublikuj SDK.

Testy jednostkowe

Testy jednostkowe uratowały nas wiele razy, więc ich nie pominę. Oto typowe kwestie, które należy wziąć pod uwagę podczas pisania testów jednostkowych:

  • Jak organizować i uruchamiać testy?
  • Jakie asercje użyć do sprawdzenia wyników?
  • Jak uruchamiać testy asynchroniczne? (Wydaje się to banalne, ale sporadycznie wywołuje problemy w niektórych językach.)
  • Jak zamockować zależności? (Nie zagłębiaj się w ten temat, dopóki nie jest niezbędny, ponieważ może prowadzić do „dziur króliczych”.)
  • Jak wygenerować raporty z pokrycia kodu?

Z tymi pytaniami w głowie stwierdziłem, że wbudowany moduł unittest okazał się niewystarczający w niektórych przypadkach. Dlatego wybrałem pytest jako framework testowy. Obsługuje testy asynchroniczne i wydaje się wystarczająco dojrzały.

Podczas tej podróży odkryłem kilka interesujących nowych pojęć, takich jak fixture. Może to również przydać się w myśleniu podczas pisania kodu w innych językach.

Formatowanie kodu

Każdy język ma swoje własne style formatowania kodu. Osobiście, spójne formatowanie sprawia, że czuję się zadowolony i komfortowo; jest to również pomocne podczas przeglądów kodu i współpracy.

Zamiast przeszukiwać argumenty na temat „najlepszego” stylu, postanowiłem wybrać opiniowanego formatera i trzymać się go.

Black wygląda na dobry wybór. Jedynym problemem jest nieregulowany rozmiar tabulacji. Jednak to niewielki problem, postanowiłem się do niego dostosować.

Zgodność z wersjami Pythona

Jako SDK, powinno być zgodne z popularnymi wersjami Pythona. Po przeszukaniu „statystyk użytkowania wersji Pythona”, postanowiłem użyć Python 3.8 jako minimalnej wersji.

Zaletą tego menedżera środowiska teraz się ukazuje. Mogę łatwo przełączać wersje Pythona, uruchamiając pyenv local 3.8 oraz poetry env use 3.8. Następnie mogłem uruchomić testy, aby ujawnić problemy z kompatybilnością.

Ciągła integracja

Ciągła integracja gwarantuje jakość każdej zmiany kodu. Ponieważ nasz repozytorium było hostowane w GitHubie, GitHub Actions były naturalnym wyborem.

Główna przepływ pracy opiera się na prostych zasadach:

  • Skonfiguruj środowisko.
  • Zainstaluj zależności.
  • Zbuduj projekt (Oczywiście w Pythonie nie jest to konieczne).
  • Uruchom testy.

GitHub Actions ma dobrą społeczność, więc zbudowanie przepływu pracy zajęło tylko kilka minut.

Stosując strategię macierzy, możemy uruchomić przepływ pracy na różnych wersjach Pythona, a nawet na różnych systemach operacyjnych.

Publikacja SDK

Ostatnim krokiem jest opublikowanie SDK. W przypadku pakietów publicznych można to zazwyczaj zrobić, przesyłając je do oficjalnego rejestru pakietów specyficznego dla danego języka. Na przykład, npm dla Node.js, PyPI dla Pythona, oraz CocoaPods dla Swift.

Poetry jest moją gwiazdą przewodnią. Wystarczy uruchomić poetry publish, aby opublikować pakiet w PyPI. To takie proste.

Końcowe przemyślenia

To była interesująca podróż. Bez wsparcia społeczności open-source byłoby znacznie trudniej. Wielkie brawa dla wszystkich współtwórców!

Oto kilka ogólnych wniosków:

  • Dokładnie określ cel i podziel go na części, a następnie zawsze trzymaj cel w pamięci.
  • Skonfiguruj stabilne i powtarzalne środowisko rozwojowe.
  • Korzystaj (dobrych) narzędzi jak najwięcej.
  • Priorytetyzuj rozwiązania wbudowane lub już istniejące.
  • Zrozum konwencje języka oraz każdy napisany przez siebie kod.
    • Jednak nie skupiaj się na drobiazgach.
  • Używaj Copilota do jasnych, opisowych zadań.

Ostateczne wyniki możesz znaleźć w tym repozytorium. Dzięki tej samej strategii, szybko zbudowałem również Logto PHP SDK. Nie wahaj się dać nam znać, jeśli masz jakiekolwiek sugestie.

Mam nadzieję, że ten artykuł okaże się pomocny w nauce nowego języka programowania. Miłego kodowania!