ãŠãŒã¶ãŒãšããŠãã·ã¹ãã ã®ååãšé»åã¡ãŒã«ã倿Žãããã
ãã®åçŽãªãŠãŒã¶ãŒã¹ããŒãªãŒãå®è£
ããã«ã¯ãèŠæ±ãåä¿¡ããæ€èšŒããããŒã¿ããŒã¹å
ã®æ¢åã®ã¬ã³ãŒããæŽæ°ãããŠãŒã¶ãŒã«ç¢ºèªã¡ãŒã«ãéä¿¡ãããã©ãŠã¶ãŒã«å¿çãè¿ãå¿
èŠããããŸãã ã³ãŒãã¯CïŒã§ã»ãŒåãã«ãªããŸãã
string ExecuteUseCase() { var request = receiveRequest(); validateRequest(request); canonicalizeEmail(request); db.updateDbFromRequest(request); smtpServer.sendEmail(request.Email); return "Success"; }
ããã³FïŒïŒ
let executeUseCase = receiveRequest >> validateRequest >> canonicalizeEmail >> updateDbFromRequest >> sendEmail >> returnMessage
幞ããªæ
ããéžè±

ã¹ããŒãªãŒã远å ããŸãããïŒ
ãŠãŒã¶ãŒãšããŠãã·ã¹ãã ã®ååãšã¡ãŒã«ã倿Žããã
äœãåé¡ãçºçããå Žåã¯ããšã©ãŒã¡ãã»ãŒãžãåç
§ããŠãã ããã
äœãããããã®ã§ããããïŒ

- ååã空ã§ãã¡ãŒã«ãæ£ãããªãå¯èœæ§ããããŸã
- ãã®IDãæã€ãŠãŒã¶ãŒãããŒã¿ããŒã¹ã«èŠã€ãããªãå¯èœæ§ããããŸã
- 確èªã¡ãŒã«ã®éä¿¡äžã«ãSMTPãµãŒããŒãå¿çããªãå ŽåããããŸã
- ...
ãšã©ãŒåŠçã³ãŒãã远å ãã
string ExecuteUseCase() { var request = receiveRequest(); var isValidated = validateRequest(request); if (!isValidated) { return "Request is not valid" } canonicalizeEmail(request); try { var result = db.updateDbFromRequest(request); if (!result) { return "Customer record not found" } } catch { return "DB error: Customer record not updated" } if (!smtpServer.sendEmail(request.Email)) { log.Error "Customer email not sent" } return "OK"; }
çªç¶ã6è¡ã§ã¯ãªã18è¡ã®ã³ãŒãã«åå²ãšãã¹ãã远å ãããèªã¿ãããã倧å¹
ã«äœäžããŸããã ãã®ã³ãŒãã®æ©èœçã«åçãªãã®ã¯äœã§ããïŒ èŠãç®ã¯ãŸã£ããåãã§ãããä»ã§ã¯ãšã©ãŒåŠçããããŸãã ããªãã¯ç§ãä¿¡ããŠããªããããããŸããããç§ãã¡ãæåŸã«å°éãããšããããçå®ã§ããããšãããããŸãã
åœä»€åã®èŠæ±å¿çã¢ãŒããã¯ãã£

ãªã¯ãšã¹ããåçããããŸãã ããŒã¿ã¯ãããã¡ãœããããå¥ã®ã¡ãœããã«ãã§ãŒã³ã§éä¿¡ãããŸãã ãšã©ãŒãçºçããå Žåã¯ãæ©æåŸ©åž°ã䜿çšããŸãã
æ©èœçãªã¹ã¿ã€ã«ã®ãªã¯ãšã¹ã/ã¬ã¹ãã³ã¹ã¢ãŒããã¯ãã£

