Upgrade to Pro — share decks privately, control downloads, hide ads and more …

From OO to FP

From OO to FP

A journey from messy strategy pattern to functional concepts in Ruby.

Tomek Rusiłko

September 16, 2016
Tweet

More Decks by Tomek Rusiłko

Other Decks in Programming

Transcript

  1. #2

  2. def score a = @property.input_1 + @property.input_2 b = (@borrower.input_1

    * @bank.param_1) / 4 c = (a / b) * @mortgage.input_1 d = if c > @bank.min_value (@bank.param_2 * @mortgage.input_3) else 0 end # . . . y = . . . z = . . . score = [ y/z, u ] score end
  3. def score a = @property.input_1 + @property.input_2 b = (@borrower.input_1

    * @bank.param_1) / 4 c = (a / b) * @mortgage.input_1 d = if c > @bank.min_value (@bank.param_2 * @mortgage.input_3) else 0 end # . . . y = . . . z = . . . score = [ y/z, u ] score end
  4. def score a = @property.input_1 + @property.input_2 b = (@borrower.input_1

    * @bank.param_1) / 4 c = (a / b) * @mortgage.input_1 d = if c > @bank.min_value (@bank.param_2 * @mortgage.input_3) else 0 end # . . . y = . . . z = . . . score = [ y/z, u ] score end
  5. def score a = @property.input_1 + @property.input_2 b = (@borrower.input_1

    * @bank.param_1) / 4 c = (a / b) * @mortgage.input_1 d = if c > @bank.min_value (@bank.param_2 * @mortgage.input_3) else 0 end # . . . y = . . . z = . . . score = [ y/z, u ] score end
  6. def score a = @property.input_1 + @property.input_2 b = (@borrower.input_1

    * @bank.param_1) / 4 c = (a / b) * @mortgage.input_1 d = if c > @bank.min_value (@bank.param_2 * @mortgage.input_3) else 0 end # . . . y = . . . z = . . . score = [ y/z, u ] score end
  7. def score a = @property.input_1 + @property.input_2 b = (@borrower.input_1

    * @bank.param_1) / 4 c = (a / b) * @mortgage.input_1 d = if c > @bank.min_value (@bank.param_2 * @mortgage.input_3) else 0 end # . . . y = . . . z = . . . score = [ y/z, w ] score end
  8. def score a = @property.input_1 + @property.input_2 b = (@borrower.input_1

    * @bank.param_1) / 4 c = (a / b) * @mortgage.input_1 d = if c > @bank.min_value (@bank.param_2 * @mortgage.input_3) else 0 end # . . . y = . . . z = . . . score = [ y/z, w ] score end
  9. def score a = @property.input_1 + @property.input_2 b = (@borrower.input_1

    * @bank.param_1) / 4 c = (a / b) * @mortgage.input_1 d = if c > @bank.min_value (@bank.param_2 * @mortgage.input_3) else 0 end # . . . y = . . . z = . . . score = [ y/z, w ] score end
  10. class ScoreCalculator def initialize(property, mortgage, borrower, settings, bank) @property =

    property @mortgage = mortgage @bank = bank # . . . end def score a = @property.input_1 + @property.input_2 # . . . [y/z, w] end end
  11. class ScoreCalculator def initialize(property, mortgage, borrower, settings, bank) @property =

    property @mortgage = mortgage @bank = bank # . . . end def score a = @property.input_1 + @property.input_2 # . . . [y/z, w] end end
  12. class ScoreCalculator def initialize(property, mortgage, borrower, settings, bank) @property =

    property @mortgage = mortgage @bank = bank # . . . end def score a = @property.input_1 + @property.input_2 # . . . [y/z, w] end end
  13. class ScoreCalculator def initialize(property, mortgage, borrower, settings, bank) @property =

    property @mortgage = mortgage @bank = bank # . . . end def score a = @property.input_1 + @property.input_2 # . . . [y/z, w] end end
  14. class ScoreCalculator def initialize(property, mortgage, borrower, settings, bank) def score

    [y/z, w] end private def borrower_total_income @borrower.basic_income + 
 @borrower.additional_income + @borrower.bonus_income end end
  15. class Borrower < ActiveRecord::Base def initialize(property, mortgage, borrower, settings, bank)

    def score [y/z, w] end private def borrower_total_income @borrower.basic_income + 
 @borrower.additional_income + @borrower.bonus_income end end
  16. class Borrower < ActiveRecord::Base def initialize(property, mortgage, borrower, settings, bank)

    def score [y/z, w] end private def total_income basic_income + 
 additional_income + bonus_income end end
  17. class ScoreCalculator def initialize(property, mortgage, borrower, settings, bank) def score

    [y/z, w] end private def borrower_income @borrower.income + 
 @borrower.additional_income + @borrower.bonus_income end end
  18. class InvestitureCalculator def initialize(property, mortgage, bank) @property = property @mortgage

    = mortgage @bank = bank end def investiture (d / e) ^ @bank.investiture_factor end private def d; end def e; end end
  19. id name param_1 param_2 param_3 … 1 bankA 0.6 55

    0.75 … 2 bankB 0.66 60 0.75 … 3 bankC 0.65 60 0.65 … … … … … … …
  20. class Borrower < ActiveRecord::Base def initialize(property, mortgage, borrower, settings, bank)

    def total_income basic_income + 
 additional_income + bonus_income end end
  21. class Borrower < ActiveRecord::Base def initialize(property, mortgage, borrower, settings, bank)

    def total_income basic_income + 
 additional_income + bonus_income * 0.5 end end
  22. id name param_1 param_2 param_3 bonus_factor 1 bankA 0.6 55

    0.75 1 2 bankB 0.66 60 0.75 1 3 bankC 0.65 60 0.65 0.5 … … … … … …
  23. • coding is not fun • slow velocity • demotivated

    team • long new developer ramp-up • bus factor
  24. Symptoms • coding is not fun • slow velocity •

    demotivated team • long new developer ramp-up • low bus factor
  25. class BankA def parameters { bank_param_1: 0.6, bank_param_2: 60, }

    end end class BankB def parameters { bank_param_1: 0.5, bank_param_2: 65 } end end
  26. class BankB def parameters; end; def evaluation_pipeline { a: A,

    b: BankB::B,
 .
 .
 . score: BankB::Score, } end end
  27. class ScoreCalculator def self.call(input_data, bank) data = input_data.merge(bank.parameters) pipe =

    bank.evaluation_pipeline pipe.each do |name, calculate| result = calculate.(data) new_pair = { name => result } data = data.merge(new_pair) end data end end Evaluate.(input_data, bank)
  28. module Evaluate def self.call(input_data, bank) data = input_data.merge(bank.parameters) pipe =

    bank.evaluation_pipeline pipe.each do |name, calculate| result = calculate.(data) new_pair = { name => result } data = data.merge(new_pair) end data end end Evaluate.(input_data, bank)
  29. module Evaluate def self.call(input_data, bank) data = input_data.merge(bank.parameters) pipe =

    bank.evaluation_pipeline pipe.each do |name, calculate| result = calculate.(data) new_pair = { name => result } data = data.merge(new_pair) end data end end Evaluate.(input_data, bank)
  30. module Evaluate def self.call(input_data, bank) data = input_data.merge(bank.parameters) pipe =

    bank.evaluation_pipeline pipe.each do |name, calculate| result = calculate.(data) new_pair = { name => result } data = data.merge(new_pair) end data end end Evaluate.(input_data, bank)
  31. module Evaluate def self.call(input_data, bank) data = input_data.merge(bank.parameters) pipe =

    bank.evaluation_pipeline pipe.each do |name, calculate| result = calculate.(data) new_pair = { name => result } data = data.merge(new_pair) end data end end Evaluate.(input_data, bank)
  32. module Evaluate def self.call(input_data, bank) data = input_data.merge(bank.parameters) pipe =

    bank.evaluation_pipeline pipe.each do |name, calculate| result = calculate.(data) new_pair = { name => result } data = data.merge(new_pair) end data end end Evaluate.(input_data, bank)
  33. module Evaluate def self.call(input_data, bank) data = input_data.merge(bank.parameters) pipe =

    bank.evaluation_pipeline pipe.each do |name, calculate| result = calculate.(data) new_pair = { name => result } data = data.merge(new_pair) end data end end Evaluate.(input_data, bank)
  34. module Evaluate def self.call(input_data, bank) data = input_data.merge(bank.parameters) pipe =

    bank.evaluation_pipeline pipe.each do |name, calculate| result = calculate.(data) new_pair = { name => result } data = data.merge(new_pair) end data end end Evaluate.(input_data, bank)
  35. module Evaluate def self.call(input_data, bank) data = input_data.merge(bank.parameters) pipe =

    bank.evaluation_pipeline pipe.reduce(data) do |data, (name, calculate)| data.merge(name => calculate.(data)) end end end Evaluate.(input_data, bank)
  36. output_data = { property_input_1: 10, property_input_2: 20, borrower_input_1: 30, mortgage_input_1:

    true, bank_param_1: 0.6, bank_param_2: 60, a: 60, b: 18.2, x: . . ., y: . . ., score: “A” }
  37. • FP is about stateless, composable functions working on immutable

    data structures. And it can be a powerful concept to have in your toolbox. • While every problem can be solved with OO, it’s not the only and best solution out there. • Some OO design patterns are workarounds of missing language features like first class functions.