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
Sponsored
·
Your Podcast. Everywhere. Effortlessly.
Share. Educate. Inspire. Entertain. You do you. We'll handle the rest.
→
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
180
Svelteで作るページビルダー
childhooooo
0
280
JavaScriptを使わない(Phoenix LiveViewの紹介)
childhooooo
0
930
Other Decks in Programming
See All in Programming
The Past, Present, and Future of Enterprise Java
ivargrimstad
0
320
インターン生でもAuth0で認証基盤刷新が出来るのか
taku271
0
190
Architectural Extensions
denyspoltorak
0
250
GISエンジニアから見たLINKSデータ
nokonoko1203
0
190
Fluid Templating in TYPO3 14
s2b
0
120
Vibe Coding - AI 驅動的軟體開發
mickyp100
0
160
CSC307 Lecture 05
javiergs
PRO
0
490
Automatic Grammar Agreementと Markdown Extended Attributes について
kishikawakatsumi
0
180
AI Agent Dojo #4: watsonx Orchestrate ADK体験
oniak3ibm
PRO
0
140
CSC307 Lecture 06
javiergs
PRO
0
670
MUSUBIXとは
nahisaho
0
110
Python札幌 LT資料
t3tra
7
1.1k
Featured
See All Featured
30 Presentation Tips
portentint
PRO
1
200
Darren the Foodie - Storyboard
khoart
PRO
2
2.3k
Are puppies a ranking factor?
jonoalderson
1
2.6k
How to build a perfect <img>
jonoalderson
1
4.9k
State of Search Keynote: SEO is Dead Long Live SEO
ryanjones
0
110
Connecting the Dots Between Site Speed, User Experience & Your Business [WebExpo 2025]
tammyeverts
11
810
Jess Joyce - The Pitfalls of Following Frameworks
techseoconnect
PRO
1
61
Designing Powerful Visuals for Engaging Learning
tmiket
0
210
The Cost Of JavaScript in 2023
addyosmani
55
9.4k
Bridging the Design Gap: How Collaborative Modelling removes blockers to flow between stakeholders and teams @FastFlow conf
baasie
0
440
My Coaching Mixtape
mlcsv
0
43
The untapped power of vector embeddings
frankvandijk
1
1.6k
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 ʂ ͜ΕงғؾΛઆ໌͢ΔͷͳͷͰɺ·ͬͨͬͯ͘ ਖ਼֬ͳίʔυͰ͋Γ·ͤΜ