ã幞ããªæ
ãã§ã¯ããã¹ãŠããŸã£ããåãã§ãã 颿°ã®æ§æã䜿çšããŠãã¡ãã»ãŒãžããã§ãŒã³ã§åãæž¡ãåŠçããŸãã ãã ããäœãåé¡ãçºçããå Žåã¯ã颿°ããã®æ»ãå€ãšããŠãšã©ãŒã¡ãã»ãŒãžãæž¡ãå¿
èŠããããŸãã ãããã£ãŠã2ã€ã®åé¡ããããŸãã
- ãšã©ãŒãçºçããå Žåã«æ®ãã®æ©èœãç¡èŠããæ¹æ³ã¯ïŒ
- 1ã€ã§ã¯ãªã4ã€ã®å€ãè¿ãæ¹æ³ïŒãšã©ãŒã®çš®é¡ããšã«1ã€ã®æ»ãå€ïŒ
颿°ãè€æ°ã®å€ãè¿ãã«ã¯ã©ãããã°ããã§ããïŒ
æ©èœçPLã§ã¯ã
ãŠããªã³åãåºãæ®åããŠããŸãã ãããã®å©ããåããŠã1ã€ã®ã¿ã€ãã®ãã¬ãŒã ã¯ãŒã¯å
ã§ããã€ãã®å¯èœãªç¶æ
ãã·ãã¥ã¬ãŒãã§ããŸãã ãã®é¢æ°ã«ã¯1ã€ã®æ»ãå€ããããŸãããçŸåšã¯æåãŸãã¯ãšã©ãŒã®ã¿ã€ãã®4ã€ã®å¯èœãªå€ã®ãããããåããŸãã ããŒã¿ã®ã¢ãããŒããäžè¬åããããã«ã®ã¿æ®ã£ãŠããŸãã
Success
ãš
Failure
ã®2ã€ã®å€ã§æ§æããã
çµæã¿ã€ãã宣èšããããŒã¿ãšãšãã«æ±çšåŒæ°ã远å ããŸãã
type Result<'TEntity> = | Success of 'TEntity | Failure of string
æ©èœèšèš

- åãŠãŒã¹ã±ãŒã¹ã¯åäžã®é¢æ°ã§å®è£
ãããŸãã
- 颿°ã¯
Success
ãšFailure
ããåéåãè¿ããŸã - ãŠãŒã¹ã±ãŒã¹ãåŠçãã颿°ã¯ãããããã1ã€ã®ããŒã¿å€æã¹ãããã«å¯Ÿå¿ãããããå°ããªé¢æ°ã®æ§æã䜿çšããŠäœæãããŸã
- åã¹ãããã§ã®ãšã©ãŒã¯çµã¿åããããŠåäžã®å€ãè¿ããŸã
æ©èœçãªã¹ã¿ã€ã«ã§ãšã©ãŒãåŠçããæ¹æ³ã¯ïŒ

FPã«ç²ŸéããŠããéåžžã«è³¢ãå人ãããå Žåã¯ã次ã®ãããªå¯Ÿè©±ããããŸãã
- 颿°åæã䜿çšãããã®ã§ããããšã©ãŒãåŠçãã䟿å©ãªæ¹æ³ããããŸãã
- ãããããã¯ç°¡åã§ãã ã¢ãããå¿
èŠã§ã
- è€éã«èãããŸãã ãããŠãã¢ãããšã¯äœã§ããïŒ
- ã¢ããã¯ããšã³ããã¡ã³ã¯ã¿ãŒã®ã«ããŽãªãŒã«ãããã¢ãã€ãã§ãã
- ???
- åé¡ã¯äœã§ããïŒ
- ãšã³ããã¡ã³ã¯ã¿ãŒãšã¯äœãªã®ãããããŸãã
- ç°¡åã§ãã ãã¡ã³ã¯ã¿ãŒã¯ãã«ããŽãªãŒéã®æºååã§ãã ãããŠããšã³ããã¡ã³ã¯ã¿ãŒã¯ãã«ããŽãªãŒãããèªäœã«ãããã³ã°ããåãªããã¡ã³ã¯ã¿ãŒã§ã
- ãã¡ããã§ãïŒ ããã§ãã¹ãŠãæããã«ãªããŸãã...
ãªãªãžãã«ã®æ¬¡ã¯ã Maybe
ïŒãã¶ãïŒãšEither
ïŒãŸãã¯ã Either
ãäžæ¹ïŒã«åºã¥ãã翻蚳äžå¯èœãªãããã§ãã Maybe
ã Either
ãã¢ããåã§ãã è±èªã®ãŠãŒã¢ã¢ã奜ãã§ãFPã®çšèªããã¢ã«ãããã¯ãã ãšæãå Žåã¯ãå¿
ãå
ã®ã¬ããŒãããã§ãã¯ããŠãã ããã
MonadãšClaysleyã®ãããããšã®æ¥ç¶

