Lei de Demétrio (Demeter)

129 views
Skip to first unread message

Abraão

unread,
Sep 8, 2010, 10:39:07 AM9/8/10
to .Net Architects
Li nos livros "CleanCode" e "CodeComplete" sobre a lei de Demétrio. Os
dois falam para tomar cuidado com a chamda de funções indiretas, tipo:

public class Venda
{
private Funcionario _Vendedor;
public Funcionario Vendedor
{
get { return _Vendedor; }
set { _Vendedor = value; }
}

public Funcionario GerenteResponsavel()
{
//code
return new Funcionario();
}
//...
}

public class Funcionario
{
private Filial _Filial;
public Filial FilialAtual
{
get { return _Filial; }
set { _Filial = value; }
}

public Filial FilialSuperior()
{
//code
return new Filial();//filial a qual o funcionario é
subordinado
}
//...
}

public class Filial
{
public string NomeCompleto { get; set; }
public string Sigla()
{
return string.Empty();// implements Sigla baseado no
nomeCompleto
}
//..
}

//segundo a Lei de Demétrio(Demeter):
string nomeFilial = venda.Vendedor.FilialAtual.NomeCompleto; //Bom
string siglaFilial =
venda.GerenteResponsavel().FilialSuperior().Sigla(); //Ruim
//Porque?

Sinceramente não entendi bem o que eles tentaram me dizer, nem vi qual
a diferença nas duas chamadas.
Será que alguem pode esclarecer esse assunto pra min?

Obrigado.


twitter.com\AbrahamAlves

Vinicius Quaiato

unread,
Sep 8, 2010, 2:50:00 PM9/8/10
to dotnetar...@googlegroups.com
Seguinte, um objeto deve fornecer acesso apenas aos seus membros.

Tell don't ask.

Ou seja, se um método A retorna um objeto B e você invocar uma operação neste objeto B, algo está errado.

O objeto A deveria fornecer um método para uma operação e internamente realizar esta operação em B, ao invés de expor ao mundo esta relação.



--
Você recebeu esta mensagem porque faz parte do grupo .Net Architects hospedado no Google Groups.
Para postar envie uma mensagem para dotnetar...@googlegroups.com
Para sair do grupo envie uma mensagem para dotnetarchitec...@googlegroups.com
Para mais opções visite o grupo em http://groups.google.com/group/dotnetarchitects?hl=pt-br

Abraão

unread,
Sep 8, 2010, 3:45:36 PM9/8/10
to .Net Architects
Então quer dizer que isso não seria errado :?

venda.NomeFilial();
funcionario.NomeFilial();
filial.NomeCompleto();

Ter vários métodos que retornem a mesma coisa em partes diferentes do
meu projeto!

Outra coisa: Porque Demeter diz que isso é errado para Métodos, mas
para Propriedades não ?



On Sep 8, 3:50 pm, Vinicius Quaiato <vinicius.quai...@gmail.com>
wrote:
> Seguinte, um objeto deve fornecer acesso apenas aos seus membros.
>
> *Tell don't ask.*
>
> Ou seja, se um método A retorna um objeto B e você invocar uma operação
> neste objeto B, algo está errado.
>
> O objeto A deveria fornecer um método para uma operação e internamente
> realizar esta operação em B, ao invés de expor ao mundo esta relação.
>
> http://en.wikipedia.org/wiki/Law_of_Demeter
>
> Tem este post em português do Fábio Margarito:http://www.mgrtconsultoria.com/blog/post/Law-of-Demeter.aspx
>
> *Vinicius Quaiato*http://viniciusquaiato.com
>
> <vquaiato> Twitter <vquaiato>
> [image: Google Talk/] vinicius.quai...@gmail.com [image: MSN/]
> vinicius.quai...@gmail.com
>
> 2010/9/8 Abraão <abraao.teodo...@gmail.com>
> > dotnetarchitec...@googlegroups.com<dotnetarchitects%2Bunsu...@googlegroups.com>

Rodrigo Vieira

unread,
Sep 8, 2010, 4:15:58 PM9/8/10
to dotnetar...@googlegroups.com
Abraão, acho que os dois exemplos abaixo são ruins, ambos vão contra a
"lei" de Demeter (deveria ser chamado de "principio" ou coisa do
gênero, não "lei", mas isso é outra história).

O design da sua classe permite que alguém faça algo do tipo

