Wednesday 10 June 2015

Don't Talk To Strangers


In ancient Greek mythology Demeter was the goddess of the harvest who presided over grains and the fertility of the earth.
In 1987 at Northeastern University in Boston as part of the Demeter project the Law of Demeter was formed, this law states that classes should,
  • Have only limited knowledge about other classes: only classes "closely" related to the current unit.
  • Only talk to friends; don't talk to strangers.
  • Only talk to immediate friends.
The purpose of the law is to promote loose coupling and information hiding by re-enforcing the idea that a class should have as little knowledge as possible about the workings of the larger system it is a part of, for this reason the law also goes by the name of the principle of least knowledge.
A Bit Of A Train Wreck
Code that breaks this law is most often identifiable by looking for long chains of function calls, each one taking another step down the rabbit hole of dependencies.
Consider two classes A and B and the following snippet,
var someData = A.GetB().SomeMethod();
When we spot code like this we should be asking ourselves questions like,
  • Why does A expose its dependency on B to perform this operation?
  • Why do we know about the existence of B?
  • Why do we know that SomeMethod() needs to be called on B?
By reaching through A to get to B we have exposed ourselves to future changes in both classes.
If code like this is found in multiple areas what happens if A no longer uses B to fulfil this dependency or the signature of SomeMethod() changes? The answer of course is that we've set ourselves up for a lot of re-factoring.
These long chains of function calls are sometimes referred to as train-wrecks, keep an eye out for them and be sure to ask yourself what has happened to the encapsulation here?
Why Have I Got To Do That?
A good approach to identifying and fixing these issues is to be lazy, to see a function call as taking some physical or mental effort.
In the previous example we should see A as slacking off, why do we have to do A's job for it, isn't that what you were coded for? I don't want to have to know about B and I certainly don't want to call SomeMethod().
In general the interface a class presents should be capable of fulfilling the functionality it is stated to offer without you as the caller taking further action on another class returned from the API. By class A returning class B we now have a dependency on B that isn't easily inverted, its won't be stated in our classes constructor but the dependency is there none the less.
This is essentially the essence of encapsulation, its the reason we write classes in the first place to gradually one step at a time move ourselves away from the detail.
Being Anti-Social
Its important when we write code that we give some thought to how it will be maintained, what will be the impact of this area of the code changing? Because its a pretty sure thing that at some point in the lifetime of the code change will be necessary.
The most effective way to ease this potential maintenance headache is to effectively manage who knows what, everything should be on a need to know basis.
The reasons a class has to change is directly related to its knowledge of the system its in, the greater the knowledge the more detail the class is exposed to and detail can change.
Encapsulation is the cloak we use to hide this information.
Write your classes to be shy, to not want to expose their internal structure and implementation to others.
Write your classes to be slightly anti-social, to not want a wide circle of friends, to be fearful of strangers.
Your classes should only be friends with classes that share a common interest, "we're friends because we all work with the database, we don't want to be friends with anyone that works with the UI".
Don't Go Breaking My Heart
This is not to say that classes should be tightly coupled, classes that are friends should enjoy a loose relationship, this is about the fact that these circle of friends should be clearly identifiable and obvious to anyone with only a passing knowledge of the system.
This isn't Facebook, every time your class gains a friend it could at some point be let down by that friend and need re-factoring to fix the relationship, more friends in this context is not better.
So whenever your introduce two classes to each other ask yourself the question "does it make sense that these two are friends?"  

No comments:

Post a Comment