Haskellã®ãã¡ã³ãªã誰ã§ããç§ã説æããã¢ãããŒãã
Either
ã¢ããã§ããããšã«æ°ä»ãã§ããããããã¯ãå·Šãã®å Žåã«ç¹åããã¿ã€ãã®ãšã©ãŒãªã¹ãã§ãã Haskellã§ã¯ã次ã®ããã«æžãããšãã§ããŸãã
type Result ab = Either [a] (b,[a])
ãã¡ãããç§ã¯ãã®ã¢ãããŒãã®çºæè
ã«ãªãããŸãããšã¯ããŠããŸããããééãšã®æããªé¡æšã®åäœè
ã ãšäž»åŒµããŠããŸãã ã§ã¯ããªãæšæºçãªHaskellã®çšèªã䜿çšããªãã£ãã®ã§ããïŒ ãŸããããã¯å¥ã®ã¢ããã¬ã€ãã§ã¯ãããŸããã 代ããã«ãäž»ãªçŠç¹ã¯ç¹å®ã®ãšã©ãŒåŠçåé¡ã®è§£æ±ºã«ãããŸãã FïŒãåŠã³å§ããã»ãšãã©ã®äººã¯ã¢ããã«æ
£ããŠããªãã®ã§ãç§ã¯å€ãã®äººã«ãšã£ãŠãåšå§çã§ãªããããèŠèŠçã§çŽæçãªã¢ãããŒãã奜ãã
第äºã«ãç¹å®ããäžè¬ãžã®ã¢ãããŒãããã广çã§ãããšç¢ºä¿¡ããŠããŸããçŸåšã®æœè±¡ãããçè§£ããŠããã°ãæ¬¡ã®æœè±¡ã®ã¬ãã«ã«ç»ãæ¹ãã¯ããã«ç°¡åã§ãã ã2ãã©ãã¯ãã¢ãããŒããã¢ãããšåŒã¶ãšãç§ã¯ééã£ãŠããã§ãããã ã¢ããã¯ããè€éã§ããããã®è³æã§ã¯
ã¢ããã®æ³åã
æ±ããããããŸããã
第äžã«ã
Either
ãããŸãã«ãäžè¬çãªæŠå¿µã§ãã ããŒã«ã§ã¯ãªããã¬ã·ãã玹ä»ããããšæããŸãã ãå°éºŠç²ãšãªãŒãã³ã䜿ãã ãããšãããã³ã®ã¬ã·ãã¯ããŸã圹ã«ç«ã¡ãŸããã ã
bind
ãš
Either
䜿çš
bind
ããšããã¹ã¿ã€ã«ã§ãšã©ãŒãåŠçããããã®ããã¥ã¢ã«ããŸã£ãã
Either
ãŸããã ãããã£ãŠã次ã®ãããªäžé£ã®ææ³ãå«ãçµ±åã¢ãããŒããæäŸããŸãã
Either String a
ãªããç¹æ®ãªãšã©ãŒã¿ã€ãã®ãªã¹ã- ãã€ãã©ã€ã³ã§ã¢ãã颿°ãæ§æããããã®
bind (>>=)
- ã¢ãã颿°ã®åæã®ããã®ã¯ã¬ã€ãºãªãŒåæïŒ
>=>
ïŒ - ãã€ãã©ã€ã³ã«éã¢ãã
fmap
ãçµ±åfmap
ããã®map
ããã³fmap
unit
ãè¿ã颿°ãçµ±åããtee
颿°ïŒFïŒã®void
ã«é¡äŒŒïŒ- äŸå€ããšã©ãŒã³ãŒãã«ãããã³ã°ãã
- 䞊ååŠçã§ã¢ãã颿°ãçµåããããã®
&&&
ïŒæ€èšŒãªã©ïŒ - ãã¡ã€ã³é§åèšèšïŒDDDïŒã§ãšã©ãŒã³ãŒãã䜿çšããå©ç¹
- ãã®ã³ã°ããã¡ã€ã³ã€ãã³ããè£åãã©ã³ã¶ã¯ã·ã§ã³ãªã©ã®æãããªæ¡åŒµ
ãã©ã¡ããã®ã¢ããã䜿çšããã以äžã®ããšã楜ããã§ãã ããã
ééã®é¡æš

