Shared kernel: quando compartilhar modelo entre contextos
1. Fundamentos do Shared Kernel no DDD
O Shared Kernel é um padrão de mapeamento de contextos (Context Mapping) do Domain-Driven Design que define um subconjunto compartilhado do modelo de domínio entre dois ou mais bounded contexts. Diferentemente de outros padrões de integração, o Shared Kernel pressupõe que o acoplamento é não apenas aceitável, mas desejável — desde que seja explícito, controlado e limitado a um núcleo semanticamente estável.
Eric Evans introduziu o conceito em seu livro "Domain-Driven Design" (2003) como uma alternativa ao Customer/Supplier (onde um contexto dita as regras) e ao Conformist (onde um contexto simplesmente se adapta). No Shared Kernel, ambas as equipes colaboram para definir e evoluir o modelo compartilhado, mantendo autonomia sobre suas extensões específicas.
A principal diferença para o Open Host Service (OHS) é que este expõe funcionalidades via interface publicada, enquanto o Shared Kernel compartilha o próprio modelo — entidades, value objects, interfaces de repositório e regras de negócio centrais.
2. Critérios para Decisão de Compartilhamento
Nem todo conceito merece entrar no Shared Kernel. A decisão deve basear-se em três critérios fundamentais:
Alta coesão semântica: os contextos devem usar o mesmo vocabulário e as mesmas regras para o conceito compartilhado. Se "Usuário" significa uma coisa no Contexto A e outra no Contexto B, o Shared Kernel não é adequado.
Baixa volatilidade: modelos que mudam frequentemente em um dos lados geram retrabalho no outro. Apenas conceitos maduros e estáveis devem ser compartilhados.
Custo de tradução vs. custo de acoplamento: implementar um Anti-corruption Layer (ACL) para traduzir entre contextos tem custo de desenvolvimento e manutenção. Se esse custo supera o custo do acoplamento direto, o Shared Kernel é a melhor escolha.
Cenários típicos incluem identidade de usuário (compartilhada entre autenticação e autorização), catálogo de produtos (entre vendas e logística) e moeda/câmbio (entre vendas e contabilidade).
3. Estrutura e Governança do Shared Kernel
O Shared Kernel deve conter apenas o subconjunto mínimo viável: entidades centrais, value objects imutáveis e interfaces de repositório. Implementações concretas e detalhes de infraestrutura ficam fora.
shared-kernel/
identity/
User.java
UserId.java
UserRepository.java
catalog/
ProductId.java
Money.java
Currency.java
A governança exige um contrato claro entre as equipes:
- Responsabilidades: quem propõe mudanças, quem revisa, quem aprova
- Versionamento: semântico (major.minor.patch) com changelog obrigatório
- Processo de mudança: pull request revisado por ambas as equipes, testes automáticos de compatibilidade
Testes de contrato (contract tests) garantem que o kernel permanece compatível com todos os consumidores. Ferramentas como Pact ou testes de integração dedicados são recomendadas.
4. Versionamento e Evolução do Modelo Compartilhado
O versionamento semântico é essencial para o Shared Kernel. Mudanças breaking (major version) exigem coordenação entre equipes e período de migração.
# shared-kernel v2.1.0
# breaking: User.rename() agora exige UserId explícito
# migration: User.rename(String name) → User.rename(UserId, String name)
Estratégias de compatibilidade retroativa incluem:
- Métodos deprecated: manter o método antigo por N versões com anotação @Deprecated
- Adaptadores de migração: classes que traduzem entre versões antiga e nova
- Event versioning: evoluir schemas de eventos sem quebrar consumidores, usando múltiplas versões simultâneas
O ideal é nunca remover um método sem antes garantir que nenhum consumidor o utiliza. Ferramentas de análise de dependências ajudam a rastrear o uso.
5. Integração com Outros Padrões de Context Mapping
O Shared Kernel não existe isoladamente. Ele frequentemente coexiste com outros padrões:
[Contexto A] ← shared kernel → [Contexto B]
↓ ↓
[Anti-corruption] [Open Host Service]
↓ ↓
[Sistema Legado] [Contexto C]
Neste exemplo, os Contextos A e B compartilham o kernel, enquanto A protege-se de um sistema legado via ACL, e B expõe funcionalidades para C via OHS.
O Event Storming é particularmente útil para identificar candidatos ao Shared Kernel: eventos, comandos e agregados que aparecem consistentemente em múltiplos contextos merecem análise de compartilhamento.
6. Riscos e Mitigações
Acoplamento excessivo: o maior risco é o kernel crescer descontroladamente, tornando-se um "big ball of mud". Mitigação: definir limites claros no início e revisar periodicamente o escopo.
Conflitos de agenda: equipes com prioridades diferentes podem bloquear evoluções necessárias. Mitigação: processo de revisão com prazo máximo e mediação técnica.
Degradação do modelo: inclusão de conceitos periféricos que não pertencem ao núcleo. Mitigação: critérios rigorosos de entrada e refatoração contínua.
Estratégia de saída: quando o Shared Kernel se torna inviável, a refatoração para Customer/Supplier (um contexto dita as regras) ou Separat Ways (cada contexto mantém seu próprio modelo com sincronização) são alternativas.
7. Casos Práticos e Padrões de Implementação
Exemplo 1: Autenticação e Autorização
Compartilhar User e Role entre contextos de Autenticação e Autorização faz sentido porque o conceito de "quem é o usuário" e "quais papéis ele possui" é semanticamente idêntico em ambos.
// shared-kernel/src/main/java/com/empresa/shared/identity/User.java
public class User {
private UserId id;
private String email;
private Set<Role> roles;
public boolean hasRole(Role role) {
return roles.contains(role);
}
}
Exemplo 2: Vendas e Contabilidade
Compartilhar Money e Currency evita erros de conversão e inconsistências contábeis.
// shared-kernel/src/main/java/com/empresa/shared/money/Money.java
public class Money {
private BigDecimal amount;
private Currency currency;
public Money add(Money other) {
if (!this.currency.equals(other.currency)) {
throw new CurrencyMismatchException();
}
return new Money(this.amount.add(other.amount), this.currency);
}
}
Checklist para decidir se um modelo deve entrar no Shared Kernel:
- O conceito é usado por dois ou mais contextos?
- O significado é idêntico em todos os contextos?
- O modelo é estável (mudanças raras)?
- O custo de tradução via ACL é maior que o custo do acoplamento?
- As equipes concordam com a governança?
Se todas as respostas forem "sim", o Shared Kernel é a escolha certa. Caso contrário, considere padrões alternativos como ACL, OHS ou Separat Ways.
Referências
- Domain-Driven Design: Tackling Complexity in the Heart of Software (Eric Evans) — Livro seminal que introduziu o conceito de Shared Kernel e Context Mapping
- Strategic Domain-Driven Design: Context Mapping (Martin Fowler) — Artigo técnico detalhando os padrões de mapeamento de contextos, incluindo Shared Kernel
- Shared Kernel Pattern in DDD (Vaughn Vernon) — Artigo prático sobre implementação e governança do Shared Kernel
- Implementing Domain-Driven Design (Vaughn Vernon) — Livro com exemplos detalhados de Shared Kernel e outros padrões de integração
- Context Mapping with Event Storming (Alberto Brandolini) — Técnica para identificar bounded contexts e candidatos a Shared Kernel através de workshops colaborativos
- Versioning in a Shared Kernel (DDD Community) — Discussão sobre estratégias de versionamento e evolução de modelos compartilhados
- Anti-corruption Layer vs Shared Kernel (Herberto Graca) — Análise comparativa dos trade-offs entre os dois padrões