BLOCO 1 · SÁBADO 02

OO de verdade.
SOLID com evidência.

Uma regra. Duas entradas. Cinco perguntas para revisar melhor.

O serviço de Pedidos continua. Agora você explica por que uma mudança é boa — e prova.

Prever→Observar→Revisar→Provar
📖 Antes🏫 Em sala🏠 Em casa
📖
Zona 1 · antes da aula · 40–60 min

Retome o pedido, traga uma pergunta

Leia esta abertura e as pausas teóricas dos atos. Em sala, voltaremos a elas conforme a dúvida aparecer.

01 · Continuidade

O mesmo pedido. Uma pergunta nova. [01]

O pedido foi pago. A API impede adicionar café. Mas uma rotina de importação consegue alterar os itens. Quem realmente está protegendo a regra?

No sábado 01, construímos o serviço de Pedidos: o domínio decide, o caso de uso coordena e os adapters traduzem HTTP e banco. Hoje vamos usar Orientação a Objetos (OO) para explicar por que esse desenho ajuda e como revisar uma proposta de mudança.

O que você já pode trazer

Seu repositório, specs e testes. CriarPedido e AdicionarItem funcionando; pagamento e consulta são a tarefa anterior. Traga também o que ficou pendente, com a última prova verde.

Se não terminou a tarefa

Use a base de retomada em outra pasta. Ela consolida a referência do Cap 01 com adicionar item, pagamento simulado e consulta. Leia RETOMADA.md e compare antes de continuar.

O Pedido do Cap 01 já recusa alterações quando está fechado. Os defeitos de hoje estão em um laboratório separado: não é necessário estragar seu domínio para refatorá-lo.

← Revisitar o Cap 01 · Abrir meu caderno livre ↗

02 · Preparação

O mapa das quatro horas [02]

Hoje a evidência de aprendizagem é uma decisão sustentada por código e teste. Não contamos classes nem interfaces. Um PR (pull request) é uma proposta de alteração para revisão; neste laboratório você pode comparar arquivos localmente, sem abrir um PR público.

13h30–17h30 · 240 minutos, incluindo intervalo
InícioDuraçãoMomentoSaída observável
13:3015 minDiagnósticoPrever a falha por outra entrada
13:4535 minObjeto e encapsulamentoSimular e localizar a regra
14:2030 minRefatoração guiadaRegressão testada pelas duas entradas
14:5015 minIntervaloPausa
15:0555 minSOLID por decisõesVocabulário com consequência
16:0040 minRevisão avaliativaParecer A–E com evidência
16:4020 minTransferênciaSpec e início de CancelarPedido
17:0015 minChecklist vira skillRevisão reproduzível
17:1515 minFechamentoDefender uma decisão

O bloco de SOLID retoma a leitura: aprofunde os princípios que aparecerem no diagnóstico. A transferência tem 20 minutos para escrever a spec e iniciar a implementação; a conclusão pode seguir em casa.

Diagnosticar o ponto de partida
Não altere arquivos. Leia AGENTS.md, CLAUDE.md e as specs relevantes do serviço pedidos.
Identifique quais operações existem e execute os testes unitários pelo Wrapper.
Separe: funcionando com evidência, falhando com causa observada, ainda não implementado.
Compare com RETOMADA.md se usei uma referência. Não adicione dependências.
Proponha o menor ponto de retomada. Aguarde meu OK antes de editar.
🏫
Zona 2 · em sala · atos de construção e revisão

Da regra protegida à decisão explicada

Preveja, observe, nomeie, teste. O agente executa; você decide o que merece mudar.

13:30 · Diagnóstico · juntos

Duas entradas, duas verdades? [03]

Uma proposta do agente protege apenas a API. O objeto tem campos privados, mas entrega a lista interna. Leia o trecho e preveja o que a importação faz com um pedido pago.

Java · trecho de leitura
// Trecho defeituoso do laboratório: não copiar para o serviço.
public void peloController(PedidoAnemico pedido, String sku) {
    if (pedido.isPago()) throw new IllegalStateException("Pedido fechado");
    pedido.getItens().add(sku);
}
public void pelaImportacao(PedidoAnemico pedido, String sku) {
    pedido.getItens().add(sku);
}
👀 Depois da previsão: o que acontece?

A importação adiciona o item. A condição só existe no controller e getItens() devolve a coleção mutável. private limita o acesso direto ao campo; não impede modificar o objeto que a referência aponta.

13:45 · Pausa teórica · encapsulamento

Objeto não é só uma sacola de campos [04]

Estado + comportamento

Estado é o que o objeto representa agora: itens e status. Comportamento é o que ele permite fazer: adicionar, pagar, cancelar. A classe define essa forma; cada objeto é uma ocorrência concreta.

Uma regra que deve permanecer verdadeira

Invariante é uma condição que as operações precisam preservar. Aqui: um pedido fechado não aceita novos itens. Essa promessa precisa valer para API, importação e chamada direta.

Encapsular é oferecer operações que preservam essa promessa e controlar como o estado é exposto. É como um caixa que permite uma retirada validada, sem entregar acesso irrestrito ao saldo. A comparação tem limite: a proteção depende de todas as operações públicas reais do código.

Pedido do Cap 01 · regra local + novo estado
public Pedido adicionarItem(ItemPedido item) {
    exigirAberto();
    var novosItens = new ArrayList<>(itens);
    novosItens.add(item);
    return new Pedido(id, clienteId, novosItens, status);
}

Domínio rico reúne dados e regras que pertencem ao negócio. Um modelo anêmico deixa essas decisões espalhadas nos serviços enquanto os objetos apenas recebem setters. Isso não transforma todo objeto de dados em erro: DTOs (Data Transfer Objects, objetos de transferência de dados) transportam informações e não precisam se tornar entidades de domínio.

Pedido decide se pode mudar. O caso de uso busca, pede a mudança e salva. O domínio não abre conexão HTTP, não envia e-mail e não chama JPA.
Prever → escolher → observar

Laboratório: onde mora a regra? [05]

Escolha onde a guarda foi implementada. Depois teste uma entrada com o pedido já pago. A importação desta simulação chama diretamente o objeto; ela pode contornar o service.

Em tela estreita, deslize o diagrama para os lados. Pelo teclado, foque a área e use as setas.

API passa por controller e service; importação vai direto ao PedidoControllerServicePedido2 unidades · 37,80APIImportação
ANTESPAGO · 2 unidades · R$ 37,80
DEPOISAinda não executado

Simulação de chamadas, sem banco. Cada tentativa parte do estado escolhido; adiciona 1 café de R$ 18,90. Nada é persistido. Uma arquitetura que obriga todas as entradas a passar pelo service também centraliza a guarda; aqui investigamos o objeto que continua vulnerável a chamadas diretas.

Agora existe um comando de terminal que chama Pedido diretamente. O que protege a promessa?

Ainda no Ato 1 · referências e cópia defensiva

Record não congela tudo sozinho [06]

O record fixa as referências dos componentes. Se um componente aponta para uma lista mutável, outra pessoa ainda pode mudar essa lista. Imutabilidade superficial é diferente de congelar todo o grafo de objetos.

Recorte para explicar a cópia · não substitui o Pedido completo
public record Pedido(List<ItemPedido> itens) {
    public Pedido {
        itens = List.copyOf(itens);
    }
}

List.copyOf produz uma lista não modificável com os elementos atuais. Alterar a lista de origem depois não muda essa lista. Os elementos continuam sendo referências: se fossem mutáveis, poderiam mudar por dentro. No nosso caso, ItemPedido usa String, int e BigDecimal, sem componentes mutáveis.

Adicionar um item cria outro Pedido; quem chamou precisa usar o retorno. Imutabilidade facilita raciocinar, mas não impede duas requisições concorrentes de sobrescrever dados. Isso pede outra decisão de persistência.

A origem recebe um novo item depois da construção com List.copyOf. O Pedido deve mudar?

Referência: Record no Java 21 e List.copyOf.

14:20 · 30 min · juntos → sozinhos

Refatore uma falha que você consegue provar [07]

Refatorar é reorganizar o código sem mudar seu comportamento observável. Aqui também vamos corrigir um bug: a importação passará a recusar algo que aceitava indevidamente. Registre a mudança da regra separadamente da reorganização.

Baixe o laboratório independente, abra outra pasta e leia RETOMADA.md. Comece por src/main/java/br/com/revisao/EntradaAlternativa.java. As classes aninhadas deixam o exemplo concentrado em um arquivo; não são uma organização obrigatória para o serviço real.

  1. Diagnostique. Rode CaracterizacaoTest. Ele fica verde ao reproduzir a falha conhecida; verde aqui não significa regra aprovada.
  2. Escreva a expectativa nova. Pago deve recusar item pela API e pela importação. Aberto aceita e preserva o original.
  3. Peça um plano. Centralizar a regra em uma operação e impedir a lista externa de alterar o objeto. Preserve os dois pontos de entrada.
  4. Autorize e revise. Atualize a expectativa do teste de falha para a regra desejada, sem simplesmente apagar o cenário. Execute e confira o diff.