ç§ã¯ãã®æ©èœãééãšå€æãã³ãã«ãšããŠè¡šãã®ã奜ãã§ãã ãªã³ãŽããããã«å€æããïŒ
apple â banana
ïŒããã³ä»ã®ãããããã§ãªãŒã«å€æããïŒ
banana â cherry
ïŒ2ã€ã®é¢æ°ããããããããçµã¿åãããŠããªã³ãŽããã§ãªãŒã«å€æããïŒ
apple â cherry
ïŒé¢æ°ãååŸããŸãã ããã°ã©ããŒã®èгç¹ããã¯ããã®é¢æ°ãã³ã³ããžã·ã§ã³ã䜿çšããŠååŸãããããæåã§äœæããããã«ããããããäž»ãªãã®ã¯ãã®çœ²åã§ãã
ãã©ãŒã¯
ããããå°ãç°ãªãã±ãŒã¹ããããŸãã1ã€ã®å€ãå
¥åã«ããã2ã€ã®å¯èœãªå€ãåºåã«ãããŸãã1ã€ã¯æ£åžžçµäºããã1ã€ã¯ãšã©ãŒã§ãã ãééãã®çšèªã§ã¯ããã©ãŒã¯ãå¿
èŠã§ãã
Validate
ããã³
UpdateDb
ã¯ããã®ãããªãã©ãŒã¯é¢æ°ã§ãã ããããäºãã«çµã¿åãããããšãã§ããŸãã
SendEmail
颿°ã
Validate
ããã³
SendEmail
ãŸãã ç§ã¯ããããè€ç·ã¢ãã«ããšåŒãã§ããŸãã äžéšã®äººã
ã¯ããã©ã¡ãã®ã¢ããããåŠçãããšã©ãŒã«å¯ŸããŠãã®ã¢ãããŒããåŒã³åºãããšã奜ã¿ãŸãããç§ã¯èªåã®ååã奜ã¿ãŸãïŒãã¢ããããšããåèªãå«ãŸããŠããªãããã ãã§ãïŒã

çŸåšããã·ã³ã°ã«ãã©ãã¯ãããã³ãããã«ãã©ãã¯ãæ©èœããããŸãã å¥ã
ã«ãäž¡æ¹ãšãé
眮ãããŸãããäºãã«é
眮ãããŸããã ãããè¡ãã«ã¯ãå°ããªãã¢ããã¿ãŒããå¿
èŠã§ãã æåããå Žåã¯ã颿°ãåŒã³åºããŠå€ãæž¡ããŸãããšã©ãŒãçºçããå Žåã¯ããšã©ãŒå€ã倿Žããã«ãã®ãŸãŸæž¡ããŸãã FPã§ã¯ããã®é¢æ°ã¯
bind
ãšåŒã°ããŸãã

çžã

let bind switchFunction = fun twoTrackInput -> match twoTrackInput with | Success s -> switchFunction s | Failure f -> Failure f // ('a -> Result<'b>) -> Result<'a> -> Result<'b>
ã芧ã®ãšããããã®é¢æ°ã¯éåžžã«åçŽã§ããã»ãã®æ°è¡ã®ã³ãŒãã§ãã 颿°ã®çœ²åã«æ³šæããŠãã ããã 眲åã¯FPã§éåžžã«éèŠã§ãã æåã®åŒæ°ã¯ãã¢ããã¿ãŒãã2çªç®ã®åŒæ°ã¯2ãã©ãã¯ã¢ãã«ã®å
¥åå€ãåºåã¯2ãã©ãã¯ã¢ãã«ã®å€ã§ãã
list
ã
asyn
ã
feature
ãŸãã¯
promise
ã䜿çšããŠãä»ã®ã¿ã€ãã§ãã®çœ²åã衚瀺ãããå Žåãåã
bind
ãŸãã ãã®é¢æ°ã¯ãããšãã°
LINQ
SelectMany
ãªã©ãå¥ã®æ¹æ³ã§åŒã³åºãããšãã§ããŸãããæ¬è³ªã¯å€ãããŸããã
æ€èšŒ