venda.Vendedor = meuAmigoQueNaoVendeuNada ou
venda.Vendedor.FilialAtual = null,

o que são coisas que vc com certeza não pode deixar acontecer...a
classe está pronta pra ser abusada!

Se vc precisa expor o nome completo da filial onde ocorreu uma venda,
deveria ter um método venda.NomeFilial() ou algo assim com nome mais
bonitinho.

Em geral quando a gente se vê escrevendo algo do tipo A.B.C.D, ou
seja, muito ".", é pra ficar de olho (a não ser em caso de interfaces
fluentes, que são outros 500)

- Rodrigo

Humberto Marchezi

unread,
Sep 8, 2010, 8:40:55 PM9/8/10
to dotnetar...@googlegroups.com
Além do que foi mencionado pelos colegas, quanto maior a extensão da chamada: a.b.c.d.e; maior a probabilidade de um desses métodos exibir um erro do tipo objeto nulo.

2010/9/8 Rodrigo Vieira <rodr...@gmail.com>
--
Você recebeu esta mensagem porque faz parte do grupo .Net Architects hospedado no Google Groups.
Para postar envie uma mensagem para dotnetar...@googlegroups.com
Para sair do grupo envie uma mensagem para dotnetarchitec...@googlegroups.com
Para mais opções visite o grupo em http://groups.google.com/group/dotnetarchitects?hl=pt-br



--
Humberto C Marchezi
---------------------------------------------------------

Rodrigo Vieira

unread,
Sep 8, 2010, 9:47:10 PM9/8/10
to dotnetar...@googlegroups.com
P.S. off-topic: Demeter em português deveria ser traduzido como
Deméter mesmo, que é a deusa grega da agricultura. Agora, pq que deram
esse nome, eu não sei :P Por mim eu chamaria de "princípio do ponto
único" rs

2010/9/8 Humberto Marchezi <hcmar...@gmail.com>:

Thiago Alves

unread,
Sep 8, 2010, 10:10:55 PM9/8/10
to dotnetar...@googlegroups.com
David bock em seu paper "
The Paperboy, The Wallet, an
d The Law Of Demeter"
:

(.... ) While working on this paper, I was trying to determine why it is called the Law of Demeter. I found several references, but none with a good explanation The Law Of Demeter was first published in [ Lieberherr +], and Demeter is the name of a research project at Northeastern University [Demeter] (...)


Aliás recomendo fortemente a leitura do paper. Um "must read"

Mas pra quem estiver com preguiça:


2010/9/8 Rodrigo Vieira <rodr...@gmail.com>

Marcio Hiroyuki Miyamoto

unread,
Sep 9, 2010, 12:01:26 AM9/9/10
to dotnetar...@googlegroups.com
Sobre a origem do nome, parece que foi inspirada no nome de um outro projeto, não consegui acesso ao paper para saber mais.



2010/9/8 Rodrigo Vieira <rodr...@gmail.com>

P.S. off-topic: Demeter em português deveria ser traduzido como
Deméter mesmo, que é a deusa grega da agricultura. Agora, pq que deram
esse nome, eu não sei :P Por mim eu chamaria de "princípio do ponto
único" rs

--
Marcio Hiroyuki Miyamoto
marcioh...@gmail.com

Hamon Vitorino

unread,
Sep 9, 2010, 8:07:15 AM9/9/10
to dotnetar...@googlegroups.com
A lei de Demeter é sobre encapsulamento, assim como o princípio Tell don't ask.
Aqui encontrei uma (ou duas) boa definição:

"Only talk to your immediate friends"
"Each unit should only talk to its friends; Don't talk to strangers"

E gostei muito desse post, que faz boas analogias e talvez seja mais simples de entender.

Não sei se pensei bobagem, mas prefiro perguntar e alguem me dizer se é bobagem. :)

Cenário

Imaginem que o código abaixo faz parte de uma aplicação desenvolvida usando DDD e que não é possivel criar objetos com estado inválido. Toda a criação é orquestrada por factories que garantem a integridade do objeto criado.

string nomeFilial  = venda.Vendedor.FilialAtual.NomeCompleto;

Venda é uma raiz e Vendedor e Filial são seus agregados.
As propriedades de Venda só tem o GET como public. Todos os SETS são privados.

Considerações

Não vejo quebra de encapsulamento. Vejo esse código como um Ask. São ou não queries?
Veria problema se os sets não fossem privados e o estado da venda ou de um de seus agregados fosse alterado por um objeto externo. Algo do tipo:

if(venda.FoiEfetuada)
    venda.Vendedor.VendasEfetuadas += 1;

Dúvidas

1. O codigo acima é ruim? // esse => string nomeFilial  = venda.Vendedor.FilialAtual.NomeCompleto;
2. Se sim, por quê?
3. O encapsulamento de alguma classe está sendo violado?
4. Se sim, como?

[]'s

Hamon Vitorino

--
Você recebeu esta mensagem porque faz parte do grupo .Net Architects hospedado no Google Groups.
Para postar envie uma mensagem para dotnetar...@googlegroups.com
Para sair do grupo envie uma mensagem para dotnetarchitec...@googlegroups.com
Para mais opções visite o grupo em http://groups.google.com/group/dotnetarchitects?hl=pt-br



--
Hamon Vitorino
http://hamonvitorino.wordpress.com
http://zonadotnet.wordpress.com

Antonio Nascimento

unread,
Sep 9, 2010, 8:44:59 AM9/9/10
to dotnetar...@googlegroups.com
É mais elegante e mais "testável" se houvesse um venda.NomeFilialVendedor.
 
A lei de Demeter não diz isso, mas o alto acoplamento entre as classes (no seu exemplo você depende de três classes: Venda, Vendedor e Filial) joga a facilidade de se criar testes unitários no lixo.
 
Att,
 
Antônio Nascimento

Rodrigo Vieira

unread,
Sep 9, 2010, 8:59:36 AM9/9/10
to dotnetar...@googlegroups.com
Hamon,

Um motivo porque eu não gosto de
venda.Vendedor.FilialAtual.NomeCompleto é que é muito chato ter que
ficar "navegando" nesse tipo de grafo; com certeza vc já se viu numa
situação similar a alguém que tem um objeto "venda" na mão, precisa
mostrar o nome da filial onde ocorreu a venda, e passa 5 minutos
mexendo com intelissense a partir de "venda." até descobrir onde tá a
danada da informação!

Se vc realmente precisa acessar a informação sobre nome da filial a
partir da venda, melhor trazer essa informação pra perto da venda. O
cara digita "venda." e pronto, tá lá o que ele precisa. E aí entra a
reflexão sobre a necessidade ou não de trazer essa informação..pode
ser que dentro do contexto q vc se encontra é melhor acessar a filial
de outra forma.

Sem falar que venda.Vendedor.FilialAtual.NomeCompleto é um convite pra
um null ref exception mais cedo ou mais tarde.

2010/9/9 Hamon Vitorino <cham...@gmail.com>:

Hamon Vitorino

unread,
Sep 9, 2010, 9:17:15 AM9/9/10
to dotnetar...@googlegroups.com
Antonio,

O que voce deseja testar com venda.NomeFilialVendedor?

Rodrigo,

Imagine-se na situação em que a Venda possui vários outros agregados. Então sempre que precisar de uma informação relacionada ao agregado devo consultar sua raíz? Fico pensando no "tamanho" da interface desse root.

Colocando em termos de preferências, prefiro um intelisense do tipo

venda...
     Vendedor
          Nome()
          Filial...
               Nome()
     Produto
          Preco()

a um do tipo

venda...
     NomeVendedor()
     FilialVendedor()
     DescricaoProduto()
     PrecoProduto()

Hamon Vitorino

unread,
Sep 9, 2010, 9:27:02 AM9/9/10
to dotnetar...@googlegroups.com
Abraão,

O Rodrigo mencionou Fluent Interfaces e seguem dois links para tentar esclarecer um pouco:

Definição
Exemplo

[]'s

Antonio Nascimento

unread,
Sep 9, 2010, 9:57:17 AM9/9/10
to dotnetar...@googlegroups.com
Qualquer coisa, o que eu quis dizer é que o alto acoplamento entre as classes causa uma grande dificuldade em se criar testes unitários, além de dificultar a manutenção.
 
Att,
 
Antônio Nascimento
 

Sent: Thursday, September 09, 2010 10:17 AM
Subject: Re: [dotnetarchitects] Lei de Demétrio (Demeter)

Luiz Augusto Moreira Costa

unread,
Sep 9, 2010, 9:59:51 AM9/9/10
to dotnetar...@googlegroups.com
Oi,

