Русский
  • python
  • программирование
  • обучение
  • sdk

Изучение Python за выходные: От нуля до полного проекта

Как быстро освоить новый язык программирования? В этой статье мы поделимся нашим опытом выходных по изучению Python через создание полного проекта.

Gao
Gao
Founder

Введение

Logto, как сервис идентификации, стремится обеспечить плавный опыт взаимодействия в различных языках программирования и фреймворках. Это часто требует создания комплектов для разработки программного обеспечения (SDK). Однако, когда речь идет о языке программирования вне нашего технологического стека и наша команда не знакома с ним, создание надежного SDK становится серьезным вызовом.

Python оказался таким вызовом для нас. Несмотря на наличие многих пользователей Python, у нас не было Python SDK, что вызывало некоторые опасения. Решив устранить этот пробел, я начал работать над этим.

Хотя у меня многолетний опыт программирования, Python остается для меня относительно неизведанной территорией. В свое время я немного поигрался с Python 2 для написания простых скриптов, но мои знания устарели. Тем не менее, пришло время погружаться!

День 1: Заложить основу

Определение цели

По моему опыту, наиболее эффективный способ изучения нового языка программирования — это создание полного проекта. К счастью, наша цель была ясна: создать SDK Logto на Python для веб-приложений.

Вместо того, чтобы сразу же приступать к написанию кода, давайте разобьем задачу на этапы. Вот список:

  1. Создать клиента Logto для задач, таких как вход, выход, информация о пользователе и управление токенами.
  2. Предоставить руководство и пример проекта, чтобы показать использование SDK.
  3. Опубликовать SDK где-нибудь, чтобы пользователи могли легко его установить.

Похоже, что задача №1 требует наибольшего объема работы, поэтому нам нужно установить границы проекта и продолжить разбивку задач. Этот шаг важен для того, чтобы определить объем проекта и избежать его увеличения и чрезмерной инженерии.

Предыдущая работа нашей команды сэкономила мне кучу времени:

  • Конвенция по SDK определила структуру и дизайн API для SDK.
  • Существующие SDK для разных языков предоставили мне представление о некоторых шаблонах и возможных улучшениях для Python.

Ссылаясь на эти ресурсы, я получил четкое представление о том, что делать. Хотя подробности выходят за рамки этой статьи, давайте двигаться дальше.

Настройка окружения

Я использую Mac, поэтому Python уже установлен. Однако, меня заинтересовало, есть ли более удобный способ управления версиями Python (я слышал о проблемах с совместимостью версий), подобно nvm для Node.js. Быстро нашел pyenv и сразу же начал его установку.

Следующим пунктом повестки дня стал менеджер пакетов и зависимостей. Обычно они идут вместе. Так почему бы не использовать pip (по умолчанию в Python)? Если взглянуть на requirements.txt, то можно увидеть, что это просто список пакетов с версиями. Но этого недостаточно для SDK, который может использоваться другими проектами. Например, нам может потребоваться добавить некоторые пакеты для разработки, но мы не хотим включать их в финальный SDK. requirements.txt слишком прост для этого.

Одним из преимуществ наличия других языков программирования в вашем технологическом стеке является возможность искать "аналог Python в другой технологии". Так я нашел Poetry, отличного кандидата:

  • Он выступает в роли менеджера пакетов, зависимостей и виртуальных окружений.
  • В нем есть файл pyproject.toml, аналогичный package.json в Node.js.
  • Он использует файл блокировки для логирования точных версий зависимостей.

Современные CLI часто включают команду init для новых проектов. Также и в Poetry. Запустил команду, и он создал для меня файл pyproject.toml.

Первая строка кода

Наконец-то настал момент начать писать код. Начинать с классической программы "Hello, World!" всегда хорошая идея. При изучении языка программирования не всегда нужен полнофункциональный IDE; достаточно редактора, поддерживаемого сильным сообществом, таким как VS Code.

Учитывая, что наш SDK ориентирован на веб-приложения, я начал с простого веб-сервера, используя популярный фреймворк Flask.

