Monday, November 16, 2015

Tell, don't ask

about rules and principles

Some time ago I wrote about the Law of Demeter, about the advantages of following this law. Today I would like to write about the “Tell, don’t ask” principle. The principle that is, at least in my opinion, the starting point for the mentioned law. Following LoD is one of the consequences of applying the TDA principle.

Ok, but what should we tell and what shouldn’t we ask about anyway?

ask for the result, not for data

In short summary, the TDA principle tells us that instead of asking objects for data we should tell them what the should do and then wait for the result of the operation.

Which means that instead of::
Age age = sebastian.getAge();
if (age >= 18) {
    letDoTheThingsThatAdultsDoes(sebastian);
}

We should write something like this:
if (sebastian.isAdult()) {
    letDoTheThingsThatAdultsDoes(sebastian);
}


Is it better now? Is it easier to read? To understand the meaning of the code?

Unfortunately it is not always obvious which solution is better.

the more you tell, the bigger objects can become...

The example above very well presents what the TDA principle is suppose to protect. I’m talking about encapsulation.
We are not pulling out data from the object. We are not letting them be known to the outside world. We are not working on them directly. Instead, we are telling the object what have to be done and we are waiting for the result.
After all, shouldn't it be an object’s responsibility to operate with its own attributes?

Yet, you cannot be too eager. Encapsulation is important, but it is as well important for an object to have appropriate API. API which allows for comfortable work.
Can you imagine what would happen if we forbade creating a method which would extract data from the object? What would happen if we changed this principle into a law?

should you always “tell”?

Each additional operation is another line of code. It is another responsibility.
These responsibilities are organized around one particular context (specific object), but… isn’t it too much for a single object?

If you wrote your code strictly following the TDA principle, you may encounter two main problems.
Firstly, classes start to grow and grow and, as a result, they become really huge. If encapsulation at all cost becomes your paranoia, you may find yourself in a place where the number of lines of code of classes would be overwhelming and your code would become hard to understand.
Secondly, increased number of dependencies and responsibilities often goes hand-in-hand with big classes. Yes, code is organized around specific object’s attributes, but many of its methods don’t have any common part.

That’s why you need to care about your object’s size and keep objects as small as possible. It’s good to have objects that provide behavior and protect data. But you have to remember that too much behavior leads to too many responsibilities. And this has a direct impact on complexity of your classes and application.

when there is more than one...

And what in a situation where a particular operation requires data from a few different objects of different type?
Let’s even simplify the problem! Let’s talk about calculations that need data from different objects of the same class. Simple example can be calculation of average age in group of people, where each person is separate object.

How should we do it?

Should we ask for the age:
Age totalAge = Age.NEWLY_BIRTH;

for (Person person : persons) {
    totalAge = totalAge.add(person.getAge());
}

return totalAge.divide(persons.size());


Or maybe we should start to think how to solve this by telling objects what we want?

summary

As you can see “Tell, don’t ask” principle cannot be treated like the rule of thumb.
We always should keep in mind encapsulation and think at least twice before we would pull out data from the object to the outer world. However, I hope that this article showed you that sometimes it is necessary.

And for those of you who want to find out more about the “Tell, don’t ask” principle, here’s a bunch of useful links: