Thanks for sharing, Petr, it's valuable to keep thinking about how to code better.
I think most everyone agrees that pushing for skinny controllers, where actions generally delegate to some PORO or even the model and then check the result object, is the way to go.
However, in projects that I have worked on we have settled for strongly preferring SRP and thus instead of a single Operator, we define a class for every meaningful business operation. Doing so provides a number of benefits:
Helps avoid helper method hell (calculate_total and calculate_vat in your example)
Supports class-level .call that wraps initialization and execution of the initialized operation. Access to operation instances is not public, only the result object is.
Easy to test - in controllers merely assert that the PORO.call occured with correct arguments and that the result was correctly used to determine the response. No need to use the deprecated receive_message_chain and *_any_instance_of.
I've also dabbled in Trailblazer, and learned a lot. I particularly like the idea of Concepts as being separate from models, a superset that decouples domain entities from the underlying RDB, so we can have concepts that have no underlying table (ad-hoc, read-only concepts), one table (the usual 1-to-1 model), or n number of tables (the fabled composite concept).
From this point of view it may be helpful for developers to forget about Rails models and controller actions for a bit, and focus on their domain, to come up with appropriate domain objects (Models-> Concepts) and Operations, and only then busying themselves with implementing them in the structures Ruby and Rails provides.
I am a freelance web developer since 2007. I’ve started as HTML & CSS coder (in time of IE 6). Then as PHP (and WordPress) developer. Since 2015, I am working with Ruby on Rails.
Location
Prague, Czech Republic
Education
Master of Business Informatics, University of Economics, Prague
Thanks for sharing, Petr, it's valuable to keep thinking about how to code better.
I think most everyone agrees that pushing for skinny controllers, where actions generally delegate to some PORO or even the model and then check the result object, is the way to go.
However, in projects that I have worked on we have settled for strongly preferring SRP and thus instead of a single Operator, we define a class for every meaningful business operation. Doing so provides a number of benefits:
calculate_total
andcalculate_vat
in your example).call
that wraps initialization and execution of the initialized operation. Access to operation instances is not public, only the result object is.PORO.call
occured with correct arguments and that the result was correctly used to determine the response. No need to use the deprecatedreceive_message_chain
and*_any_instance_of
.I've also dabbled in Trailblazer, and learned a lot. I particularly like the idea of Concepts as being separate from models, a superset that decouples domain entities from the underlying RDB, so we can have concepts that have no underlying table (ad-hoc, read-only concepts), one table (the usual 1-to-1 model), or n number of tables (the fabled composite concept).
From this point of view it may be helpful for developers to forget about Rails models and controller actions for a bit, and focus on their domain, to come up with appropriate domain objects (Models-> Concepts) and Operations, and only then busying themselves with implementing them in the structures Ruby and Rails provides.
Hi Augusts, thank you for your feedback and information 🙂