Slide 1

Slide 1 text

Immortal Ruby

Slide 2

Slide 2 text

Marcos Matos

Slide 3

Slide 3 text

marcosccm

Slide 4

Slide 4 text

ThoughtWorks

Slide 5

Slide 5 text

Immutability

Slide 6

Slide 6 text

Have you tried rebooting the server? ! the complete guide to fixing software

Slide 7

Slide 7 text

“Cool! The problem magically fixed itself” ! Do you really believe in that?

Slide 8

Slide 8 text

It’s a BUG!

Slide 9

Slide 9 text

I would have written simpler code, but I did not have the time. ! Blaise Pascal (or maybe Mark Twain, or Newton) on writing code

Slide 10

Slide 10 text

The path of the bug is full of complexity and misunderstanding ! or anger and small paychecks

Slide 11

Slide 11 text

Many smart folks believe that our dependency on mutable state is a huge cause of complexity ! See all of Rich Hickey’s presentations…

Slide 12

Slide 12 text

mutable state led us to the TAR PIT

Slide 13

Slide 13 text

state makes ! Reasoning hard Testing hard Concurrency hard Life hard

Slide 14

Slide 14 text

I must not mutate state. State is the code-killer. State is the little-death that brings total complication. ! The Litany against State

Slide 15

Slide 15 text

but that’s how I learned how to program!

Slide 16

Slide 16 text

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

Slide 17

Slide 17 text

small caveat

Slide 18

Slide 18 text

we need some state!

Slide 19

Slide 19 text

we call it user input ! users are sadly not referentially transparent

Slide 20

Slide 20 text

Data vs State

Slide 21

Slide 21 text

Data ! Things your application needs in order to work

Slide 22

Slide 22 text

State ! all the mutations we impose on our data without necessity

Slide 23

Slide 23 text

so how do one atone for his sinful stateful ways?

Slide 24

Slide 24 text

Solution #1 ! write everything in Haskell

Slide 25

Slide 25 text

no, I want to keep using Ruby

Slide 26

Slide 26 text

Solution #2 ! just mutate less stuff

Slide 27

Slide 27 text

nothing in Ruby prevents you from writing immutable code

Slide 28

Slide 28 text

nothing helps either…

Slide 29

Slide 29 text

Why is so hard to write immutable OO code?

Slide 30

Slide 30 text

Values vs Identity

Slide 31

Slide 31 text

Values ! Atomic concepts that cannot change

Slide 32

Slide 32 text

Values ! 42, phone numbers, dates

Slide 33

Slide 33 text

Identity ! A logical entity composed by values that change over time

Slide 34

Slide 34 text

Identity ! you, me, your bank account

Slide 35

Slide 35 text

How Ruby handles this?

Slide 36

Slide 36 text

> 42 => 42 ! => 42.next > 43 ! > n = 42 > n = n + 1 => 43 ! > 42 = 42 + 1 => WhatTheHellAreYouDoingError You can’t change natural numbers

Slide 37

Slide 37 text

> dish1 = “potato” > dish2 = dish1 > dish1[0] = “d” ! > puts dish1 => “dotato” ! > puts dish2 => “dotato” You can, however, redefine the Scottish cuisine

Slide 38

Slide 38 text

> 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

Slide 39

Slide 39 text

how we avoid mutating our values?

Slide 40

Slide 40 text

> dish1 = “potato” > dish2 = dish1 ! > dish1 = dish1.sub(’b’,’d’) ! > puts dish1 => “dotato” ! > puts dish2 => “potato” avoid the !

Slide 41

Slide 41 text

> 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

Slide 42

Slide 42 text

> glasgow = “rainy” > glasgow.freeze ! > glasgow.sub!(“rainy”, “sunny”) => Can’t modify frozen String (RunTimeError) What killed the dinosaurs? The Ice Age! Mr Freeze

Slide 43

Slide 43 text

> 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

Slide 44

Slide 44 text

> 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

Slide 45

Slide 45 text

> 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

Slide 46

Slide 46 text

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

Slide 47

Slide 47 text

what about more complex objects?

Slide 48

Slide 48 text

Value Objects ! Objects that are defined by the total of their values

Slide 49

Slide 49 text

Don’t give a value object any identity and avoid the design complexities necessary to maintain entities. Eric Evans on value objects

Slide 50

Slide 50 text

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

Slide 51

Slide 51 text

> 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

Slide 52

Slide 52 text

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!

Slide 53

Slide 53 text

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

Slide 54

Slide 54 text

Hurray! ! We have Immutable Addresses!

Slide 55

Slide 55 text

what about our core domain objects?

Slide 56

Slide 56 text

Objects a collection of state and methods that operate on top of that state

Slide 57

Slide 57 text

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

Slide 58

Slide 58 text

Objects a snapshot of state and methods that exposes possibilities on top of that state

Slide 59

Slide 59 text

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

Slide 60

Slide 60 text

we can reduce state mutation where it really matters!

Slide 61

Slide 61 text

what about Active Record?

Slide 62

Slide 62 text

class Address < ActiveRecord::Base attr_readonly :street attr_readonly :complement attr_readonly :city end good guy active record

Slide 63

Slide 63 text

> 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?

Slide 64

Slide 64 text

what about performance?

Slide 65

Slide 65 text

Immutability everywhere

Slide 66

Slide 66 text

Immutable Databases Datomic ! Immutable Frontend ClojureScript

Slide 67

Slide 67 text

Recap

Slide 68

Slide 68 text

Mutable state brings complexity

Slide 69

Slide 69 text

We can have Immutability in Ruby

Slide 70

Slide 70 text

go beyond Value Objects

Slide 71

Slide 71 text

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

Slide 72

Slide 72 text

Obrigado!

Slide 73

Slide 73 text

Discussion Time!