ããšãã°ã3ã€ã®æ€èšŒã«ãŒã«ããããŸãã
bind
ïŒåã«ãŒã«ããããã«ãã©ãã¯ã¢ãã«ãã«å€æããïŒãšé¢æ°æ§æã䜿çšããŠãããã€ãã®æ€èšŒã«ãŒã«ãããã§ãŒã³ãã§ããŸãã ããããšã©ãŒåŠçã®ç§å¯ã§ãã
let validateRequest = bind nameNotBlank >> bind name50 >> bind emailNotBlank
ããã§ãå
¥åèŠæ±ãåãå
¥ããŠå¿çãè¿ãã2ã¬ãŒã³ã颿°ãã§ããŸããã ä»ã®æ©èœã®æ§æèŠçŽ ãšããŠäœ¿çšã§ããŸãã
å€ãã®å Žåã
bind
>>=
æŒç®åã§ç€ºãããŸãã HaskellããåçšããŠããŸãã
>>=
ã䜿çšããå Žå
>>=
ã³ãŒãã¯æ¬¡ã®ããã«ãªããŸãã
let (>>=) twoTrackInput switchFunction = bind switchFunction twoTrackInput let validateRequest twoTrackInput = twoTrackInput >>= nameNotBlank >>= name50 >>= emailNotBlank
bind
åãã§ãã¯ã¯ä»¥åãšåãããã«æ©èœããŸãã æ§æå¯èœãªé¢æ°ãããå Žåã¯ã
bind
ãé©çšããåŸãæ§æå¯èœãªãŸãŸã«ãªããŸãã 颿°ãæ§æå¯èœã§ãªãå Žåã
bind
ã¯ããããŸããã
ãããã£ãŠããšã©ãŒåŠçã®åºç€ã¯æ¬¡ã®ãšããã§ãã
bind
ã䜿çšããŠé¢æ°ãã2ãã©ãã¯ã¢ãã«ãã«å€æããåæã䜿çšããŠããããçµåããŸãã ãã¹ãŠãæ£åžžã«ãªããŸã§ç·ã®ãã ã¡ã«æ²¿ã£ãŠç§»åãããããšã©ãŒã®å Žåã¯èµ€ã«å€ãããŸãã
ããããããã ãã§ã¯ãããŸããã ãã®ã¢ãã«ã«é©åããå¿
èŠããããŸã
- ãšã©ãŒã®ãªãã·ã³ã°ã«ãã©ãã¯æ©èœ
- è¡ãæ¢ãŸãã®æ©èœ
- äŸå€ã¹ããŒæ©èœ
- å¶åŸ¡æ©èœ
ãšã©ãŒã®ãªãã·ã³ã°ã«ãã©ãã¯æ©èœ

let canonicalizeEmail input = { input with email = input.email.Trim().ToLower() }
canonicalizeEmail
颿°ã¯éåžžã«ç°¡åã§ãã äœåãªã¹ããŒã¹ãåãæšãŠãã¡ãŒã«ãå°æåã«å€æããŸãã ãšã©ãŒãšäŸå€ãå«ããã¹ãã§ã¯ãããŸããïŒNREãé€ãïŒã ããã¯åãªãæåå倿ã§ãã
åé¡ã¯ã2ãã©ãã¯æ©èœã®ã¿ã
bind
ããŠäœæããããšãåŠãã ããšã§ãã ãã1ã€ã®ã¢ããã¿ãŒãå¿
èŠã§ãã ãã®ã¢ããã¿ãŒã¯
map
ãšåŒã°ã
map
ïŒ
LINQ
Select
ïŒã
let map singleTrackFunction twoTrackInput = match twoTrackInput with | Success s -> Success (singleTrackFunction s) | Failure f -> Failure f // map : ('a -> 'b) -> Result<'a> -> Result<'b>
map
ã¯
bind
ã䜿çšããŠäœæã§ããŸããããã®éã¯ã§ããªãããã
map
ã¯
bind
ããã匱ã颿°ã§ãã

è¡ãæ¢ãŸãæ©èœ