Prompt 1 · planejar a correção
Leia as instruções deste projeto e EntradaAlternativa.java com seus testes.
Não edite ainda. Explique o caminho que permite adicionar a um pedido pago.
Proponha uma spec curta e um plano restrito a esse exemplo e aos testes:
- pago recusa nas duas entradas;
- aberto aceita e o original permanece igual;
- lista de origem e lista exposta não permitem alterar o Pedido;
- sem Spring, banco, nova dependência ou mudança nos casos A–E.
Mostre quais testes atuais caracterizam defeitos e como mudar a expectativa.
Aguarde meu OK.
👀 Refatoração-modelo, depois de tentar
Java · trecho de leitura
public Pedido pelaImportacao(Pedido pedido, String sku) {
    return pedido.adicionar(sku);
}

As duas entradas chamam a mesma operação. A guarda e a criação do novo estado ficam em Pedido. A lista é copiada no construtor. No serviço real, esse desenho já existe: compare com adicionarItem em vez de renomear seu domínio para coincidir com o exemplo.

Checkpoint: prove as duas recusas, o caminho aberto e a cópia defensiva. Registre uma decisão que mudou e uma que você preservou.
14:50–15:05 · intervalo de 15 minutos
15:05 · Pausa teórica · duas perguntas

O que deve mudar junto? [08]

Um teste unitário verifica um comportamento sem exigir a aplicação inteira ou serviços externos. Um fake é uma implementação simples usada no teste, como um repositório em memória. Ele permite observar o contrato; não prova que o banco real funciona. Essa segunda evidência vem do teste de integração.

Coesão descreve quanto as partes de um módulo colaboram para uma responsabilidade clara. Acoplamento descreve quanto uma parte depende de outra. Precisamos de colaboração; o objetivo é tornar as dependências deliberadas e as mudanças compreensíveis.

Juntar pelo mesmo motivo

Adicionar, pagar e cancelar preservam o ciclo de vida de Pedido. Ter vários métodos não torna a classe ruim. Eles operam o mesmo estado e suas regras.

Separar por mudança independente

A equipe comercial altera cálculo; comunicação altera a mensagem; infraestrutura altera a conexão. Uma edição de texto não deveria exigir revisar a regra monetária.

Um método curto pode estar no lugar errado. Um arquivo grande pode conter uma responsabilidade coesa. Procure o motivo e o efeito da mudança, não um limite mágico de linhas.

Composição, herança e polimorfismo

Reutilizar não exige virar um subtipo [09]

Herança cria uma relação de subtipo: quem espera a classe base também pode receber a derivada. Reaproveitar algumas linhas não basta para justificar essa promessa. Composição faz um objeto colaborar com outro, recebido por construtor, sem afirmar que um é uma versão do outro.

Java · trecho de leitura
// Ideia problemática: Pix herda a promessa de parcelar do cartão.
class PagamentoPix extends PagamentoCartao { /* ... */ }

// Colaboração: o caso de uso recebe quem sabe autorizar.
public AutorizarPedido(Autorizador autorizador) {
    this.autorizador = autorizador;
}

Interface declara operações disponíveis. O contrato completo também inclui entradas aceitas, resultados e falhas permitidas. Polimorfismo permite chamar a mesma operação por esse contrato e obter o comportamento da implementação recebida.

Usamos cartão e Pix como simulações. Neste sistema, ambos autorizam, mas só cartão parcela. Em outro produto, as capacidades podem ser diferentes. Composição também tem custo: mais objetos para montar e mais relações para entender.

Escolha o contrato e a implementação

Laboratório: a promessa sobrevive à troca? [10]

O cliente foi escrito com uma expectativa. Troque quem atende e observe se ele continua conseguindo fazer a mesma chamada válida.

Cliente
parcelar(2)
Cartão
Aguardando

Resultados locais fixos. “Autorizar” aqui ilustra uma capacidade; não faz cobrança, rede ou validação financeira.

