21 pontos por GN⁺ 2025-07-17 | 6 comentários | Compartilhar no WhatsApp
  • Com a tendência recente do desenvolvimento de IA, começou a estudar e usar Python de forma séria, e agora sente grande satisfação com esse ecossistema
  • Python evoluiu muito em relação ao passado e se tornou uma linguagem mais rápida e moderna, e ele percebe avanços significativos como os ganhos de desempenho com Cython
  • Está adotando ativamente ferramentas e bibliotecas modernas de desenvolvimento como uv, ruff, pytest e Pydantic no seu fluxo de trabalho para aumentar a produtividade
  • Também aplica estruturas de projeto e automação para reduzir a diferença entre ambientes de produção e o desenvolvimento baseado em notebooks/scripts Jupyter
  • Usa GitHub Actions, Docker etc. para montar de forma eficiente CI/CD, testes e gerenciamento de infraestrutura

Resumo de I’m Switching to Python and Actually Liking It

Por que migrou para Python

  • Em ambientes de desenvolvimento centrados em IA, Python se consolidou como a linguagem padrão de fato
  • Antes era usado apenas para scripts simples, mas recentemente passou a utilizá-lo seriamente para criar “apps práticos” como RAG, agentes e IA generativa
  • Nesse processo, percebeu que o ecossistema Python evoluiu muito em comparação com o passado

3 pontos fortes do Python

  1. Ecossistema rico de bibliotecas e ferramentas: especializado em processamento de dados, análise, web e IA
  2. Melhorias de desempenho com Cython e afins: possibilita otimização baseada em compilação
  3. Melhor legibilidade da sintaxe: sintaxes legadas como __init__ e __new__ ficam ocultas, e a linguagem oferece uma sintaxe mais intuitiva

Estrutura do projeto (baseada em monorepo)

  • Prefere uma estrutura de monorepo que integra backend e frontend
    • Escolheu um único repositório por motivos como eficiência na gestão do código, facilidade de busca e simplificação dos pipelines de deploy e teste
    • Considera que separar demais um projeto em vários repositórios é um sinal de overengineering
  • Um exemplo típico de estrutura de projeto é o seguinte
    project/  
    ├── .github/ : workflows de CI/CD como GitHub Actions  
    ├── .vscode/ : configurações do ambiente VSCode  
    ├── docs/ : documentação estática e site com base em MkDocs  
    ├── project-api/ : backend FastAPI incluindo dados/notebooks/ferramentas/código-fonte/testes  
    ├── project-ui/  : frontend React/Next.js  
    ├── docker-compose.yml (execução integrada)  
    └── Makefile e outros scripts de automação  
    
  • Separação de responsabilidades em que o frontend busca via requisições HTTP os dados processados no servidor de API
    • O frontend fica proibido de fazer processamento pesado de dados e delega as requisições HTTP para a API de backend baseada em Python
  • Cada diretório de módulo Python é definido explicitamente com __init__.py
  • Dentro de project-api, a estrutura é separada em pastas como src/app, notebooks, tools e tests

