Cover do episódio 90: app.py com 800 linhas: como a estrutura do projeto me ensinou a dividir responsabilidade
#09015 de julho, 20193 min leituraBastidores do CódigoS3 · 2018–2019

app.py com 800 linhas: como a estrutura do projeto me ensinou a dividir responsabilidade

Meu primeiro projeto profissional em Python era um arquivo. Oitocentas linhas, tudo misturado. Aqui está o que foi forçando a separação — e por que estrutura importa antes de framework.

PythonArquiteturaBackendFlask

Tinha um app.py com 800 linhas.

Routes, models, lógica de negócio, helpers de email, configuração — tudo num arquivo só. Quando precisava de algo, dava um Ctrl+F e rezava para encontrar.

Funcionava. O problema apareceu quando um colega começou a trabalhar no mesmo projeto.

Dois commits no mesmo arquivo quase todo dia. Merge conflict em coisa que não tinha relação nenhuma. Eu editava a route de leads, ele editava o modelo de usuário, os dois no mesmo arquivo, Git confuso.


O que forçou a mudança

Não foi arquitetura. Foi dor prática.

Primeiro split: models.py. Tirei tudo relacionado a banco para um arquivo separado. Merge conflict caiu à metade.

Segundo split: utils.py. Tudo que não sabia onde colocar foi para lá. Não é solução boa — utils.py vira lixo com o tempo — mas era melhor que app.py de 1.200 linhas.

O problema do utils.py apareceu quando precisava de algo e tinha que procurar: "isso é utils? é models? ta no app?"


O que funcionou: separar por domínio, não por tipo

Ao invés de "todos os models juntos, todas as routes juntas", separei por recurso:

projeto/
  app.py           # só inicialização e registro de blueprints
  config.py        # variáveis de ambiente
  leads/
    routes.py      # HTTP: parse request → chama service → retorna JSON
    service.py     # lógica de negócio
    model.py       # estrutura de dados e queries
  usuarios/
    routes.py
    service.py
    model.py
  tests/
    test_leads.py
    test_usuarios.py

A separação que importa não é onde o arquivo fica. É que routes.py nunca tem lógica de negócio.

Route: recebe request, valida formato, chama service, retorna response. Não sabe de banco.

Service: contém as regras. Não sabe de HTTP.

Quando isso está separado, você consegue testar o service sem montar request HTTP. Consegue trocar o framework web sem reescrever lógica de negócio.


O teste que mostra se a separação está certa

Se precisar trocar Flask por FastAPI, quantas linhas você reescreve?

Se a resposta é "só as routes", tá bom. Se a resposta é "preciso mexer em todo lugar", o framework vazou para dentro da lógica.

Não é questão de framework. É questão de o quê pode mudar independentemente do quê.

Essa semana: abre o projeto que você mais trabalha. Tem algum arquivo com mais de 300 linhas? Provavelmente tem mais de uma responsabilidade ali. Não precisa refatorar tudo — só identificar onde está misturado. O split acontece naturalmente quando você sabe onde está o problema.