DEV Community

Discussion on: Business logic in Rails with operators

Collapse
epigene profile image
Augusts Bautra • Edited on

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:

  1. Helps avoid helper method hell (calculate_total and calculate_vat in your example)
  2. 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.
  3. 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.

Collapse
citronak profile image
Petr Hlavicka Author

Hi Augusts, thank you for your feedback and information 🙂