Principais ferramentas e configurações

  • uv

    • Gerenciador moderno de pacotes Python e ferramenta de build fornecido pela Astral
    • Executa rapidamente a maior parte das tarefas, como gerenciamento de dependências, criação de ambiente virtual e inicialização de projetos
    • pyproject.toml é o arquivo central de configuração, reunindo todos os metadados e as informações de dependências
    • É possível configurar rapidamente o ambiente do projeto com os comandos uv init, uv add e uv sync
  • ruff

    • Linter Python ultrarrápido e formatador de código
    • Ferramenta que integra isort, flake8, autoflake etc.
    • Faz lint e correções automáticas com ruff check e ruff format
    • Suporte nativo ao guia de estilo PEP 8
  • ty

    • Verificador estático de tipos para Python criado pela Astral
    • Em conjunto com typing, é eficaz para análise estática e prevenção inicial de bugs
    • Apesar de ainda estar em estágio inicial de desenvolvimento, já está em um nível utilizável com estabilidade
  • pytest

    • Framework de testes Python mais representativo para testes unitários e ambientes de teste extensíveis
    • Com regras simples de nome de arquivo e um único comando, já é possível integrar testes imediatamente
      • Configure os testes como test_*.py e execute com uv run pytest
    • Sintaxe concisa e ecossistema rico de plugins
  • Pydantic

    • Biblioteca para validação de dados e gerenciamento de configurações de ambiente
    • Carregamento de configurações baseado em variáveis de ambiente .env e validação de tipos
    • Permite gerenciar com segurança chaves de API, URLs de banco de dados etc. por meio da classe BaseSettings
  • MkDocs

    • Dá suporte simples à geração de sites estáticos e documentação para projetos Python
    • Permite aplicar rapidamente um design elegante no estilo de projetos open source
    • Integração fácil com GitHub Pages
  • FastAPI

    • Framework para criação rápida de APIs RESTful
    • Vantagens como validação e documentação automáticas, alto desempenho e integração fácil com Pydantic
    • Baseado em Starlette e Pydantic, oferece alta segurança de tipos e desempenho
  • Dataclasses

    • Recurso padrão do Python que permite definir classes centradas em dados com facilidade
    • Reduz fortemente boilerplate graças à geração automática de métodos especiais

Controle de versão e automação

  • GitHub Actions

    • Configura pipelines de CI separados para project-api e project-ui
    • Oferece workflows ideais para construir pipelines de CI em vários sistemas operacionais
    • Com ambiente de testes baseado em Docker, é possível testar no mesmo ambiente da produção
  • Dependabot

    • Automatiza a atualização de dependências e o gerenciamento de patches de segurança
  • Gitleaks

    • Ferramenta para evitar vazamento de informações sensíveis (senhas, chaves de API etc.), executando verificações de segurança antes dos commits no git
  • Pre-commit Hooks

    • Ferramenta para lint, formatação e verificações de segurança automáticas antes do commit
    • Usada com ruff, gitleaks etc. para manter consistência e qualidade do código

Automação de infraestrutura

  • Make

    • Oferece um fluxo de desenvolvimento consistente com comandos como make test e make infrastructure-up
    • Há um Makefile na raiz do projeto e outro em project-api
  • Docker & Docker Compose

    • project-api e project-ui são executados separadamente em contêineres
    • Toda a aplicação pode ser iniciada com uma única linha: docker compose up --build -d
    • O Dockerfile inclui a instalação do uv e o comando para executar a aplicação FastAPI

Encerrando

  • Como mostrado acima, o ambiente moderno de desenvolvimento com Python permite montar um fluxo de trabalho de produção eficiente e robusto
  • É possível aproveitar muitos benefícios do crescimento do ecossistema Python e da evolução das ferramentas em áreas como IA, dados e desenvolvimento web
  • Dá para implementar uma cultura de desenvolvimento integrada, cobrindo estrutura de monorepo, ferramentas de automação, linter e verificador de tipos, ambiente de testes imediato, documentação e orquestração de infraestrutura

6 comentários

 
howudoin 2025-07-18

Estou migrando para Python e, sinceramente, estou gostando bastante.

Python tem a vantagem de contar com bibliotecas e frameworks abundantes, mas a desvantagem é que o gerenciamento de versões de pacotes não funciona tão bem e os conflitos são frequentes.
A tendência dos prós e contras é parecida com a do Java do passado.

 
kylian 2025-07-18

O uv mencionado no texto é realmente incrível. Além de ser muito rápido, também gerencia versões e dependências muito bem, meio no estilo do npm, então estou me estabelecendo com o uv.

 
wyatt216 2025-07-18

Mesmo assim, ultimamente parece que, com uv e poetry, os conflitos e o gerenciamento de versões foram praticamente resolvidos na maior parte.

 
shakespeare 2025-07-18

Será que ele também é adequado para abranger o ecossistema, incluindo o React e esses tipos de partes?

 
wyatt216 2025-07-18

