John Smith
John Smith

Reputation: 6197

Tell-dont-ask princible uses more memory, how to make a compromise?

class Operation
{
    private $op;

    public function __construct()
    {
        $this->op = [];
        for ($i = 1; $i < 1000; $i++)
        {
            $this->op[] = rand(1,9999);
        }
    }

    public function getOps()
    {
        return $this->op;
    }
}

class TestTellDontAsk
{
    public function doItBAD(Operation $op)
    {
        foreach($op->getOps() as $item)
        {
            echo $item.'; ';
        }
    }

    public function doItGOOD(array $ops)
    {
        foreach($ops as $item)
        {
            echo $item.'; ';
        }
    }
}

$m = [
    memory_get_peak_usage(true),
    memory_get_peak_usage(false),
    memory_get_peak_usage(true),
    memory_get_peak_usage(false)
];
$op = new Operation();
switch(mt_rand(0,1))
{
    case 0: (new TestTellDontAsk())->doItBAD($op); break;
    case 1: (new TestTellDontAsk())->doItGOOD($op->getOps()); break;
}
echo '<hr>';
echo memory_get_peak_usage(true) - $m[0].'<br>';
echo memory_get_peak_usage(false) - $m[1].'<br>';
echo memory_get_peak_usage(true) - $m[2].'<br>';
echo memory_get_peak_usage(false) - $m[3].'<br>';

this demostrates the whole in BAD and GOOD usage.

The doItBAD() is bad, because passing an object is an unnecessary knowledge for the function but MEMORY-GOOD, since it just passes a reference, not the whole array itself

The doItGOOD() is good, because it only passes an array but MEMORY-BAD, since it just passes a all the data instead of a reference.

Now how to decide which one to use?

Upvotes: 0

Views: 44

Answers (1)

Philip Couling
Philip Couling

Reputation: 14903

This is a much wider question than simply "tell don't ask". Here you have two concepts. Its very common to trade off one against the other.

  • Good Software Design
  • Efficient Software design

Both concepts are subjective. What constitutes good code is argued about endlessly. "Efficient" software has multiple different meanings depending on context (eg: efficient on CPU, or efficient on memory).

Therefore any answer to this question WILL BE SUBJECTIVE AND OPEN TO DEBATE. Some will say this is not a good stack overflow question.

When to write "less good" code for the sake of efficiency?

This is experience.

If you don't have the experience then here's some tips of what to think about:

  • How critical is this code to performance? Is it going to be executed once a day or a billion times a day with a million concurrent threads?
  • How big is the performance hit? It's not worth worrying about loosing 1 second CPU time per day. Its not worth worrying about the odd KB of RAM. But if this code is the difference between 500MB or 1/2MB then maybe you should think a little more carefully.
  • How much are you breaking the principles by? If 9/10 functions in a class take the object and only one can take just the array, then you're unlikely to improve your code that much. You might actually be breaking the principle of least astonishment.
  • Development time. Lets say your time is being billed at $100 an hour? Is finding the perfect answer to this worth 2 hours of your time when an imperfect answer could be done in 5 minutes? Sometimes the answer to that is "YES!". Very often the answer is "no".

Rule of thumb

BAD: If you have no performance requirement then never worry about performance. I've spent too many years fixing those people's code. It's a false economy.

BETTER: If you have no specific reason to worry about performance then don't... But test performance as you go. That way your code might actually work when it goes into production.

More Clearly: Go for good design at the expense of performance. Only push for performance when you need to.

Upvotes: 1

Related Questions