404 Not Found

404 Not Found


nginx

Design de Projeto — Blueprint de Arquitetura Full-Stack do PriceTracker

Design de projeto é como a planta antes de construir um prédio—se você começar a construção sem uma planta, pode descobrir que o alicerce não é forte o suficiente ao chegar no terceiro andar, e não terá escolha a não ser demolir e recomeçar. Uma boa planta não é algo que você desenha e depois descarta; ela serve como guia durante todo o processo de construção.

1. O Que Você Vai Aprender


2. A História Real da Alice

(1) Dor: Quanto mais funcionalidades são adicionadas, mais bagunçado fica

O PriceTracker evoluiu de uma API simples para um serviço com um número crescente de funcionalidades, mas carecia de um design unificado—os limites entre produtos e preços eram nebulosos, a lógica de assinatura estava espalhada por 10 endpoints, e o sistema de notificações era fortemente acoplado à lógica de negócio. Toda vez que uma nova funcionalidade era adicionada, cinco arquivos tinham que ser modificados, e bugs de regressão ocorriam frequentemente.

(2) Solução com Design Orientado ao Domínio

O Design Orientado ao Domínio (DDD) identifica domínios core e limites de uma perspectiva de negócio: Agregado Product, Agregado Price, Agregado User, e Agregado Subscription—cada agregado tem limites claros e responsabilidades, e a comunicação entre agregados ocorre via eventos, eliminando interdependências.

(3) Resultado

Para adicionar novas funcionalidades, você só precisa modificar o código dentro do agregado correspondente; as mudanças não afetam mais todo o sistema. A lógica de assinatura está centralizada no agregado Subscription, e as notificações são acionadas via evento PriceUpdated, garantindo desacoplamento completo.


3. Análise de Requisitos

(1) Casos de Uso Core

Papel Caso de Uso Prioridade
Usuário (Alice) Cadastro/Login P0
Usuário Consultar Preço do Produto P0
Usuário Assinar Notificação de Alteração de Preço P1
Administrador Importar Preços em Lote P0
Administrador Gerenciar CRUD de Produtos P0
Front End (Bob) Chamar a API para obter dados P0
DevOps (Charlie) Monitorar Saúde do Sistema P1
Sistema Extração Automática de Preços P2

(1) ▶ Exemplo: Script para Ordenação de Casos de Uso por Prioridade

PYTHON
# scripts/prioritize_use_cases.py
use_cases = [
    {"role": "User", "action": "register_login", "priority": "P0", "effort": 2},
    {"role": "User", "action": "query_price", "priority": "P0", "effort": 1},
    {"role": "User", "action": "subscribe_alert", "priority": "P1", "effort": 3},
    {"role": "Admin", "action": "bulk_import", "priority": "P0", "effort": 5},
]

# Ordenar por prioridade; dentro da mesma prioridade, ordenar em ordem crescente por carga de trabalho
order = {"P0": 0, "P1": 1, "P2": 2}
sorted_cases = sorted(use_cases, key=lambda x: (order[x["priority"]], x["effort"]))
for uc in sorted_cases:
    print(f"[{uc['priority']}] {uc['role']}: {uc['action']} (effort={uc['effort']}d)")

Saída:

TEXT
# Execução Bem-sucedida

(2) Requisitos Não Funcionais

Requisitos Objetivos Restrições
QPS Milhões (cluster) Nginx LB + elasticidade K8s
Latência P99 < 50 ms Cache Redis + DB Assíncrono
Disponibilidade 99,9% Múltiplas réplicas + Recuperação Automática
Volume de Dados Milhões de produtos + dezenas de milhões de preços Particionamento PostgreSQL

4. Design do Modelo de Domínio

(1) Diagrama ER

