Slide 1

Slide 1 text

with TypeScript υϝΠϯۦಈઃܭͱؔ਺ܕϓϩάϥϛϯά 2017.02.20 Gunma.web#30 Hikaru Otabe

Slide 2

Slide 2 text

ࣗݾ঺հ w େా෦ߊɹ!DIJMEIPPPPP w ೥લ͸ϩέοτؔ܎ͷ૊ΈࠐΈΤϯδχΞʢ$ʣ w ࠷ۙ͸8FCؔ܎ͷ࢓ࣄ w $ 1ZUIPO &MJYJS +BWB4DSJQU 1)1FUD Profile

Slide 3

Slide 3 text

ؔ਺ܕϓϩάϥϛϯάͱ͍͑͹ What comes to your mind ?

Slide 4

Slide 4 text

਺ֶ map Ϟφυ ෭࡞༻ ϥϜμࣜ ࢀরಁաੑ ஗ԆධՁ ؔ਺ͷ߹੒ ΧϦʔԽ ΧϦʔԽ ςετ ͳʹͦΕʁ ฒߦॲཧ ύλʔϯϚον ࠶ؼ

Slide 5

Slide 5 text

਺ֶ map Ϟφυ ෭࡞༻ ϥϜμࣜ ࢀরಁաੑ ஗ԆධՁ ؔ਺ͷ߹੒ ΧϦʔԽ ΧϦʔԽ ςετ ͳʹͦΕʁ ฒߦॲཧ ύλʔϯϚον ࠶ؼ

Slide 6

Slide 6 text

ࠓճ஫໨͢Δಛ௃ lؔ਺ܕϓϩάϥϛϯάͰ͸ࢀরಁաੑ͕อূ͞ΕΔz

Slide 7

Slide 7 text

ࠓճ஫໨͢Δಛ௃ lؔ਺ܕϓϩάϥϛϯάͰ͸ࢀরಁաੑ͕อূ͞ΕΔz ͞ΕΔͱ͍͏͔ɺ͢Δɻ

Slide 8

Slide 8 text

ࢀরಁաੑΛഁյ͢Δ΋ͷ Who breaks Referential transparency ?

Slide 9

Slide 9 text

1. ࠶୅ೖ 2. ɹม਺ͷࢀরಁաੑΛഁյ ෭࡞༻ͷ͋Δؔ਺ ɹؔ਺ͷࢀরಁաੑΛഁյ

Slide 10

Slide 10 text

࠶୅ೖʹΑΔࢀরಁաੑͷഁյ > var x = 1 undefined

Slide 11

Slide 11 text

࠶୅ೖʹΑΔࢀরಁաੑͷഁյ > var x = 1 undefined > x = 2 2

Slide 12

Slide 12 text

࠶୅ೖʹΑΔࢀরಁաੑͷഁյ > var x = 1 undefined > x = 2 2 > x 2

Slide 13

Slide 13 text

࠶୅ೖʹΑΔࢀরಁաੑͷഁյ > var x = 1 undefined > x = 2 2 > x 2 Broken!

Slide 14

Slide 14 text

࠶୅ೖʹΑΔࢀরಁաੑͷഁյ > var x = 1 undefined > x = 2 2 > x 2 > const y = 1 undefined > y = 2 TypeError Broken!

Slide 15

Slide 15 text

ؔ਺ͷ෭࡞༻ʹΑΔࢀরಁաੑͷഁյ > var counter = 0 undefined > const count = (x) => counter += x undefined > count(3) 3 > count(3) 6

Slide 16

Slide 16 text

ؔ਺ͷ෭࡞༻ʹΑΔࢀরಁաੑͷഁյ > var counter = 0 undefined > const count = (x) => counter += x undefined > count(3) 3 > count(3) 6 Broken!

Slide 17

Slide 17 text

υϝΠϯۦಈઃܭ Domain-Driven Design

Slide 18

Slide 18 text

υϝΠϯϞσϧͷߏ੒ཁૉ w ஋ΦϒδΣΫτ w ΤϯςΟςΟ w αʔϏε w FUDʜ

Slide 19

Slide 19 text

υϝΠϯϞσϧͷߏ੒ཁૉ w ஋ΦϒδΣΫτ w ΤϯςΟςΟ w αʔϏε w FUDʜ

Slide 20

Slide 20 text

υϝΠϯϞσϧͷߏ੒ཁૉ w ஋ΦϒδΣΫτ w ΤϯςΟςΟ w αʔϏε w FUDʜ ؔ਺ܕϓϩάϥϛϯάͰͲͷΑ͏ʹදݱ͢Δ͔ʁ

Slide 21

Slide 21 text

υϝΠϯϞσϧͷߏ੒ཁૉ w ஋ΦϒδΣΫτ w ΤϯςΟςΟ w αʔϏε w FUDʜ ؔ਺ܕϓϩάϥϛϯάͰͲͷΑ͏ʹදݱ͢Δ͔ʁ ʂ ׬ᘳͳ࣮ફ͸೉͍͠Ͱ͢

Slide 22

Slide 22 text

