## Functional objects on Ruby programming language #### 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; * Public contract is a `#call` method; * Enables SRP; * Enables composition; * Enables polymorphism; * Enables to receive 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; * 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. * Collaborators are also other functional objects (they're named as verbs); * 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. ```