SOLID reúne cinco princípios de projeto orientado a objetos. Use as letras para nomear perguntas de revisão; elas não substituem o contexto nem formam uma pontuação automática de qualidade.
Single Responsibility Principle · responsabilidade única

S · Uma razão de mudança por responsabilidade [11]

Um recibo reúne dois trabalhos: calcular o preço promocional e escrever o e-mail. A equipe comercial muda a promoção; comunicação muda a saudação. Os motivos são independentes, embora ambos mencionem Pedido.

Coisas que mudam pelo mesmo motivo tendem a ficar juntas. Mudanças de atores distintos pedem uma fronteira clara. “Responsabilidade única” não significa um método por classe.

Recorte didático · versões compiláveis no laboratório
class ResumoPedido {
    BigDecimal total(BigDecimal subtotal) { /* regra comercial */ }
    String email(String cliente) { /* texto de comunicação */ }
}
👀 Refatoração e consequência

Extraia PrecoPromocional e MensagemPedido. Um coordenador pode chamar ambos; ele não precisa escrever o texto nem recalcular a regra. Mudar “Olá” agora alcança a mensagem, sem editar o cálculo.

Experimente uma mudança de texto

Comunicação pediu trocar “Olá” por “Oi”. Selecione a organização e veja onde essa edição cai.

Uma classe Pedido tem adicionar, pagar e cancelar. Devemos separar só por ter três métodos?

Leitura de origem: Single Responsibility Principle. O caso de Pedidos e os critérios acima são a aplicação didática deste capítulo.

Open–Closed Principle · aberto para extensão, fechado para modificação

O · Uma variação com um lugar para entrar [12]

Uma campanha oferece 10%; outra desconta R$ 5. O time precisa variar o abatimento sem repetir a conta final, seu arredondamento e suas validações.

Escolha uma fronteira estável para uma variação conhecida. A regra comum usa um contrato; outra implementação acrescenta um comportamento. Algum lugar ainda precisa selecionar e montar essa implementação.

Recorte didático · versões compiláveis no laboratório
interface Desconto {
    BigDecimal abatimento(BigDecimal subtotal);
}
// A calculadora recebe Desconto e faz a parte comum:
return subtotal.subtract(abatimento).setScale(2, RoundingMode.HALF_UP);
👀 Refatoração e consequência

Com subtotal 100, dez por cento produz 90.00; cinco reais produz 95.00. Com subtotal 3, o desconto fixo limita o abatimento a 3 e resulta em 0.00. OCP não exige abstrair cada if: um conjunto pequeno e estável pode continuar explícito.

Troque a campanha, preserve a conta

A escolha da política muda na montagem. A calculadora permanece a mesma. O resultado final é arredondado para duas casas; o Java usa BigDecimal. HALF_UP aproxima para o valor mais próximo e, no empate, afasta do zero: 0.045 vira 0.05. Arredondamos o total final, não cada etapa intermediária.

A única promoção está estável há anos. O agente propõe um registro de plugins. O que revisar?

Leitura de origem: Open–Closed Principle. O caso de Pedidos e os critérios acima são a aplicação didática deste capítulo.

Liskov Substitution Principle · substituição de Liskov

L · Trocar a implementação sem quebrar a promessa [13]

O cliente recebe PagamentoCartao e chama parcelar(2), permitido de 1 a 12 vezes. PagamentoPix herda cartão, mas lança UnsupportedOperationException para essa chamada.

Uma implementação substituta deve respeitar o contrato esperado pelo cliente: não pode exigir condições mais fortes nem enfraquecer o resultado prometido. O compilador verificar tipos não prova o comportamento.

Recorte didático · versões compiláveis no laboratório
PagamentoCartao pagamento = new PagamentoPix();
pagamento.parcelar(2); // compila; a promessa falha em execução
👀 Refatoração e consequência

Compartilhe apenas autorizar por MeioPagamento; mantenha parcelar no cartão. Uma recusa de negócio prevista no contrato é diferente de não implementar uma operação prometida. Tipos relacionados no mundo real não são automaticamente bons subtipos no código.

O contrato permite retornar Recusado por limite insuficiente. Isso viola LSP?

Leitura de origem: Liskov Substitution Principle. O caso de Pedidos e os critérios acima são a aplicação didática deste capítulo.

Interface Segregation Principle · segregação de interfaces

I · O cliente depende só do que precisa [14]

Consulta precisa de buscar. Recebe um Repositorio que também obriga salvar e exportarTodos. Até o fake de consulta precisa conhecer capacidades que não usa.