Благодаря возможностям Poetry установка Flask может быть легко выполнена путем запуска команды poetry add flask. Затем, следуя официальному руководству по быстрому старту Flask, я написал файл "hello.py" со следующим фрагментом:

Запустив сервер с помощью команды flask --app hello run и перейдя по адресу http://localhost:5000 в браузере, я получил желаемый результат. Всё работает!

Будучи новичком, я не спешил писать больше кода. Вместо этого, из данного фрагмента кода можно почерпнуть много информации:

  • Для импорта модуля или класса используется from x import y.
  • Строки не заканчиваются точкой с запятой (о нет).
  • Можно определить новую переменную, вводя произвольное имя и присваивая ему значение.
  • Создание экземпляра класса без ключевого слова new.
  • Python поддерживает декораторы, и @app.route является декоратором, который регистрирует функцию в качестве обработчика маршрута.
    • Возвращаемое значение функции интерпретируется как тело ответа.
  • Функция определяется с помощью ключевого слова def.

Как видишь, если попытаться понять каждую строку кода, а не просто "запустить её", можно много узнать. Между тем, официальная документация Flask подробно объяснила этот фрагмент.

Начало проекта

Теперь пришло время начать проект. Скоро я определил класс LogtoClient и попытался добавить несколько свойств и методов, чтобы почувствовать язык:

Затем интегрировал этот класс в Flask:

Начало напоминать реальный проект. Но мне казалось, что чего-то не хватает: типовой системы.

Система типов

Поскольку это SDK, включение системы типов поможет пользователям понять API и уменьшит вероятность ошибок при разработке.

Python ввел типовые подсказки в версии 3.5. Это не столь мощная система, как TypeScript, но лучше, чем ничего. Я добавил несколько типовых подсказок в класс LogtoClient:

Теперь это выглядит намного лучше. Но сложность возрастает, когда речь заходит о сложных типах, например, объекты с заранее определенными ключами. Например, нам нужно определить класс LogtoConfig, чтобы представить объект конфигурации:

Это выглядит нормально, но вскоре нам придется столкнуться с проблемами кодирования, декодирования и проверки объекта из JSON.

После небольших исследований я выбрал pydantic в качестве решения. Это библиотека для валидации данных, работающая с типовыми подсказками. Она поддерживает различные функции для работы с JSON без необходимости писать скучный шаблонный код.

Таким образом, класс LogtoConfig можно переписать так:

Кроме того, это дало мне понимание наследования классов в Python — достаточно прописать круглые скобки после имени класса.

Асинхронные операции

Внутри SDK Logto нам нужно делать HTTP-запросы к серверу Logto. Если у тебя есть опыт работы с JavaScript, фраза "ад коллбеков" наверняка звучит знакомо. Это распространенная проблема при работе с асинхронными операциями. Современные языки программирования предлагают похожие решения, такие как Promise или корутины.

К счастью, Python предлагает встроенное решение с использованием async и await. Перед их использованием следует убедиться в совместимости с популярными фреймворками. В Flask это можно сделать, установив async extra и используя async def вместо def:

Затем можно использовать await для ожидания результата асинхронной операции.

HTTP запросы

HTTP-запросы — интересная тема. Практически в каждом языке программирования есть встроенное решение, но разработчики обычно выбирают сторонние библиотеки, если это упрощает задачу. Примеры:

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

То же самое верно для Python. Мой выбор пал на aiohttp из-за его поддержки async и await, а также популярности.

Магия Copilot

Раньше на этом этапе уже начинался запутанный процесс написания бизнес-логики. Но теперь, с помощью конвенций SDK и других SDK, я мог писать описательные комментарии для каждого метода перед написанием кода.

Это повышает читаемость кода, а также помогает разработчикам понимать API прямо в IDE или редакторе через возможности автодополнения кода.

Например, рассмотрим метод generateCodeChallenge, комментарии можно составить так:

Это стало отличным сигналом для моделей больших языков (LLM): методы, описанные четкими комментариями. И Copilot не разочаровал:

Могут потребоваться незначительные корректировки, но это неважно. Это уже изменило правила игры.

Завершение первого дня

На этом завершился первый день работы. Это был долгий день, но с современными инструментами и технологиями все оказалось гораздо лучше, чем я ожидал.