Como a integração direta com React é difícil por serem linguagens diferentes, acho que algumas partes podem ser possíveis dependendo do que você deseja.
Pessoalmente, considero que o desenvolvimento de frontend com Python ainda não é uma área muito difundida.

 
GN⁺ 2025-07-17
Comentários no Hacker News
  • No código, quando faltam variáveis de ambiente, exibir uma mensagem com OR como “YOUTUBE_API_KEY ou YOUTUBE_CHANNEL_ID ausente” acaba irritando o usuário numa situação em que nem precisa usar OR. É muito melhor verificar cada valor separadamente e informar claramente qual está faltando. Como a diferença no tempo de desenvolvimento é quase nula, eu recomendo fazer assim

    • É um detalhe bem minucioso, mas acho que esse é um caso perfeito para usar o operador := (walrus). Por exemplo, dá para escrever direto algo como if not (API_KEY := os.getenv("API_KEY")):. Pessoalmente, em ferramentas internas eu simplesmente deixo os.environ["API_KEY"] estourar um KeyError. Acho isso claro o suficiente também

    • Indo além, acho muito melhor verificar as condições uma por uma e, se estiver faltando qualquer coisa, informar tudo de uma vez. Isso reduz o incômodo de rodar o programa por causa de uma variável ausente e depois descobrir outro erro de variável na sequência. Dependendo da situação, às vezes não dá para evitar esse incômodo, mas sempre que possível é melhor mostrar tudo de uma vez

    • O melhor é buscar todas as variáveis de ambiente e reportar de uma vez só quais estão faltando

    • Também dá para usar uma flag booleana e fazer um único exit(1) no final. Assim você consegue mostrar todas as variáveis de ambiente ausentes de uma vez

    • Também é possível encerrar com código 1 já imprimindo a mensagem, como em exit("Missing ...")

  • Se você está procurando uma ferramenta para gerar automaticamente a estrutura do projeto, recomendo o cookiecutter. Tenho alguns templates que uso com frequência, como python-lib, click-app, datasette-plugin e llm-plugin. É só usar assim: uvx cookiecutter gh:simonw/python-lib

    • Eu fiz algo chamado baker em Ruby. O baker não copia um repositório de template; ele cria uma lista de tarefas a executar (uma lista de etapas em modo imperativo) e pode misturar tarefas manuais (como obter e configurar uma API key) com tarefas automáticas (como uv init). Também dá para usar interpolação de strings do Ruby e bash na sintaxe Markdown. Acabei fazendo isso porque estava muito cansado de configs baseadas em yml

    • O que está em alta ultimamente é uma ferramenta chamada Copier. Veja a documentação do copier para mais detalhes

    • Eu até gosto de configurar projetos novos. Não tenho tanta vontade assim de automatizar isso

    • Na verdade, acho que esse tipo de ferramenta de automação estrutural combina perfeitamente com workflows modernos de desenvolvimento com LLMs baseados em agentes

  • A avaliação de que “Python é mais amigável para humanos porque já vem instalado por padrão na maioria dos Unix” é um pouco otimista. Passou de import json, você cai rapidamente no inferno de virtualenv. Se quiser rodar em Python 3.13.x em Ubuntu 22.04 ou 24.04, Rocky 9 etc., no fim venv, contêineres ou gerenciadores de versão acabam sendo obrigatórios

    • Mesmo algo da biblioteca padrão como import json, se fosse uma linguagem sem isso embutido, precisaria ser instalado à parte, mas o Python oferece alta produtividade no começo graças à biblioteca padrão. Claro que, em projetos grandes, a biblioteca padrão não basta, mas eu realmente já distribuí vários códigos de produção usando só a biblioteca padrão, sem problemas de deploy ou de gestão de segurança. Gerenciar venv também não é mais tão difícil quanto antes, e os gerenciadores de pacotes evoluíram

    • Uma das minhas teorias meio em tom de piada é que metade do motivo de Docker/contêineres terem se espalhado tão rápido foi por ajudarem a superar o inferno de dependências do Python. Minha primeira experiência com Python foi instalar um serviço Python num servidor em 2012, e foi horrível: inferno de dependências, comandos de venv, configuração de ambiente difícil de lidar. Fiquei apanhando com pip, brew e ambiente macOS, e passei a evitar Python sempre que podia. Mas recentemente, por causa do uv, sinto que Python melhorou bastante até para iniciantes. Só uv init, uv add e uv run já bastam

    • Acho que sempre se deve usar virtualenv. No fim das contas é só um diretório e, hoje em dia, se você tentar instalar algo globalmente com pip, ainda recebe aviso e tudo mais, então não é tão difícil quanto já foi

    • É melhor mesmo usar virtualenv ou container. Mesmo que pareça difícil de lidar, isso evita afetar o sistema inteiro por causa de atualizações ou mudanças de versão de bibliotecas

    • Antigamente, era comum o sistema vir só com Python2 por padrão, e às vezes o próprio sistema dependia desse Python2, então isso era ainda mais perigoso

  • Tenho a sensação de que Python consegue ser ao mesmo tempo verboso e insuficiente. Para fazer algo simples, ou você acaba colocando umas 500 dependências, ou então o código cresce para dezenas, às vezes centenas de linhas até para tarefas muito triviais. Por isso evito Python: tem trabalho desnecessário demais. Prefiro Perl, porque consigo terminar muito mais rápido e de forma mais concisa. Com Python, muitas vezes parece programação pela programação, em vez de resolver o trabalho em si

    • Eu também faço muitos projetos sem dependências. Dá para fazer muita coisa de verdade só com a biblioteca padrão e um arquivo único. Se Python estiver instalado, dá até para baixar com curl e rodar direto. Por exemplo, tenho uma ferramenta CLI de controle de dinheiro com 2000 linhas, o plutus, que usa só umas 12 bibliotecas padrão. Cerca de 25% do código é só a parte de parse de comandos com argparse. Eu gosto de escrever de forma explícita, tipo uma linha por parâmetro

    • Você disse que Perl é mais rápido e poderoso que Python; fiquei curioso sobre quais exemplos concretos você tem em mente

    • No Python, é prático aninhar estruturas de dados sem precisar pensar muito. Você pode misturar livremente lista, tupla, dicionário etc. e acessar tudo com uma sintaxe consistente. Perl certamente é mais esperto e mais divertido, mas justamente por isso embaralha mais a minha cabeça, então não funciona tão bem para mim. Python é mais sem graça, mas a clareza é grande o suficiente para eu ainda entender o código daqui a 5 anos

    • Acho que Python é totalmente utilizável só com a biblioteca padrão

  • Eu gosto de monorepo, mas numa empresa em que trabalhei antes, essa abordagem acabou virando uma estrutura gigantesca e inchada, e ninguém queria mexer em nada com medo de tocar sem querer no código de outra equipe. O cerne do problema não era o repositório em si, e sim coisas como manter um único requirements.txt para o repositório inteiro ou scripts de build enrolados. Em teoria, bastaria atualizar dependências uma vez para que todo o código ficasse seguro com os patches mais recentes, mas na prática ninguém conseguia encostar nisso. Monorepo só funciona bem quando a organização tem uma cultura muito NIH (como o Google, de fazer tudo internamente). Por causa dessa experiência, passei a valorizar mais uma estrutura de microsserviços em que cada serviço corresponde à estrutura de equipes da organização. Vale ver também a Lei de Conway

  • Python é a linguagem que mais se aproxima de como eu escrevo pseudocódigo. Sempre que eu penso “isso está claro na minha cabeça”, o Python também tende a me oferecer uma abstração intuitiva para aquilo. Como venho de uma base mais matemática, isso me agradou bastante. Claro, hoje eu também gosto de outras linguagens, mas Python ainda tem seu charme

    • Para quem pensa de forma matemática, o lado OOP acaba dificultando mais o raciocínio. O que importa é raciocínio equacional, lambdas melhores, evitar efeitos colaterais, imutabilidade dos dados etc. OOP é o paradigma que conheci que me parece mais distante da matemática
  • Eu monto meus projetos quase sempre com o mesmo padrão. É tão parecido que chega a ser assustador. Fico achando que o ecossistema de desenvolvedores Python está convergindo cada vez mais para um mesmo estilo. Antes eu achava que minhas escolhas eram únicas, mas vendo tanta gente fazer igual, dá vontade de perguntar para onde foi meu livre-arbítrio. Parece o fenômeno dos nomes de bebê: você acha que fez uma escolha original, mas na verdade escolheu o segundo nome mais popular

    • Esse tipo de estrutura já era popular em Python há uns 10 anos. No fim, parece que vários engenheiros racionais acabam convergindo naturalmente para esse padrão depois de pensar bastante

    • Tenho a sensação de que o ego humano está espalhado por todo o espectro como uma onda piloto quântica, e dali se transforma em existência. becoming-being, dá até risada

  • Fico feliz de ver mais gente passando a gostar de Python. Eu originalmente preferia Ruby, mas acabei tendo que usar Python por exigência de clientes. Antigamente Ruby era muito lento, mas, ao ser forçado a aprender Python, fui me acostumando aos poucos e hoje até gosto. Tenho algumas divergências sobre o uso de Make; se você não usa dependências de jeito nenhum, isso não é tão diferente assim de um script com case... falando meio na brincadeira, mas dá uma tristeza ver que a geração atual não está tão acostumada com Make. Dá aquela sensação de “no meu tempo..."

    • Ruby tem uma sintaxe muito mais bonita. Não curto essa ideia do Python de delimitar escopo só com indentação

    • Eu comecei com um script usando case e, no fim, evoluí para um Makefile simples. Makefile é mais padronizado e mais fácil de entender do que um script aleatório

  • Estou em dúvida entre usar Dataclass e Pydantic BaseModel. Se você já usa Pydantic, será que não faz sentido simplesmente padronizar tudo com Pydantic? Fico pensando se ainda existe motivo para usar Dataclass

    • O projeto attrs tem um texto comparativo muito bem organizado. Tem a comparação oficial do attrs; claro que há um pouco de viés, mas acho que os fundamentos são bem lógicos. E este blog também ajuda

    • Dataclass não oferece suporte à validação de objetos aninhados. Então, para estruturas simples e planas usadas para passar argumentos entre funções, é melhor usar dataclass. É mais claro do que ficar recebendo um monte de argumentos demais em lista

    • Existe uma questão de queda de desempenho por causa da validação dos dados na criação. Há alternativas bem mais leves e rápidas, como msgspec

    • Se você não precisa de validação nem serialização, então Pydantic acaba sendo overhead desnecessário. Minha regra é: se precisa de serialização, Pydantic; se não, dataclass

    • Dá para usar uma dataclass existente direto com algo como TypeAdapter(MyDataclass), então fico pensando se realmente há motivo para criar um modelo Pydantic separado

  • Ultimamente, na verdade, tenho estado mais satisfeito migrando para outras linguagens em vez de Python. Organizei meus pensamentos sobre Python neste texto. Se eu tiver chance de usar Python de novo no futuro, quero com certeza experimentar uv, ruff e ty

    • Eu também troquei Python por JS no backend e estou curtindo bastante há um bom tempo. Concordo que a instalação e o gerenciamento de pacotes do Python estão quebrados. Mas, para mim, o maior ganho de produtividade foi async. Python tem asyncio, mas há várias abordagens concorrentes coexistindo e nunca se consolidou um padrão. No JS, isso ficou concentrado em uma coisa só, o que foi muito mais confortável para mim. Somando também vários detalhes pequenos, a diferença ficou grande: em Python, escopo por indentação, problemas de caminho relativo em imports; no JS, a sintaxe de objetos etc. me parece mais agradável. Veja esta explicação relacionada