Reputation: 6431
Please tell me if I'm applying the Tell, dont't ask principle in right way in this example.
I have two classes, CalculationResults
has a function calculateMe()
, which uses Data
to make some calculations. It is important that it stores the results.
class Data {
private:
int dataForCalculations;
public:
void calculate(CalculationResults& calculationResults) {
calculationResults.calculateMe(dataForCalculations);
}
};
class CalculationResults {
private:
int calculatedData;
public:
void calculateMe(int dataForCalculations) {
calculatedData = someCalculations(dataForCalculations);
}
};
// somewhere else:
Data data;
CalculationResults calculationResults;
data.calculate(calculationResults);
First version of this code (before applying Tell, don't ask) didn't use Data::calculate
function but it has a getter
for dataForCalculations
, so somewhere I called calculationResults.calculateMe(data.getDataForCalculations())
.
Is the new version better?
Upvotes: 1
Views: 357
Reputation: 6221
Is the new version better?
That depends on who you ask. But to be sure, the new version is 100% tell, don't ask. It's easy to tell, because your methods return void.
Personally, I have had my run with trying to purely follow the tell, don't ask principle, and have given up on it for a couple reasons.
For one, the tell, don't ask principle can lead to conceptually confusing object interactions. Take your code for example. I wouldn't expect a Data
object to be able to calculate itself. I would expect Data
to be the input of something else.
As another example. If I were writing a program that modeled making a call to someone, I might have a Phone
, and PhoneNumber
, and a Person
object. Now, according to tell, don't ask, you are supposed to ask the object with the data to accomplish a certain action. So, in this case PhoneNumber
might have a dial() method on it: phoneNumber.dial()
. But does that make sense, conceptually? Really, a Person
dials a PhoneNumber
into a Phone
.
So, that's my first problem. I find it harder to understand, and I find it more difficult to come up with natural interactions between object with tell, don't ask, which slows me down.
Secondly, often times it's not clear which object should be called first when two objects need to share data. Take a Book
and a Pen
for example. Do you say book.writeWith(pen)
or pen.writeOn(book)
? Maybe an argument can be made with that example, but often times you'll find the difference is arbitrary, and I hate that.
Thirdly, with tell, don't ask, an object will slowly build up more and more responsibilities. Do you tell the object to save itself? Do you tell it to display itself? What if you have more than one view technology? What if you need to display your object in different formats? Do you ask your object to email itself? Having an object with many responsibilities isn't necessarily bad. It's less flexible to change, but provides an easier to work with API. However, most people prefer flexibility, and having an object with few responsibilities is part of SOLID code.
Fourthly, what really is the difference between having your object pass it's private's around to other objects by using tell, don't ask (when you need to share data), and having a getter? Not much, if you ask me.
I know this is very oppinion based, but I prefer your first version better because it it simpler, and clearer. However, I would write it instead as:
calculationResults.calculate(data);
Anyways, just my 2 cents.
Upvotes: 5