Most of the developers who are digging deeper into proper way to build software might have had problem in understanding the law of Demeter in first go. Here is our attempt to simplify this for the new generation of developers.
You can read the formal definitions here :\ Wikipedia: https://en.wikipedia.org/wiki/Law_of_Demeter
The law of Demeter fundamentally describes following things:
- Each unit should have only limited knowledge about other units: only units “closely” related to the current unit.
- Each unit should only talk to its friends; don’t talk to strangers.
- Only talk to your immediate friends.
In our context as programmers, an object should avoid calling on methods of a member object returned by another method. For many modern object oriented languages that use a dot as field identifier, the law can be stated simply as “use only one dot”. That is, the code a.b.Method() breaks the law where a.Method() does not.
Ruby on Rails Bad smell code:
class Project < ActiveRecord::Base belongs_to :user end project.user.name project.user.address project.user.cellphone
These lines break law of Demeter. To solve this we should use methods like as:
project.user_name project.user_address Project.user_cellphone
Now, this follows the law of Demeter. But if we use methods for each field then we need to add bunch of methods in the model.
class Project < ActiveRecord::Base belongs_to :user def user_name user.name end def user_address user.address end def user_cellphone user.cellphone end end class User < ActiveRecord::Base has_many :projects end
To remove above bad smell Rails provides a helper method delegate which utilizes the DSL way to generates the wrapper methods. This is the best practice.
The concept of delegation is to take some methods and send them off to another object to be processed.
:to - Specifies the target object
:prefix - Prefixes the new method with the target name or a custom prefix
:allow_nil - if set to true, prevents a NoMethodError to be raised
class Project < ActiveRecord::Base belongs_to :user delegate :name, :address, :cellphone, to: :user, prefix: true, allow_nil: true end class User < ActiveRecord::Base has_many :projects end project.user_name project.user_address
This is how the method can now be accessed with delegate enabled.
Now, we do not break the law of Demeter. Due to addition of allow_nil if the project does not have any user then we will just get nil when calling name and no exception!
Now we know what the law of Demeter is . But why use it ?. Most of the blog posts out there does not answer this specific question. What are the benefits or advantages of implementing law of Demeter in our ruby software’s?
In general , Law of Demeter is an example of loose coupling which states that one component should not heavily rely on other components for getting the job done. \ Not when we decrease this coupling. Things are much much easier to change.
But what about the famous method chaining we are used to ?
But If we followed it all the time we could never do method chaining
Method chains are what makes ruby well ruby ! As an example, here’s a method which takes a string and generates a “slug” for generating a friendly url:
def slug(string) string.strip.downcase.tr_s('^\[a-z0-9]', '-‘) end
That’s three levels of method call chaining. That does not follow the Law of Demeter. But the law never says anything about the number of methods called, or the number of objects a method uses. It is strictly concerned with the number of types a method deals with.
The #slug method expects a String, and calls three methods, each one returning… another String. In fact, because it only calls methods for the type of object (String) passed into it as parameters, we can conclude that it follows the Law of Demeter.
Ruby is a dynamic, high-level, general-purpose programming language known for its simplicity and productivity. Explore our awesome projects on Ruby .
Need a team of expert Ruby developers for your next big project? Hire the best team of developers from Gurzu. Book a free consultation call with us today to learn more!