Tomada de Decisão Técnica
Líderes técnicos escolhem entre opções imperfeitas sob incerteza. Decisões ranqueadas tornam os trade-offs explícitos, documentam escolhas erradas e definem gatilhos de revisão para que as escolhas de stack Python (FastAPI vs Django, síncrono vs assíncrono) não se tornem religião permanente.
Como Usar Esta Lista
- Percorra as decisões em ordem ao planejar arquitetura ou upgrades.
- Registre o rank escolhido e por quê em um ADR ou ticket.
- Defina um gatilho de revisão (escala, tamanho da equipe, falha de SLO) para chamadas reversíveis.
- Use spikes para reduzir o risco de opções "2ª" antes de se comprometer com "Melhor".
- Reavalie quando o gatilho for acionado - substitua o ADR, não desvie silenciosamente.
Decisão 1: Framework HTTP para uma nova API Python
Cenário: API B2B Greenfield, 6 engenheiros, SLO p95 200ms, Postgres, necessita de OpenAPI.
| Rank | Escolha | Abordagem |
|---|---|---|
| Melhor | FastAPI | Rotas assíncronas, Pydantic v2, OpenAPI nativo, cliente de teste httpx |
| 2ª | Django + DRF | Admin, maturidade ORM, pool de contratação; mais pesado por requisição |
| 3ª | Flask | Mínimo; compor extensões; menos "batteries included" |
Escolha errada: Flask para 40+ endpoints sem disciplina - proliferação de blueprints e validação inconsistente.
Por que a melhor é a melhor: O SLO da equipe e os contratos tipados favorecem o FastAPI; já existe um plugin de autenticação interna compartilhado.
Decisão 2: Workers Gunicorn síncronos vs Uvicorn assíncronos
Cenário: API CRUD, principalmente I/O de Postgres, ocasional CPU para geração de PDF.
| Rank | Escolha | Abordagem |
|---|---|---|
| Melhor | Gunicorn síncrono + pool de threads para CPU | Modelo mental simples; SQLAlchemy síncrono bem estabelecido |
| 2ª | Uvicorn assíncrono | Se WebSockets ou I/O concorrente de alto fan-out |
| 3ª | Síncrono + gevent | Legado; depuração mais difícil |
Escolha errada: Assíncrono em tudo com ORM síncrono nas rotas - interrupções por bloqueio do event loop.
Por que a melhor é a melhor: A carga de trabalho é limitada por I/O, mas a equipe conhece SQLAlchemy síncrono; as partes de CPU são isoladas em ProcessPoolExecutor.
Decisão 3: Monolito vs serviços divididos
Cenário: 8 engenheiros, um produto, Postgres compartilhado, deploy semanal.
| Rank | Escolha | Abordagem |
|---|---|---|
| Melhor | Monolito modular | Limites claros de pacotes; deploy único; extrair depois |
| 2ª | Dois serviços (API + workers) | Quando a escala do Celery e o domínio de falha diferem |
| 3ª | Microserviços por domínio | Imposto operacional prematuro |
Escolha errada: Cinco microserviços antes da existência da segunda equipe - CFR e lead time sofrem.
Por que a melhor é a melhor: O tamanho da equipe e os limites de transação se encaixam em um único deploy com módulos.
Decisão 4: SQLAlchemy síncrono vs engine assíncrono
Cenário: Serviço FastAPI considerando SQLAlchemy 2.0 assíncrono.
| Rank | Escolha | Abordagem |
|---|---|---|
| Melhor | Engine síncrono + pool de threads | Se a equipe for nova em DB assíncrono; menos surpresas com o pool |
| 2ª | Engine assíncrono (asyncpg) | I/O de leitura concorrente alta, equipe treinada |
| 3ª | Apenas SQL bruto | Raro; perde a produtividade do ORM |
Escolha errada: Engine assíncrono com chamadas bloqueantes nas dependências - esgotamento do pool mascarado como latência.
Por que a melhor é a melhor: A maturidade da equipe e a concorrência moderada ainda não justificam a complexidade do DB assíncrono.
Decisão 5: Tarefas em background Celery vs in-process
Cenário: Enviar e-mail, gerar PDF, faturamento noturno - tarefas de minutos.
| Rank | Escolha | Abordagem |
|---|---|---|
| Melhor | Celery + broker Redis | Retentativas, visibilidade, escala workers independentemente |
| 2ª | BackgroundTasks do FastAPI | Apenas para fire-and-forget <2s |
| 3ª | Dramatiq / RQ | Menor footprint operacional; menos recursos |
Escolha errada: BackgroundTasks para lote de faturamento - mata os workers da API sob carga.
Por que a melhor é a melhor: A duração da tarefa e a política de retentativa exigem uma fila real com DLQ.
Decisão 6: Configurações Pydantic vs parser de env customizado
Cenário: Configuração de doze fatores entre dev/staging/prod.
| Rank | Escolha | Abordagem |
|---|---|---|
| Melhor | pydantic-settings | Boot tipado e validado; .env apenas para local |
| 2ª | python-decouple | Leve; menos validação |
| 3ª | os.environ manual | Propenso a erros em escala |
Escolha errada: os.getenv espalhado sem validação - prod inicia com DATABASE_URL vazio.
Por que a melhor é a melhor: A validação "fail-fast" corresponde aos padrões da frota; emparelha com modelos Pydantic em outros lugares.
Decisão 7: Rigor de verificação de tipos em CI
Cenário: Monolito de 200k LOC misto tipado/não tipado.
| Rank | Escolha | Abordagem |
|---|---|---|
| Melhor | Pyright gradual em caminhos alterados | reportMissingImports rigoroso em CI para pacotes tocados |
| 2ª | mypy rigoroso módulo a módulo | Mais lento; bom para bibliotecas |
| 3ª | Sem tipos em CI | Débito se acumula |
Escolha errada: Mudar o repositório inteiro para rigoroso da noite para o dia - meses de churn bloqueiam a entrega.
Por que a melhor é a melhor: O gate de caminho alterado melhora a qualidade sem parar o trabalho de recursos.
Decisão 8: Empacotamento com uv vs Poetry
Cenário: Novo repositório de serviço, equipe padronizando toolchain.
| Rank | Escolha | Abordagem |
|---|---|---|
| Melhor | uv + pyproject.toml + lock | CI rápido, compatível com pip, padrão moderno |
| 2ª | Poetry | Maduro; CI mais lento; equipe já especialista |
| 3ª | Apenas pip-tools | Funciona; UX de desenvolvimento menos ergonômico |
Escolha errada: Sem lockfile em imagens de produção - incidentes de drift de dependência.
Por que a melhor é a melhor: A organização está migrando para uv 0.6+; hash de lock em rótulos de imagem.
FAQs
Quantas opções por decisão?
Três opções ranqueadas mais uma escolha errada explícita são suficientes; mais cria paralisia de análise.
Quando executar um spike?
Quando duas opções pontuam dentro de 10% ponderado - defina tempo limite de 2-3 dias com critérios de sucesso.
Quem desempata?
O líder técnico ou arquiteto documenta a decisão; o EM pondera apenas o risco de cronograma.
Quão reversíveis são essas decisões?
Frameworks e divisões de monolitos são custosos - defina gatilhos de revisão. Configurações e flags são baratas.
Os clientes votam?
Input do produto sobre resultados; engenharia detém os ranks técnicos.
Como documentar?
Link para Architecture Decision Records (ADRs) para log persistente.
E sobre construir vs comprar?
Mesma tabela ranqueada: construir, comprar, adiar com observação de escolha errada sobre construção prematura.
Como lidar com incidentes urgentes?
O IC pode contornar o processo; seguir com um ADR retroativo em uma semana.
Upgrades de versão Python?
Rank: bump menor in-place vs deploy lado a lado vs atraso; vincular à política de EOL.
Quando revisitar uma decisão?
Quando o gatilho de revisão for acionado - tráfego 2x, equipe +50%, ou classe de incidente repetida.
Relacionados
- Architecture Decision Records (ADRs) - persistir escolhas
- Executando Revisões de Design - socializar opções
- Lidando com Desacordos Técnicos - discordar e se comprometer
- Decisões de Arquitetura Python - catálogo de padrões
- Melhores Práticas de Liderança - hábitos da equipe
Versões de Stack: Esta página foi escrita para Python 3.14.0 (estável 3.14, manutenção 3.13), FastAPI 0.115+, Django 5.2, Flask 3.1, Pydantic 2, PyTorch 2.6+, pandas 2.2+, Polars 1.x, ruff 0.9+, e uv 0.6+.