Aprenda Python em um fim de semana: De zero a um projeto completo
Como podemos aprender rapidamente uma nova linguagem de programação? Neste artigo, vamos compartilhar nossa experiência de fim de semana aprendendo Python construindo um projeto completo.
Introdução
O Logto, como um serviço de identidade, proporcionar uma experiência suave em várias linguagens de programação e frameworks é essencial. Isso muitas vezes envolve a criação de Kits de Desenvolvimento de Software (SDKs). No entanto, quando a linguagem de programação está fora da nossa pilha de tecnologia e nossa equipe não tem familiaridade, construir um SDK robusto torna-se um desafio.
Python representou tal desafio para nós. Apesar de termos muitos usuários de Python, faltava-nos um SDK em Python, uma preocupação persistente. Determinado a resolver isso, comecei a preencher essa lacuna.
Embora eu tenha anos de experiência em programação, Python ainda é relativamente desconhecido para mim. Embora eu tenha brincado com Python 2 brevemente para scripts simples anos atrás, meu conhecimento estava desatualizado. No entanto, era hora de mergulhar de cabeça!
Dia 1: Lançar as bases
Definir o objetivo
Na minha experiência, a abordagem mais eficaz para aprender uma nova linguagem de programação é construir um projeto completo. Felizmente, nosso objetivo estava claro: construir um SDK Logto em Python para aplicativos web.
Em vez de pular direto para o código, vamos dividir o processo. Aqui está a lista:
- Criar o cliente Logto para tarefas como login, logout, informações de usuário e gerenciamento de tokens.
- Fornecer um tutorial e um projeto exemplo mostrando o uso do SDK.
- Publicar o SDK em algum lugar para que os usuários possam instalá-lo facilmente.
Parece que a tarefa 1 tem o maior volume de trabalho, então precisamos confirmar o escopo e continuar a dividi-la. Este passo é crucial para garantir os limites do projeto, evitando expansão de escopo e engenharia excessiva.
Trabalhos anteriores de nossa equipe me salvaram muito tempo:
- Uma convenção de SDK delineou a estrutura e o design da API dos SDKs.
- SDKs existentes para diferentes linguagens proporcionaram insights sobre padrões e possíveis melhorias para Python.
Referenciando esses recursos, posso ver um panorama claro do que fazer. Embora os detalhes estejam além do escopo deste artigo, vamos avançar.
Configurar o ambiente
Estou usando um Mac, então o Python já está instalado. No entanto, estava me perguntando se existia uma forma melhor de gerenciar as versões do Python (ouvi sobre a dor da compatibilidade de versões), assim como o nvm
para Node.js. Rapidamente, encontrei o pyenv e comecei a instalá-lo diretamente.
O próximo item na agenda: um gerenciador de pacotes e dependências. Normalmente eles estão acoplados. Então, por que não o pip
(o padrão do Python)? Se você der uma olhada no requirements.txt
, verá que é apenas uma lista de pacotes com versões. Isso não é suficiente para um SDK que pode ser usado por outros projetos. Por exemplo, podemos precisar adicionar alguns pacotes para desenvolvimento, mas não queremos incluí-los no SDK final. O requirements.txt
é muito simples para lidar com isso.
Um dos benefícios de se ter outras linguagens de programação na sua pilha de tecnologia é que você pode procurar um "equivalente em Python". Então eu procurei por "equivalente do package.json em Python" e encontrei o Poetry, um candidato excelente:
- Funciona como um gerenciador de pacotes, gerenciador de dependências e gerenciador de ambiente virtual.
- Possui um arquivo
pyproject.toml
, semelhante aopackage.json
no Node.js. - Emprega um arquivo de bloqueio (
lockfile
) para registrar versões exatas de dependências.
CLIs modernos muitas vezes incluem um comando init
voltado para novos projetos. O mesmo ocorre com o Poetry. Executei o comando e ele criou um arquivo pyproject.toml
para mim.
A primeira linha de código
Finalmente, o momento para escrever código chegou. Começar com o clássico programa "Hello, World!" é sempre uma boa escolha. Ao aprender uma linguagem de programação, IDEs completas não são sempre essenciais; um editor respaldado por uma comunidade forte, como o VS Code, é totalmente adequado.
Dado o foco do nosso SDK em aplicativos web, comecei com um servidor web simples utilizando o popular framework Flask.
Aproveitando as capacidades do Poetry, instalar o Flask pode ser feito facilmente executando poetry add flask
. Em seguida, seguindo o guia de início rápido oficial do Flask, compus um arquivo 'hello.py' com o seguinte trecho:
Lançando o servidor via flask --app hello run
e navegando até http://localhost:5000 no meu navegador obtive o resultado desejado. Funcionou!
Como iniciante, eu não estava com pressa de escrever mais código. Em vez disso, há muitas informações para obter do trecho de código:
- Use
from x import y
para importar um módulo ou uma classe. - Não há ponto e vírgula para terminar as linhas (oh não).
- Podemos definir uma nova variável inserindo qualquer nome arbitrário e atribuindo um valor a ela.
- Criando uma instância de uma classe sem a palavra-chave
new
. - Python suporta decoradores, e o
@app.route
serve como decorador que registra uma função como manipulador de rota.- O valor de retorno da função é interpretado como o corpo da resposta.
- Podemos definir uma função usando a palavra-chave
def
.
Como você pode ver, se tentarmos entender cada linha de código em vez de "apenas fazer funcionar", podemos aprender muito com isso. Enquanto isso, a documentação oficial do Flask explicou ainda mais o trecho de código em detalhes.
Início do projeto
Agora é hora de começar o projeto. Logo defini uma classe LogtoClient
e tentei adicionar algumas propriedades e métodos para sentir a linguagem:
Em seguida, integrei a classe com o Flask:
Começou a parecer um projeto real. Mas senti que faltava algo: um sistema de tipos.
Sistema de tipos
Como é um SDK, incorporar um sistema de tipos ajudará os usuários a entender a API e reduzirá a chance de erros durante o desenvolvimento.
Python introduziu type hints na versão 3.5. Não é tão poderoso quanto o TypeScript, mas é melhor do que nada. Adicionei algumas type hints à classe LogtoClient
:
Parece muito melhor agora. Mas o desafio surgiu quando se trata de um tipo complexo como um objeto com chaves predefinidas. Por exemplo, precisamos definir uma classe LogtoConfig
para representar o objeto de configuração:
Parece bom, mas logo teremos que enfrentar problemas de codificação, decodificação e validação do objeto a partir do JSON.
Após alguma pesquisa, escolhi o pydantic como solução. É uma biblioteca de validação de dados que trabalha com type hints. Ela suporta diversas funcionalidades JSON sem precisar seguir códigos boilerplate tediosos.
Assim, a classe LogtoConfig
pode ser reescrita como:
Isso também me ensinou sobre herança de classes em Python ao adicionar parênteses após o nome da classe.
Operações assíncronas
Dentro do SDK Logto, precisamos fazer requisições HTTP ao servidor Logto. Se você tem experiência com JavaScript, a expressão "callback hell" provavelmente lhe soa familiar. É um problema comum quando se lida com operações assíncronas. Linguagens de programação modernas apresentam soluções semelhantes como Promise
ou coroutine
.
Felizmente, Python tem uma solução nativa de async
e await
. Antes de usá-los, certifique-se de que há compatibilidade com frameworks populares. No Flask, isso pode ser feito instalando o extra async
e usando async def
em vez de def
:
Então podemos usar await
para esperar pelo resultado de uma operação assíncrona.
Requisições HTTP
Requisições HTTP são um tópico interessante. Quase toda linguagem de programação tem uma solução nativa, mas os desenvolvedores geralmente usam uma biblioteca de terceiros pela facilidade de uso. Alguns exemplos:
- JavaScript:
XMLHttpRequest
vs.fetch
vs.axios
- Swift:
URLSession
vs.Alamofire
- Java:
HttpURLConnection
vs.OkHttp
Isso também é verdade para Python. Minha decisão foi usar o aiohttp pois ele suporta async
e await
, além de ser bastante popular.
A magia do Copilot
Antes do Copilot, agora estaríamos chegando à parte tediosa de escrever a lógica de negócios. Com a ajuda da convenção de SDK e de outros SDKs, posso escrever os comentários descritivos para cada método antes de escrever o código.
Isso adiciona mais legibilidade ao código, além de ajudar os desenvolvedores a entender a API diretamente no IDE ou editor via inteligência de código.
Por exemplo, considere o método generateCodeChallenge
, os comentários podem ser escritos como:
Isso proporcionou um excelente prompt para Modelos de Linguagem Grandes (LLMs): inclui definições de métodos por comentários claros. E o Copilot não decepcionou:
Alguns ajustes podem ser necessários, mas não importa. Já mudou o jogo.
Conclusão do dia
Esse foi basicamente o progresso alcançado no primeiro dia. Foi um dia longo, mas com ferramentas e tecnologias modernas, foi muito melhor do que eu esperava.
Dia 2: Eleve o nível
Com base no trabalho do primeiro dia, a lógica de negócios foi concluída rapidamente. Mas para um SDK, ainda é insuficiente. Aqui estão as tarefas para o segundo dia:
- Adicionar testes unitários.
- Impor formatação de código.
- Verificar compatibilidade de versões do Python.
- Adicionar integração contínua.
- Publicar o SDK.
Testes unitários
Testes unitários nos salvaram muitas vezes, então não os pularei. Aqui estão considerações comuns ao escrever testes unitários:
- Como organizar e executar os testes?
- Como afirmar o resultado?
- Como executar testes assíncronos? (Parece uma brincadeira, mas ocasionalmente causa problemas em algumas linguagens.)
- Como simular as dependências? (Não se aprofunde neste tópico até ser imprescindível, pois pode levar a buracos de coelho.)
- Como gerar relatórios de cobertura de código?
Com essas perguntas em mente, descobri que o módulo unittest
embutido era insuficiente para alguns casos. Então escolhi o pytest como o framework de testes. Ele suporta testes assíncronos e parece maduro o suficiente.
A jornada revelou alguns novos conceitos interessantes como fixture
para mim. Isso também pode melhorar a mentalidade ao escrever código em outras linguagens.
Formatação de código
Toda linguagem tem seus próprios estilos de formatação de código. Pessoalmente, formatação consistente pode me deixar feliz e confortável; também é útil para revisão de código e colaboração.
Em vez de navegar pela discussão sobre o "melhor" estilo, decidi escolher um formatador opinativo e me manter fiel a ele.
Black parece uma boa escolha. A única frustração é o tamanho da tabulação não modificável. Mas não é um grande problema, escolhi me adaptar a isso.
Compatibilidade de versão do Python
Como um SDK, ele deve ser compatível com as versões predominantes do Python. Ao buscar "estatísticas de uso de versão do python", determinei usar Python 3.8 como a versão mínima.
A virtude do gerenciador de ambiente agora se destaca. Posso alternar facilmente a versão do Python executando pyenv local 3.8
e poetry env use 3.8
. Eu então poderia rodar os testes para revelar problemas de compatibilidade.
Integração contínua
A integração contínua garante a qualidade de cada alteração de código. Como nosso repositório estava hospedado no GitHub, o GitHub Actions foi a escolha natural.
O fluxo de trabalho principal segue princípios simples:
- Configurar o ambiente.
- Instalar dependências.
- Construir o projeto (não necessário com Python).
- Executar os testes.
O GitHub Actions tem uma boa comunidade, então leva apenas alguns minutos para construir o fluxo de trabalho.
Empregando estratégias de matriz, podemos executar o fluxo de trabalho em diferentes versões do Python, até mesmo em diferentes sistemas operacionais.
Publicar o SDK
O passo final é publicar o SDK. Para pacotes públicos, isso pode ser normalmente feito enviando para o registro oficial da linguagem específica. Por exemplo, npm para Node.js, PyPI para Python, e CocoaPods para Swift.
Poetry é a minha estrela guia. Basta executar poetry publish
para publicar o pacote no PyPI. É simples assim.
Pensamentos finais
Foi uma jornada envolvente. Sem a ajuda da comunidade open-source, teria sido muito mais difícil. Aplausos para todos os contribuidores!
Aqui estão alguns aprendizados gerais:
- Defina precisamente o objetivo e divida-o, depois sempre mantenha o objetivo em mente.
- Configure um ambiente de desenvolvimento estável e reprodutível.
- Use (boas) ferramentas tanto quanto possível.
- Priorize soluções nativas ou já existentes.
- Compreenda convenções de linguagem e cada linha de código que você escreve.
- No entanto, não se prenda aos detalhes pontuais.
- Use o Copilot para tarefas claras e descritivas.
Você pode encontrar o resultado final neste repositório. Com a mesma estratégia, também construí rapidamente o SDK Logto em PHP. Não hesite em nos informar se tiver alguma sugestão.
Espero que este artigo seja útil para aprender uma nova linguagem de programação. Boas hackings!