Command

Represents an action to be carried in the near or distant future

It's very common to create wide classes named service which contains many methods related by an entity or by some sort of functionality. Think of a UserService or a ProductService for example.

The problem with these classes is that they tend to be bloated rather rapidly, are terribly difficult to test and have poor cohesion : the methods are mostly unrelated.

class UserService {
    register() {}
    update() {}
    ban() {}
    remove() {}
    getInfo() {}
    getPurchaseHistory() {}
}

Terrifying, isn't it ?

So instead, we like to represent one action, one behavior in the system, as a Command. This is heavily inspired by the principle of UseCase, so many developers tend to conflate the two. But they're strictly equivalent.

In this scheme, a Command represent an action to be carried by the system, and a CommandHandler an object that will execute that command.

class RegisterCommand {
    constructor(
        public readonly emailAddress: string, 
        public readonly password: string
    ) {}
}

class RegisterCommandHandler {
    execute(command: RegisterCommand) {
        // proceed
    }
}

The command only does one action, and depends on collaborators to perform this action specifically. Thus, you can limit your knowledge to only what you need, a case of Interface Segregation Principle.

This pattern is at the heart of the Clean Architecture. Each Command represents an action and contains everything required to perform that action, so that each behavior is documented inside your folder structure with carefully named objects.

Also, a Command is an unit of test. The minimal unit of behavior being a Command, they're a perfect target for a unit test to exerce the behavior of your code. It's often a good idea to develop these Commands using a TDD practice.

Last updated