ããã¡ã€ã³ã¢ããªã³ã°ã«ããã颿°åãã¿ãŒã³â仿§ãã¿ãŒã³ãã翻蚳ããŸãã
æžç±ãå®è·µãã¡ã€ã³é§åèšèš (Object Oriented Selection)ããåºçãããŠããã¡ã€ã³é§åèšèšïŒDDDïŒã®ç¥å床ãäžãã£ãŠããŠããããã§ãã
ãã®DDDã«é¢é£ããåéã®ïŒã€ãšããŠãDSLïŒãã¡ã€ã³ç¹åèšèªïŒãæããããšãã§ãããšæããŸãã
ããã·ãã·ã¥ã»ãŽãŒã·ã¥ããïŒDebasish GhoshïŒã¯ãDSLã®ãšãã¹ããŒãã§ããå®è·µããã°ã©ãã³ã°DSLãïŒåé¡ "DSLs in Action"ïŒãšããæ¬ãåºãããŠããŸãããã®æ¬ã®ç¬¬ïŒç« ã®ã¿ã€ãã«ã¯ãããã¡ã€ã³ã®èšèãè©±ãæ¹æ³ãåŠã¶ããšãªã£ãŠããŸãã
ããã·ãã·ã¥ããã®ããã°èšäºã®ãã¡ã®ïŒã€ã"Functional Patterns in Domain Modeling - The Specification Pattern" ã«æ¹ãããŠã翻蚳ãããŸããã翻蚳èšäºã®å ¬éã«ã€ããŠãèè ãæ¬äººãã快諟é ããããã以äžã«æ²èŒãããŠé ããŸãã
ãã¡ã€ã³ã¢ããªã³ã°ã«ããã颿°åãã¿ãŒã³â仿§ãã¿ãŒã³
åæURLïŒhttp://debasishg.blogspot.in/2014/03/functional-patterns-in-domain-modeling.html
2014幎3æ31æ¥ææ
ãã¡ã€ã³ãã¢ããªã³ã°ãããšãã¯ããã¡ã€ã³ã®ãšã³ãã£ãã£ãšæ¯ãèããã¢ãã«åããããšãªãã¯ã»ãšãŽã¡ã³ã¹ãæžç±ããã¡ã€ã³é§åèšèšãã§è¿°ã¹ãããã«ãçŠç¹ãåãããã¹ãã¯ãã¡ã€ã³ããèªäœã ãèšèšãå®è£ ããã¢ãã«ã¯ããŠããã¿ã¹èšèªãèªã£ãŠããªããã°ãªããªããå®è£ ã«ã®éœåã«ãããå¶æçãªè€éæ§ãå€ã çããŠãããã¡ã€ã³ã®æ¬è³ªãæããããšãã§ããããã«ããããã ã衚çŸåã®è±ããªã¢ãã«ã«ããã«ã¯ãæ¡åŒµå¯èœã§ããããšãå¿ èŠã§ããããããŠãç§ãã¡ãæ¡åŒµæ§ã«ã€ããŠèªããšããé¢é£ããæ§è³ªãšããŠåææ§ãããã
颿°ã¯ããªããžã§ã¯ããããèªç¶ã«åæãè¡ããããã§ããã®èšäºã§ã¯ããã¡ã€ã³é§åèšèšã®ã³ã¢ãæããã¿ãŒã³ã®ãã¡ã®ïŒã€ãå®è£ ããããã«ã颿°åããã°ã©ãã³ã°ã®ã€ãã£ãªã ãçšãããŒ ä»æ§ãã¿ãŒã³ã ã 仿§ãã¿ãŒã³ã§æãå€ããŠãŒã¹ã±ãŒã¹ã¯ããã¡ã€ã³ã®ããªããŒã·ã§ã³ãå®è£ ããããšã§ããããšãªãã¯ã®DDDæ¬ã«ã¯ã仿§ãã¿ãŒã³ã«ã€ããŠæ¬¡ã®ããã«æžãããŠããïŒ
仿§ã®çšéã¯è€æ°ããããæãåºæ¬çãªæŠå¿µãäŒããŠããã®ã¯ãã©ããªãªããžã§ã¯ãã§ãè©äŸ¡ããŠãå®çŸ©ãããåºæºãæºãããŠãããã©ããã調ã¹ããšããäœ¿ãæ¹ã§ããã
仿§ã¯è¿°èªãšããŠå®çŸ©ãããããã«ãã£ãŠãæ¥åã«ãŒã«å士ãããŒã«è«çã䜿ã£ãŠäºãã«é£éãããŠçµåã§ããããã«ãªãããã®ããã«åæã®æŠå¿µãããã®ã§ããã®ãã¿ãŒã³ã«ã€ããŠèªããšãã¯åæä»æ§ïŒComposite SpecificationïŒãšããŠèªãããšãã§ããã ãããDDDã«ãããåçš®ã®æç®ã§ã¯ããããCompositeãã¶ã€ã³ãã¿ãŒã³ã䜿ã£ãŠå®è£ ããŠãããããäžè¬çã«ã¯ã¯ã©ã¹éå±€ãšã³ã³ããžã·ã§ã³ãçšããããŠããããã®èšäºã§ã¯ããã®ä»£ããã«é¢æ°åæã䜿ãã
仿§ã¯ã©ãã«ããã®ãïŒ
ã¢ãã«ãèšèšããéã«ããããåé¡ãšããŠãéçŽã«ãŒãããšã³ãã£ãã£ã®ããªããŒã·ã§ã³ãè¡ãã³ãŒããã©ãã«çœ®ãã®ãããšãã話ãããã
ãšã³ãã£ãã£ã®äžã§ããªããŒã·ã§ã³ããããïŒ ããã¯ãã¡ã ããšã³ãã£ãã£ãè¥å€§åããŠããŸããåããšã³ãã£ãã£ã®ã³ã¢ã§ããã³ã³ããã¹ãã«ãã£ãŠããªããŒã·ã§ã³ãå€ãããããšãããã
ã€ã³ã¿ãŒãã§ã€ã¹ã®äžéšãšããŠããªããŒã·ã§ã³ããããïŒ JSONã䜿ã£ãŠããã®å€åŽã§ãšã³ãã£ãã£ãæ§ç¯ãããããããªãããããã«ãããçš®ã®ããªããŒã·ã§ã³ã¯ã€ã³ã¿ãŒãã§ã€ã¹ã«å±ãããšèšããããããã«ããªããŒã·ã§ã³ã眮ãããšã«éåæã¯ç¡ãã
ãããããã£ãšãè峿·±ãããªããŒã·ã§ã³ã¯ããã¡ã€ã³ã¬ã€ã€ãŒã«å±ãããã®ã ãæ¥åã®ããªããŒã·ã§ã³ïŒãããã¯ä»æ§ïŒã§ããããšãªãã¯ã»ãšãŽã¡ã³ã¹ãä»ã®ãªããžã§ã¯ãã®ç¶æ ã«é¢ããå¶çŽãã®ã¹ããã®ãšå®çŸ©ããŠããã æ¥åã«ãŒã«ãšããŠããšã³ãã£ãã£ã次ã®åŠçãžæž¡ãåã«ããªããŒã·ã§ã³ããããªããã°ãªããªãã
åçŽãªäŸã§èããããæ³šæïŒOrderïŒãšã³ãã£ãã£ãšãã®ã¢ãã«ããããšãããæ°ããæ³šæã¯ãåŠçå·¥çšã«å ¥ãåã«ãäžèšã®ãã¡ã€ã³ã®ã仿§ããæºãããã®ãšããã
劥åœïŒvalidïŒãªæ³šæã§ãªããã°ãªããããã¡ã€ã³ãå¿ èŠãšããæ£åœãªæ¥ä»ãæ£åœãªåååç®ããšãã£ãå¶çŽã«åŸããªããã°ãªããªãã
æ£ããæš©éã§æ¿èªïŒapprovedïŒãããŠããªããã°ãªããªããåŠçå·¥çšã®æ¬¡æ®µéã«é²ããã®ã¯ãã®å Žåã ãã ã
顧客ããã©ãã¯ãªã¹ãã«èŒã£ãŠããªãããšãä¿èšŒãããããç¶æ ã審æ»ããªããã°ãªããªãã
泚æå¯èœãã©ããã調ã¹ããããåååç®ã®åšåº«ã確èªããªããã°ãªããªãã
åã ã®æé ã«åãããŠããŠã泚æã®åŠçå·¥çšã«æ²¿ã£ãŠé 次å®äºããŠããããã®ããã«ããŠã泚æã®åã«ã泚æå®è¡ã®çšæãæŽã£ãŠããã©ãããæ€èšŒãããã©ããã§ãšã©ãŒããããšã泚æã¯åŠçå·¥çšããå€ããŠãããã§åŠçãçµããããããŠãç§ãã¡ãèšèšããã¢ãã«ã¯ããã®é åºãç¥ã£ãŠããå¿ èŠãããããæé ã®äžéšãšããŠçµãã¹ãå¶çŽã¯ãã¹ãŠèª²ãå¿ èŠãããã
泚æãå€åãããã®ã¯æé ã ãã§ããâããã¯éèŠãªãã€ã³ãã ããã¹ãŠã®ä»æ§ã¯ãæåã®æ³šæã®ã³ããŒãå ¥åãšããŠåãåãããã¡ã€ã³ã«ãŒã«ãæ€èšŒåŸãåŠçå·¥çšã®æ¬¡ã®æé ãžé²ãŸããŠè¯ããã©ããå€å®ããã
å®è£ ãžâŠâŠ
ç§ãã¡ããããŸã§ã§åŠãã§ããããšããµãŸããŠãå®è£ ã«èœãšãããã§ã¿ããã
泚æã¯ãå°ãªããšãä»åã®æäœã®æµãã«ãããŠã¯ãäžå€ã®ãšã³ãã£ãã£ã«ã§ããã
ãã¹ãŠã®ä»æ§ã¯ïŒã€ã®æ³šæãå¿ èŠãšããããããããªãã¯ã«ãªã£ãŠããŠã仿§ã«æ³šæã€ã³ã¹ã¿ã³ã¹ãé æ¬¡æž¡ãããšã§ãAPIãã·ã³ãã«ã«ä¿ã€ããšãã§ããã
颿°åããã°ã©ãã³ã°ã®ååã«ãããäžèšã®åŠçæé ãåŒãšããŠã©ã®ããã«ã¢ãã«åã§ããããçµæãæåŸãŸã§åæå¯èœã«ä¿ã¡ã泚æå®äºåŸã®æ¬¡å·¥çšãžæž¡ãã«ã¯ã©ããããïŒæ¬¡å·¥çšã«ã€ããŠã¯ãããããŸãå¥ã®èšäºã§è°è«ãããïŒã
ãã¹ãŠã®é¢æ°ã¯äŒŒãã·ã°ããã£ãæã£ãŠããããã âç§ãã¡ã¯é¢æ°ããããã«åæããå¿ èŠãããã
ãããããšèª¬æãçè«ãæã¡åºããããããŸãã¯åºæ¬çãªãã«ãã£ã³ã°ãããã¯ã䜿ã£ãŠãã¡ã€ã³ãšãã¹ããŒããšãšããŸãšããå 容ãå®è£ ããŠãããã
type ValidationStatus[S] = \/[String, S] type ReaderTStatus[A, S] = ReaderT[ValidationStatus, A, S] object ReaderTStatus extends KleisliInstances with KleisliFunctions { def apply[A, S](f: A => ValidationStatus[S]): ReaderTStatus[A, S] = kleisli(f) }
ValidationStatusã¯ãã©ã®é¢æ°ãããçµæãšããŠè¿ãåãå®çŸ©ããŠãããããã¯ç¶æ SããŸãã¯äœããã®ç°åžžãå ±åãããšã©ãŒæååãšãªããæ£ç¢ºã«ã¯scalazã§å®è£ ãããŠããEitheråïŒå³åŽãæ£ïŒã§ããã
ãã®å®è£ ãåªããŠããã®ã¯ããã¹ãŠã®ã¡ãœããã§æ³šæãã©ã¡ãŒã¿ãç¹°ãè¿ãããããšãªãåŠçæé ãåŒã³åºãããããã ããã®ããã«ããã€ãã£ãªã ã®ïŒã€ãšããŠãReaderã¢ããã䜿ãããããããŠãç§ãã¡ã¯ãã§ã«ã¢ããâ\/ã¯ã¢ããã âãæã£ãŠãããããã§ãåŠççµæãã¢ãã倿åã䜿ã£ãŠç©ã¿äžããŠãããReaderTããã®äœæ¥ãåãæã€ãçµæå士ãçµã³ã€ããŠããããããããåãšããŠReaderTStatusãå®çŸ©ããã
次ã®ã¹ãããã¯ReaderTStatusã®å®è£ ã§ãã¯ã©ã€ã¹ãªãšåŒã°ããå¥ã®æœè±¡ã䜿ããscalazã©ã€ãã©ãªã䜿ã£ãŠãã¯ã©ã€ã¹ãªã®èšèã§ReaderTãå®è£ ãããå®è£ ã®è©³çްã«ç«ã¡å ¥ã話ã¯ããªãã§ããâããèå³ãããã®ã§ããã°ããŠãŒãžãŒã³ã«ããåªããè«æãåç §ããŠã»ããã
ããŠããµã³ãã«ã®ä»æ§ã¯ã©ã®ããã«ãªãã®ãïŒ
話ã«å ¥ãåã«ãåºæ¬çãªæœè±¡ãçšæããïŒããããããã®ãããããåçŽã«ããŠããïŒã
// åºåºã®æœè±¡ sealed trait Item { def itemCode: String } // ãµã³ãã«å®è£ case class ItemA(itemCode: String, desc: Option[String], minPurchaseUnit: Int) extends Item case class ItemB(itemCode: String, desc: Option[String], nutritionInfo: String) extends Item case class LineItem(item: Item, quantity: Int) case class Customer(custId: String, name: String, category: Int) // 泚æã®ã¹ã±ã«ãã³ case class Order(orderNo: String, orderDate: Date, customer: Customer, lineItems: List[LineItem])
ãããŠãäžèšã泚æãªããžã§ã¯ãã®å¶çŽãæ€æ»ãã仿§ã§ããã
// åºæ¬çãªããªããŒã·ã§ã³ private def validate = ReaderTStatus[Order, Boolean] {order => if (order.lineItems isEmpty) left(s"Validation failed for order $order") else right(true) }
ããã¯èª¬æçšã®äŸã«éããªãã®ã§ããã¡ã€ã³ã«ãŒã«ãå€ãå«ãŸããŠããããã§ã¯ãªãã éèŠãªã®ã¯ã颿°ãå®è£ ããããã«å®çŸ©ããåãã©ã䜿ã£ãŠãããã ã æ³šæã¯é¢æ°ã«å¯Ÿããæé»ã®åŒæ°ã§ã¯ãªãâããã¯ã«ãªãŒåãããã颿°ã¯ReaderTStatusãè¿ããReaderTStatusèªäœã¯ã¢ããã§ããããããã£ãŠãå¥ã®ä»æ§ãšäœµããŠåŠçå·¥çšãæé åããŠããããšãã§ãããã€ãŸããæ±ºããããé åºã®èŠæ±ããåŒæåããã°ã©ãã³ã°ã®æ çµã¿ã®äžã§è§£æ±ºã§ããã®ã ã
åéãããã¡ã€ã³ç¥èã«åºã¥ã仿§ã¯ã»ãã«ããã£ãã
private def approve = ReaderTStatus[Order, Boolean] {order => right(true) } private def checkCustomerStatus(customer: Customer) = ReaderTStatus[Order, Boolean] {order => right(true) } private def checkInventory = ReaderTStatus[Order, Boolean] {order => right(true) }
ããããäºãã«ã€ãªãããš
ãããããã¡ã€ã³ãäžããæäœé åºã衚ãã«ã¯ããããã®ããŒã¹ãã©ãã€ãªãã°è¯ãã®ã ãããã¢ãã«ã§åææ§ã«ããå©ç¹ã享åããã«ã¯ã©ãããã®ãïŒ ããã¯éåžžã«ç°¡åã ãåæã«é©ããåå®çŸ©ãšããé£ããä»äºã¯ãã§ã«çµãã£ãŠããã
以äžã®isReadyForFulfilmentã¡ãœããã§ã¯ãåæä»æ§ããå®çŸ©ããŠããŠãforå å 衚èšïŒfor-comprehensionïŒã§ãããŸããåã ã®ä»æ§ãã¹ãŠãé çªã«åŒã³åºããŠããã
def isReadyForFulfilment(order: Order) = { val s = for { _ <- validate _ <- approve _ <- checkCustomerStatus(order.customer) c <- checkInventory } yield c s(order) }
ãã®ããã«ãã¢ããã£ãã¯ãªçµåã«ãããé åºç«ãŠãããäžé£ã®åŠçããæœè±¡ã®åææ§ãä¿ã¡ã€ã€å®è£ ããããšãã§ãããæ¬¡åã¯ã泚æã®åŸå·¥çšãåæå¯èœã«ããæ¹æ³ããšã³ãã£ãã£ã®æ å ±ãèªãã ãã§ãªãå¯å€ãšããããæ¹ã«ã€ããŠãèŠãŠãããããã¡ããã颿°åã®ã¢ãããŒãã§ã
翻蚳åŸèš
ãã®èšäºã¯ãååŠè ã®ç§ããè䌞ã³ãããŠå匷ããªããèš³ãããã®ã§ããæšæ²ãéããŸãããã誀蚳çãå«ãŸããŠããå¯èœæ§ã¯ãããŸããããäœããããŸãããããææé ãããšå¹žãã§ãã
é¢é£èšäº
Practical DDD #1: Specificationãã¿ãŒã³ã®äŸ
ãã¡ã€ã³ã¢ãã«ã®ããã®åãDomain Kataãã䜿ã£ãŠã¿ãŸãã
åè
Modegramming Style: Scala Tips / Validation (10) - applicative
å®åè ã®ããã®ããããScalaz














