I remember an exchange somewhere in an episode of The Bikeshed with one host laying out this sort of solution, and contrasting it with having DoerOfThing objects all use a #call method. The other host responded “So then don’t you just want a collection of stateless functions in namespaces?”
To which the first admitted “Yeah I guess I do want that.”
I feel similarly.
Thus far, in $WORK_CODEBASE we avoided some of the issues presented in the article by actively choosing to not use the term “service object”, and instead have several categories for “doer of things” objects, and appropriate naming conventions. For about half of these, we do just use #call, and so far this has not resulted in the apocalypse.
This does limits the “implicit, undocumented paths” problem, though does not entirely solve it. It is much easier to know where you will find something you are looking for, and to have an obvious answer where new code belongs when implementing new behavior. It is a solid step beyond a junk drawer “services” folder, but falls short of trying to write Clojure in Ruby.