I'm looking for feedback for a design pattern that aims to remove all side-effects from business logic. I'm using PHP but the pattern can be applied to any OOP language. The point is to enforce pure business logic from the framework, by not injecting any dependencies that have side-effects, e.g. database connections, curl, file, output buffer, etc, and replace them by command objects (see command design pattern) in a pipeline.
The motivation behind removing side-effects is to make testing easier by removing the need for mocking. In general, you can mock pure methods, but you don't have to mock them the same why you have to mock, say, a database connection.
Here's an example of a controller action that reverts the admin status of a user:
function updateUser(int $userId, SideEffectFactoryInterface $make)
{
return [
$make->query('SELECT * FROM user WHERE id = ' . $userId),
function ($user) use ($make) {
$reverted = $user->is_admin ? 0 : 1;
return [
null,
$make->query(
sprintf(
'UPDATE user SET is_admin = %d WHERE id = %d',
$reverted,
$user->id
)
)
];
},
$make->output('Updated user')
];
}
As you can see, all side-effects are created as command objects from the SideEffectFactory.
When running the list of callables, there will be a dependency resolver so that query objects get their database connection, file readers their file IO methods, etc.
Of course the question is if mocks will be easier, and if it's worth it since readability might suffer.
sprintf('UPDATE user SET is_admin = %d WHERE id = %d', $reverted, $user->id)
. Please, please, please, don't do that.