Tell, Don’t Ask

Tell, Don’t Ask is an object oriented programming principle saying we should just tell objects what to do, without asking them unnecessary questions.

Asking is when we’re writing conditionals solely based on one object’s internals. Either we’re checking a property or a method returning a result, if we’re doing it to tell the object to do something else, we’re breaking the Tell, Don’t Ask principle.

Here are two examples:

// bad
if ($order->subtotal() > 10000) {
    $order->shipping_price = 0;
}

// better
$order->calculateShippingPrice();


// bad: we're asking the user object if it's enrolled to $course
// if not, then we're telling the user to enroll to the $course
if (!$user->isEnrolled($course)) {
    $user->enroll($course)
}

// better: the enroll method is responsible to check wether the user should be enrolled or not
$course->enroll($user);

When you can ignore TDA?

TDA violations are fixed by moving the decision inside the object. But doing so, the object gains new responsibilities. Pushing too many responsibilities inside one object is also bad as the object will end up “doing too much”.

The get out of jail free card for breaking Tell, Don’t Ask is when you find new objects to host that new responsibility.

Ben’s example of the SubscriptionCharger fits this bill. A user has a subscription, and you can charge that subscription. But instead of doing it in some controller, or moving it inside the user object, stuffing even more responsibility into it (following TDA), you move it to a dedicated class representing the concept of charging.

class SubscriptionCharger
{
    private $subscription;

    public function __construct(Subscription $subscription)
    {
        $this->subscription = $subscription;
    }

    public function __invoke() 
    {
        if ($this-subscription->isActive()) {
            $this->subscription->charge($this->subscription->amount);
        } else {
            $this->subscription->charge(0);
        }
    }
}

TDA is just a reminder that in object oriented programming data and the behaviour operating on that data should go together.

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.