Um dos problemas de violar a lei (eu prefiro princípio) é que vc conhece coisas demais sobre o grafo de objetos. Na minha opinião viola o encapsulamento sim. O fato de vc ter conhecimento demais sobre todos os objetos envolvidos na relação, pode tornar seu código frágil. Frágil no sentido de mudanças, se alguém resolver mudar ou renomear o nome de uma property, ou até mesmo mudar a abstração que está relacionada, pode quebrar seu código.


1) Eu acho que o código é frágil.
2) O fato de que mudanças nos objetos que estão relacionados com venda, podem impactar clientes da classe Venda.
3) Na minha opinião sim, vc tem conhecimentos demais sobre as relações da classe Venda
4) Venda.filialAtual.NomeCompleto. A property NomeCompleto, não faz parte do objeto venda, então quem usar a classe venda e acessar diretamente esta property, pode sofrer com as conseqüências de uma eventual mudança neste caso.

Agora, como eu disse no início, eu vejo a demeter como um princípio que deve ser considerado, em alguns casos por praticidade (talvez) ele possa ser ignorado, é uma questão de trade off. 


Até
Luiz Costa


2010/9/9 Hamon Vitorino <cham...@gmail.com>

Rodrigo Vieira

unread,
Sep 9, 2010, 10:16:30 AM9/9/10
to dotnetar...@googlegroups.com
Exato.

O Martin Fowler uma vez falou o seguinte: "I'd prefer it to be called
the Occasionally Useful Suggestion of Demeter." :)

Por exemplo dentro do DDD, acho q não tem tanto problema vc navegar
dentro do seu aggregate root, a coisa só fica feia se através de um
método vc se vê pulando de um aggregate pra outro.

Vinicius Quaiato

unread,
Sep 10, 2010, 9:17:26 AM9/10/10
to dotnetar...@googlegroups.com
A questão é sobre encapsulamento(e dependências...)

Se seu código está cheio disso:

objetoA.ObjetoB.MetódoObjetoB().PropriedadeDoObjetoC

Acontece que você não pode mudar a estrutura interna do objetoA sem "ferrar" com todo seu código.
Você está expondo ao mundo qual a estrutura interna do objetoA.

A idéia é que, se você precisa obter algo que venha de uma dependência interna de A ou executar algo em uma dependência interna de A, você deve dizer para A realizar isso. Como ele vai fazer isso já é um problema dele.

Então temos:

objetoA.RealizaAlgumaOperacaoEmUmaDependencia()
ou
objetoA.ObtemUmaPropriedadeDeUmaDependencia

Desta forma você NÃO revela a estrutura e funcionamento de A. Qualquer alteração em A está encapsulada em A, e o mundo que conhece A não precisa conhecer os "amigos e vizinhos" de A.

Abraços.
2010/9/9 Rodrigo Vieira <rodr...@gmail.com>

Bruno Batista

unread,
Sep 10, 2010, 11:07:28 AM9/10/10
to dotnetar...@googlegroups.com
Vinícius,
veja se entendi direito a sua explicação:

class ClasseA
{
     public ClasseB ObjetoB{get;set;}
}

class ClasseB
{
    public void ExecutaTask(){ }
}


Pelo que entendi, eu deveria ter um metodo na classeA chamado ExecutaTaskB, e não chamar o ExecutaTask diretamente, é isso?

objetoA.ExecutaTaskB(); //Certo
objetoA.ObjetoB.ExecutaTask(); //Errado

Esse é o princípio ou falei besteira aqui?

[]'s
Bruno Batista
(21)8374-0016


2010/9/10 Vinicius Quaiato <vinicius...@gmail.com>

Vinicius Quaiato

unread,
Sep 10, 2010, 12:28:07 PM9/10/10
to dotnetar...@googlegroups.com
É mais ou menos isso.

Claro, o nome não precisa ser "ExecutaTaskEmB". deve ser um nome que tenha relação com o contexto de A. Mas a idéia é essa mesma. 
2010/9/10 Bruno Batista <bru...@gmail.com>

Bruno Batista

unread,
Sep 10, 2010, 1:53:20 PM9/10/10
to dotnetar...@googlegroups.com
Beleza, so coloquei esse nome pra ficar explicito... hehehe

Hamon Vitorino

