Design de Código
Projete módulos profundos: muito comportamento por trás de uma interface pequena, colocada em uma costura onde chamadores e testes se encontram. Busque alavancagem para chamadores, localidade para mantenedores e testes que sobrevivam a refatorações.
Regras
- Profundidade é uma propriedade da interface, não da implementação. Um módulo profundo pode ser construído a partir de partes pequenas e intercambiáveis; elas simplesmente não fazem parte de sua interface. Ele pode ter costuras internas para seus próprios testes, além da costura externa em sua interface.
- Execute o teste da delegação. Imagine deletar o módulo. Se a complexidade desaparecer, era um módulo de passagem. Se a complexidade reaparecer espalhada pelos chamadores, ele merece existir.
- A interface é a superfície de teste. Chamadores e testes cruzam a mesma costura. Se você precisar testar além da interface, o módulo provavelmente tem o formato errado.
- Um adaptador significa uma costura hipotética; dois tornam-na real. Adicione uma costura apenas onde algo realmente varia, geralmente produção e teste.
- Reduza a interface. Menos métodos, parâmetros mais simples, mais complexidade escondida internamente.
- Aceite dependências em vez de criá-las. Passe o gateway de pagamento como parâmetro, em vez de construí-lo dentro da função.
- Retorne resultados em vez de produzir efeitos colaterais quando o design permitir.
Vocabulário
Use estes termos exatamente. Não substitua por "componente", "serviço", "API" ou "fronteira".
- Módulo: qualquer coisa com uma interface e uma implementação, em qualquer escala: uma função, classe, pacote ou fatia entre camadas.
- Interface: tudo que um chamador precisa saber para usar o módulo corretamente: tipos, invariantes, ordenação, modos de erro, configuração necessária e desempenho. Não apenas a assinatura.
- Implementação: o código dentro de um módulo. Um adaptador pequeno pode ter uma implementação grande (um repositório Postgres), e um adaptador grande pode ter uma implementação pequena (um fake em memória).
- Profundidade: alavancagem na interface, significando o comportamento que um chamador ou teste pode exercitar por unidade de interface que precisa aprender. Um módulo é profundo quando muito comportamento fica atrás de uma interface pequena, e raso quando a interface é quase tão complexa quanto a implementação.
- Costura (seam) (Michael Feathers): um lugar onde o comportamento pode mudar sem editar aquele lugar; onde a interface de um módulo reside. Escolher a costura é uma decisão em si.
- Adaptador: uma coisa concreta que preenche uma interface em uma costura. Ele nomeia um papel, não o conteúdo.
- Alavancagem: o que os chamadores ganham com a profundidade. Uma implementação paga dividendos em vários pontos de chamada e testes.
- Localidade: o que os mantenedores ganham com a profundidade. Mudança, bugs, conhecimento e verificação concentram-se em um só lugar.
Enquadramentos rejeitados: profundidade como a razão entre linhas de implementação e linhas de interface, porque recompensa o preenchimento; "interface" como apenas uma palavra-chave de tipo ou os métodos públicos, porque é muito restrito; "fronteira", porque conflita com o contexto delimitado do DDD.
Se o projeto mantiver um glossário em CONTEXT.md, use seus termos de domínio junto com estes.
Aprofundando
- Para aprofundar um aglomerado de módulos rasos por tipo de dependência, leia DEEPENING.md.
- Para comparar várias interfaces radicalmente diferentes, leia DESIGN-IT-TWICE.md. Ele inicia três ou mais subagentes, então use-o apenas quando o usuário solicitar.