let updateDb request = // do something // return nothing at all
ãããããã¯é¢æ°ã¯ãç«ãšå¿åŽã®ç²Ÿç¥ã§ã®æžãèŸŒã¿æäœã§ããããŒã¿ããŒã¹ã®å€ãæŽæ°ãããããã¡ã€ã«ãæžã蟌ã¿ãŸãã æ»ãå€ã¯ãããŸããã ãŸããããã«ãã©ãã¯æ©èœã§ã¯æ§æããŸããã å¿
èŠãªã®ã¯ãå
¥åå€ãååŸãããããããšã³ãã颿°ãå®è¡ããå€ããã§ãŒã³ã®ããã«äžã«æž¡ãããšã§ãã
bind
ããã³
map
ãšã®é¡æšã«ãã
map
tee
颿°ïŒ
tap
ãšåŒã°ããããšããã
map
宣èšããŸãã
let tee deadEndFunction oneTrackInput = deadEndFunction oneTrackInput oneTrackInput

äŸå€ã¹ããŒæ©èœ

ãããããç¹å®ã®ããã¿ãŒã³ããçŸãå§ããŠããããšã«ãæ°ã¥ãã§ãããã ç¹ã«ãå
¥å/åºåã§æ©èœããæ©èœã ãã®ãããªã¡ãœããã®ã·ã°ããã£ã¯ãæ£åžžã«å®äºããããšã«å ããŠãäŸå€ãã¹ããŒããå¯èœæ§ãããããã远å ã®åºå£ç¹ãäœæãããããã§ãã ããã¯çœ²åããã¯èŠããŸãããç¹å®ã®é¢æ°ãã¹ããŒããäŸå€ãç¥ãããã«ãããã¥ã¡ã³ããããçè§£ããå¿
èŠããããŸãã
äŸå€ã¯ããã®2ãã©ãã¯ã¢ãã«ã«ã¯é©ããŠããŸããã ããããåŠçããŸãããïŒ
SendEmail
颿°ã¯å®å
šã«èŠããŸãããäŸå€ãã¹ããŒããå¯èœæ§ããããŸãã å¥ã®ãã¢ããã¿ãŒãã远å ãããã®ãããªãã¹ãŠã®é¢æ°ãtry / catchãããã¯ã§ã©ããããŸãã
ã ãããããªãã詊ããŠã¯ãããªã ã-ãšãŒãã§ãããå¶åŸ¡ãããŒã«äŸå€ã䜿çšããããšãæšå¥šããŠããŸããã Adam Sitnikã®äŸå€çãªäŸå€ ïŒè±èªïŒã®ã¬ããŒãã§ããã®ãããã¯ã«é¢ããå€ãã®è峿·±ãããšããããŸã ã
å¶åŸ¡æ©èœ

ãã®ãããªé¢æ°ã§ã¯ãããšãã°ãæåããæäœãŸãã¯ãšã©ãŒããããã¯ãã®äž¡æ¹ã®ã¿ããã°ã«èšé²ãããªã©ã远å ã®ããžãã¯ãå®è£
ããå¿
èŠããããŸãã è€éãªããšã¯äœããããŸãããåã®ã±ãŒã¹ãšã®é¡æšã«ãã£ãŠè¡ããŸãã
ãã¹ãŠããŸãšãã

