Aprende Python en un fin de semana: De cero a un proyecto completo
¿Cómo podemos aprender rápidamente un nuevo lenguaje de programación? En este artículo, compartiremos nuestra experiencia de fin de semana al aprender Python construyendo un proyecto completo.
Introducción
Logto, como servicio de identidad, proporcionar una experiencia fluida en diversos lenguajes de programación y marcos es esencial. Esto a menudo implica crear Kits de Desarrollo de Software (SDKs). Sin embargo, cuando el lenguaje de programación está fuera de nuestra pila tecnológica y nuestro equipo carece de familiaridad, crear un SDK robusto se convierte en un reto.
Python nos presentó tal desafío. A pesar de contar con muchos usuarios de Python, carecíamos de un SDK de Python, una preocupación persistente. Determinado a abordar esto, comencé a cerrar esta brecha.
Aunque tengo años de experiencia en programación, Python sigue siendo un territorio relativamente inexplorado para mí. Aunque jugueteé con Python 2 brevemente para scripts simples años atrás, mi conocimiento estaba desactualizado. Sin embargo, ¡era momento de sumergirse!
Día 1: Establecer las bases
Definir el objetivo
En mi experiencia, el enfoque más efectivo para aprender un nuevo lenguaje de programación es construir un proyecto completo. Afortunadamente, nuestro objetivo era claro: construir un SDK de Python para Logto enfocado en aplicaciones web.
En lugar de saltar directamente al código, vamos a desglosarlo. Aquí está la lista:
- Crear el cliente de Logto para tareas como iniciar sesión, cerrar sesión, obtener información del usuario y gestionar tokens.
- Proporcionar un tutorial y un proyecto de ejemplo que muestre el uso del SDK.
- Publicar el SDK en algún lugar para que los usuarios puedan instalarlo fácilmente.
Parece que la tarea 1 tiene la mayor carga de trabajo, por lo que necesitamos confirmar el alcance y continuar desglosándolo. Este paso es crucial para asegurar los límites del proyecto, y evitar la expansión del alcance y la sobre-ingeniería.
El trabajo previo de nuestro equipo me ahorró mucho tiempo:
- Una convención de SDK que describe la estructura y el diseño de la API de los SDKs.
- Los SDKs existentes para diferentes lenguajes proporcionaron ideas sobre patrones y posibles mejoras para Python.
Al referenciar estos recursos, tengo una imagen clara de lo que hay que hacer. Aunque los detalles están fuera del alcance de este artículo, sigamos adelante.
Configurar el entorno
Estoy usando una Mac, por lo que Python ya está instalado. Sin embargo, me preguntaba si hay una mejor manera de gestionar las versiones de Python (he oído sobre el dolor de la compatibilidad de versiones), al igual que nvm
para Node.js. Rápidamente encontré pyenv y empecé a instalarlo directamente.
Lo próximo en la agenda: un gestor de paquetes y dependencias. Usualmente están acoplados. Entonces, ¿por qué no pip
(el predeterminado de Python)? Si echas un vistazo al requirements.txt
, verás que es solo una lista de paquetes con versiones. Esto no es suficiente para un SDK que puede ser usado por otros proyectos. Por ejemplo, podríamos necesitar agregar algunos paquetes para desarrollo, pero no queremos incluirlos en el SDK final. El requirements.txt
es demasiado simple para manejar esto.
Uno de los beneficios de tener otros lenguajes de programación en tu pila tecnológica es que puedes buscar el "equivalente en Python". Así que busqué "equivalente a package.json en Python" y encontré Poetry, un candidato estelar:
- Funciona como un gestor de paquetes, gestor de dependencias y gestor de entornos virtuales.
- Tiene un archivo
pyproject.toml
, similar apackage.json
en Node.js. - Emplea un archivo de bloqueo para registrar versiones precisas de dependencias.
Las CLI modernas a menudo incluyen un comando init
diseñado para nuevos proyectos. Poetry también lo tiene. Ejecuté el comando y me creó un archivo pyproject.toml
.
La primera línea de código
Finalmente, había llegado el momento de escribir código. Empezar con el clásico programa "¡Hola, Mundo!" es siempre una buena elección. Al aprender un lenguaje de programación, los IDEs con todas las funciones no siempre son esenciales; un editor respaldado por una comunidad sólida, como VS Code, es completamente adecuado.
Dado que nuestro SDK se centra en aplicaciones web, comencé con un simple servidor web utilizando el popular framework Flask.
Aprovechando las capacidades de Poetry, instalar Flask se puede hacer fácilmente ejecutando poetry add flask
. Luego, siguiendo la guía de inicio rápido oficial de Flask, compuse un archivo 'hello.py' con el siguiente fragmento:
Al lanzar el servidor a través de flask --app hello run
y navegar a http://localhost:5000 en mi navegador, obtuve el resultado deseado. ¡Funcionó!
Como principiante, no tenía prisa por escribir más código. En cambio, hay mucha información que recibir del fragmento de código:
- Usar
from x import y
para importar un módulo o clase. - No se necesita punto y coma para terminar las líneas (oh no).
- Podemos definir una nueva variable ingresando un nombre arbitrario y asignarle un valor.
- Crear una instancia de una clase sin la palabra clave
new
. - Python admite decoradores, y
@app.route
sirve como un decorador que registra una función como un manejador de rutas.- El valor de retorno de la función se interpreta como el cuerpo de la respuesta.
- Podemos definir una función utilizando la palabra clave
def
.
Como puedes ver, si intentamos entender cada línea de código en lugar de "simplemente hacerlo funcionar", podemos aprender mucho de ella. Mientras tanto, la documentación oficial de Flask explicó en detalle el fragmento.
Inicio del proyecto
Ahora es momento de comenzar el proyecto. Pronto definí una clase LogtoClient
e intenté agregar algunas propiedades y métodos para sentir el lenguaje:
Posteriormente, integrar la clase con Flask:
Empezó a sentirse como un proyecto real. Pero sentí que faltaba algo: un sistema de tipado.
Sistema de tipado
Ya que es un SDK, incorporar un sistema de tipos ayudará a los usuarios a entender la API y reducir la posibilidad de errores al desarrollar.
Python introdujo indicaciones de tipo en la versión 3.5. No son tan poderosas como TypeScript, pero es mejor que nada. Agregué algunas indicaciones de tipo a la clase LogtoClient
:
Ahora se ve mucho mejor. Pero el desafío surge cuando se trata de un tipo complejo, como un objeto con claves predefinidas. Por ejemplo, necesitamos definir una clase LogtoConfig
para representar el objeto de configuración:
Parece estar bien, pero pronto tendremos que enfrentar los problemas de codificación, decodificación y validación del objeto desde JSON.
Después de investigar un poco, elegí pydantic como la solución. Es una biblioteca de validación de datos que trabaja con las indicaciones de tipo. Admite diversas funcionalidades con JSON sin tener que seguir un código repetitivo y tedioso.
Así, la clase LogtoConfig
se puede reescribir como:
También me enseñó sobre la herencia de clases en Python agregando paréntesis después del nombre de la clase.
Operaciones asíncronas
Dentro del SDK de Logto, necesitamos realizar solicitudes HTTP al servidor de Logto. Si tienes experiencia con JavaScript, probablemente "callback hell" te suene. Es un problema común al tratar con operaciones asíncronas. Los lenguajes de programación modernos presentan soluciones similares como Promise
o coroutine
.
Afortunadamente, Python tiene una solución integrada de async
y await
. Antes de usarlos, asegúrate de la compatibilidad con los marcos populares. En Flask, esto se puede hacer instalando el extra async
y usando async def
en lugar de def
:
Entonces podemos usar await
para esperar el resultado de una operación asincrónica.
Solicitudes HTTP
Las solicitudes HTTP son un tema interesante. Casi todos los lenguajes de programación tienen una solución nativa, pero los desarrolladores suelen utilizar una biblioteca de terceros por facilidad de uso. Algunos ejemplos:
- JavaScript:
XMLHttpRequest
vs.fetch
vs.axios
- Swift:
URLSession
vs.Alamofire
- Java:
HttpURLConnection
vs.OkHttp
Esto también es cierto para Python. Mi decisión fue usar aiohttp ya que admite async
y await
, junto con su popularidad.
La magia de Copilot
Antes de Copilot, ahora deberíamos llegar a la parte tediosa de escribir la lógica del negocio. Con la ayuda de la convención del SDK y otros SDKs, puedo escribir los comentarios descriptivos para cada método antes de escribir el código.
Esto agrega más legibilidad al código, y también ayuda a los desarrolladores a entender la API directamente en el IDE o editor a través de la inteligencia de código.
Por ejemplo, considera el método generateCodeChallenge
, los comentarios pueden escribirse como:
Esto presentó un gran prompt para los Modelos de Lenguaje Grande (LLMs): componer definiciones de métodos mediante comentarios claros. Y Copilot no decepcionó:
Algunos ajustes podrían ser necesarios, pero no importa. Ya cambió las reglas del juego.
Resumen
Esto es básicamente el progreso logrado en el primer día. Fue un día largo, pero con las herramientas y tecnologías modernas, fue mucho mejor de lo que esperaba.
Día 2: Elevar el listón
Basándome en el trabajo del primer día, la lógica del negocio se completó rápidamente. Pero para un SDK, todavía es insuficiente. Aquí están las tareas para el segundo día:
- Agregar pruebas unitarias.
- Hacer cumplir el formateo del código.
- Verificar la compatibilidad de versiones de Python.
- Agregar integración continua.
- Publicar el SDK.
Pruebas unitarias
Las pruebas unitarias nos han salvado muchas veces, por lo que no las voy a omitir. Aquí hay consideraciones comunes al escribir pruebas unitarias:
- ¿Cómo organizar y ejecutar las pruebas?
- ¿Cómo afirmar el resultado?
- ¿Cómo ejecutar pruebas asincrónicas? (Parece una obviedad, pero ocasionalmente causa problemas en algunos lenguajes.)
- ¿Cómo simular las dependencias? (No te sumerjas en este tema hasta que sea indispensable, ya que puede llevarte a madrigueras sin fin.)
- ¿Cómo generar informes de cobertura de código?
Con estas preguntas en mente, descubrí que el módulo unittest
incorporado se quedaba corto en algunos casos. Así que elegí pytest como el marco de pruebas. Admite pruebas asíncronas y parece lo suficientemente maduro.
El viaje reveló algunos conceptos nuevos e interesantes como fixture
para mí. Esto también puede beneficiar la mentalidad al escribir código en otros lenguajes.
Formateo del código
Cada lenguaje tiene sus propios estilos de formateo de código. Personalmente, el formateo consistente puede hacerme feliz y cómodo; también es útil para la revisión de código y la colaboración.
En lugar de andar buscando el argumento del "mejor" estilo, decidí elegir un formateador con opinión y adherirme a él.
Black parece una buena elección. La única frustración es el tamaño de tabulación no modificable. Pero no es un gran problema, elegí adaptarme a él.
Compatibilidad de versiones de Python
Como un SDK, debería ser compatible con las versiones prevalentes de Python. Al buscar "estadísticas de uso de las versiones de Python", decidí usar Python 3.8 como la versión mínima.
La ventaja del gestor de entornos ahora se muestra. Puedo cambiar fácilmente la versión de Python al ejecutar pyenv local 3.8
y poetry env use 3.8
. Luego podría ejecutar las pruebas para descubrir problemas de compatibilidad.
Integración continua
La integración continua garantiza la calidad de cada cambio de código. Como nuestro repositorio se alojaba en GitHub, GitHub Actions era la opción natural.
El flujo de trabajo central sigue principios sencillos:
- Configurar el entorno.
- Instalar dependencias.
- Compilar el proyecto (No es necesario para Python, sin embargo).
- Ejecutar las pruebas.
GitHub Actions tiene una buena comunidad, por lo que solo toma unos minutos construir el flujo de trabajo.
Al emplear estrategias de matrices, podemos ejecutar el flujo de trabajo en diferentes versiones de Python, incluso en diferentes sistemas operativos.
Publicar el SDK
El último paso es publicar el SDK. Para paquetes públicos, esto generalmente se puede hacer enviándolo al registro oficial de paquetes específico del lenguaje. Por ejemplo, npm para Node.js, PyPI para Python, y CocoaPods para Swift.
Poetry es mi estrella guía. Solo ejecuta poetry publish
para publicar el paquete en PyPI. Es así de simple.
Reflexiones finales
Fue un viaje atractivo. Sin la ayuda de la comunidad de código abierto, habría sido mucho más difícil. ¡Aplausos a todos los contribuidores!
Aquí hay algunos aprendizajes generales:
- Define el objetivo con precisión y desglósalo, luego mantén siempre el objetivo en mente.
- Configura un entorno de desarrollo estable y reproducible.
- Usa (buenas) herramientas tanto como sea posible.
- Prioriza soluciones integradas o existentes.
- Comprende las convenciones del lenguaje y cada línea de código que escribas.
- Sin embargo, no te fijes en los detalles.
- Usa Copilot para tareas claras y descriptivas.
Puedes encontrar el resultado final en este repositorio. Con la misma estrategia, también construí rápidamente el SDK de Logto para PHP. No dudes en hacernos saber si tienes alguna sugerencia.
Espero que este artículo sea útil para aprender un nuevo lenguaje de programación. ¡Feliz hacking!