ۜߦޱ࠲ΞϓϦέʔγϣϯͷྫ

Slide 23

Slide 23 text

ΤϯςΟςΟʢؔ਺ܕϓϩάϥϛϯάʣ class Account { constructor(public id: UserID, public balance: Balance) { Object.freeze(this); } debit(amount: number):Balance { if(this.balance.amount < amount) { return [“error”, “This is an error message.”]; } else { return [“success”, ɹnew Account(this.id, new Balance(this.balance.amount - amount))]; } } credit(amount: number):Balance { return [“success”, new Account(this.id, new Balance(this.balance.amount + amount))]; } }

Slide 24

Slide 24 text

จࣈ͕খ͍͞

Slide 25

Slide 25 text

GitHub github.com/childhooooo/ddd-fp-ts

Slide 26

Slide 26 text

஋ΦϒδΣΫτ w ࢒ߴΛද࣌͢͸ɺ/VNCFSܕͰ͸ͳ͘ɺ#BMBODFܕΛ w ෆมੑʜҰ౓ੜ੒ͨ͠ΒɺଐੑΛมߋ͢Δ͜ͱ͸ग़དྷͳ͍ w ౳ՁੑʜࢀরઌͰ͸ͳ͘ɺଐੑͰ൑அ Value objects

Slide 27

Slide 27 text

஋ΦϒδΣΫτ class Balance { constructor(public amount: number = 0) { Object.freeze(this); } } const balance = new Balance(100); balance.amount = 50 //error

Slide 28

Slide 28 text

ΤϯςΟςΟ w ಉҰੑʜଐੑ͕ҟͳ͍ͬͯͯ΋ɺ*%͕ಉ͡ͳΒ͹ಉҰͷ΋ ͷͱͯ͠ѻ͏ w ϥΠϑαΠΫϧͷ࿈ଓੑ Entities

Slide 29

Slide 29 text

ΤϯςΟςΟʢҰൠతͳΦϒδΣΫτࢦ޲ʣ class Account { constructor(public id: UserID, public balance: Balance) {} debit(amount: number):string { if(this.balance.amount < amount) {
 return “error”; } else { this.balance = new Balance(this.balance.amount - amount); return “success”; } } credit(amount: number):string { this.balance = new Balance(this.balance.amount + amount); return “success”; } }

Slide 30

Slide 30 text

ΤϯςΟςΟΛ࢖͏ʢҰൠతͳΦϒδΣΫτࢦ޲ʣ let account = new Account(“A”, new Balance(200)); console.log(account.balance.amount); //200 result = account.debit(100); console.log(result, account.balance.amount); //“success” 100

Slide 31

Slide 31 text

ΤϯςΟςΟΛ࢖͏ʢҰൠతͳΦϒδΣΫτࢦ޲ʣ let account = new Account(“A”, new Balance(200)); console.log(account.balance.amount); //200 result = account.debit(100); console.log(result, account.balance.amount); //“success” 100 Broken!

Slide 32

Slide 32 text

ΤϯςΟςΟʢؔ਺ܕϓϩάϥϛϯάʣ class Account { constructor(public id: UserID, public balance: Balance) { Object.freeze(this); } debit(amount: number):Account { if(this.balance.amount < amount) { return [“error”, “This is an error message.”]; } else { return [“success”, ɹnew Account(this.id, new Balance(this.balance.amount - amount))]; } } credit(amount: number):Account { return [“success”, new Account(this.id, new Balance(this.balance.amount + amount))]; } }

Slide 33

Slide 33 text

ΤϯςΟςΟΛ࢖͏ʢؔ਺ܕϓϩάϥϛϯάʣ const pattern = require(“matches”).pattern; //matches.js const account = new Account(new UserID(1), new Balance(200)); const operated = account.debit(100); pattern({ ‘[“success”, a@Account ]’: (a) => console.log(a.balance.amount), ‘[“error”, message ]’: (message) => console.log(message) })(operated); //100

Slide 34

Slide 34 text

αʔϏε w ஋ΦϒδΣΫτ΍ΤϯςΟςΟʹଐ͞ͳ͍ॏཁͳॲཧ w ಠཱͨ͠ΠϯλʔϑΣΠε w ঢ়ଶΛ࣋ͨͳ͍ Services

Slide 35

Slide 35 text

αʔϏε const transfer = (from: Account, to: Account, amount: number) => { const [res, debited] = from.debit(amount); return if_success([res, debited, …to.credit(amount)], ([a, credited]) => [“success”, a, credited[1]]); }

Slide 36

Slide 36 text

αʔϏεΛ࢖͏ const pattern = require(“matches”).pattern; //matches.js const from = new Account(new UserID(1), new Balance(500)); const to = new Account(new UserID(2), new Balance(300)); const transferred = transfer(from, to, 300); pattern({ ‘[“success”, f, _]’: (f) => console.log(f.balance.amount), ‘[“error”, message]’: (message) => console.log(message) })(transferred); //200

Slide 37

Slide 37 text

ঢ়ଶΛ൐͏ܭࢉʹ͍ͭͯ State monad

Slide 38

Slide 38 text