Forme contratos pelas necessidades dos clientes. Uma classe concreta pode implementar mais de um contrato. Segregar não exige um serviço, uma classe e uma implantação separados para cada método.

Recorte didático · versões compiláveis no laboratório
interface ConsultaPedidos { String buscar(String id); }
interface GravacaoPedidos { void salvar(String id); }
interface ExportacaoPedidos { List<String> exportarTodos(); }
// Consulta recebe apenas ConsultaPedidos.
👀 Refatoração e consequência

Agora o teste da consulta fornece só buscar; exportação pode evoluir sem ampliar esse contrato. O port Pedidos do Cap 01 tem buscar e salvar usados juntos pelos casos de uso: isso não exige dividi-lo automaticamente.

Monte apenas o fake da consulta

Buscar e salvar são usados pelos mesmos clientes e mudam juntos. Separar é obrigatório?

Leitura de origem: Interface Segregation Principle. O caso de Pedidos e os critérios acima são a aplicação didática deste capítulo.

Dependency Inversion Principle · inversão de dependência

D · Quem escolhe o detalhe externo? [15]

O caso de uso cria new GatewayHttp(). Ao testar uma aprovação, já ficamos presos ao serviço externo. O detalhe técnico passou a decidir como a regra pode ser executada.

A política de alto nível depende de um contrato adequado à sua necessidade. O adapter externo implementa esse contrato. A montagem escolhe o concreto e entrega ao caso de uso.

Recorte didático · versões compiláveis no laboratório
interface Autorizador { boolean autorizar(String id); }
public AutorizarPedido(Autorizador autorizador) {
    this.autorizador = autorizador;
}
👀 Refatoração e consequência

No teste, um fake devolve aprovado ou recusado sem rede. Na aplicação real, config monta o adapter. Injeção pelo construtor é uma técnica; DIP é a direção das dependências. Receber GatewayHttp pelo construtor ainda prende o cliente ao tipo concreto.

Consigo testar uma recusa sem rede?

O desenho mostra dependências declaradas. Criar o objeto na configuração é necessário, mas não basta: o tipo recebido pelo núcleo também importa.

Um service recebe GatewayHttp no construtor. O que já sabemos?

Leitura de origem: Dependency Inversion Principle. O caso de Pedidos e os critérios acima são a aplicação didática deste capítulo.

16:00 · 40 min · avaliativo · sozinho → dupla

Agora você é o revisor [16]

Abra Propostas.java no ZIP do laboratório. Os cinco casos abaixo são independentes; seu trabalho é produzir um parecer e dirigir uma correção. Tente antes de abrir o diagnóstico-modelo.

Entrega: cinco achados com local, comportamento afetado, princípio justificado, correção mínima e prova. Depois escolha um caso, escreva a spec, aprove o plano e revise o diff da correção. Não vale apenas escrever “viola SOLID”.
Caso A · O resumo ganhou dois trabalhos
Recorte · arquivo completo em src/main/java/br/com/revisao/Propostas.java
class ResumoPedido {
    BigDecimal total(BigDecimal subtotal) { /* promoção */ }
    String email(String cliente) { /* comunicação */ }
}
Caso B · Chegou uma campanha nova
Recorte · arquivo completo em src/main/java/br/com/revisao/Propostas.java
if (campanha.equals("DEZ")) { /* 10% */ }
if (campanha.equals("SEM")) return subtotal;
throw new IllegalArgumentException("Campanha desconhecida");
Caso C · A implementação trocada
Recorte · arquivo completo em src/main/java/br/com/revisao/Propostas.java
class PagamentoPix extends PagamentoCartao {
    public String parcelar(int vezes) {
        throw new UnsupportedOperationException("Pix não parcela aqui");
    }
}
Caso D · A consulta trouxe bagagem
Recorte · arquivo completo em src/main/java/br/com/revisao/Propostas.java
interface Repositorio {
    String buscar(String id);
    void salvar(String id);
    List<String> exportarTodos();
}
Caso E · O detalhe nasceu no caso de uso
Recorte · arquivo completo em src/main/java/br/com/revisao/Propostas.java
class AutorizarPedido {
    private final GatewayHttp gateway = new GatewayHttp();
}
Rubrica proposta · 10 pontos · 2 por caso
Critério em cada casoPontos
Localiza e nomeia o princípio com justificativa0,5
Explica a consequência no contexto fornecido0,5
Propõe correção pequena e reconhece seu custo0,5
Indica teste ou comparação observável0,5

