views:

50

answers:

2

In this simple example (ofcourse my real world problem is a tad more complex, although the basics are the same), how do I enforce tell dont ask to the max? Id like to maximize tell dont ask in the process method, in its current state its harder to mock and test.

public class Processor
{
    public void Process()
    {
        var data = new Task1().DoStuff();
        new Task2().DoStuffToData(data);
    }
}

public class Task1
{
    public Data DoStuff(){return new Data();}
}

public class Data {}

public class Task2
{
    public void DoStuffToData(Data data){}
}

EDIT: Updated sample more DIish

public class Processor
    {
public Processor(ITask1 task1, ITask2 task) {...}
        public void Process()
        {
            var data = task1.DoStuff();
            task2.DoStuffToData(data);
        }
    }
A: 

One option is to use Depenancy Injection (DI). However, ensure that this does not over-complicate your code. DI can be useful for unit testing and mocking, but it can also lead to classes that are too small.

cofiem
DI itself will not lead to classes that are too small, the developer can easily do that without DI. Removing dependencies from your classes is *the good thing* for avoiding spaghetti code, or classes that are *to big*. And as a really nice *side effect*, your code will be much easier to unit test.
Peter Lillevold
All good points. Nice explanation. I just have a very recent vision in my head of bunches of interfaces, each with one method. And huge long lists of constructor parameters.
cofiem
Yes, in the real world code I use DI, but basic problem is the same. Task1 returns data that Task2 requires. Basically id like state to be shared some other way that Task1 returning data. The code is harder to test because I have to setup expectations just to return data from Task1 although that expectation isnt really required for the test in question. Maybe I oversimply the problem, but I need new ideas =)
MatteS
Updated sample. To make sure I understand your suggestion correctly, please provide sample code.
MatteS
+1  A: 

This code doesn't seem too bad from a tell-don't-ask perspective.

Tell-don't-ask basically means you shouldn't query an object about it state, make a decision based on it's state and then tell the same object what to to. If the object has all the information it needs, it should decide for itself.

You get data from task1 and consume this information with task2, without telling task1 what to do. So I'd say this OK from tell-don't-ask perspective.

With regard to Processor.Process: nothing wrong there either. A client would call myProcessor.Process and thereby tells it what to do, without asking.

Tell-don't-ask looks OK, maybe there is something else about the code you don't like? For instance, you could consider putting the DoStuffToData in the Data class, thereby combining state and behavior. But whether this is better depends on the model and its context.

Marijn
Yes, you'r right, it looks ok from that perspective, I think I may have asked the wrong question. I was reading point 9 of http://binstock.blogspot.com/2008/04/perfecting-oos-small-classes-and-short.html at the time, but looking from a pure tell dont ask perspective its OK. Your suggestion is one way of solving my problem, so I think ill try it out.
MatteS
Also, I read somewhere that when writing tests, mocks returning other mocks usually indicates a problem with the design. So if I write a test for the Process method mocking task1 and task2, in my example, write an expect for task1 to return data, even though my test should be testing that task2 is called. Imagine having 10 tasks like these in different combinations, and I have to setup alot of mocks for every test, although Im testing a single thing each time. On the other hand, if implementing your suggestion, im even more enforced to have a mock expectation return another mock...
MatteS
Generally speaking, combining _related_ data and behavior is good practice. But you're rightfully worried when you find yourself passing around mocks, without really testing anything.
Marijn