Validate
ã
Canonicalize
ã
UpdateDb
ãããã³
UpdateDb
ã®æ©èœãçµã¿åãããŸããã 1ã€ã®åé¡ãæ®ã£ãŠããŸãã ãã©ãŠã¶ã¯ãããã«ãã©ãã¯ã¢ãã«ããçè§£ããŸããã ããã§ããåäžãã©ãã¯ãã¢ãã«ã«æ»ãå¿
èŠããããŸãã 颿°
returnMessage
ã远å ããŸãã æåã®å Žåã¯httpã³ãŒã200ãšJSONãè¿ãããšã©ãŒã®å Žåã¯
BadRequest
ãšã¡ãã»ãŒãžã
BadRequest
ãŸãã
let executeUseCase = receiveRequest >> validateRequest >> updateDbFromRequest >> sendEmail >> returnMessage
ãã®ããããšã©ãŒåŠçã®ãªãã³ãŒãã¯ãšã©ãŒåŠçã®ããã³ãŒããšåäžã«ãªããšçŽæããŸããã å°ãã ãŸããŠãæ°ããåå空éã®æ°ãã颿°ãçºè¡šããŸãããbindã®å·ŠåŽã®é¢æ°ãã©ããããŸãã
ãã¬ãŒã ã¯ãŒã¯ã®æ¡å€§
- èããããèšèšãšã©ãŒãèæ
®ããŸã
- 䞊åå
- ãã¡ã€ã³ã€ãã³ã
èããããèšèšãšã©ãŒãèæ
®ããŸã
ãšã©ãŒåŠçã¯ãœãããŠã§ã¢èŠä»¶ã®äžéšã§ããããšã匷調ããããšæã
ãŸã ã æåããã·ããªãªã«ã®ã¿çŠç¹ãåœãŠãŸãã æåããã·ããªãªãšæš©å©ã®ãšã©ãŒãå¹³æºåããå¿
èŠããããŸãã
let validateInput input = if input.name = "" then Failure "Name must not be blank" else if input.email = "" then Failure "Email must not be blank" else Success input // happy path type Result<'TEntity> = | Success of 'TEntity | Failure of string
æ€èšŒæ©èœãæ€èšããŠãã ããã ãšã©ãŒã«ã¯æååã䜿çšããŸãã ããã¯å«ãªã¢ã€ãã¢ã§ãã ãšã©ãŒçšã®ç¹å¥ãªã¿ã€ãã玹ä»ããŸãã FïŒã¯éåžžãenumã§ã¯ãªãunionåã䜿çšããŸãã ã¿ã€ãErrorMessageã宣èšããŸãã ããã§ãæ°ãããšã©ãŒãçºçããå ŽåãErrorMessageã«å¥ã®ãªãã·ã§ã³ã远å ããå¿
èŠããããŸãã ããã¯è² æ
ã®ããã«æãããããããŸãããããã®ãããªã³ãŒãã¯èªå·±ææžåãããŠãããããéã«è¯ããšæããŸãã
let validateInput input = if input.name = "" then Failure NameMustNotBeBlank else if input.email = "" then Failure EmailMustNotBeBlank else if (input.email doesn't match regex) then Failure EmailNotValid input.email else Success input // happy path type ErrorMessage = | NameMustNotBeBlank | EmailMustNotBeBlank | EmailNotValid of EmailAddress
ã¬ã¬ã·ãŒã³ãŒãã䜿çšããããšãæ³åããŠãã ããã ã·ã¹ãã ãã©ã®ããã«æ©èœãããã¯æ³åã§ããŸãããäœãééã£ãŠããã®ãæ£ç¢ºã«ã¯ããããŸããã èãããããã¹ãŠã®ãšã©ãŒã説æãããã¡ã€ã«ãããå Žåã¯ã©ããªããŸããïŒ ããã«éèŠãªããšã¯ãããã¯åãªãããã¹ãã§ã¯ãªãã³ãŒãã§ããããããã®æ
å ±ã¯é¢é£æ§ããããŸãã
ãã®ã¢ãããŒãã¯ãJavaã®ãã§ãã¯äŸå€ã«éåžžã«äŒŒãŠããŸãã 圌ããé¢éžããªãã£ãããšã¯æ³šç®ã«å€ããã
DDDãå®è·µããã°ããã®ã³ãŒãã«åºã¥ããŠããžãã¹ãŠãŒã¶ãŒãšã®ã³ãã¥ãã±ãŒã·ã§ã³ãæ§ç¯ã§ããŸãã ãã®ç¶æ³ãŸãã¯ãã®ç¶æ³ãã©ã®ããã«åŠçãããã«ã€ããŠè³ªåããå¿
èŠããããŸããããã«ãããèšè𿮵éã§ããã«å€ãã®ãŠãŒã¹ã±ãŒã¹ãæ€èšããããã«ãªããŸãã
æååããšã©ãŒã¿ã€ãã«çœ®ãæããåŸã
retrunMessage
颿°ã倿ŽããŠãã¿ã€ããæååã«å€æããå¿
èŠããããŸãã
let returnMessage result = match result with | Success _ -> "Success" | Failure err -> match err with | NameMustNotBeBlank -> "Name must not be blank" | EmailMustNotBeBlank -> "Email must not be blank" | EmailNotValid (EmailAddress email) -> sprintf "Email %s is not valid" email // database errors | UserIdNotValid (UserId id) -> sprintf "User id %i is not a valid user id" id | DbUserNotFoundError (UserId id) -> sprintf "User id %i was not found in the database" id | DbTimeout (_,TimeoutMs ms) -> sprintf "Could not connect to database within %i ms" ms | DbConcurrencyError -> sprintf "Another user has modified the record. Please resubmit" | DbAuthorizationError _ -> sprintf "You do not have permission to access the database" // SMTP errors | SmtpTimeout (_,TimeoutMs ms) -> sprintf "Could not connect to SMTP server within %i ms" ms | SmtpBadRecipient (EmailAddress email) -> sprintf "The email %s is not a valid recipient" email
倿ããžãã¯ã¯ã³ã³ããã¹ãã«äŸåããå ŽåããããŸãã ããã«ãããåœéåã¿ã¹ã¯ã倧å¹
ã«å®¹æã«ãªããŸããã³ãŒãããŒã¹å
šäœã«æ£åšããè¡ãæ¢ãã®ã§ã¯ãªããUIã¬ã€ã€ãŒã«å¶åŸ¡ãç§»ãçŽåã«1ã€ã®é¢æ°ã«å€æŽãå ããã ãã§æžã¿ãŸãã èŠçŽãããšããã®ã¢ãããŒãã«ã¯æ¬¡ã®å©ç¹ããããŸãã
- äœããããŸããããªãã£ããã¹ãŠã®å Žåã®ããã¥ã¡ã³ã
- ã¿ã€ãã»ãŒããæéåãã«ããããšã¯ã§ããŸãã
- é ãããã·ã¹ãã èŠä»¶ãæããã«ãã
- åäœãã¹ããç°¡çŽ å
- åœéåãç°¡çŽ åãã
䞊åå

æ€èšŒã®ããäŸã§ã¯ãã·ãŒã±ã³ã·ã£ã«ã¢ãã«ã¯ãã©ã¬ã«ã¢ãã«ã«æ¯ã¹ãŠäœ¿ãåæãå£ããŸããåãã£ãŒã«ãã®æ€èšŒãšã©ãŒãåãåã代ããã«ããã¹ãŠã®ãšã©ãŒãäžåºŠã«ååŸããŠåæã«ä¿®æ£ããæ¹ã䟿å©ã§ãã
ãã¢ã«æäœãé©çšããçµæãšããŠåãã¿ã€ãã®ãªããžã§ã¯ããååŸã§ããå Žåããã®ãããªæäœããªã¹ãã«ãé©çšã§ããŸãã ããã¯ã¢ãã€ãã®ç¹æ§ã§ãã ãã®ãããã¯ãããæ·±ãçè§£ããã«ã¯ãã
æ¶ã®ãªãã¢ãã€ã ããšããèšäºãèªãããšãã§ããŸãã
ãã¡ã€ã³ã€ãã³ã

å Žåã«ãã£ãŠã¯ãè¿œå æ
å ±ãäŒããå¿
èŠããããããããŸããã ãããã¯ãšã©ãŒã§ã¯ãªããæäœã®ã³ã³ããã¹ãã§ããã«éèŠãªãã®ã§ãã ãããã®ã¡ãã»ãŒãžããæåãããã¹ãã®æ»ãå€ã«è¿œå ã§ããŸãã
ãã®èšäºã®ç¯å²å€
- ãµãŒãã¹ã®å¢çãè¶ãããšã©ãŒã®åŠç
- éåæã¢ãã«
- è£åååŒ
- ãã®ã³ã°
ãŸãšã æ©èœçãªã¹ã¿ã€ã«ã®ãšã©ãŒåŠç

Result
ã¿ã€ããäœæããŸãã å€å
žçãªEither
ããã«æœè±¡çã§ã Left
ããããã£ãšRight
ããããã£ãå«ãŸããŠããŸãã ç§ã®Result
ã¿ã€ãResult
ãããå°éçãªãã®ã§ãã- ãã€ã³ãã䜿çšããŠã颿°ããããã«ãã©ãã¯ã¢ãã«ãã«å€æããŸã
- ã³ã³ããžã·ã§ã³ã䜿çšããŠåã
ã®æ©èœããªã³ã¯ããŸã
- ãšã©ãŒã³ãŒãã¯æåã®ã¯ã©ã¹ã®ãªããžã§ã¯ããšèŠãªããŸã
åç
§è³æ
- ãµã³ãã«ä»ãã®ãœãŒã¹ã³ãŒãã¯githubã§å
¥æã§ããŸã
- CïŒã§å®è£
ãããã¬ããŒãã«åºã¥ãHabréã®èšäº