Inteligência artificial, sem ruído.
Tutoriais3 min

7 práticas de Python que separam desenvolvedores seniores de iniciantes

Sete hábitos de engenharia que desenvolvedores Python seniores seguem — e iniciantes costumam ignorar — para reduzir surpresas em produção.

7 práticas de Python que separam desenvolvedores seniores de iniciantes

Existe um tipo de código que passa em qualquer linter, mas quebra em produção: a função que cria o próprio cliente HTTP, espera na rede para sempre e registra “falha no processamento” sem dizer qual job falhou. Nenhum desses problemas é de estilo — são de engenharia. É aí que a prática sênior em Python começa.

1. Passe dependências em vez de escondê-las

Código é mais fácil de testar quando quem chama a função consegue ver quais colaboradores ela precisa. Em vez de a função construir o próprio httpx.Client() e chamar a rede de verdade, aceite o colaborador como parâmetro, tipado como Protocol:

from typing import Protocol

class OrderClient(Protocol):
    def submit(self, payload: dict) -> dict: ...

def process_order(order: dict, client: OrderClient) -> str:
    response = client.submit(order)
    return response["status"]

Com isso, um fake de cinco linhas substitui a rede nos testes. Uma ressalva honesta: Protocol é um contrato para o type checker, não valida nada em tempo de execução.

2. Deixe os context managers cuidarem da limpeza

Adquirir e liberar recursos no mesmo bloco visível é a função do with — e vale para muito além de arquivos: locks, transações de banco, diretórios temporários. O ponto crítico é o caso de falha: se o corpo levantar uma exceção, a limpeza ainda acontece.

3. Dê um prazo para cada espera externa

Uma espera sem limite é um modo de falha não declarado. No Python 3.11+, asyncio.timeout() resolve para código assíncrono; para clientes síncronos, cada biblioteca (HTTP, banco, fila) tem seu próprio mecanismo. O hábito é o prazo mais uma decisão sobre o que fazer quando ele estourar.

4. Registre eventos com contexto para investigar

“Processing failed” não é um registro operacional. A biblioteca padrão já resolve sem dependência de logging estruturado:

log.info("import finished", extra={"job_id": "j-193", "records": 4211})

A regra de ouro: nomes de eventos estáveis e campos úteis — nunca tokens, senhas ou payloads sensíveis.

5. Teste o contrato de falha, não só o caminho feliz

Um teste que passa com um único input amigável não diz quase nada sobre como o código se comporta sob pressão. Use pytest.mark.parametrize para cobrir os inputs feios e monkeypatch para forçar o caminho de timeout ou resposta malformada.

6. Trate os metadados do pacote como parte do contrato

Declare no pyproject.toml como o projeto compila, do que depende e quais versões de Python suporta. Declarar httpx>=0.27 é uma suposição; bloquear versões exatas é outra decisão — confundir as duas é como dois ambientes “idênticos” divergem.

7. Depreque antes de deletar

Comportamento público não se remove sem aviso. Use warnings.warn com stacklevel=2 para apontar o aviso para a linha de quem chama, e sempre nomeie o substituto na mensagem. Surpresa para quase todo mundo: o Python esconde DeprecationWarning fora do __main__ — torne-o explícito nos testes com filterwarnings = ["error::DeprecationWarning"].

O hábito que resume tudo

As sete práticas colapsam em uma única pergunta de code review: onde este código espera, do que ele depende, e qual contrato acabou de mudar? Nenhum desses hábitos adiciona cerimônia por si só — cada um move uma suposição da cabeça de alguém para um lugar onde outro desenvolvedor, um teste ou um operador consegue enxergá-la.


Descubra mais sobre noticiAI

Assine para receber nossas notícias mais recentes por e-mail.

R
Sobre o autorRedação Noticiai

Equipe editorial dedicada a explicar inteligência artificial com clareza, independência e contexto.