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.

Avatar for Tomek Rusiłko

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.