Boas Praticas

✅ 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

2. Fallback é Essencial

3. Padrão 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


📚 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


🔄 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


🚫 Anti-Padrões

❌ Evitar

  1. Hardcoded Secrets
    python password = "senha123" # ❌ NUNCA

  2. SQL Injection
    python query = f"SELECT * FROM users WHERE id = {user_id}" # ❌ NUNCA

  3. Logs Não Estruturados
    python print(f"User {user_id} did {action}") # ❌ NUNCA

  4. Sem Fallback
    python from common.common_logging import setup_logging # ❌ Pode falhar

  5. Sem Error Handling
    python result = external_api.get() # ❌ Pode quebrar app

  6. Processamento Pesado Síncrono
    python @app.post("/process") async def process(): heavy_processing() # ❌ Bloqueia request


📖 Referências


Última atualização: 2025-12-01

🔊 Text-to-Speech

1.0x
1.0
Pronto para reproduzir