Há sobreposição entre princípios: aceite outro enquadramento bem demonstrado. A avaliação mede julgamento. Na revisão do próprio projeto, não invente cinco problemas para preencher esta tabela.

Prompt 2 · executar uma revisão sem corrigir
Leia Propostas.java, RETOMADA.md e os testes. Não edite arquivos.
Para cada caso A–E, mostre: arquivo/linha, contrato afetado, consequência reproduzível,
princípio com justificativa, menor correção e teste que a sustentaria.
Diferencie falha observada, risco inferido e preferência de estilo.
Não exija uma interface por classe. Não transforme simulação em integração real.
Entregue o parecer. Escolherei um caso e pedirei o plano antes de autorizar código.
Revisão coletiva · depois do parecer

Uma correção pequena também precisa de prova [17]

👀 Diagnóstico e refatoração-modelo A–E
  1. A · SRP. PrecoPromocional e MensagemPedido isolam motivos distintos. Preserve 100 → 90.00 e o texto esperado. Um teste de saída não prova separação: confira também o diff.
  2. B · OCP. Desconto informa abatimento; Calculadora valida limites, subtrai e arredonda. Percentual de 10%: 37.80 → 34.02. Fixo de 5: 3 → 0.00. A composição escolhe a política.
  3. C · LSP. Cartão e Pix implementam apenas o contrato comum MeioPagamento.autorizar. Parcelar continua específico do cartão. Teste as implementações pelo mesmo tipo.
  4. D · ISP. Consulta depende de ConsultaPedidos. Uma implementação ainda pode oferecer gravação e exportação. Teste a consulta com um fake que só busca.
  5. E · DIP. AutorizarPedido recebe Autorizador. Fakes aprovam/recusam sem rede. Não transferir a decisão de negócio para um DTO do fornecedor.

Referência completa para comparar após a tentativa: laboratório resolvido. Execute os testes em outra pasta. O ZIP não é uma refatoração automática do seu serviço.

Refatoração reorganiza código preservando comportamento observável. Corrigir uma regra ou adicionar cancelamento muda comportamento e precisa ser nomeado como mudança funcional. No caso B, preservamos campanhas existentes e acrescentamos uma variação: registre ambas as partes.

O agente criou sete interfaces para um cálculo estável de três linhas. Qual evidência pedir?

16:40 · 20 min · sozinho · início em sala

Transfira: cancelar sem espalhar a regra [18]

Seu domínio já tem Pedido.cancelar(): ABERTO passa a CANCELADO; fechado recusa. Agora exponha essa operação pelo mesmo caminho de aplicação, port e adapter do Cap 01. É uma funcionalidade nova, não apenas refatoração.

Contrato do exercício · POST /pedidos/{id}/cancelamento, sem corpo
AntesRespostaPersistência
ABERTO200 · CANCELADOMesmo UUID, itens e total; salva uma vez
PAGO ou CANCELADO409Não salva
Não existe404Não salva

Cancelar de novo retorna 409 neste contrato. Não inclui estorno, autenticação, eventos ou garantia de concorrência. O total do café continua 37.80: cancelamento altera status, não apaga histórico.

  1. Escreva a spec em um novo arquivo livre da sua pasta .specs/. Declare resultado, limites e evidências.
  2. Revise o plano: CancelarPedido/Service, método REST, bean de montagem e testes. Reutilize Pedidos e as exceções existentes.
  3. Prove primeiro com fake em memória. Depois ligue HTTP e valide 200/404/409 com Postgres e releitura.
Dica 1 · quem faz o quê?

O service busca, chama atual.cancelar() e salva o retorno. Controller traduz HTTP; config injeta o caso de uso. A regra do estado permanece em Pedido.

Dica 2 · plano para o agente
Prompt 3 · planejar a transferência
Leia minhas instruções, spec de cancelamento e o código existente. Não edite ainda.
POST /pedidos/{id}/cancelamento sem corpo: aberto -> 200/CANCELADO;
pago ou cancelado -> 409; ausente -> 404. Preservar UUID, itens e total.
Não gravar em recusas. Reutilize Pedido.cancelar(), Pedidos e handler existentes.
Sem nova dependência, DTO sem necessidade, evento, estorno ou tabela.
Proponha testes unitários e HTTP/JPA que provem os critérios e preservem as operações anteriores.
Mostre arquivos a alterar e aguarde meu OK.
👀 Depois de tentar: núcleo da solução
Java · trecho de leitura
Pedido atual = pedidos.buscar(pedidoId)
    .orElseThrow(() -> new PedidoNaoEncontradoException(pedidoId));
