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

DDD by Functional programming with TypeScript

Childhooooo
January 20, 2018

DDD by Functional programming with TypeScript

Gunma.web#30のLTスライドです。
勘違いがあればどうかご指摘ください。

参考
https://qiita.com/nunulk/items/7447e6dadae29a41af3d

Childhooooo

January 20, 2018
Tweet

More Decks by Childhooooo

Other Decks in Programming

Transcript

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

  23. ΤϯςΟςΟʢؔ਺ܕϓϩάϥϛϯάʣ
    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))];
    }
    }

    View full-size slide

  24. จࣈ͕খ͍͞

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

  29. ΤϯςΟςΟʢҰൠతͳΦϒδΣΫτࢦ޲ʣ
    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”;
    }
    }

    View full-size slide

  30. ΤϯςΟςΟΛ࢖͏ʢҰൠతͳΦϒδΣΫτࢦ޲ʣ
    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

    View full-size slide

  31. ΤϯςΟςΟΛ࢖͏ʢҰൠతͳΦϒδΣΫτࢦ޲ʣ
    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!

    View full-size slide

  32. ΤϯςΟςΟʢؔ਺ܕϓϩάϥϛϯάʣ
    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))];
    }
    }

    View full-size slide

  33. ΤϯςΟςΟΛ࢖͏ʢؔ਺ܕϓϩάϥϛϯάʣ
    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

    View full-size slide

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

    View full-size slide

  35. αʔϏε
    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]]);
    }

    View full-size slide

  36. αʔϏεΛ࢖͏
    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

    View full-size slide

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

    View full-size slide

  38. ҰൠతͳΦϒδΣΫτࢦ޲ͷ৔߹
    > 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

    View full-size slide

  39. ҰൠతͳΦϒδΣΫτࢦ޲ͷ৔߹
    > 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!

    View full-size slide

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

    View full-size slide

  41. ؔ਺ܕͰී௨ʹ΍ͬͯΈΔ
    > 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

    View full-size slide

  42. ؔ਺ܕͰී௨ʹ΍ͬͯΈΔ
    > 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
    ຊ౰ʹ͜ΕͰ͍͍ͷʁ

    View full-size slide

  43. ؔ਺ܕͰී௨ʹ΍ͬͯΈΔ
    > 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ͱ͍ͬͨঢ়ଶΛ͍࣋ͬͯΔ

    View full-size slide

  44. ͦΕͳΒͬͪ͜ͷ΄͏͕Θ͔Γ΍͍͢
    > 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

    View full-size slide

  45. ͦΕͳΒͬͪ͜ͷ΄͏͕Θ͔Γ΍͍͢
    > 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
    Ͱ΋ɺͲ͏΍ͬͯࢀর౳ՁੑΛอͭͷ͔

    View full-size slide

  46. ಄ͷྑ͍ਓ͸ߟ͑ͨ

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide