Aula Soluções
Questões discursivas
(Da Fronteira Genérica à Regra de Ouro) Escolha um sistema que você conhece bem (um aplicativo, um jogo, um sistema acadêmico) e identifique, com exemplos concretos, o que nele seria núcleo estável e o que seria periferia volátil. Em seguida, explique — usando a Regra de Ouro — o que aconteceria de errado, na prática, se a dependência entre esses dois lados estivesse invertida.
(A Matriz como Ferramenta de Diagnóstico) Considere um sistema de streaming de vídeo que precisa: (a) escolher entre diferentes algoritmos de compressão conforme a banda disponível do usuário; (b) integrar-se a três provedores de CDN externos com APIs incompatíveis entre si; e (c) notificar um número variável de painéis de monitoramento sempre que a qualidade do stream cai abaixo de um limiar. Para cada um dos três problemas, identifique qual padrão da matriz se aplica e justifique com base no tipo específico de acoplamento que cada padrão ataca.
(Do TRUE ao Isolamento Arquitetural) Retome o acrônimo TRUE (Transparent, Reasonable, Usable, Exemplary) apresentado na Aula 1 e os três sintomas de design deficiente (rigidez, fragilidade, imobilidade). Escolha dois dos quatro padrões estudados nas Aulas 10–13 e explique, para cada um, exatamente qual sintoma ele elimina e por qual propriedade do TRUE essa eliminação se manifesta.
Questões de Verdadeiro/Falso
Cada bloco de 4 itens trata do mesmo tema. A questão só é considerada correta se todos os 4 itens forem julgados corretamente (deixar em branco tem penalidade de 20% da nota da questão).
- □ Um módulo que implementa uma regra de cálculo de comissão de vendas, alterada a cada campanha promocional trimestral pelo departamento de marketing, deveria ser tratado como periferia volátil, mesmo estando fisicamente dentro do mesmo pacote de código que as regras centrais de faturamento.
- □ Se um sistema não tiver nenhuma interface explícita entre suas camadas, isso automaticamente implica que ele não possui nenhum núcleo estável, mesmo que parte de seu código de fato mude com muito menos frequência que o restante.
- □ Um framework de testes automatizados que nunca precisa ser trocado ao longo de toda a vida de um projeto, mas que não expressa nenhuma regra de negócio do domínio, não deveria ser classificado como núcleo estável apenas por sua baixa frequência de mudança — a definição de núcleo usada nesta aula exige também conter contratos ou regras de negócio do domínio.
- □ Um sistema acadêmico de matrícula em que a lógica de “o que conta como pré-requisito satisfeito” muda a cada reforma curricular, enquanto o mecanismo de armazenamento em banco de dados permanece intacto desde o lançamento do sistema, deveria tratar essa lógica de pré-requisitos como periferia volátil apesar de ela expressar uma regra do domínio acadêmico — porque o que determina a classificação é a frequência real de mudança, não a categoria intuitiva “regra de negócio = núcleo”.
- □ Se uma classe do núcleo estável instanciar diretamente (via
new) uma classe concreta pertencente à periferia volátil, isso por si só já viola a Regra de Ouro, independentemente de existir ou não uma interface abstrata entre as duas.
- □ Em um sistema onde tanto o núcleo quanto a periferia dependem exclusivamente de interfaces definidas dentro do próprio núcleo, a Regra de Ouro estaria sendo respeitada mesmo que a periferia contenha a maior parte das linhas de código do sistema.
- □ Se duas classes voláteis da periferia dependerem diretamente uma da outra (sem passar por nenhuma abstração do núcleo), isso por si só já é uma violação da Regra de Ouro, do mesmo jeito que seria se o núcleo dependesse diretamente da periferia.
- □ Um sistema em que o núcleo depende de uma interface, e essa interface é implementada por uma única classe concreta que nunca muda ao longo de toda a vida do projeto, ainda se beneficia estruturalmente da Regra de Ouro, mesmo sem nunca ter havido uma segunda implementação até hoje.
- □ Um sistema que já usa Strategy para escolher entre três algoritmos de cálculo de frete, todos implementando a mesma interface
CalculadoraDeFrete definida internamente, não precisaria do Adapter mesmo que decidisse futuramente integrar um serviço de frete de terceiros cuja API pública tenha uma assinatura de método completamente diferente da interface CalculadoraDeFrete.
- □ Se um SDK de terceiros já for compatível, desde o primeiro dia, com a interface que o núcleo do sistema espera, ainda seria estruturalmente válido envolvê-lo num Adapter, embora esse Adapter faria apenas repasse puro, sem nenhuma tradução real de assinatura.
- □ Um sistema de recomendação que troca, em tempo de execução, entre diferentes algoritmos de ranqueamento de produtos — todos já implementando a mesma interface
RankeadorDeProdutos do próprio sistema — está resolvendo um problema de acoplamento condicional, não sintático, e por isso a ferramenta correta da matriz é o Strategy, não o Adapter.
- □ Como tanto Strategy quanto Adapter usam injeção de dependência via construtor, qualquer classe que receba uma dependência dessa forma está necessariamente aplicando um dos dois padrões, mesmo que a dependência recebida não varie nem precise de tradução de interface.
- □ Um sistema de assinatura de streaming que permite empilhar, de forma independente e cumulativa, complementos como “sem anúncios”, “qualidade 4K” e “download offline” sobre um plano-base, está diante de um cenário mais bem resolvido pela intenção principal do Decorator do que pela do Observer.
- □ Se um sistema de pedidos precisar apenas notificar exatamente um sistema de log fixo, que nunca mudará ao longo de toda a vida da aplicação, aplicar o Observer nesse caso não traria nenhuma vantagem estrutural sobre uma chamada direta e permanente a esse único sistema de log.
- □ Um cenário em que um pedido precisa acumular selos de fidelidade opcionais (Decorator) e, ao mesmo tempo, notificar um número variável de sistemas de estoque (Observer) exige escolher apenas um dos dois padrões, já que ambos operam sobre decisões tomadas em tempo de execução.
- □ Um sistema de edição de texto colaborativo em que múltiplos cursores de usuários diferentes precisam ser avisados sempre que o documento compartilhado é alterado, sem que o documento conheça quantos cursores existem, está aplicando a mesma estrutura de acoplamento temporal/identidade que o Observer resolve para o
Pedido.
- □ Um sistema de emissão de notas fiscais que precisa se adaptar a três formatos de arquivo XML distintos exigidos por diferentes prefeituras, cada formato com uma estrutura de tags incompatível entre si, mas mantendo uma única interface interna
GeradorDeNotaFiscal, está diante de um cenário cuja intenção principal bate com a do Adapter, não com a do Strategy.
- □ Um sistema de jogos que precisa trocar dinamicamente o comportamento de movimento de um personagem (andar, voar, nadar) conforme o terreno em que ele se encontra, todos os comportamentos já implementando a mesma interface
ComportamentoDeMovimento definida pelo próprio jogo, está diante de um cenário resolvido pela intenção do Adapter, já que o comportamento muda em tempo de execução.
- □ Um sistema de pagamento que precisa acumular, de forma opcional e cumulativa, taxas de conveniência, seguro de compra e parcelamento sobre o valor de uma transação, sem que o número de combinações possíveis gere uma nova subclasse para cada combinação, está diante de um cenário cuja intenção principal bate com a do Decorator.
- □ Um sistema de alerta de estoque que precisa avisar automaticamente um número variável de compradores cadastrados sempre que um produto esgotado volta a ficar disponível, sem que o estoque conheça a identidade concreta de cada comprador cadastrado, está diante de um cenário cuja intenção principal bate com a do Observer.
- □ Um sistema em que trocar o algoritmo de cálculo de frete exige apenas registrar uma nova implementação de
CalculadoraDeFrete, sem alterar nenhuma classe já existente, satisfaz a propriedade Reasonable do TRUE de forma mais direta do que a propriedade Transparent, já que o custo da mudança (uma classe nova) é proporcional ao benefício (uma nova opção de frete).
- □ Um sistema que aplica o Adapter para integrar um SDK de pagamento legado, mas cujo Adapter concreto não pode ser reaproveitado em nenhum outro contexto do sistema além daquele SDK específico, ainda estaria satisfazendo plenamente a propriedade Usable do TRUE, já que o Adapter isola a incompatibilidade sintática do núcleo.
- □ Se um sistema apresentar o sintoma de fragilidade descrito na Aula 1 (quebrar em pontos sem conexão lógica com o que foi alterado) mesmo depois de aplicar Strategy, Adapter, Decorator e Observer em todos os pontos de variação conhecidos, isso indica necessariamente que os quatro padrões foram implementados incorretamente, e não que pode haver uma quinta fonte de acoplamento ainda não identificada.
- □ A conclusão de que “os quatro padrões estudados neste curso são, em conjunto, uma resposta madura ao problema do custo de mudança” depende logicamente de cada um deles, isoladamente, já resolver sozinho todos os três sintomas (rigidez, fragilidade, imobilidade) apresentados na Aula 1.