Pedido cancelado = atual.cancelar();
return pedidos.salvar(cancelado);

() -> é a função executada se a busca estiver vazia. A IDE pode desenhar uma seta; digite - seguido de >. Fonte completa e testes: checkpoint de cancelamento, para comparar em outra pasta.

17:00 · 15 min · juntos

Seu checklist vira uma skill [19]

Uma skill empacota instruções reutilizáveis para uma tarefa. Aqui ela não “sabe SOLID” por mágica: orienta o agente a ler a spec, examinar evidências e produzir um parecer consistente. Ela também pode errar; revise o resultado.

Comece salvando o SKILL.md de revisar-solid. No Claude Code, a skill de projeto fica em .claude/skills/revisar-solid/SKILL.md e pode ser chamada por /revisar-solid. Para outro agente, peça explicitamente que leia o arquivo e siga o roteiro; confirme o mecanismo nativo de descoberta da ferramenta antes de depender dele.

Conteúdo completo · SKILL.md
---
name: revisar-solid
description: Revisar mudanças Java por contratos, encapsulamento e SOLID, com evidência e correção mínima. Use ao pedir revisão de um diff do serviço de Pedidos.
---
Leia as instruções do projeto e a spec da mudança. Identifique o diff a revisar;
se ele não foi indicado, peça o intervalo ou os arquivos antes de concluir.
Não edite arquivos, não faça commit, push nem abra PR durante a revisão.

1. Resuma o comportamento prometido e os limites da mudança.
2. Confira quem protege cada invariante e se outra entrada a contorna.
3. Examine SOLID pelo contexto: motivos de mudança, variação real,
   substituição, necessidade dos clientes e direção das dependências.
4. Para cada achado, informe arquivo/linha, consequência, princípio,
   evidência observada (ou hipótese explícita), correção mínima e teste.
5. Não invente um achado por letra. Não exija interface por classe.
6. Execute apenas testes locais pertinentes dentro das permissões do projeto;
   diga quais rodaram e quais não rodaram. Não use serviços pagos ou produção.
7. Separe defeitos, riscos e preferências. Se não houver achados, diga isso e
   registre os limites da revisão. Termine com uma decisão que merece ser mantida.

Saída: resumo do contrato, achados priorizados, testes/evidências e limites.
Aguarde uma solicitação de implementação antes de corrigir qualquer coisa.
Prompt 4 · experimentar a revisão
Leia o arquivo revisar-solid/SKILL.md no caminho em que o salvei e siga suas instruções.
Revise apenas meu diff de CancelarPedido em relação ao commit anterior à implementação.
Se não identificar esse intervalo com segurança, pergunte antes de revisar.
Não altere arquivos. Confronte 200/404/409, UUID/itens/total e ausência de gravação em recusas.
Não invente problemas para preencher as cinco letras. Mostre evidências e limites.

Formato e descoberta no Claude Code: documentação oficial de skills. O roteiro de revisão é específico desta aula.

17:15 · 15 min · turma

Defenda uma decisão, não uma quantidade de classes [20]

Compare as duas pranchetas. Escolha um trecho do seu parecer e explique a cadeia: mudança → risco → princípio → correção → prova. O colega deve conseguir reconstruir seu argumento sem decorar a sigla.

“Mudei para uma interface, então ficou SOLID.” O que falta?

Próxima aula: quando uma solução recorrente merece um padrão com nome, e como testar adapters com infraestrutura reproduzível. Hoje bastava justificar a fronteira; não antecipamos um catálogo de padrões.
🏠
Zona 3 · até o próximo sábado · 2–3h

Concluir, revisar e trazer evidências

O seu serviço evolui; a revisão passa a ser um artefato que outra pessoa consegue conferir.

Tarefa · conclusão e transferência

O que trazer para o sábado 03 [21]

Use o caderno para registrar o que não concluiu e a última evidência verde. Exportar um backup evita depender apenas do armazenamento deste navegador. Leituras e materiais do Cap 03 serão incorporados quando estiverem disponíveis; o tema é padrões, Testcontainers e Flyway.