nus-cs2030 / 2122-s2

CS2030 repository and wiki for AY 2021/2022 Sem 2
MIT License
0 stars 0 forks source link

Discussion on Tell-Don't-Ask principle #158

Open tygq13 opened 2 years ago

tygq13 commented 2 years ago

Hi, this is a general discussion on tell-don't-ask principle.

Taking a step back, I would sometimes be confused about whether tell-don't-ask principle is good (I would sometimes be confused about other principles too).

One example is that I have a "Book" class that contains the data of its authors, content, etc. If I have a librarian and want to categorise a list of books, and I cannot take out the data of the book (like the "content"), then I have to add the method in "Book" class to let it categorise itself. I wonder if this is a good way (should "Book" class have the behaviour of classifying itself to comic, self-help, etc.?). What if I want to classify the books based on the origin of the book authors now, does it make sense to let "Book" class knows its authors belong to a certain country?

While the example could possibly be solved by some design patterns, I think the more general question is that in tell-don't-ask principle when we are handling an object, we have to add the method in the target object although such method is not a general behaviour of the target object but just for this specific handling, is asking for data really not as good as telling it to do what it shouldn't do?

NUST007 commented 2 years ago

I'm not sure whether my opinion may fit totally with that of the mod, but I'd like to offer my 2 cents. It happens that most of my thoughts happen to align with yours.

I believe that tell-don't-ask principle shouldn't really be applied as an absolute, but to be balanced with the needs of your program and concepts of other paradigms. One such example is the use of Comparators - it allows us to create multiple comparators that may compare objects of the same type differently (e.g. comparators based on author name, comparator based on word count, etc).

For the most part, while there are some methods that we expect our classes to be able to perform on their own, we can't expect classes to account for every use-case, such as being able to be compared by different attributes (e.g. comparing circle by their centre points vs radii). So, we try to keep to data-abstraction as much as possible, but be flexible to adapt where needed. Of course, one can argue that you can make every attribute in the class be its own class if necessary such that there is a has-a relationship, then you can perform methods on attributes by passing into the class methods that make use of the attribute's class, but at that point you'd also be making some trade-offs as well...

tlylt commented 2 years ago

Also just sharing my random 2 cents.

I think the OOP approach is good in that it tells you where a piece of code should belong. So now you can have a Book class that keeps all the relevant information of a book and methods that work with a Book. Then the tell-don't-ask principle, at least to me, feels like a guideline that says: given the objects and the interactions between objects that I need to create in order to fulfill some business logic, I should make objects responsible for what they do and abstract out things as attributes or methods within an object so that the details are hidden and the interaction between the objects are clear and concise.

Going to the Book example raised in the description,

I have to add the method in "Book" class to let it categorise itself. I wonder if this is a good way (should "Book" class have the behaviour of classifying itself to comic, self-help, etc.?).

I feel pretty comfortable with a Book knowing about what category it is in. And if the Book does carry that information, anyone getting hold of a Book will be able to access this information easily (which makes the librarian's job easier as well).

What if I want to classify the books based on the origin of the book authors now, does it make sense to let "Book" class knows its authors belong to a certain country?

It's probably the Author object's job to know which country the author belongs to. Some form of abstraction can be used to deal with this new requirement.

Lastly, if the business logic changes (for example, the way that things are categorized changes), it doesn't mean that the code should never change. Although that might be what we aimed to achieve, it could still be necessary that we have to adjust the code somewhat. I guess the hope of tell-don't-ask is that it makes the code more resistant to changing requirements and easier to change if needed.

Zhenyubbx commented 2 years ago

Based on what my TA mentioned before, he said that it depends on what the parent class is expected to do. If the parent class is expected to do some computation but if we use a getter to return the variables for child class to do that calculation, then this is considered a violation. If the child just expects the parent to return information but doesn't expect parent to do some task on its behalf, then it's not considered a violation.