✅ Boas Práticas - C-Suite Ecosystem
Guia de boas práticas para desenvolvimento no ecossistema C-Suite
🎯 Princípios Fundamentais
1. Sempre Use Módulos Comuns
- ✅ Use módulos de
common/ao invés de duplicar código - ✅ Mantenha fallback graceful se módulo não disponível
- ✅ Documente quando não usar módulo comum (e por quê)
2. Fallback é Essencial
- ✅ Todos os imports devem ter fallback
- ✅ App deve funcionar mesmo se módulos comuns não disponíveis
- ✅ Log warnings quando módulos não disponíveis
3. Padrão Consistente
- ✅ Siga o padrão estabelecido nos apps existentes
- ✅ Use o template de app (
templates/app_template.py) - ✅ Mantenha estrutura de diretórios consistente
📝 Padrões de Código
Imports com Fallback
# ✅ BOM
try:
from common.common_logging import setup_logging, get_logger
LOGGING_ENABLED = True
except ImportError:
LOGGING_ENABLED = False
import logging
logger = logging.getLogger(__name__)
# ❌ RUIM
from common.common_logging import setup_logging # Falha se não disponível
Error Handling
# ✅ BOM
if ERROR_HANDLING_ENABLED:
raise CSuiteError(
error_code=ErrorCode.RESOURCE_NOT_FOUND,
message="Recurso não encontrado"
)
else:
raise HTTPException(status_code=404, detail="Not found")
# ❌ RUIM
raise Exception("Erro genérico") # Sem código de erro padronizado
Logging
# ✅ BOM
logger.info("Operação realizada", extra={"user_id": user_id, "action": "create"})
# ❌ RUIM
print("Operação realizada") # Não estruturado
HTTP Client
# ✅ BOM - Com Circuit Breaker
async with get_http_client(
base_url="http://api.externa.com",
circuit_breaker_name="api_externa"
) as client:
response = await client.get("/endpoint")
# ❌ RUIM - Sem Circuit Breaker
async with httpx.AsyncClient() as client:
response = await client.get("http://api.externa.com/endpoint")
🏗️ Estrutura de App
Estrutura Recomendada
meu-app/
├── app/
│ ├── main.py # App FastAPI principal
│ ├── routers/ # Routers organizados
│ ├── models/ # Modelos Pydantic
│ └── services/ # Lógica de negócio
├── tests/
│ ├── test_main.py
│ └── test_routers.py
├── scripts/
│ └── setup.sh
├── requirements.txt
├── .env.example
├── Dockerfile
└── README.md
Organização de Código
# ✅ BOM - Separado por responsabilidade
# app/routers/decisions.py
from fastapi import APIRouter
router = APIRouter()
@router.post("/decide")
async def decide(...):
...
# app/main.py
from app.routers import decisions
app.include_router(decisions.router, prefix="/api/v1")
# ❌ RUIM - Tudo em main.py
# 500+ linhas em um único arquivo
🔒 Segurança
Validação de Input
# ✅ BOM
from common.common_validation import validate_sql_column, sanitize_search_term
column = validate_sql_column(request.sort_by, allowed_columns=["id", "name"])
search = sanitize_search_term(request.search)
# ❌ RUIM
query = f"SELECT * FROM table WHERE {request.sort_by} LIKE '%{request.search}%'"
# SQL Injection vulnerável
Secrets
# ✅ BOM
from common.common_secrets import get_db_password
password = get_db_password("CSUITE_DB_PASSWORD")
# ❌ RUIM
password = "hardcoded_password" # Nunca faça isso!
Data Masking
# ✅ BOM
from common.common_data_masking import mask_data
# Em respostas públicas
return mask_data({"email": user.email, "phone": user.phone})
# ❌ RUIM
return {"email": user.email, "phone": user.phone} # PII exposto
📊 Observabilidade
Logging Estruturado
# ✅ BOM
logger.info("Decision created", extra={
"decision_id": decision_id,
"customer_id": customer_id,
"org_id": org_id,
"action": "create_decision"
})
# ❌ RUIM
logger.info(f"Decision {decision_id} created for customer {customer_id}")
# Não estruturado, difícil de buscar
Métricas
# ✅ BOM
if BUSINESS_METRICS_ENABLED:
get_business_metric("decisions_total").labels(
org_id=str(org_id),
decision_type="offer"
).inc()
# ❌ RUIM
# Sem métricas - não há visibilidade
Tracing
# ✅ BOM
if TRACING_ENABLED:
tracer = get_tracer("meu-app")
with tracer.start_as_current_span("process_decision") as span:
span.set_attribute("customer_id", customer_id)
# Lógica aqui
# ❌ RUIM
# Sem tracing - não há rastreabilidade
⚡ Performance
Cache
# ✅ BOM
from common.common_cache import cache_result
@cache_result(ttl=300, key_prefix="policies")
def load_policies(org_id: int):
# Carregar políticas
return policies
# ❌ RUIM
def load_policies(org_id: int):
# Sempre consulta banco
return query_policies(org_id)
Connection Pooling
# ✅ BOM
from common.common_db_pool import get_db_session
session = get_db_session("csuite")
# Usa pool configurado
# ❌ RUIM
# Criar conexão nova a cada request
Async Processing
# ✅ BOM - Para processamento pesado
@async_task(name="app.process_heavy_data")
def process_heavy_data(data: dict):
# Processamento pesado
return result
# Endpoint retorna task_id imediatamente
task_result = delay_task(process_heavy_data, data)
return {"task_id": task_result.id}
# ❌ RUIM - Processamento pesado síncrono
@app.post("/process")
async def process(data: dict):
# Bloqueia request por 30 segundos
result = heavy_processing(data)
return result
🧪 Testes
Estrutura de Testes
# ✅ BOM
from common.common_testing import test_client, assert_json_response
def test_endpoint(test_client):
response = test_client(app).get("/api/endpoint")
assert_json_response(response, expected_status=200)
assert response.json()["status"] == "success"
# ❌ RUIM
# Sem testes ou testes incompletos
Cobertura
- ✅ Meta: > 80% de cobertura
- ✅ Testar casos de sucesso e erro
- ✅ Testar fallbacks quando módulos não disponíveis
📚 Documentação
Docstrings
# ✅ BOM
def process_decision(customer_id: int, org_id: Optional[int] = None) -> dict:
"""
Processa uma decisão para um cliente.
Args:
customer_id: ID do cliente
org_id: ID da organização (opcional)
Returns:
Dict com resultado da decisão
Raises:
CSuiteError: Se cliente não encontrado
"""
...
# ❌ RUIM
def process_decision(customer_id, org_id=None):
# Processa decisão
...
README
- ✅ Incluir setup básico
- ✅ Documentar endpoints principais
- ✅ Incluir exemplos de uso
- ✅ Referenciar documentação comum
🔄 Versionamento
API Versioning
# ✅ BOM
from common.common_api_versioning import create_versioned_router
v1_router = create_versioned_router("v1", tags=["API v1"])
@v1_router.post("/decide")
async def decide_v1(...):
...
# ❌ RUIM
@app.post("/decide") # Sem versionamento
async def decide(...):
...
✅ Checklist de Novo App
- [ ] Usar template de app (
templates/app_template.py) - [ ] Configurar módulos comuns com fallback
- [ ] Adicionar health checks
- [ ] Adicionar métricas
- [ ] Adicionar tracing
- [ ] Configurar error handling
- [ ] Adicionar validação de input
- [ ] Configurar logging estruturado
- [ ] Criar testes básicos
- [ ] Documentar no README
- [ ] Configurar .env.example
- [ ] Criar Dockerfile
🚫 Anti-Padrões
❌ Evitar
-
Hardcoded Secrets
python password = "senha123" # ❌ NUNCA -
SQL Injection
python query = f"SELECT * FROM users WHERE id = {user_id}" # ❌ NUNCA -
Logs Não Estruturados
python print(f"User {user_id} did {action}") # ❌ NUNCA -
Sem Fallback
python from common.common_logging import setup_logging # ❌ Pode falhar -
Sem Error Handling
python result = external_api.get() # ❌ Pode quebrar app -
Processamento Pesado Síncrono
python @app.post("/process") async def process(): heavy_processing() # ❌ Bloqueia request
📖 Referências
- Template de App:
templates/app_template.py - Guia Rápido:
docs/GUIA_RAPIDO_REFERENCIA.md - Onboarding:
docs/ONBOARDING.md - Cheat Sheet:
docs/CHEAT_SHEET.md
Última atualização: 2025-12-01