День 2: Поднятие планки

На основе выполненной работы первого дня бизнес-логика была завершена быстро. Но для SDK этого недостаточно. Вот задачи на второй день:

  • Добавить модульные тесты.
  • Обеспечить форматирование кода.
  • Проверить совместимость с версиями Python.
  • Настроить непрерывную интеграцию.
  • Опубликовать SDK.

Модульные тесты

Модульные тесты не раз спасали нас, поэтому я не пропустил их. Вот основные вопросы, которые необходимо учитывать при написании модульных тестов:

  • Как организовать и запускать тесты?
  • Как проверять результат?
  • Как запускать асинхронные тесты? (Звучит очевидно, но иногда возникают проблемы в некоторых языках.)
  • Как эмулировать зависимости? (Не углубляйся, пока это не станет абсолютно необходимым, так как можно легко угодить в кроличью нору.)
  • Как создавать отчеты о покрытии кода?

Ответы на эти вопросы показали мне, что встроенный модуль unittest не подходит для некоторых случаев. Поэтому я выбрал pytest как тестовый фреймворк. Он поддерживает асинхронные тесты и кажется достаточно зрелым.

В ходе работы я обнаружил множество интересных новых концепций, таких как fixture. Это также полезно для изменения подхода к написанию кода на других языках.

Форматирование кода

У каждого языка программирования есть свои стили форматирования кода. Лично я считаю, что достижение консистентности форматирования делает меня счастливыми и комфортными; это также полезно для организации обзора и сотрудничества в коде.

Вместо того чтобы углубляться в споры о "лучшем" стиле, я решил взять на вооружение категоричный форматер и придерживаться его.

Black мне понравился. Единственное огорчение — невозможность изменить размер табуляции. Но это не критично, я решил привыкнуть.

Совместимость версий Python

Как SDK, он должен быть совместим со всеми распространенными версиями Python. Поискав "статистику использования версий Python", я решил использовать Python 3.8 как минимум.

Достоинство менеджера окружения стало очевидным. Я легко переключил версию Python, запустив pyenv local 3.8 и poetry env use 3.8. Теперь я мог запускать тесты и выявлять проблемы совместимости.

Непрерывная интеграция

Непрерывная интеграция гарантирует качество каждого изменения кода. Поскольку наш репозиторий размещается на GitHub, естественным выбором стало GitHub Actions.

Основной рабочий процесс следует простым принципам:

  • Настройка окружения.
  • Установка зависимостей.
  • Сборка проекта (в Python это не требуется).
  • Запуск тестов.

У GitHub Actions хорошее сообщество, так что на создание рабочего процесса у меня ушло всего несколько минут.

Используя стратегии матриц, мы можем запускать рабочий процесс на разных версиях Python, даже на разных операционных системах.

Публикация SDK

Последним шагом стала публикация SDK. Для публичных пакетов это обычно делается путем отправки в официальный реестр пакетов для конкретного языка. Например, npm для Node.js, PyPI для Python и CocoaPods для Swift.

Poetry стал моим руководством. Просто запустил команду poetry publish, чтобы опубликовать пакет в PyPI. Всё очень просто.

Заключительные мысли

Это было увлекательное путешествие. Без помощи сообщества с открытым исходным кодом это было бы намного сложнее. Аплодирую всем участникам!

Вот несколько выводов, которые можно усвоить:

  • Четко определяйте цель и разбивайте её на составляющие, и всегда держите её в голове.
  • Настройте стабильное и воспроизводимое окружение для разработки.
  • Используйте (хорошие) инструменты как можно чаще.
  • Отдавайте предпочтение встроенным или существующим решениям.
  • Понимание конвенций языка и каждой строки вашего кода.
    • Однако не зацикливайтесь на мелочах.
  • Используйте Copilot для ясных, описательных задач.

Исходное решение можно найти в этом репозитории. С той же стратегией я также быстро создал Logto PHP SDK. Не стесняйтесь сообщить нам, если у вас есть предложения.

Надеюсь, эта статья окажется полезной для изучения нового языка программирования. Удачи в кодинге!