Single Responsibility Functions

Many people understand the Single Responsibility Principle, but very few pay attention to how it affects whether function (and methods) should return something. In this blog post, I'm looking at a case for taking that principle to the "extreme" and looking at how functions could be written to only ever have a single reason to change.

Checking for Success

A common thing return statements can help do is verify that operations were successful by returning boolean values, see this example:

if (UpdateUser(user)) {
    if (SendEmail(user.email)) {
        // log operation
    } else {
        // retry sending email
    }
} else {
    // log failure
}

Returning false only says the functions failed but it doesn't say why., this is what exceptions are for. If the functions UpdateUser and SendEmail were rewritten to throw exceptions, we eliminate the need for the conditionals, make the whole code easier to read and handle errors better.

try {
    const createdUser = UpdateUser(userData);
    SendMail(user.email):
} catch (e) {
    // log error
}

This implementation is easier to read, allows for better error handling (Exceptions should contain error messages) Writing the functions this way brings up the question, "What then (if anything) should the UpdateUser and SendMail functions return?"

Command Query Separation

Taking the Single Responsible Principle to the extreme in this case, let's employ CQRS. CQRS states that a method or function should either be a Command that changes state or a Query that returns values, but never both. In this light, the UpdateUser function should only ever update a user with no side-effects and return nothing, same thing with the SendMail function.

try {
    UpdateUser(userData);
    const user = GetUser(userId);
    SendMail(user.email):
} catch (e) {
    // log error
}

This makes everything a whole lot clearer and more consistent. It's easy to know exactly what a function does (knowing that it doesn't do anything else). Satisfying the Principle of Least Astonishment as there are no side-effects and functions/methods do not return needless information.

Conclusion

CQRS and SOLID are some important tested and trusted principles. Ultimately, stick to what works for your use case.

No Comments Yet