pointer-image   31   Tell, Don’t Ask

 

“Don’t trust other objects. After all, they were written by other people, or even by you last month when you weren’t as smart. Get the information you need from others, and then do your own calculations and make your own decisions. Don’t give up control to others!”

images/devil.png

“Procedural code gets information and then makes decisions. Object-oriented code tells objects to do things.” Alec Sharp Smalltalk by Example: The Developer’s Guide [Sha97] hit the nail on the head with that observation. But it’s not limited to the object-oriented paradigm; any agile code should follow this same path.

As the caller, you should not make decisions based on the state of the called object and then change the state of that object. The logic you are implementing should be the called object’s responsibility, not yours. For you to make decisions outside the object violates its encapsulation and provides a fertile breeding ground for bugs.

David Bock illustrates this well with the tale of the paperboy and the wallet.[33] Suppose the paperboy comes to your door, requesting his payment for the week. You turn around and let the paperboy pull your wallet out of your back pocket, take the two bucks (you hope), and put the wallet back. The paper boy then drives off in his shiny new Jaguar.

The paperboy, as the “caller” in this transaction, should simply tell the customer to pay $2. There’s no inquiry into the customer’s financial state, or the condition of the wallet, and no decision on the paperboy’s part. All of that is the customer’s responsibility, not the paperboy’s. Agile code should work the same way.

A helpful side technique related to Tell, Don’t Ask is known as command-query separation Object-Oriented Software Construction [Mey97]. The idea is to categorize each of your functions and methods as either a command or a query and document them as such in the source code (it helps if all the commands are grouped together and all the queries are grouped together).

A routine acting as a command will likely change the state of the object and might also return some useful value as a convenience. A query just gives you information about the state of the object and does not modify the externally visible state of the object. That is, queries should be side effect free as seen from the outside world (you may want to do some pre-calculation or caching behind the scenes as needed, but fetching the value of X in the object should not change the value of Y).

Mentally framing methods as commands helps reinforce the idea of Tell, Don’t Ask. And keeping queries as side effect free is just good practice anyway, because you can use them freely in unit tests, call them from assertions, or from the debugger, all without changing the state of the application.

Explicitly considering queries separately from commands also gives you the opportunity to ask yourself why you’re exposing a particular piece of data. Do you really need to do so? What would a caller do with it? Perhaps there should be a related command instead.

images/angel.png

Tell, don’t ask.

Don’t take on another object’s or component’s job. Tell it what to do, and stick to your own job.

What It Feels Like

Smalltalk uses the concept of “message passing” instead of method calls. Tell, Don’t Ask feels like you’re sending messages, not calling functions.

Keeping Your Balance

  • Objects that are just giant data holders are suspect. Sometimes you need such things, but maybe not as often as you think.

  • It’s OK for a command to return data as a convenience (it’d be nice to be able to retrieve that data separately, too, if that’s needed).

  • It’s not OK for an innocent-looking query to change the state of an object.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.133.96.37