Page MenuHomePhabricator

Should MediaWiki services encourage the command pattern or avoid it?
Closed, ResolvedPublic

Description

Follow up to a code review comment.

The patch created a new "factory" service that uses the command pattern. Effectively the service creates a new object that contains all of the dependencies and necessary state to perform any actions. In a sense, the "services" created by the factory are "disposable" in the sense that it is expected to create them and throw them away multiple times within an execution.

The advantage of this pattern is that it utilizes object-oriented programming (OOP) practices and has it's dependencies injected into it. It also (potentially) avoids re-processing data as that can be done a single time in the constructor.

The disadvantage is that a new instance may be created only to run a single command, and then the instance is destroyed and the associated state is lost. A more functional approach would be to create "value objects" that only hold state (and do not perform actions) and are passed into a single service's methods. This keeps the service methods pure and free of side-effects while also keeping dependencies away from the value object.

Regardless, this pattern is preferable to the existing "active record" type objects like User, Title, and Block. However, the pattern does permit a command object to have the same abilities as these existing objects. The biggest difference would be that the dependencies would be injected. For instance, if there was a factory service that created "command" object with an injected database and some params, that "command" object could have a save() method that accepts no arguments. In this way, it is easy for command objects to devolve into the same types of objects we have now (although, the benefit would be that their dependencies would be injected).

Should MediaWiki services encourage the command pattern or avoid it (or neither)?

Event Timeline

eprodromou subscribed.

Interesting issue, moving to tech planning review.

The "command" pattern is useful especially for operations that take a lot of operations or parameters, and that produce complex state. Creating dedicated value objects for the input and output would be possible, but I don't see the advantage in that. It seems awkward to have a PageMover and a PageMoveParameters and a PageMoveResult class. a MovePage command comming from a PageCommandFactory seems more straight forward.

Note that constructing the PageMoveParameters and PageMoveResult value objects would require complex constructor signatures. It seems to me that they would not be better than complicated methods signatures on the service itself.

I think neither approach is strictly better, nor do I think that either pattern should be discouraged in general.

What matters to me is that the code is understandable and maintainable by a team, is well-documented and follows general best practices and conventions that we share, and that others can easily make use of and debug the code as needed in their own areas.

If your team is or has stepped up as steward for the User blocks feature, I think it'd be fine to revert or otherwise restructure to your team's liking.

Krinkle claimed this task.