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

Immortal Ruby

Sponsored · Ship Features Fearlessly Turn features on and off without deploys. Used by thousands of Ruby developers.

Immortal Ruby

Talk about Immutability and Ruby presented on RubyNation 2014

More Decks by Marcos Castilho da Costa Matos

Other Decks in Programming

Transcript

  1. I would have written simpler code, but I did not

    have the time. ! Blaise Pascal (or maybe Mark Twain, or Newton) on writing code
  2. The path of the bug is full of complexity and

    misunderstanding ! or anger and small paychecks
  3. Many smart folks believe that our dependency on mutable state

    is a huge cause of complexity ! See all of Rich Hickey’s presentations…
  4. I must not mutate state. State is the code-killer. State

    is the little-death that brings total complication. ! The Litany against State
  5. atual <- 1! ant <- 0! repita! num <- atual

    + ant! escreva ("num")! ant <- atual! atual <- num! cont <- cont + 1! ate (cont = n-2) The (not really) amazing Portugol
  6. > 42 => 42 ! => 42.next > 43 !

    > n = 42 > n = n + 1 => 43 ! > 42 = 42 + 1 => WhatTheHellAreYouDoingError You can’t change natural numbers
  7. > dish1 = “potato” > dish2 = dish1 > dish1[0]

    = “d” ! > puts dish1 => “dotato” ! > puts dish2 => “dotato” You can, however, redefine the Scottish cuisine
  8. > col1 = [1,2,3] > col2 = col1 > col1

    << 4 ! > puts col1 => [1,2,3,4] ! > puts col2 => [1,2,3,4] Arrays suffer the same fate
  9. > dish1 = “potato” > dish2 = dish1 ! >

    dish1 = dish1.sub(’b’,’d’) ! > puts dish1 => “dotato” ! > puts dish2 => “potato” avoid the !
  10. > col1 = [1,2,3] > col2 = col1.dup > col1

    << 4 ! > puts col1 => [1,2,3,4] ! > puts col2 => [1,2,3] the attack of the clones
  11. > glasgow = “rainy” > glasgow.freeze ! > glasgow.sub!(“rainy”, “sunny”)

    => Can’t modify frozen String (RunTimeError) What killed the dinosaurs? The Ice Age! Mr Freeze
  12. > iceberg = [”big”,”chunk”,”ice”] > iceberg.freeze ! > iceberg.shift(“very”) =>

    RuntimeError: can't modify frozen Array ! > iceberg[0].sub!(“big”, “small”) => [”small”,”chunk”,”ice”] more like Array#chill_out
  13. > require ‘ice_nine' ! > iceberg = [”big”,”chunk”,”ice”] > IceNine.deep_freeze(iceberg)

    ! > iceberg.shift(“very”) => RuntimeError: can't modify frozen Array ! > iceberg[0].sub!(“big”, “small”) => RuntimeError: can't modify frozen String github.com/dkubb/ice_nine
  14. > require ‘hamster' ! > addr = Hamster.hash(street: ‘Queen St’,

    number: ‘152’) => { :street => ‘Queen St’, :number => ‘152’ } ! > with_city = addr.put(:city, ‘Glasgow’) => { :street => ‘..’, :number => ‘..’, city => ‘Glasgow’ } ! > addr => { :street => ‘Queen St’, :number => ‘152’ } https://github.com/hamstergem/hamster
  15. > require ‘hamster' ! > without_city = addr.delete(:city) => {

    :street => ‘Queen St’, :number => ‘152’ } ! > with_city => { :street => ‘..’, :number => ‘..’, city => ‘Glasgow’ } https://github.com/hamstergem/hamster
  16. Don’t give a value object any identity and avoid the

    design complexities necessary to maintain entities. Eric Evans on value objects
  17. class Address attr_reader :street, :complement, :city ! def initialize(street, complement,

    city) @street = street @complement = complement @city = city end ! def to_s "#{street}, #{complement}, #{city}" end end A boring Address
  18. > address = Address.new(“Queen st”, “a secret”, “Glasgow”) > puts

    address => “Queen St, a secret, Glasgow” ! > addess.street = “Argyle St” => bla undefined method street=bla bla ! > address.street.gsub!(/Queen/,”Lolz”) > puts address => “Lolz St, a secret, Glasgow” Lolz Encapsulation
  19. require 'ice_nine' ! class Address attr_reader :street, :complement, :city !

    def initialize(street, complement, city) @street = street @complement = complement @city = city IceNine.deep_freeze!(self) end ! def to_s "#{street}, #{complement}, #{city}" end end Immutability at last!
  20. require 'virtus' ! class Address include Virtus.value_object ! values do

    attribute :street, String attribute :complement, String attribute :city, String end end github.com/solnic/virtus
  21. class BankAccount attr_reader :current ! def initialize @current = 0

    end ! def deposit(amount) @current = current + amount end ! def withdrawal(amount) @current = current - amount end end a robust banking system
  22. class BankAccount attr_reader :current ! def initialize(current) @current = current

    end ! def deposit(amount) BankAccount.new(current + amount) end ! def withdrawal(amount) BankAccount.new(current - amount) end end no mutations
  23. > address = Address.create(street: “Queen st”) > Address.first.street => “Queen

    St” ! > addess.update_attributes(street: “Argyle St”) > address.street => “Argyle St” ! > Address.find(1).street => “Queen St” bug or feature?
  24. Wanna learn more? ! Amazing blog post from the author

    of the Hamster lib http://www.harukizaemon.com/blog/2010/03/01/functional-programming-in-object-oriented- languages/ ! Anything Rich Hickey http://thechangelog.com/rich-hickeys-greatest-hits/ ! The Tar Pit paper http://shaffner.us/cs/papers/tarpit.pdf ! Clojure’s take on State http://clojure.org/state