Como usar este material: leia em ordem na primeira vez e, depois, use o sumário para revisão rápida. Esta versão foi expandida para cobrir os tópicos dos slides com explicações, critérios de decisão, trade-offs e exemplos aplicados ao contexto da disciplina.

Sumário

  1. Visão geral e objetivos da aula
  2. Gang of Four e a origem dos padrões
  3. Antes dos padrões: o problema que eles resolvem
  4. Categorias de padrões: criacionais, estruturais e comportamentais
  5. Singleton
  6. Factory Method
  7. Observer
  8. Strategy
  9. Decorator
  10. Adapter
  11. Chain of Responsibility
  12. Padrões no sistema Blog/Analytics
  13. Tendências modernas (2020+)
  14. Modern C# patterns
  15. Event Sourcing
  16. CQRS
  17. CQRS + Event Sourcing
  18. Microservices patterns essenciais
  19. Circuit Breaker
  20. Saga
  21. API Gateway
  22. Strangler Fig
  23. Service Mesh e observabilidade
  24. Padrões funcionais
  25. Anti-patterns
  26. Quando nao usar padrões
  27. Cheat sheet + roteiro de estudo

1) Visão Geral e Objetivos

O que você precisa dominar ao fim da aula
GoF Arquitetura C# Microsserviços

O objetivo central desta aula é transformar "padrões" de um tema teórico em uma ferramenta prática de projeto. Você deve sair sabendo responder: que padrão usar, quando usar, por que usar e quando evitar.

2) Gang of Four (GoF): por que isso importa até hoje

Em 1994, Erich Gamma, Richard Helm, Ralph Johnson e John Vlissides organizaram um vocabulário comum para problemas recorrentes em software orientado a objetos. O valor principal não é decorar os 23 padrões, e sim aprender a reconhecer formas recorrentes de problema e de solução.

Ideia-chave: padrões reduzem custo de comunicação entre pessoas e equipes.

Quando alguém diz "isso parece Strategy" ou "vamos usar Adapter para integrar legado", a equipe já compartilha uma estrutura mental, acelera decisões e reduz divergências de implementação.

3) Antes dos Padrões: o Caos

Sem padrões, projetos crescem por acumulação de decisões locais: duplicação, condicionais gigantes, acoplamento alto e baixa previsibilidade. O custo aparece depois: bugs frequentes, refatorações caras e dificuldade para onboarding de novos desenvolvedores.

Atenção: padrão não é "copiar receita". É um modelo conceitual adaptado ao contexto.

4) As 3 Categorias de Padrões

Uma boa heurística: se o problema envolve "quem cria", pense em criacionais; se envolve "quem conversa com quem", pense em estruturais/comportamentais.

5) Singleton

Definição: garante uma única instância e um ponto global de acesso.

Quando usar
Risco principal

Acoplamento global e teste difícil. Em C#, priorize DI com lifetime Singleton no container em vez de instância estática manual.

// via DI (recomendado)
services.AddSingleton<IClock, SystemClock>();

public sealed class SystemClock : IClock
{
    public DateTime UtcNow() => DateTime.UtcNow;
}

6) Factory Method

Definição: encapsula criação e permite escolher a implementação concreta sem acoplar o cliente.

Sinal de que você precisa
public interface INotifier { Task SendAsync(string msg); }

public interface INotifierFactory
{
    INotifier Create(string channel);
}
Ganho: Open/Closed na prática para fluxo de criação.

7) Observer

Quando um sujeito muda de estado, vários observadores recebem notificação. É a base de sistemas orientados a eventos.

Decisão arquitetural: Observer local (in-process) para baixo acoplamento interno; pub/sub externo para integração entre serviços.

8) Strategy

Encapsula algoritmos intercambiáveis. O cliente mantém o mesmo contrato e troca comportamento por configuração, perfil de usuário, feature flag ou tipo de dado.

public interface ISentimentStrategy
{
    Sentiment Analyze(string text);
}

// runtime: escolhe estratégia por idioma, domínio ou custo
var strategy = strategyResolver.Resolve(context.Language);
var result = strategy.Analyze(comment);
Resultado: elimina condicionais profundas e facilita teste A/B.

9) Decorator

Adiciona responsabilidades sem alterar a classe base e sem explosão de herança.

Cuidado: excesso de camadas dificulta rastreamento. Mantenha pipeline observável.

10) Adapter

Converte uma interface em outra esperada pelo cliente. É essencial para integrar legado e terceiros sem contaminar o domínio.

Regra prática

Dependência externa sempre entra por adapter. Assim, se a API externa mudar, você altera uma borda, não o sistema inteiro.

11) Chain of Responsibility

Requisições percorrem uma cadeia de handlers. Cada etapa processa, enriquece ou repassa.

var pipeline = new ValidateHandler(
    new EnrichHandler(
      new PersistHandler(
        new NotifyHandler(null))));

12) Padrões no Sistema de Blog/Analytics

Padrão Onde aparece Problema resolvido Resultado esperado
Factory Method Criação de notificações Email/SMS/Push Criação acoplada ao cliente Extensão sem quebrar fluxos
Observer Eventos de publicação e analytics Propagação manual de atualizações Reatividade e desacoplamento
Strategy Análise de sentimento e ranking Algoritmo único para cenários distintos Troca dinâmica por contexto
Decorator Pipeline de enriquecimento de comentário Cross-cutting espalhado Composição limpa de responsabilidades
Adapter Integrações externas de dados Incompatibilidade de interfaces Domínio protegido de mudanças externas

13) Tendências Modernas (2020+)

14) Modern C# Patterns (C# 9-12)

public record CommentCreated(Guid CommentId, Guid PostId, string Author, string Text);

