Evolving your design with the Principle of Least Knowledge

One of the principles of object-oriented development is that you should strive for a design that favors low coupling among objects.  Given that change is constant in a software project, this principle provides many benefits when rightfully applied:

  • Code is easier to maintain because any change can be isolated to a very limited number of objects (hopefully only one)
  • Code is easier to use and reuse because your objects are not tightly related to a web of other objects
  • Code is easier to understand because we can focus on the behavior of a very limited number of objects (hopefully only one)
  • Code is easier to test because of the reasons stated above (it also reduces the use of mock objects in our tests which simplifies writing and maintaining them)

The last point is very important.  Code that is easier to test favors the writing of unit tests, which avoids potential bugs infesting the system, and embraces change as we have confidence in refactoring the codebase because our unit tests act as a safety net so that if we should brake something in the system, we’ll be notified in a short time…if the tests were well written of course, but that’s a subject for another post.

The Principle of Least Knowledge, also known as the Law of Demeter, is one of those principles which favor low coupling in your codebase.  The most excellent book “Head First Design Patterns” defines this principle as the following:

The Principle of Least Knowledge guides us to reduce the interactions between objects to just a few close “friends”.

But what does this mean in real terms?  It means when you are designing a system, for any object, be careful of the number of classes it interacts with and also how it comes to interact with those classes.

This principle prevents us from creating designs that have a large number of classes coupled together so that changes in one part of the system cascade to other parts.  When you build a lot of dependencies between many classes, you are building a fragile system that will be costly to maintain and complex for others to understand.  — “Head First Design Patterns”, pages 265-266.

In other words, this principle states that given an object, any of its method should only invoke methods that belong to:

  • The object itself
  • Objects passed in as a parameter to the method
  • Any object the method creates or instantiates
  • Any components of the object

Least but nonetheless important is another pointer which makes the whole difference (like spreading Nutella on whole wheat bread): methods should avoid invoking methods belonging to objects that were returned from some other call.

For example, you should avoid writing the following:.

public void DepositAmount(int accountId, double amount)
{
  Account account = bank.GetAccount( accountId );
  account.Deposit( amount );
}


And instead opt for this:

public void DepositAmount(int accountId, double amount)
{
  bank.Deposit( accountId, amount );
}

You should see that the latter implementation is easier to maintain, reuse, understand and test.  We haven’t changed the interface of the method, just its implementation.  This implementation is easier to reuse and test because we don’t have to rely on another external (whether concrete or abstract) object, in this case an Account, to fulfill the service.  We only have one object, the Bank, to deal with.

One of my mentors refers to this principle as the “Tell, don’t ask” principle.  It makes a lot of sense.  Alec Sharp, author of Smalltalk by Example, summarizes this principle in other words:

Procedural code gets information then makes decisions.  Object-oriented code tells objects to do things. — Alec Sharp

That was the theory behind the principle.  Let’s see a concrete and simple example which demonstrates what we should avoid and what we should strive for in our design.

This example doesn’t follow the Principle of Least Knowledge:

namespace ConsoleApplication1
{
  class Program
  {
    static void Main(string[] args)
    {
      var car = new Car();
      var driver = new Driver( car );

      driver.Car.Engine.Start(); // Not good.
                                 // Changing the signature of Start() will force to change
                                 // the callers too because of the strong coupling.
                                 // It also breaks the encapusalation of CarEngine because
                                 // the Driver knows too much about that class.
    }
  }

  class Driver
  {
    public Driver( Car car )
    {
      Car = car;
    }

    public Car Car { get; private set; }
  }

  class Car
  {
    private readonly CarEngine _engine;

    public Car()
    {
      _engine = new CarEngine();
    }

    public CarEngine Engine
    {
      get
      {
        return _engine;
      }
    }

    public class CarEngine
    {
      public void Start()
      {
        Console.WriteLine( "vroum! vroum!" );
      }
    }
  }
}


Whereas this same example does respect the Principle of Least Knowledge:

namespace ConsoleApplication1
{
  class Program
  {
    static void Main(string[] args)
    {
      var car = new Car();
      var driver = new Driver( car );

      driver.Car.Start(); /* Much better.  Why?
                             Now, we can also make CarEngine private to the Car class.
                             Even though CarEngine.Start is public doesn't mean we should
                             use it!  Here we decided to remove the Engine property in the Car
                             class.

                             With this approach, the Driver could care less HOW the Car gets
                             started.  Now, CarEngine can evolve on its own without impacting
                             the rest of the system.

                             In other words...just because there's a gun laying on the ground
                             outside Montreal East and it's past 2AM...doesn't mean you should
                             take it!  Not everything that's public is good to take.
                             */
    }
  }

  class Driver
  {
    public Driver( Car car )
    {
      Car = car;
    }

    public Car Car { get; private set; }
  }

  class Car
  {
    private readonly CarEngine _engine;

    public Car()
    {
      _engine = new CarEngine();
    }

    class CarEngine
    {
      public void Start()
      {
        Console.WriteLine( "vroum! vroum!" );
      }
    }

    public void Start()
    {
      _engine.Start();
    }
  }
}

As you can see from the preceding example, adopting the Principle of Least Knowledge in your design allows you to easily evolve other components in your system since they’re not tightly coupled with other components in other areas of the system.  In this instance, I can easily evolve CarEngine without impacting the rest of the system.  For example, I can change the way an engine is started.  Furthermore, I can even make the CarEngine class abstract, then have various implementations of it and still avoid rippling changes to my system.  The Principle of Least Knowledge gives me so much ease, flexibility and possibilities to evolve my design and test my system.

Using a tool like NDepend can help you to pinpoint locations in your code where coupling is strong so that you leverage this principle and step-by-step eliminate the unnecessary coupling among components.

In conclusion, I urge you to not get too personal with objects.  Don’t be too polite with them neither.  With people yes, but not with objects.  If you need an object to do something for you, tell it to do so.  Another variation of "tell" is "command".  Don’t tell the object to ask another object to do some job for you.  If you see that happening, you should remove the intermediate object and have the one that knows more about the underlying operation to execute the job for you.  In his book Applying UML and Patterns, Craig Larman refers to the Information Expert pattern for this kind of situation.  According to that pattern, you should "assign a responsibility to the information expert – the class that has the information necessary to fulfill the responsibility".

As you can see, there are many different interpretations for this principle.  Whether you know it as the Principle of Least Knowledge, the Law of Demeter or the Information Expert pattern, what’s important is that you understand and apply the essence behind it.  It’s all about doing object-oriented development right.

This post has been viewed: 1283 times. kick it on DotNetKicks.com

 

Similar posts you might be interested in reading:

One Comment

  1. software development company:

    Interesting,

    That is a truely clean code.

    Thanks for bringing this up

Leave a comment

Powered by WP Hashcash