Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
DDD by Functional programming with TypeScript
Search
maku.
January 20, 2018
Programming
2
2.2k
DDD by Functional programming with TypeScript
Gunma.web#30のLTスライドです。
勘違いがあればどうかご指摘ください。
参考
https://qiita.com/nunulk/items/7447e6dadae29a41af3d
maku.
January 20, 2018
Tweet
Share
More Decks by maku.
See All by maku.
Agent on Rails - AIをDDDのレールの上で制御する
childhooooo
0
190
Svelteで作るページビルダー
childhooooo
0
280
JavaScriptを使わない(Phoenix LiveViewの紹介)
childhooooo
0
940
Other Decks in Programming
See All in Programming
余白を設計しフロントエンド開発を 加速させる
tsukuha
7
2.2k
Premier Disciplin for Micro Frontends Multi Version/ Framework Scenarios @OOP 2026, Munic
manfredsteyer
PRO
0
160
日本だけで解禁されているアプリ起動の方法
ryunakayama
0
350
kintone + ローカルLLM = ?
akit37
0
110
生成AIを活用したソフトウェア開発ライフサイクル変革の現在値
hiroyukimori
PRO
0
130
Amazon Bedrockを活用したRAGの品質管理パイプライン構築
tosuri13
5
870
Vibe Coding - AI 驅動的軟體開發
mickyp100
0
190
Oxlintはいいぞ
yug1224
5
1.4k
責任感のあるCloudWatchアラームを設計しよう
akihisaikeda
3
190
Gemini for developers
meteatamel
0
120
izumin5210のプロポーザルのネタ探し #tskaigi_msup
izumin5210
1
320
個人開発は儲からない - それでも開発開始1ヶ月で300万円売り上げた方法
taishiyade
0
110
Featured
See All Featured
RailsConf & Balkan Ruby 2019: The Past, Present, and Future of Rails at GitHub
eileencodes
141
35k
The AI Revolution Will Not Be Monopolized: How open-source beats economies of scale, even for LLMs
inesmontani
PRO
3
3.1k
Jess Joyce - The Pitfalls of Following Frameworks
techseoconnect
PRO
1
77
Stop Working from a Prison Cell
hatefulcrawdad
273
21k
Accessibility Awareness
sabderemane
0
65
Leo the Paperboy
mayatellez
4
1.4k
How to build a perfect <img>
jonoalderson
1
5.2k
SEO Brein meetup: CTRL+C is not how to scale international SEO
lindahogenes
0
2.4k
Pawsitive SEO: Lessons from My Dog (and Many Mistakes) on Thriving as a Consultant in the Age of AI
davidcarrasco
0
72
svc-hook: hooking system calls on ARM64 by binary rewriting
retrage
1
120
The Illustrated Children's Guide to Kubernetes
chrisshort
51
51k
Faster Mobile Websites
deanohume
310
31k
Transcript
with TypeScript υϝΠϯۦಈઃܭͱؔܕϓϩάϥϛϯά 2017.02.20 Gunma.web#30 Hikaru Otabe
ࣗݾհ w େా෦ߊɹ!DIJMEIPPPPP w લϩέοτؔͷΈࠐΈΤϯδχΞʢ$ ʣ w ࠷ۙ8FCؔͷࣄ w $
1ZUIPO &MJYJS +BWB4DSJQU 1)1FUD Profile
ؔܕϓϩάϥϛϯάͱ͍͑ What comes to your mind ?
ֶ map Ϟφυ ෭࡞༻ ϥϜμࣜ ࢀরಁաੑ ԆධՁ ؔͷ߹ ΧϦʔԽ ΧϦʔԽ
ςετ ͳʹͦΕʁ ฒߦॲཧ ύλʔϯϚον ࠶ؼ
ֶ map Ϟφυ ෭࡞༻ ϥϜμࣜ ࢀরಁաੑ ԆධՁ ؔͷ߹ ΧϦʔԽ ΧϦʔԽ
ςετ ͳʹͦΕʁ ฒߦॲཧ ύλʔϯϚον ࠶ؼ
ࠓճ͢Δಛ lؔܕϓϩάϥϛϯάͰࢀরಁաੑ͕อূ͞ΕΔz
ࠓճ͢Δಛ lؔܕϓϩάϥϛϯάͰࢀরಁաੑ͕อূ͞ΕΔz ͞ΕΔͱ͍͏͔ɺ͢Δɻ
ࢀরಁաੑΛഁյ͢Δͷ Who breaks Referential transparency ?
1. ࠶ೖ 2. ɹมͷࢀরಁաੑΛഁյ ෭࡞༻ͷ͋Δؔ ɹؔͷࢀরಁաੑΛഁյ
࠶ೖʹΑΔࢀরಁաੑͷഁյ > var x = 1 undefined
࠶ೖʹΑΔࢀরಁաੑͷഁյ > var x = 1 undefined > x =
2 2
࠶ೖʹΑΔࢀরಁաੑͷഁյ > var x = 1 undefined > x =
2 2 > x 2
࠶ೖʹΑΔࢀরಁաੑͷഁյ > var x = 1 undefined > x =
2 2 > x 2 Broken!
࠶ೖʹΑΔࢀরಁաੑͷഁյ > var x = 1 undefined > x =
2 2 > x 2 > const y = 1 undefined > y = 2 TypeError Broken!
ؔͷ෭࡞༻ʹΑΔࢀরಁաੑͷഁյ > var counter = 0 undefined > const count
= (x) => counter += x undefined > count(3) 3 > count(3) 6
ؔͷ෭࡞༻ʹΑΔࢀরಁաੑͷഁյ > var counter = 0 undefined > const count
= (x) => counter += x undefined > count(3) 3 > count(3) 6 Broken!
υϝΠϯۦಈઃܭ Domain-Driven Design
υϝΠϯϞσϧͷߏཁૉ w ΦϒδΣΫτ w ΤϯςΟςΟ w αʔϏε w FUDʜ
υϝΠϯϞσϧͷߏཁૉ w ΦϒδΣΫτ w ΤϯςΟςΟ w αʔϏε w FUDʜ
υϝΠϯϞσϧͷߏཁૉ w ΦϒδΣΫτ w ΤϯςΟςΟ w αʔϏε w FUDʜ ؔܕϓϩάϥϛϯάͰͲͷΑ͏ʹදݱ͢Δ͔ʁ
υϝΠϯϞσϧͷߏཁૉ w ΦϒδΣΫτ w ΤϯςΟςΟ w αʔϏε w FUDʜ ؔܕϓϩάϥϛϯάͰͲͷΑ͏ʹදݱ͢Δ͔ʁ
ʂ ᘳͳ࣮ફ͍͠Ͱ͢
ۜߦޱ࠲ΞϓϦέʔγϣϯͷྫ
ΤϯςΟςΟʢؔܕϓϩάϥϛϯάʣ 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))]; } }
จࣈ͕খ͍͞
GitHub github.com/childhooooo/ddd-fp-ts
ΦϒδΣΫτ w ߴΛද࣌͢ɺ/VNCFSܕͰͳ͘ɺ#BMBODFܕΛ w ෆมੑʜҰੜͨ͠ΒɺଐੑΛมߋ͢Δ͜ͱग़དྷͳ͍ w ՁੑʜࢀরઌͰͳ͘ɺଐੑͰஅ Value objects
ΦϒδΣΫτ class Balance { constructor(public amount: number = 0) {
Object.freeze(this); } } const balance = new Balance(100); balance.amount = 50 //error
ΤϯςΟςΟ w ಉҰੑʜଐੑ͕ҟͳ͍ͬͯͯɺ*%͕ಉ͡ͳΒಉҰͷ ͷͱͯ͠ѻ͏ w ϥΠϑαΠΫϧͷ࿈ଓੑ Entities
ΤϯςΟςΟʢҰൠతͳΦϒδΣΫτࢦʣ 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”; } }
ΤϯςΟςΟΛ͏ʢҰൠతͳΦϒδΣΫτࢦʣ 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
ΤϯςΟςΟΛ͏ʢҰൠతͳΦϒδΣΫτࢦʣ 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!
ΤϯςΟςΟʢؔܕϓϩάϥϛϯάʣ 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))]; } }
ΤϯςΟςΟΛ͏ʢؔܕϓϩάϥϛϯάʣ 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
αʔϏε w ΦϒδΣΫτΤϯςΟςΟʹଐ͞ͳ͍ॏཁͳॲཧ w ಠཱͨ͠ΠϯλʔϑΣΠε w ঢ়ଶΛ࣋ͨͳ͍ Services
αʔϏε 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]]); }
αʔϏεΛ͏ 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
ঢ়ଶΛ͏ܭࢉʹ͍ͭͯ State monad
ҰൠతͳΦϒδΣΫτࢦͷ߹ > 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
ҰൠతͳΦϒδΣΫτࢦͷ߹ > 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!
ؔܕϓϩάϥϛϯάঢ়ଶΛ࣋ͨͳ͍ͣɾɾɾ
ؔܕͰී௨ʹͬͯΈΔ > 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
ؔܕͰී௨ʹͬͯΈΔ > 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 ຊʹ͜ΕͰ͍͍ͷʁ
ؔܕͰී௨ʹͬͯΈΔ > 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ͱ͍ͬͨঢ়ଶΛ͍࣋ͬͯΔ
ͦΕͳΒͬͪ͜ͷ΄͏͕Θ͔Γ͍͢ > 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
ͦΕͳΒͬͪ͜ͷ΄͏͕Θ͔Γ͍͢ > 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 ͰɺͲ͏ͬͯࢀরՁੑΛอͭͷ͔
಄ͷྑ͍ਓߟ͑ͨ
͜ΜͳͷͲ͏͔ > const account = new Account(new UserID(5)) undefined >
showBalance(account, “Կ͍ͯ͠ͳ͍”) 0 > showBalance(account, “200आΓͯɺ100ିͯ͠ɺ50ିͨ͠”) 50
͜ΜͳͷͲ͏͔ > const account = new Account(new UserID(5)) undefined >
showBalance(account, “Կ͍ͯ͠ͳ͍”) 0 > showBalance(account, “200आΓͯɺ100ିͯ͠ɺ50ିͨ͠”) 50 ঢ়ଶΛ໌ࣔతʹ͢
͜ΜͳͷͲ͏͔ > const account = new Account(new UserID(5)) undefined >
showBalance(account, “Կ͍ͯ͠ͳ͍”) 0 > showBalance(account, “200आΓͯɺ100ିͯ͠ɺ50ିͨ͠”) 50 Ҿ͕ҧ͏ͷͰɺࢀরՁੑ͕อͨΕͨʂ ঢ়ଶΛ໌ࣔతʹ͢
ঢ়ଶΛ͏ܭࢉʹ͍ͭͯ State monad
ঢ়ଶΛ͏ܭࢉʹ͍ͭͯ State monad
4UBUFϞφυ > const account = new Account(new UserID(5)) undefined >
const state = new State(“200आΓͯɺ100ିͯ͠ɺ50ିͨ͠”) undefined > showBalance(state.runState(account)) 50 ʂ ͜ΕงғؾΛઆ໌͢ΔͷͳͷͰɺ·ͬͨͬͯ͘ ਖ਼֬ͳίʔυͰ͋Γ·ͤΜ