100%
erDiagram
    User ||--o{ Subscription : has
    User ||--o{ Product : creates
    User ||--o{ Alert : sets
    Product ||--o{ Price : has
    Product ||--o{ Alert : watched_by
    Subscription ||--o{ Feature : includes
    
    User {
        int id PK
        string email UK
        string hashed_password
        string role
        datetime created_at
    }
    
    Product {
        int id PK
        string name
        string category
        float base_price
        string sku UK
        int user_id FK
        datetime created_at
    }
    
    Price {
        int id PK
        int product_id FK
        float price
        string currency
        string source
        datetime recorded_at
    }
    
    Subscription {
        int id PK
        int user_id FK
        string plan
        datetime starts_at
        datetime expires_at
    }
    
    Alert {
        int id PK
        int user_id FK
        int product_id FK
        float target_price
        string status
    }

(2) Identificação de Raízes de Agregação

Raiz de Agregação Entidades Contidas Regras de Limite
User User, Subscription, Alert O usuário possui assinaturas e alertas
Product Product, Price O produto tem histórico de preços
PriceImport Informações de Lote, Status de Importação Importação em lote é uma transação separada

(1) ▶ Exemplo: Definições de Eventos de Domínio

PYTHON
# domain/events.py
from dataclasses import dataclass, field
from datetime import datetime
from enum import Enum

class EventType(Enum):
    PRICE_CHANGED = "price_changed"
    ALERT_TRIGGERED = "alert_triggered"
    USER_SUBSCRIBED = "user_subscribed"

@dataclass
class DomainEvent:
    event_type: EventType
    aggregate_id: int
    occurred_at: datetime = field(default_factory=datetime.utcnow)
    payload: dict = field(default_factory=dict)

# Uso: Evento de Alteração de Preço
price_event = DomainEvent(
    event_type=EventType.PRICE_CHANGED,
    aggregate_id=42,
    payload={"old_price": 299.9, "new_price": 249.9, "currency": "CNY"},
)

Saída:

TEXT
# Execução Bem-sucedida

5. Decisões de Seleção de Tecnologia

(1) Comparação de Modelos

Necessidade Opção A Opção B Decisão Motivo
Frameworks Web FastAPI Flask/Django FastAPI Assíncrono + Auto-documentação + Verificação de Tipos
Banco de Dados PostgreSQL MySQL/MongoDB PostgreSQL JSONB + Driver Assíncrono Maduro
Cache Redis Memcached Redis Estruturas de dados ricas + persistência
Fila de Tarefas Celery+Redis RQ/Dramatiq Celery Ecossistema maduro + monitoramento robusto
Comunicação em Tempo Real WebSocket SSE WebSocket Bidirecional + Baixa Latência
Contêiner Docker Bare Metal/VM Docker Consistência + Orquestração

(2) Visão Geral da Arquitetura do Sistema

100%
flowchart TD
    Client[Cliente / Bob Frontend] --> Nginx[Nginx Load Balancer]
    Nginx --> API1[FastAPI Pod 1]
    Nginx --> API2[FastAPI Pod 2]
    Nginx --> APIN[FastAPI Pod N]
    
    API1 --> PG_Master[(PostgreSQL Master)]
    API2 --> PG_Master
    APIN --> PG_Master
    
    PG_Master --> PG_Replica[(PostgreSQL Replica)]
    
    API1 --> Redis[(Redis Cluster)]
    API2 --> Redis
    APIN --> Redis
    
    Redis --> CW1[Celery Worker 1]
    Redis --> CW2[Celery Worker 2]
    
    CW1 --> PG_Master
    CW2 --> PG_Master
    
    API1 --> WS[WebSocket Hub]
    API2 --> WS
    
    Prometheus[Prometheus] --> API1
    Grafana[Grafana] --> Prometheus

6. Estratégia de Versionamento de API

(1) Versão por URL vs. Versão por Header

Dimensão Versão por URL /api/v1/ Versão por Header Accept: v=1
Visibilidade Alta (URL é explícita) Baixa (oculta no header)
Roteamento Simples (baseado em prefixo) Complexo (requer parsing de middleware)
Cache Cache de URL independente Requer Header Vary
Swagger Agrupamento automático Requer configuração manual
Recomendado ✅ Como Usar o PriceTracker Adequado para APIs Internas

(1) ▶ Exemplo: Estrutura de Roteamento com Versionamento por URL

PYTHON
from fastapi import APIRouter

# Rotas V1
v1_router = APIRouter(prefix="/api/v1", tags=["v1"])
v1_products = APIRouter(prefix="/products", tags=["products"])
v1_prices = APIRouter(prefix="/prices", tags=["prices"])
v1_auth = APIRouter(prefix="/auth", tags=["auth"])

# Rotas V2 (futuro)
v2_router = APIRouter(prefix="/api/v2", tags=["v2"])

# Montar roteadores
app.include_router(v1_auth)
app.include_router(v1_products, dependencies=[Depends(get_current_user)])
app.include_router(v1_prices, dependencies=[Depends(get_current_user)])
app.include_router(v1_router)

Saída:

TEXT
# Execução Bem-sucedida

❓ Perguntas Frequentes

P Qual é o propósito de uma raiz de agregação no DDD?
R Uma raiz de agregação define limites de transação e garante consistência de dados. Como Product é a raiz de agregação, Price só pode ser modificado através de Product e não pode ser adicionado ou excluído independentemente, garantindo assim a consistência dos dados.
P Como implementar separação leitura/escrita no PostgreSQL?
R Use o banco de dados primário para escritas e o secundário para leituras. Configure duas engines no SQLAlchemy (write_engine e read_engine), e use a read_engine para se conectar ao banco secundário para operações de leitura. Você precisará considerar a latência de replicação.
P Por que escolher Redis em vez de Memcached?
R O Redis suporta persistência, múltiplas estruturas de dados (Hash/Set/ZSet), e Pub/Sub, enquanto o Memcached suporta apenas pares chave-valor simples. O Redis oferece uma gama mais ampla de recursos.
P Quando as versões de API são atualizadas?
R Versões são atualizadas apenas quando há mudanças quebradoras (como remover campos ou alterar a estrutura de resposta). Adicionar novos campos ou endpoints não constitui uma mudança quebradora e não requer uma nova versão.
P Como os eventos de domínio são implementados?
R Uma abordagem simples usa tarefas Celery (como publish_price_updated_event.delay(product_id, new_price)), enquanto uma abordagem mais complexa usa filas de mensagens (RabbitMQ/Kafka).
P Quão detalhado deve ser um diagrama arquitetural?
R Para a equipe, basta ser "suficiente." Over-engineering desperdiça tempo, enquanto under-engineering gera confusão. O PriceTracker encontra o equilíbrio certo com sua arquitetura de três camadas e raízes de agregação.

📖 Resumo


📝 Exercícios

  1. Questão Básica (Dificuldade: ⭐): Desenhe um diagrama de arquitetura de sistema para o PriceTracker (incluindo FastAPI, PostgreSQL, Redis, Celery e Nginx), e rotule as responsabilidades de cada componente e o fluxo de dados. Dica: flowchart Mermaid
  2. Problema Avançado (Dificuldade ⭐⭐): Projete um diagrama ER para o modelo de domínio do PriceTracker, identifique três raízes de agregação (User, Product, PriceImport), e defina as entidades incluídas em cada agregado e suas regras de limite. Dica: Mermaid erDiagram + tabela de raízes de agregação
  3. Desafio (Dificuldade: ⭐⭐⭐): Complete o blueprint arquitetural completo do PriceTracker—incluindo o documento de requisitos (casos de uso core + requisitos não funcionais), uma tabela de comparação de tecnologias, código para a estrutura de roteamento de versionamento de API, e um diagrama de topologia de implantação (incluindo bancos de dados master-slave, camadas de cache e cluster Celery). Dica: Incorpore todo o conteúdo abordado nesta lição.

---|

Web-Tutorial.com

Equipe Técnica Web-Tutorial

Uma plataforma de tutoriais mantida por diversos desenvolvedores. Cada tutorial é escrito e revisado por profissionais da área correspondente. Trabalhamos para manter nosso conteúdo preciso e confiável — se encontrar algum problema, avise-nos.

100%