## Functional objects on Ruby programming language #### Goals * Less questions asked. E.g: * How should I name my objects that carry behavior? They're nouns or verbs? * Should I expose attr_readers/writers/accessors? * What kind of input should it receive from constructor/initializers? And what about methods? * More consistent style among classes definitions. #### Benefits * Message passing is natural; * Emphasize **what system does** rather rhan **what system is**; * Usage of mocking frameworks can be **dropped off**; #### Guidelines * Start class names with a verb; * ("do thing" instead of "thing doer"); ```ruby # Bad class BackupProcedure def perform end end # Good class PerformBackupProcedure def call end end ``` * Public contract is a `#call` method; * Enables SRP; * Enables composition/polymorphism through proc/callables objects; * Receive stateful/impure collaborators through the object initializer; * This permits easy mocking/substitution. * This resembles curry-like functions; * Receive "pure function" inputs through the `#call` method; * Collaborators are also other functional objects (they're named as verbs); * The `#call` calling always returns a value, preferably 'result'-like objects; * This avoids 'primitive obssesion' anti-pattern; * Consider monadics operations; * Define stateful/impure functions as default implementation, in case nothing is received; ```ruby #... private def get_page_title @get_page_title ||= begin lambda do |url| mechanize = Mechanize.new mechanize.get(url).title end end end end ``` * Object internal state is used only for stateful/impure collaborators. * Stateful/impure functions are always returned as closures/lambda; ```ruby extract_utm_campaign_value_from(url) # is pure get_page_title.call(url) # is impure ``` #### Quote from "Functional and Reactive Domain Modeling" book ``` # Why mixing domain logic and side effects is bad ### Entanglement of domain logic and side effects. Violates separation of concerns. Domain logic and side effects are orthogonal to each other—entanglement violates a basic software engineering principle. ### Difficult to unit test. If domain logic is entangled with side effects, unit testing becomes difficult. You need to resort to mocking stuff that leads to other complications in your source code. ### Difficult to reason about the domain logic. You can’t reason about the domain logic that’s entangled with the side effect. ### Side effects don’t compose and hinder modularity of your code. Your entangled code remains an island that can’t be composed with other functions. ```