string Severity(Comment c) => c switch
{
    { IsSpam: true } => "High",
    { Likes: > 100 } => "Medium",
    _ => "Low"
};

15) Event Sourcing

Em vez de salvar somente o estado final, salvamos os eventos de mudança. O estado passa a ser derivado por replay.

Vantagens
Trade-offs
public interface IDomainEvent { DateTime OccurredAt { get; } }

public sealed record MoneyDeposited(decimal Amount, DateTime OccurredAt) : IDomainEvent;

public sealed class AccountAggregate
{
    private readonly List<IDomainEvent> _changes = new();
    public decimal Balance { get; private set; }

    public void Deposit(decimal amount)
    {
        var evt = new MoneyDeposited(amount, DateTime.UtcNow);
        Apply(evt);
        _changes.Add(evt);
    }

    public void Apply(IDomainEvent evt)
    {
        if (evt is MoneyDeposited d) Balance += d.Amount;
    }
}

16) Event Store e Snapshots

Event store guarda eventos por stream/aggregate. Snapshot guarda foto periódica do estado para acelerar reconstrução.

Regra prática: comece sem snapshot e adicione quando métricas mostrarem custo real de replay.
// carga otimizada
var snapshot = snapshotRepo.Get(streamId);
var aggregate = snapshot is null ? new AccountAggregate() : AccountAggregate.FromSnapshot(snapshot);
var events = eventStore.LoadAfter(streamId, snapshot?.Version ?? 0);
foreach (var evt in events) aggregate.Apply(evt);

17) CQRS (Command Query Responsibility Segregation)

Separa escrita e leitura com modelos diferentes. Write side foca consistência de domínio. Read side foca performance e experiência de consulta.

Quando vale a pena
Quando pode ser exagero

18) CQRS + Event Sourcing juntos

Combinação natural: Event Sourcing alimenta write model; projeções assíncronas alimentam read model.

Command -> Aggregate -> Events -> Event Store -> Projectors -> Read DB -> Query API
Ponto crítico: aceite consistência eventual e deixe o contrato da API claro para o cliente.

19) Microservices Patterns: por que precisamos deles

Em sistemas distribuídos, falha é comportamento normal, não exceção. Padrões de microserviços existem para conter falhas, coordenar transações distribuídas e reduzir acoplamento operacional.

20) Circuit Breaker

Protege o sistema quando uma dependência degrada. Estados usuais: Closed, Open, Half-Open.

// Polly (conceito)
var policy = Policy
  .Handle<HttpRequestException>()
  .CircuitBreakerAsync(handledEventsAllowedBeforeBreaking: 5, durationOfBreak: TimeSpan.FromSeconds(30));

21) Saga Pattern

Coordena transações locais entre serviços com compensações quando algo falha. Em vez de rollback global (2PC), cada passo tem ação compensatória.

Modelos
Dica: desenhe compensações no mesmo nível de rigor que o fluxo feliz.

22) API Gateway

Ponto único de entrada para clientes. Roteia, autentica, aplica limite de taxa e pode agregar respostas.

// cenário comum
Cliente -> Gateway -> BlogService + CommentService + UserService -> resposta agregada

23) Strangler Fig Pattern

Migração incremental de monolito para serviços. O gateway/proxy roteia partes do tráfego para o novo serviço, enquanto o legado continua em produção.

  1. Escolher um bounded context.
  2. Extrair capacidade mínima para novo serviço.
  3. Rotear parcela pequena de tráfego.
  4. Medir, estabilizar e ampliar rollout.
  5. Remover trecho equivalente do monolito.
Vantagem: reduz risco de "big bang rewrite".

24) Service Mesh e Observabilidade

Service mesh move preocupações de comunicação para infraestrutura (retry, TLS mútuo, roteamento, telemetria), normalmente com sidecars/proxies.

Custo: mais componentes operacionais e curva de observabilidade.

25) Functional Programming Patterns

Padrões funcionais aumentam previsibilidade: imutabilidade, funções puras e modelagem explícita de sucesso/erro.

public abstract record Result<T>;
public sealed record Success<T>(T Value) : Result<T>;
public sealed record Failure<T>(string Error) : Result<T>;

Result<Comment> Save(string text) =>
    string.IsNullOrWhiteSpace(text)
      ? new Failure<Comment>("Texto vazio")
      : new Success<Comment>(new Comment(text));

26) Anti-Patterns: o que evitar

Sinal de alerta: se o código só é compreendido por quem escreveu, a arquitetura falhou.

27) Quando nao usar padrões

Princípios norteadores: KISS, YAGNI e refatoração incremental.

28) Cheat Sheet de Decisão Rápida

Se o problema for... Padrão sugerido Pergunta de validação
Criação de objetos variáveis Factory Method Novos tipos surgem com frequência?
Troca de algoritmo em runtime Strategy Hoje existe `if/else` por tipo de regra?
Notificações para vários interessados Observer Precisa desacoplar produtor e consumidores?
Adicionar capacidades sem herança Decorator Você quer compor comportamentos por camada?
Integrar interface incompatível Adapter A dependência externa pode mudar?
Histórico completo e auditoria Event Sourcing Eventos de domínio são ativos estratégicos?
Leitura e escrita com perfis distintos CQRS Há gargalo de query no modelo atual?
Resiliência a dependência instável Circuit Breaker Falha externa está causando cascata?

29) Atividade Guiada (pós-aula)

  1. Escolha um fluxo do projeto (publicar post, analisar sentimento, gerar dashboard).
  2. Mapeie 2 problemas atuais de acoplamento ou legibilidade.
  3. Proponha 2 padrões e justifique por que eles resolvem o problema.
  4. Liste trade-offs e como você medirá se a mudança deu certo.

Entrega ideal: diagrama simples + explicação de decisão arquitetural (1 a 2 páginas).

Referências