Chapter 7. Performing tasks

 

This chapter covers

  • Using command methods to perform tasks
  • Using events and event listeners to split up larger tasks
  • Dealing with failure in command methods
  • Introducing abstractions for commands
  • Creating test doubles for command calls

Besides retrieving information from objects, you can use objects to perform a variety of tasks for you:

  • Send a reminder email
  • Save a record in the database
  • Change the password of a user
  • Store something on disk
  • And so on . . .

The following sections provide rules for methods that perform tasks like these.

7.1. Use command methods with a name in the imperative form

We already discussed query methods and how you should use them to retrieve information. Query methods have a specific return type and no side effects, meaning that it’s safe to call them several times, and the application’s state won’t be any different afterwards.

For performing tasks, you should always use a command method, which has a void return type. The name of such a method should indicate that the client can order the object to perform the task that the method name indicates. When looking for a good name, you should always use the imperative form. The following listing shows some examples.

Listing 7.1. Some command methods with imperative names
public function sendReminderEmail(
    EmailAddress recipient,
    // ...
): void {
   // ...
}

public function saveRecord(Record record): void
{
   // ...
}

7.2. Limit the scope of a command method, and use events to perform secondary tasks

7.3. Make services immutable from the outside as well as on the inside

7.4. When something goes wrong, throw an exception

7.5. Use queries to collect information and commands to take the next steps

7.6. Define abstractions for commands that cross system boundaries

7.7. Only verify calls to command methods with a mock

Summary

Answers to the exercises