unread,
Sep 14, 2010, 5:32:34 AM9/14/10
to dotnetar...@googlegroups.com
Luiz,

Como vc recuperaria a descrição de um dos produtos registrados na venda, considerando o mesmo cenário e assumindo que a venda possui vários produtos agregados?

Luiz Augusto Moreira Costa

unread,
Sep 14, 2010, 11:14:47 PM9/14/10
to dotnetar...@googlegroups.com
Oi Hamon,

Eu sou bastante pragmatico em algumas situações. Uma solução para este caso seria obter os itens da venda e obter sua descrição.
Items items = venda.obterItems(); // poderia ser uma solução


Ou até obter os produtos da venda:
Produtos produtos = vendas.obterProdutos();

Se vc tiver um cenário onde o acoplamento com a classe produto não for desejável (não consigo pensar neste caso), vc pode até criar um método na classe venda para retornar a descrição de um produto.

venda.obterDescricaoDoProduto(codigoDoProduto);


Até
Luiz Costa




2010/9/14 Hamon Vitorino <cham...@gmail.com>

Hamon Vitorino

unread,
Sep 16, 2010, 7:12:32 AM9/16/10
to dotnetar...@googlegroups.com
Então, Luiz.
Era aí que eu queria chegar.

Esse código 

Items items = venda.obterItems()

também expõe o grafo da venda. E se o item tiver algum agregado, ele será exposto da mesma forma

Items items = venda.obterItems()
Agregados agregados = items[0].obterAgregados()

Então, IMO, isso é ruim quando o encapsulamento de comandos é violado, o que não é o caso do código anterior - consulta. Olha o cenário:

Don't Confuse Your Dog

Quoted from the Portland Pattern Repository a.k.a. The WikiWikiWeb

"If you want your dog to run, do you talk [to] your dog or to each leg? Further, should you be able to manipulate the dog's leg without it knowing about it? What if your dog wants to move its leg and it doesn't know how you left it? You can really confuse your dog."

The moral: Change the state of a contained object only through the containing object's interface.

"Aha!" you say. "If I employ the technique of encapsulation, then a method won't even know of the existence of any contained objects."

That's precisely the point. To walk your dog, you don't need to know of the existence of its legs. (And in fact, dogs with fewer than four legs can go for walks. There is even a case of a dog whose hindquarters rested on a little carriage; its "walk" method employed two legs and two wheels (these latter, one hopes, encapsulated within a "carriage" interface).)


Destaco a moral:

The moral: Change the state of a contained object only through the containing object's interface.

A chave dessa frase é Change the state. 

Antonio Nascimento

unread,
Sep 16, 2010, 8:22:10 AM9/16/10
to dotnetar...@googlegroups.com
Show de bola!!!!
 
 
Para complementar: 
    Tell, Don't Ask - "Procedural code gets information then makes decisions. Object-oriented code tells objects to do things." http://pragprog.com/articles/tell-dont-ask
 
Att,
 
Antônio Nascimento

Sent: Thursday, September 16, 2010 8:12 AM
Subject: Re: [dotnetarchitects] Lei de Demétrio (Demeter)

Luiz Augusto Moreira Costa

unread,
Sep 16, 2010, 9:49:21 AM9/16/10
to dotnetar...@googlegroups.com
Oi Hamon,

Concordo com o texto e com a sua argumentação, mas não tenho certeza se este acoplamento com a classe produto não é desejado no caso em que vc quer exibir a descrição do produto.
Eu até citei um caso parecido no email anterior, que é vc obter a descrição de um produto pela venda. Só que na minha opinião, eu não consigo pensar em um caso onde este acoplamento é tão indesejado assim, segue a parte do email:

Se vc tiver um cenário onde o acoplamento com a classe produto não for desejável (não consigo pensar neste caso), vc pode até criar um método na classe venda para retornar a descrição de um produto.

venda.obterDescricaoDoProduto(codigoDoProduto);

Acho que a maior dificuldade, é definir: "Vendas (ou item de Venda) tem que cuidar realmente de tudo que um produto faz?" 
Eu acho que o perigo desta resposta é violar a coesão da classe venda ou da classe item em pró de se evitar um acoplamento que muitas vezes pode ser desejado sim.

Ah, legal o texto ;

Valeu
Luiz Costa


2010/9/16 Hamon Vitorino <cham...@gmail.com>
Reply all
Reply to author
Forward
0 new messages