ҰൠతͳΦϒδΣΫτࢦ޲ͷ৔߹ > const account = new Account(new UserID(5)) undefined //ҎԼɺ࢒ߴΛฦؔ͢਺showBalance(account)͕ఆٛͯ͋͠Δͱ͢Δɻ > showBalance(account) 0 > account.credit(200) undefined > account.debit(100) undefined > account.debit(50) undefined > showBalance(account) 50

Slide 39

Slide 39 text

ҰൠతͳΦϒδΣΫτࢦ޲ͷ৔߹ > const account = new Account(new UserID(5)) undefined //ҎԼɺ࢒ߴΛฦؔ͢਺showBalance(account)͕ఆٛͯ͋͠Δͱ͢Δɻ > showBalance(account) 0 > account.credit(200) undefined > account.debit(100) undefined > account.debit(50) undefined > showBalance(account) 50 Broken!

Slide 40

Slide 40 text

ؔ਺ܕϓϩάϥϛϯά͸ঢ়ଶΛ࣋ͨͳ͍͸ͣɾɾɾ

Slide 41

Slide 41 text

ؔ਺ܕͰී௨ʹ΍ͬͯΈΔ > const a0 = new Account(new UserID(5)) undefined > showBalance(a0) 0 > const a1 = a0.credit(200) undefined > const a2 = a1.debit(100) undefined > const a3 = a2.debit(50) undefined > showBalance(a3) 50

Slide 42

Slide 42 text

ؔ਺ܕͰී௨ʹ΍ͬͯΈΔ > const a0 = new Account(new UserID(5)) undefined > showBalance(a0) 0 > const a1 = a0.credit(200) undefined > const a2 = a1.debit(100) undefined > const a3 = a2.debit(50) undefined > showBalance(a3) 50 ຊ౰ʹ͜ΕͰ͍͍ͷʁ

Slide 43

Slide 43 text

ؔ਺ܕͰී௨ʹ΍ͬͯΈΔ > const a0 = new Account(new UserID(5)) undefined > showBalance(a0) 0 > const a1 = a0.credit(200) undefined > const a2 = a1.debit(100) undefined > const a3 = a2.debit(50) undefined > showBalance(a3) 50 ݁ہɺBɾBͱ͍ͬͨঢ়ଶΛ͍࣋ͬͯΔ

Slide 44

Slide 44 text

ͦΕͳΒͬͪ͜ͷ΄͏͕Θ͔Γ΍͍͢ > const account = new Account(new UserID(5)) undefined > showBalance(account) 0 > account.credit(200) undefined > account.debit(100) undefined > account.debit(50) undefined > showBalance(account) 50

Slide 45

Slide 45 text

ͦΕͳΒͬͪ͜ͷ΄͏͕Θ͔Γ΍͍͢ > const account = new Account(new UserID(5)) undefined > showBalance(account) 0 > account.credit(200) undefined > account.debit(100) undefined > account.debit(50) undefined > showBalance(account)() 50 Ͱ΋ɺͲ͏΍ͬͯࢀর౳ՁੑΛอͭͷ͔

Slide 46

Slide 46 text

಄ͷྑ͍ਓ͸ߟ͑ͨ

Slide 47

Slide 47 text

͜Μͳͷ͸Ͳ͏͔ > const account = new Account(new UserID(5)) undefined > showBalance(account, “Կ΋͍ͯ͠ͳ͍”) 0 > showBalance(account, “200आΓͯɺ100ିͯ͠ɺ50ିͨ͠”) 50

Slide 48

Slide 48 text

͜Μͳͷ͸Ͳ͏͔ > const account = new Account(new UserID(5)) undefined > showBalance(account, “Կ΋͍ͯ͠ͳ͍”) 0 > showBalance(account, “200आΓͯɺ100ିͯ͠ɺ50ିͨ͠”) 50 ঢ়ଶΛ໌ࣔతʹ౉͢

Slide 49

Slide 49 text

͜Μͳͷ͸Ͳ͏͔ > const account = new Account(new UserID(5)) undefined > showBalance(account, “Կ΋͍ͯ͠ͳ͍”) 0 > showBalance(account, “200आΓͯɺ100ିͯ͠ɺ50ିͨ͠”) 50 Ҿ਺͕ҧ͏ͷͰɺࢀর౳Ձੑ͕อͨΕͨʂ ঢ়ଶΛ໌ࣔతʹ౉͢

Slide 50

Slide 50 text

ঢ়ଶΛ൐͏ܭࢉʹ͍ͭͯ State monad

Slide 51

Slide 51 text

ঢ়ଶΛ൐͏ܭࢉʹ͍ͭͯ State monad

Slide 52

Slide 52 text

4UBUFϞφυ > const account = new Account(new UserID(5)) undefined > const state = new State(“200आΓͯɺ100ିͯ͠ɺ50ିͨ͠”) undefined > showBalance(state.runState(account)) 50 ʂ ͜Ε͸งғؾΛઆ໌͢Δ΋ͷͳͷͰɺ·ͬͨ͘΋ͬͯ ਖ਼֬ͳίʔυͰ͸͋Γ·ͤΜ