Navigation Menu

Skip to content

Instantly share code, notes, and snippets.

@rondy
Last active March 2, 2021 11:14
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save rondy/a9f167cca216dfb51d1dc1fac56755b1 to your computer and use it in GitHub Desktop.
Save rondy/a9f167cca216dfb51d1dc1fac56755b1 to your computer and use it in GitHub Desktop.

Functional objects on Ruby programming language

Goals

  • Less questions asked. E.g:
  • 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");
# 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;
  #...
  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;
    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.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment