Ao fazer uma revisão de código, é provável que você receba este comentário pelo menos uma vez.
“Esta linha tem pontos (.) demais, não?”
Escrever tudo em sequência numa única linha parece até mais limpo, mas qual é o problema?
O ponto central desta história é a Lei de Demeter.
Hoje vamos entender o que é a Lei de Demeter e, com exemplos, por que alguns encadeamentos de métodos são aceitáveis e outros se tornam código ruim.
Vamos começar pela conclusão.
A Lei de Demeter é a regra de “não converse com objetos desconhecidos”.
O encadeamento de métodos não é ruim por si só; ele se torna código ruim quando atravessa os detalhes internos de outros objetos.
Se você lembrar apenas desta frase, já terá absorvido metade do artigo.
O que é a Lei de Demeter
A Lei de Demeter (Law of Demeter) também é chamada de “princípio do menor conhecimento”.
Em termos simples:
Um objeto deve conversar apenas com seus “amigos próximos”, ou seja, com objetos que conhece diretamente.
Os problemas começam quando você passa a usar também os amigos dos amigos e os amigos deles.
Em geral, os alvos que podem ser chamados dentro de um método são estes:
- Métodos do próprio objeto (self)
- Objetos recebidos como parâmetros do método
- Objetos criados diretamente dentro do método
- Objetos das propriedades (membros) que ele mantém
A ideia é conversar apenas dentro desse escopo.
Daí surgiu a conhecida regra prática de “um ponto por linha”.
É claro que a quantidade de pontos é apenas uma pista, não uma regra absoluta.
Por que o encadeamento de métodos pode ser código ruim?
Vou mostrar usando um código que encontrei na prática.
O cenário era obter o nome da cidade do cliente a partir de um pedido.
// Aprofunda-se em sequência do pedido até o cliente, o endereço e a cidade
let city = order.customer
.address
.city
.name
À primeira vista, parece limpo, não é?
Mas essa linha significa que Order conhece todo o interior de Customer, além de Address e City dentro dele.
É aí que o problema aparece.
Se a estrutura de Address mudar ou City desaparecer, este código também quebra.
Como estamos enfiando a mão até as gavetas da casa alheia, nosso código quebra quando a estrutura dessa casa muda.
Esse encadeamento que percorre o grafo de objetos costuma ser chamado de “acidente de trem (train wreck)”.
Porque ele se parece com vagões conectados um após o outro.
Então, como diferenciar um encadeamento bom de um ruim?
Esta é a parte mais importante do artigo.
Nem todo encadeamento de métodos é ruim.
O critério é um só.
“Enquanto encadeia, você continua extraindo objetos internos de outros objetos?”
Como no exemplo anterior, aprofundar-se continuamente em objetos alheios diferentes — customer → address → city — é uma violação.
Por outro lado, o encadeamento é aceitável quando trabalha com objetos do mesmo tipo e devolve continuamente a si próprio, como abaixo.
// filter·map O encadeamento não viola a regra porque sempre devolve o “mesmo contexto”
let names = users
.filter { $0.isActive }
.map(\.name)
Esse encadeamento de funções de alta ordem e o padrão Builder não vasculham o interior de outros objetos, por mais pontos que tenham.
Eles apenas devolvem a si próprios, o mesmo fluxo, para continuar.
Comparando os dois códigos numa tabela, temos o seguinte.
| Categoria | Encadeamento ruim | Encadeamento bom |
|---|---|---|
| Alvo | Extrai continuamente objetos internos alheios | Retorna o mesmo fluxo/tipo |
| Exemplo | order.customer.address | filter { }.map { } |
| Acoplamento | Alto (vulnerável a mudanças estruturais) | Baixo |
| Avaliação | Violação de Demeter | Não é uma violação |
Como corrigir o código que viola a regra
A solução é mais simples do que parece.
Basta lembrar de “Diga, não pergunte (Tell, Don’t Ask)”.
Em vez de extrair o interior, peça ao objeto que faça o trabalho.
No exemplo anterior da cidade, podemos fazer assim.
// OrderPergunta-se apenas pelo resultado necessário
let city = order.shippingCity
Dentro de Order, fazemos com que Customer e Address sejam percorridos automaticamente e que a cidade seja retornada.
Assim, mesmo que a estrutura de Address mude, o código externo permanece intacto.
O escopo da alteração fica totalmente limitado ao interior de Order.
Ao refatorar dessa forma, percebi que depois caiu bastante o número de lugares que precisavam ser alterados quando a estrutura mudava.
Para resumir:
A Lei de Demeter não é uma regra para contar pontos, mas um lembrete para não mexer de qualquer jeito no interior de outros objetos.
Quando encontrar um encadeamento longo, faça apenas uma pergunta.
“Estou abrindo as gavetas de outra pessoa?”
Só de fazer essa pergunta, o código fica muito mais limpo.

