ã©ããããã¨ãã ãã§ãã
æ¾å²¡ãã(id:little_hands)ã以ä¸ã®è¨äºãæ´æ°ãããããã§ããæ¾å²¡ããèªèº«ãæ©ã¾ããä¸ã§æ¤è¨ãããªãã·ã§ã³ã§ãã£ã¦ãå¯ä¸ã®æ£è§£ã§ã¯ãªãã¨è¸ã¾ããããã§ãçç´ãªææ³ãè¿°ã¹ããã¨æãã¾ããçµè«ããããã¨ãè«æ¨ã¯ååã®è¨äºã¨å¤ããã¾ããããã³ã¼ãä¾ã§å ·ä½çãªèãæ¹ã示ãã¦ããç¹ã工夫ãã¦ãã¾ãã
ååã®èå¯è¨äºãå¤ããªã£ãã®ã§ãææ°ã®è¨äºã«ä½µãã¦èå¯ãã¾ã¨ãç´ãããã¨æãã¾ãã
ãã¡ã¤ã³ã¢ãã«
ãã¡ã¤ã³ã¢ãã«å³ã追å ããã¦ãã¾ããã以ä¸ã®ï¼ã¤ã®éç´ãããããã§ãããä¸ã¤ã®éç´ã«ã¾ã¨ããã°ãããããã¨ããææ¡ã¯ãªãã¨ããåæã§èãã¾ãã
- ã¦ã¼ã¶ã¼
- ã¿ã¹ã¯
- ã¢ã¯ãã£ããã£ã»ã¬ãã¼ã
ãã¢ã¯ãã£ããã£ã»ã¬ãã¼ããã¯ãã¿ã¹ã¯ããããã¯ãã¦ã¼ã¶ã¼ãã«é¢é£ãæã¤ããã§ãã
ããããã®ã¢ãã«ãã©ã使ãããã®ãããç¥ããã¨ãã£ã¨æçãªè°è«ãã§ãããã§ããã¦ã¼ã¹ã±ã¼ã¹ããªãã¨ä½¿ããã¢ãã«ãã©ããå¤æã§ããªãã¨æãã¾ãâ¦ã
主ãªã¦ã¼ã¹ã±ã¼ã¹ã¯æ³å®ã§èãããªã以ä¸ã¨ãï¼ãã¡ã¤ã³ã®æ¯ãèãã«ãã©ã¼ã«ã¹ããããã«ãæå³çã«ã確èªããããã¯ãé²è¦§ãããã¦ã¼ã¹ã±ã¼ã¹ã¯çç¥ãã¾ããããã¢ã¯ãã£ããã£ã»ã¬ãã¼ããã¯ã¦ã¼ã¶ã¼ãä½ããã®ã§ã¯ãªããã·ã¹ãã å é¨ã§ä½ããããã®ã§ãããããã£ã¨ã
- ã¦ã¼ã¶ã¼ãã¦ã¼ã¶ã¼ã¢ã«ã¦ã³ããæ´æ°ãã
- ã·ã¹ãã ãã¦ã¼ã¶ã¢ã«ã¦ã³ãã®ã¢ã¯ãã£ããã£ã»ã¬ãã¼ãã追å ãã
- ã¦ã¼ã¶ã¼ãã¿ã¹ã¯ãä½æãã
- ã·ã¹ãã ãã¿ã¹ã¯ã®ã¢ã¯ãã£ããã£ã»ã¬ãã¼ãã追å ãã
ãã®ã¦ã¼ã¹ã±ã¼ã¹ã§ã¯CRUDèããããªãã®ã§ãããå°ãã¢ãã«ãæç«ããã«ã¼ã«ã¿ãããªãã®ãããã°é¢ç½ãã®ã§ããâ¦ã
以ä¸ã®ãããªéç´ã«ã¼ãã«ãªãã®ã§ãããã(ã³ã¼ãã¯Scalaã§ããdef
ãfun
ã«å¤ãã£ãããããªã®ã§èªããã¨æãã¾ã)ã
case class User(id: UserId, name: UserName, ...) { // ... } case class Task(id: TaskId, name: TaskName, userId: UserId, ...) { // ... } case class ActivityReport(id: ActivityId, taskId: Option[TaskId], userId: Option[UserId], ...) { // ... }
ã¢ã¯ãã£ããã£ã»ã¬ãã¼ãã«å¯¾ããéåæ
ä½åº¦ãã¢ã¯ãã£ããã£ã»ã¬ãã¼ãã¨ããååã声ã«åºãã¦ã¿ããæåã§å
¥åãã¦ã¿ããActivityReport
ã¨ããååã¯ActivityReport = Activity + Report
ã«å解ã§ããããReport
ã¯ä½ãããã®ã¬ãã¼ãå½¢å¼ãæ¡ç¨ããã®ãããããªããActivity
ãReport
ããã®ã ããActivityReport
ã®åã«ã¾ãActivity
ã¨ããæ¦å¿µã¯ããããã ãâ¦ãããã¨ãActivityReport
ã§ã¯ãªãActivity
ã¨ããååã®æ¹ãé©åï¼
ãããããµãã«ããã±ã¨ããã³ãã§ããã¨ãããã³ãããã¾ã使ã£ã¦ã¢ããªã³ã°ãæ·±æããã¦ããã¾ããã¢ãã«ã®è§£éãåºãã¦ããã¨ãã¯ãã±ããã¾ã使ãå¿ è¦ãããã¾ãããä»åã¯ããã³ããå ¥ãã¦ã¿ã¾ããããã®ãããã®è©±ã¯åå¼·ã®å²å¦ã«ããããæ¸ãã¦ããã®ã§åèã«ãã¦ã¿ã¦ãã ããã
åå¼·ã®å²å¦ãæ¥ããã¹ããã«ã®ããã«ãå¢è£ç (ææ¥æ庫)
- ä½è :åè é ä¹
- çºå£²æ¥: 2020/03/10
- ã¡ãã£ã¢: Kindleç
Activity
ãªããã¡ã¤ã³ã«é¢é£ãã¦ããã ããActivityReport
ã«ãªãã¨æ¥ã«ãã¥ã¼ã«è¦ãã¦ãã¾ãâ¦ãé ã®ä¸ã§ããã¯Activity
ã ã¨æã£ã¦è©±ããé²ãã¾ã(ã¨ããã§ãActivity
ã£ã¦ä½ï¼ããããéå»ã«èµ·ãã£ãåºæ¥äºï¼ããã¡ã¤ã³ã¤ãã³ãã«ä¼¼ã¦ã¾ããâ¦)ã
ããã«ãã¦ããActivityReport
ã®taskId
, userId
ã¯ã©ã¡ããä¸æ¹ãã使ãããªãããã§ãå¾®å¦ã§ããâ¦ãå¥ã
ã®åãéåã«è¦ãããTaskActivity
ãUserActivity
ã®ã»ãããããããããªãããâãªããããããããã©ããâã¯å¤åã«ã¦ã¼ã¶ã¼ã®é¢å¿ãå©å®³ã«çµã³ä»ãããã ã¾ããããç¥ãããâ¦ã
ãªã©ã¨ããã®æç¹ã§ãããããè«ããå±éããã¨ãæ¬é¡ã«å ¥ããªãã®ã§ããã®ã¢ãã«ã§ãããã¨ã«ãã¦è©±ãé²ããã¾ã(ç¬)ã
å®è£ æ¹æ³1. ã¦ã¼ã¹ã±ã¼ã¹ã§è¤æ°éç´ãæ´æ°ãã
ãè¤æ°éç´ã1ã¦ã¼ã¹ã±ã¼ã¹ã§æ´æ°ãã¦è¯ãã®ãï¼ãã«ã¤ãã¦
ã¦ã¼ã¹ã±ã¼ã¹ã¯ããæ©è½ãä¸é£ã®ããã°ã©ã (å¼æ¬¡ç¬¬ã®ã¤ã¡ã¼ã¸)ã¨ãã¦è¡¨ç¾ãããã®ã¨ç解ãã¦ãã¾ãããã®ããã«ãè¦ä»¶ã«ãã£ã¦ã¯è¤æ°ã®éç´ãå¼ã³åºããã¨ãããã§ããã®ä»¶ã¯åé¡ããªãã¨ããèªèãã¨ããããåã¯ããèªä½ã¯å¦å®ã¯ãã¦ãã¾ããããããè¤éãªã¦ã¼ã¹ã±ã¼ã¹ã§ã¯è¤æ°ã®åã®éç´ãå©ç¨ããå¿ è¦ãããã¾ãã ãªã®ã§ããã®ãããªå®è£ ã«ãªãã ããã¨æãã¾ãã
ãã ããè¤æ°éç´ã®æ´æ°ãåä¸ãã©ã³ã¶ã¯ã·ã§ã³ã«å«ãããã«ã¤ãã¦ã¯ç°è«ãããã¾ããéç´ã®ä¸ã§ã¯å¼·ãæ´åæ§(RDBã®ãã©ã³ã¶ã¯ã·ã§ã³ãªã©)ããå¤ã§ã¯å¼±ãæ´åæ§(çµææ´åæ§)ã使ãã¹ãã ããã§ããããã¯ååã®ããã°è¨äºã«æ¸ããéãã§ãã
ã¡ãªããã»ãã¡ãªããã«ã¤ãã¦
- ã¡ãªãã
- ç¹ã«ç°è«ã¯ãªãã§ãã
- ãã¡ãªãã
- ãã¢ã¯ãã£ããã£ã»ã¬ãã¼ããããæ´æ°ãå¿ãããã®ä»¶
- ä»æ§ãæºããã¦ããªãããã°ã©ã ãªã®ã§ãã°ã¨ãããã¨ãã¨æãã¾ããã¾ãã¯ããããã¹ãã表æã§å¯¾çã§ããªããããã¡ããåã§è¡¨æã§ããã°ãã¹ãã§ããããéããã¨ä»£åãããããã§ãããã«ã¤ãã¦ã¯ä»ã®å®è£ æ¹æ³ã¨ä½µãã¦å¾è¿°ãã¾ãã
- ãã£ãããæ´æ°ãå¿ããã以å¤ã®ãã¡ãªãããããã¾ã(åºæ¬çã«ååã®è¨äºã§æ¸ããéãã§ã)
- å¼·ãæ´åæ§ã®å¢çãæã¤éç´ããããå¤å´ã«äºéã«å¼·ãæ´åæ§ã®å¢ç(Transactionalã¢ããã¼ã·ã§ã³ã§å²ã£ã¦ããç¯å²)ãè¨ãã¦ããã¨ããç¹ã§ããæ¬æ¥ã¯éç´ã¨ãã©ã³ã¶ã¯ã·ã§ã³ã®å¢çãä¸è´ãã¦ãããã¨ãæã¾ããã®ã§ããã以ä¸ã®ãããªã¦ã¼ã¹ã±ã¼ã¹æ¯ã«å¼·ãæ´åæ§ã®å¢çãè¨å®ããã¦ãã¾ããã¦ã¼ã¹ã±ã¼ã¹ã®å
å´ã«å¼µãå·¡ãããããéç´ã®æ ãé£ã³è¶ããå¼·ãæ´åæ§ãåºã«ãã¸ãã¯ãçµã¾ãããã¨ã«ãªãã¾ãâ¦ãéç´ã¯ããåä½ã§æ´åæ§ãç¬ç«ããã¯ãã§ããããã®è¨è¨ã§ã¯ç¬ç«ãã¦ããªããã¨ã«ãªã£ã¦ãã¾ãããã§ãããã®ãããªç°å¢ä¸ã§ã¯ãäºã¤ã®éç´ã®é¢ä¿ã¯å¯çµåã«ãªããªã¹ã¯ãããã¾ããã¨ããã®ãDDDã¨ãã¦ã®ç«ã¦ä»ãã ã¨æãã¾ãã
- å人çã«ã¯ãä»åã®ã±ã¼ã¹ã§ã¯RDB以å¤ã¯ãªãæ³å®ã§ããããTransactionalã¢ããã¼ã·ã§ã³ãã¤ãã¦ã大ããªå®å®³ã¯ãªãããã§ããDDDã®éç´ã®èãæ¹ã«æ²¿ããªãçµææ´åã§ã¦ã¼ã¹ã±ã¼ã¹ãå®è£ ããã¹ãã§ããããã¡ãããã以å¤ã®è¨è¨ã®é¸æã¯ããã¾ã*1ãã¤ã¾ãã¨ãããã©ããªé¸æãããã«ãã¦ãè¨è¨(How)ã®ã³ã³ããã¹ã(Why)ã«ç´å¾æãããã°ããã®ã§ã¯ãªãã§ãããããã¨ã¯ããããã®ããã«éç´ã¨ã¯ç°ãªããã®ããéç´ãã¨å¼ã¶ã®ã¯ããããªãã®ãã¨æã£ã¦ãã¾ããæ¬æ¥ã®éç´ã¨ã¯éã解éã®ãéç´ãããå²ãçªçè«çã«æãããã¦ãã¾ããªã¹ã¯ãæ¸å¿µãã¾ãã
- å¼·ãæ´åæ§ã®å¢çãæã¤éç´ããããå¤å´ã«äºéã«å¼·ãæ´åæ§ã®å¢ç(Transactionalã¢ããã¼ã·ã§ã³ã§å²ã£ã¦ããç¯å²)ãè¨ãã¦ããã¨ããç¹ã§ããæ¬æ¥ã¯éç´ã¨ãã©ã³ã¶ã¯ã·ã§ã³ã®å¢çãä¸è´ãã¦ãããã¨ãæã¾ããã®ã§ããã以ä¸ã®ãããªã¦ã¼ã¹ã±ã¼ã¹æ¯ã«å¼·ãæ´åæ§ã®å¢çãè¨å®ããã¦ãã¾ããã¦ã¼ã¹ã±ã¼ã¹ã®å
å´ã«å¼µãå·¡ãããããéç´ã®æ ãé£ã³è¶ããå¼·ãæ´åæ§ãåºã«ãã¸ãã¯ãçµã¾ãããã¨ã«ãªãã¾ãâ¦ãéç´ã¯ããåä½ã§æ´åæ§ãç¬ç«ããã¯ãã§ããããã®è¨è¨ã§ã¯ç¬ç«ãã¦ããªããã¨ã«ãªã£ã¦ãã¾ãããã§ãããã®ãããªç°å¢ä¸ã§ã¯ãäºã¤ã®éç´ã®é¢ä¿ã¯å¯çµåã«ãªããªã¹ã¯ãããã¾ããã¨ããã®ãDDDã¨ãã¦ã®ç«ã¦ä»ãã ã¨æãã¾ãã
- ãã¢ã¯ãã£ããã£ã»ã¬ãã¼ããããæ´æ°ãå¿ãããã®ä»¶
ãå®è£ æ¹æ³2. ã¦ã¼ã¹ã±ã¼ã¹ã§è¤æ°éç´ãæ´æ°ãããããå®è£ æ¹æ³3. ãã¡ã¤ã³ã¤ãã³ãã使ç¨ãããã«ã¤ãã¦
çµè«ããããã¨ãããå æ¸ãé£ããã¨ããã§ãããå®è£ æ¹æ³2ãå®è£ æ¹æ³3ããæ´æ°æ¼ããé²ããããã«ä½è¨ãªè¤éããå°å ¥ãã¦ãã¾ã£ã¦ããã¨æãã¾ãã
å®è£ æ¹æ³1ã§ãã£ã¦ãã以ä¸ã®æ¹æ³ã§æ£ãããæ¤è¨¼ããã°ããã®ã§ã¯ãªãã§ãããã
- ãã¹ãã§æ¯ãèããæ£ãããã¨ãæ¤è¨¼ãã
- ã¦ã¼ã¹ã±ã¼ã¹ã®executeã¡ã½ããã®äºå¾æ¡ä»¶ã表æãã
ãã¡ããããã®å ´åã§ããã¹ããäºå¾æ¡ä»¶èªä½ãééã£ã¦ãããã©ãããã®ãããã¹ããæ£ããã¦ãä»æ§ãééã£ã¦ãããã©ãããã®ããä»æ§ãæ£ããã¦ãè¦ä»¶ãééã£ã¦ãããâ¦ãªã©ã¨ç¡éã«ç¶ãã¾ããæ¾å²¡ããææ¡ã®æ¹æ³ã§ããTaskCreateParameter
ãééã£ã¦å®è£
ãã¦å©ç¨ããã¨ãçµå±æå¾
ããæ£ãããå¾ããã¨ãã§ãã¾ããã
ã¤ã¾ãã¨ããã½ããã¦ã§ã¢ã®ããããæ£ããã¨ã¯ç¸å¯¾çãªæ¦å¿µãªã®ã§ã(åºå ¸ ãªãã¸ã§ã¯ãæåå ¥é 第11ç« å¥ç´ã«ããè¨è¨ï¼ä¿¡é ¼æ§ã®é«ãã½ããã¦ã§ã¢ãæ§ç¯ãã)ãæ£ããã®è¨¼æã¯æ¬æ¥ééããªãã®ã§ãã³ã¹ãã¨ãªã¿ã¼ã³ã®åè¡¡ãåããé©å½ãªã¨ããã§çµ¶å¦ã«å¦¥åããå¿ è¦ãããã¾ãããã¡ã¤ã³ãªãã¸ã§ã¯ãã®åã¨ãã¦ééã£ã使ãæ¹ãã§ããªãããã«èãããã¨ã¯éè¦ãªãã¨ã§ããããã®ããã«è¤éãªã³ã¼ããçµã¿è¾¼ãã§ãã¾ãããããªããç«ã¡æ¢ã¾ã£ã¦ãã¹ãã表æã®ç¯å²ã«çãã¾ãã
- ä½è :ãã¼ãã©ã³ãã»ã¡ã¤ã¤ã¼
- çºå£²æ¥: 2007/01/10
- ã¡ãã£ã¢: åè¡æ¬ï¼ã½ããã«ãã¼ï¼
ã¾ã確ãã«ããã¢ã¤ãã¢ãæãã¤ãã¦ãå¢ãã§ãªãã¡ã¯ã¿ãªã³ã°ãããã¨ãããã¾ãããããããã¨ãã»ã©ããã¯ãã¹çå群(åºå ¸ ã¬ã¬ã·ã¼ã½ããã¦ã§ã¢æ¹åã¬ã¤ã 4.1 è¦å¾ãããªãã¡ã¯ã¿ãªã³ã°)ãçºçããªãããã«ãä¸åº¦å·éã«ãªã£ãæ¹ãè¯ãã¨æã£ã¦ãã¾ãã
ã¬ã¬ã·ã¼ã½ããã¦ã§ã¢æ¹åã¬ã¤ã (Object Oriented Selection)
- ä½è :ã¯ãªã¹ã»ãã¼ãã£ã«
- çºå£²æ¥: 2016/11/11
- ã¡ãã£ã¢: åè¡æ¬ï¼ã½ããã«ãã¼ï¼
ãå®è£ æ¹æ³3. ãã¡ã¤ã³ã¤ãã³ãã使ç¨ãããã«ã¤ãã¦ãããæ´æ°æ¼ããé²ãããã¨ã¨å¤©ç§¤ã«ããã¦ãã©ã³ã¹ã§ããã§ãããããåã¯ããæãã¾ãããEvent Sourcingãã·ã¹ãã ã®èé害æ§ãã¹ã±ã¼ã©ããªãã£ã確ä¿ããããã«å°å ¥ãããªãããã¡ã¤ã³ã¤ãã³ããæ¡ç¨ãã価å¤ã¯ããããã§ããâ¦ð¤
ãããã©ãããã®
ãæ´æ°æ¼ããé²ããã¯ä¸è¨ã®æ¹æ³ã§ãã©ã³ã¹ãã¨ããã¨ã«ãã¦ãã¦ã¼ã¹ã±ã¼ã¹é¨åãã©ãå®è£ ãããè¯ãããèãã¦ã¿ã¾ããã大è¢è£ãªä»çµã¿ãå°å ¥ããªãã§ãçµææ´åã«ããæ¹æ³ã¯ããã¨ãã話ã§ãã
ã¦ã¼ã¹ã±ã¼ã¹ãRDBã®ãã©ã³ã¶ã¯ã·ã§ã³å¢çã«ããªã
ã¦ã¼ã¹ã±ã¼ã¹ã®execute
ã¯åä¸ãã©ã³ã¶ã¯ã·ã§ã³ã«å«ããã«ã以ä¸ã®ããã«ãã¾ãã(1),(2)ã¯ããããç¬ç«ãããã©ã³ã¶ã¯ã·ã§ã³ã«ãªãã¾ãã
class CreateTaskUseCase1( taskRepository: TaskRepository, activityReportRepository: ActivityReportRepository, ) { def execute(taskName: String): Unit = { val task = Task(taskName) taskRepository.store(task) // (1) ãªãã¸ããªå ã§ãã©ã³ã¶ã¯ã·ã§ã³ãéãã val activityReport = ActivityReport(task) activityReportRepository.store(activityReport) // (2) ãªãã¸ããªå ã§ãã©ã³ã¶ã¯ã·ã§ã³ãéãã } }
æ³å®åçéã¯ä»¥ä¸ã§ãã
- Q1, (1)â(2)ã®é ã«å¦çã(2)ã失æãããã©ãããã®ï¼
- æ®éã« å¼ã³åºãå ã«ã¯ã¨ã©ã¼ãè¿ãã¾ããã¯ã©ã¤ã¢ã³ãã«ãã¨ã©ã¼ãè¿ãã¾ãã
- Q2,
Task
ã ãä¿åãããã¨Task
ã¨ActivityReport
ãçµåããã¯ã¨ãªããããããªãã®ã§ã¯ï¼Task LEFT JOIN ActivityReport
ã ã¨ãããããªãã¾ãããã (1)â(2)ã®é åºãªãActivityReport LEFT JOIN Task
çãªã¯ã¨ãªãããã°åé¡ã¯ããã¾ããã
- Q3, ã¦ã¼ã¹ã±ã¼ã¹ã¯åå®è¡ããã¨åãã¿ã¹ã¯IDã§
INSERT
ããã®ã§å¤±æããã®ã§ã¯ï¼- åãã¿ã¹ã¯IDãªãã
INSERT
orUPDATE
ãã¦ãã ãã- ã¤ã¾ãã¯ã©ã¤ã¢ã³ããã¦ã¼ã¹ã±ã¼ã¹ãåå®è¡ã§ããããã«ãªã£ã¦ããªãã¨ããã¾ãããã¹ãçæ§ãæ ä¿ããå¿ è¦ãããã¾ã
- é½åº¦IDçæãããªããã´ã
Task
ãæ®ããã¨ã«ãªãã¾ã- 失ææã®ã´ãã¬ã³ã¼ã vs åä¸ãã©ã³ã¶ã¯ã·ã§ã³ã«ãã£ã¦ãã¸ãã¯ãå¯çµåã«ãªããªã¹ã¯ã®ãã¬ã¼ããªãã«ãªãã¾ã
- åãã¿ã¹ã¯IDãªãã
çµææ´åã®å ´åã¯ããã¹ã¦ã®æ´æ°ãå®äºããã°çµæçã«æ£ããç¶æ ã«åæãã¾ããæ´æ°ä¸ã¯ä¸éç¶æ ãè¦ããããããã¾ãããããã«ãã£ã¦ãã¸ãã¹ä¸å¤§ããªåé¡ãèµ·ããªãããã«æ³å®ãã¦ããå¿ è¦ãããã¾ãã
ãã®èãæ¹ã§å®éã«éç¨ãããã¨ããã®ï¼ã£ã¦è©±ã§ãããããã¾ããèªè¨¼/èªå¯ã«é¢ä¿ãããã¨ããã¦ã§ãã¢ããªã±ã¼ã·ã§ã³ããã®èãæ¹ã§è¨è¨ãã¦æ°å¹´éç¨ãã¦ãã¾ãããå®ç¨ä¸æ´åæ§ã«é¢ããåé¡ã¯ããã¾ãããéã«ä½ã§ãããã§ããã©ã³ã¶ã¯ã·ã§ã³ã«å«ããã¦ã¼ã¹ã±ã¼ã¹ã«ãã£ã¦ãã©ã³ã¶ã¯ã·ã§ã³å¢çãã¡ãã¯ãã«ç°ãªãã±ã¼ã¹ã§ã¯ãããããªåé¡(ä¸çªã¤ãããã¤ã¯ãããããã¯â¦)ãèµ·ãããã¨ãä½é¨ãã¦ãã¾ãâ¦ã
Taskãæ´æ°ããã¦ã¼ã¹ã±ã¼ã¹ã§ã¯
ä»åã®å ´åã¯æ°è¦è¿½å ãªã®ã§ã¬ã¼ã¹ã³ã³ãã£ã·ã§ã³ã¯èµ·ãããªãã§ãããæ¢åã®éç´ãæ´æ°ããã¦ã¼ã¹ã±ã¼ã¹ãèãã¦ã¿ã¾ãã
class RenameTaskUseCase1( taskRepository: TaskRepository, activityReportRepository: ActivityReportRepository, ) { def execute(taskId: TaskId, taskName: TaskName): Unit = { val task = taskRepository.findById(taskId) // (F1) val renamedTask = task.withTaskName(taskName) taskRepository.store(renamedTask) // (S2) val activityReport = ActivityReport(task) activityReportRepository.store(activityReport) // (S3) } }
ä¸è¨ã®ã³ã¼ãã§ã¯ä»¥ä¸ã®ããã«Aã¨Bã®ä¸¦è¡å¦çãããå ´åãäºã¤ã®æä½ã«åé¢æ§ãç¬ç«æ§ããªãã®ã§ãæå¾ ããçµæã«ã¯ãªãã¾ããã
(A-F1) -> (A-S1) -> (B-F1) -> (B-S1) -> (B-S2) -> (A-S2) -> ...
ããã¯ããã¯ãå°å
¥ããã°è§£æ±ºã§ãã¾ããã¯ã©ã¤ã¢ã³ããµã¼ãåã®ã·ã¹ãã ã§ã¯ãSELECT ... FROM ... FOR UPDATE
ã§æ²è¦³çããã¯ãå©ç¨ãããã¨ãããã¾ãããå
¥åâ確èªâæ´æ°ãããããªã¦ã§ãã®ã¦ã¼ã¹ã±ã¼ã¹ã§ã¯ãªã¯ã¨ã¹ããè·¨ãã£ã¦ãã©ã³ã¶ã¯ã·ã§ã³ãä¿æãç¶ããã«ã¯ç¡çãããã¾ããã¨ãããã¨ã§ãã¦ã§ãã§ã¯æ¥½è¦³ããã¯ã使ããã¨ãå¤ãã§ãã
class RenameTaskUseCase1( taskRepository: TaskRepository, activityReportRepository: ActivityReportRepository, ) { def execute(taskId: TaskId, taskName: TaskName, taskVersion: TaskVersion): Unit = { val task = taskRepository.findById(taskId, taskVersion) // (F1) val renamedTask = task.rename(taskName) taskRepository.store(renamedTask) // (S2) val activityReport = ActivityReport(task) activityReportRepository.store(activityReport) // (S3) } }
ä¸è¨ã®å ´åã¯ãBã®F1ã¯ãã¼ã¸ã§ã³ããã§ã«æ´æ°ããã¦ããã®ã§Task
ãåå¾ã§ããªãããããã¯Bã®(S2)ã§ãã¼ã¸ã§ã³ãé²ãã§ããããä¿åã«å¤±æããã®ã§ãã¦ã¼ã¹ã±ã¼ã¹ã®å¦çã¯ã¨ã©ã¼ã«ãªããã¼ã¿ã®ä¸æ´åãé²ãã¾ãã (S3)ã楽観ããã¯ãæä¾ãã¦ãããã§ããã常ã«è¿½è¨ã«ãªããªãä¸è¦ã§ãããã
RDBéä¾åã®è¯ã
åè¿°ããããã«ãã¦ã¼ã¹ã±ã¼ã¹ãRDBéä¾åã¨ãã¦è¨è¨ãã¦ããã°ããªãã¸ããªã®ã¹ãã¬ã¼ã¸ãRDBã§ãNoSQLã§ããããªãã¾ããå¥ã®ãã¤ã¯ããµã¼ãã¹ä¸ã«åå¨ããéç´ãå¼ã³åºããã¨ãå¯è½ã§ããä»ã©ãã®åæ£ããã·ã¹ãã ã«ããã¦ã¯ãRDBã®ãã©ã³ã¶ã¯ã·ã§ã³ã¯ä¸ã¤ã®é¸æè¢ã§ãããããããå±é¢ã§ä½¿ããããã§ã¯ããã¾ããã
éãè¨ãã°ãRDBãã使ããªãã·ã¹ãã ãªãä¸è¨ã¯èæ ®ããã«ãã¦ã¼ã¹ã±ã¼ã¹ãRDBã®ãã©ã³ã¶ã¯ã·ã§ã³å¢çã«ãã¦ãåé¡ãªãã§ãããããã£ãã»ãã¨ã«ï¼åæ£ãã£ãã·ã¥ã使ãããã¨ãSQSã使ãããã¨ãå¾ããè¨ããªãã§ãï¼ã£ã¦æå³ã«ãªãã¾ãã
å®éãå¾ããRedis, Memcachedãªã©åæ£ãã£ãã·ã¥ããSQSãKafkaãªã©ã®ã¡ãã»ã¼ã¸ã³ã°åºç¤ãªã©ãå¿ è¦ãããã¨ã¯ããããã¾ããã¬ãã¥ã¼ã§å®éãã£ãã®ã¯ãRDBåæã«ãªã£ã¦ãã¾ã£ãã¦ã¼ã¹ã±ã¼ã¹ã»ãã¸ãã¯ã«ã以ä¸ã®ãããªã³ã¼ãã追å ãããäºä¾ãããã¾ããâ¦ãã¾ããã£ãã·ã¥ã ãæ®ããã¨ããã¾ãããâ¦ãèªè ã®ã¿ãªããã¯ãããªééããããªãã¨æãã¾ãããRDBã¯ä¾¿å©ãªã®ã§ããããã®ã±ã¼ã¹ã§ã¯ä½¿ãæ¹ãééã£ã¦ããã¨è¨ããããå¾ã¾ãããåè¿°ããããã«çµææ´åã®èãæ¹ã§ã¦ã¼ã¹ã±ã¼ã¹ãæ¸ãç´ããã»ããç¡é£ã§ãã
class RenameTaskUseCase1( taskRepository: TaskRepository, activityReportRepository: ActivityReportRepository, ) { @Transcational def execute(taskId: TaskId, taskName: TaskName): Unit = { val task = taskRepository.findById(taskId) val renamedTask = task.rename(taskName) taskRepository.store(renamedTask) // (1), ãã£ãã·ã¥ã¨ãã¦Redisã«æ¸ãè¾¼ãã§ããã // (2)ã§ãã¼ã«ããã¯ãã¦ãRedisã«æ°¸ç¶åããããã¼ã¿ã¯ãã¼ã«ããã¯ã§ããªã⦠taskCacheRepository.store(renamedTask) val activityReport = ActivityReport(task) // (2), DB I/Oã¨ã©ã¼ãçºçããã¼ã«ããã¯ãã activityReportRepository.store(activityReport) } }
(è足) ã¢ã¯ãã£ããã£ã»ã¬ãã¼ãã¯ãã¥ã¼ã¢ãã«ï¼
è¨ããããã¨ã¯ä»¥ä¸ãªã®ã§ãããè«æ¨ãå¾®å¦ã«ãããã¢ã¯ãã£ããã£ã»ã¬ãã¼ãã«ã¤ãã¦ã®èå¯ã§ããè足ãªã®ã§æéãããæ¹ã®ã¿ã©ããã
åºæ¬çãªèãæ¹ã¯ä¸è¨ã¨å¤ããã¾ããããã¢ã¯ãã£ããã£ã»ã¬ãã¼ãã®ã¢ãã«ã«ã¤ãã¦èãã¦ã¿ã¾ããã
ã¢ã¯ãã£ããã£ã»ã¬ãã¼ããã©ããªå±æ§ãæã¤ãããããªãã®ã§ãããã¦ã¼ã¹ã±ã¼ã¹ãé²è¦§ã®ã¿ãªãã°ãã¢ã¯ãã£ããã£ã»ã¬ãã¼ãã¯ãã¥ã¼ã¢ãã«ããªã¼ãã¢ãã«ã«è¦ãã¾ããåé ã§ããã£ãããã«åºæ¥äº(ãã¡ã¤ã³ã¤ãã³ã)ããã¾ã使ããªãããéç´å é¨ã§çºçããåºæ¥äº(ãã¡ã¤ã³ã¤ãã³ã)ãã¢ããªã³ã°ãã¦ã¯ã©ãããæ¯ãèãã®çµæã¯æ°ããç¶æ ã表ç¾ããã¤ã³ã¹ã¿ã³ã¹ã¨ãã¡ã¤ã³ã¤ãã³ããè¿ãããã«ãã¾ãã*2ãããã¦ããã¡ã¤ã³ã¤ãã³ãããã¢ã¯ãã£ããã£ã»ã¬ãã¼ããçæã§ããã°ãããããªæ°ããã¾ããã¾ãæ©è½çãªãã¸ãã¯ã¨ãã¦ã¯ã»ã¼å¤ãããªãã§ãããã¢ã¯ãã£ããã£ã»ã¬ãã¼ãã«ãã¥ã¼ã®ç¥èããããªããã®ããã«ãã¦åé¢ãããã¨ãå¯è½ã§ã¯ã¨ãã話ã§ãã
case class Task(id: TaskId, name: TaskName, userId: UserId, ...) { def rename(value: TaskName): (Task,TaskRenamed) = (copy(name = value), TaskRenamed(...)) def complete: (Task, TaskCompleted) = (copy(status = Completed), TaskCompleted(...)) } object Task { def apply(id: TaskId, name: TaskName, userId: UserId, ...): (Task, TaskCreated) = { (Task(...), TaskCreated(...)) } } sealed trait TaskEvent { def id: TaskEventId def taskId: TaskId } case class TaskCreated(id: TaskEventId, taskId: TaskId, ... ) extends TaskEvent case class TaskAssigned(id: TaskEventId, taskId: TaskId, assignerId: UserId, assigneeId: UserId, ... ) extends TaskEvent case class TaskRenamed(id: TaskEventId, taskId: TaskId, taskName: TaskName, ... ) extends TaskEvent case class TaskCompleted(id: TaskEventId, taskId: TaskId, ..., createdAt: Instant ) extends TaskEvent class CompletedTaskUseCase1( taskRepository: TaskRepository, activityReportRepository: ActivityReportRepository, ) { def execute(taskId: TaskId, taskName: TaskName, taskVersion: TaskVersion): Unit = { val task = taskRepository.findById(taskId, taskVersion) val (completedTask, taskCompleted) = task.complete taskRepository.store(completedTask) taskEventRepository.store(taskCompleted) } } class ActivityReportDao { // ActivityReportã¯ãªã¼ãã¢ãã«ã¨ãã¦æ±ã def findByTaskId(taskId: TaskId): Seq[TaskActivityReportDto] = { // TaskEventãä¿åããã¦ãããã¼ãã«ããSELECT ... FROM ... JOIN ... ããã¨ãã // TaskEventãåºã«å¥ã®ãã¼ã¿ãä½æãããããã¯ã¨ãªã§è¿ãã¨ããæ¹æ³ã¯ããã¤ãããã¾ã } }
TaskEvent
, UserEvent
ã®ããã«åã¨ãã¦åããã®ããEvent
ã¨ãã¦ã¾ã¨ããåã«ããã®ãããã®ãããã¯ããåããã¾ãããããã®è¨è¨ã ã¨Task
ã®ã¹ãã¼ãã¨Task
ã®ã¤ãã³ã(ä¸ã¤ã®éç´ã¨è¦ãªãã)ãããã«ã©ã¤ããããã¨ã«ãªãã¾ãããããã¯å¦¥åã«ãªã£ã¦ãã¾ããã¨ã
Event Sourcingã§ã¯
ã¡ãªã¿ã«ãEvent Sourcingã§ã¯ã¹ãã¼ãã¯ã¤ãã³ãããå°åºã§ããã®ã§ã¤ãã³ãããæ¸ãè¾¼ã¿ã¾ããã以ä¸ã®ãããªã¤ã¡ã¼ã¸ã«ãªãã¾ããããã®ã¾ã¾ã ã¨ããããåé¡ããã¾ãã(1)(2)ã§é·å¤§ãªtaskEvents
ããªã¯ã¨ã¹ãæ¯èªã¿è¾¼ãã¨ããã©ã¼ãã³ã¹ã«ç¸å¿ã®ããã«ãã£ãããã¾ãã(3)ã®æ¥½è¦³ããã¯ããªãã¨(4)ã¯ç¡æ¡ä»¶ã«è¿½è¨ããã¦ãã¾ãããããã®åé¡ã¯Akkaãªãç°¡åã«è§£æ±ºã§ãã¾ãã
åè¿°ããããã«ãã·ã¹ãã ã®èé害æ§ãã¹ã±ã¼ã©ããªãã£ã確ä¿ããå¿ è¦ããããªãEvent Sourcingã¯æè³å¯¾å¹æããã©ã³ã¹ã§ããããããã¾ããããããããç®çããªããªãæ段ã¨ãã¦è¦åããªãã¨æãã¾ãããèãæ¹ã¯åèã«ãªãã¨æãã¾ãã
class CompletedTaskUseCase1( taskRepository: TaskRepository, activityReportRepository: ActivityReportRepository, ) { def execute(taskId: TaskId, taskName: TaskName, taskVersion: TaskVersion): Unit = { val taskEvents = taskEventRepository.findById(taskId) // (1) val task = Task.fromEvents(taskEvents) // (2) val taskCompleted = task.complete(taskVersion) // (3) taskå é¨ã®versionã¨å¼æ°ã®versionãä¸è´ãããªãcompleteç¶æ ã«é·ç§»ã§ãã taskEventRepository.store(taskCompleted) // (4) } }
Akkaå®è·µãã¤ãã« ã¢ã¯ã¿ã¼ã¢ãã«ã«ãã並è¡ã»åæ£ã·ã¹ãã ã®å®ç¾
- ä½è :ã¬ã¤ã¢ã³ãã»ãã¹ãã³ãã¼ã°,ããã»ããã«ã¼,ããã»ã¦ã£ãªã¢ã ãº,ååº ç¥å¾,æ ¹æ¥ åè¼,éå± äºé
- çºå£²æ¥: 2017/12/13
- ã¡ãã£ã¢: Kindleç
ã¾ã¨ã
ã¨ãããã¨ã§ã以ä¸ã¾ã¨ãã§ãã
- ä»åã®ã¢ãã«æ§é èªä½ã«ç°è«ã¯ãªã
- ã¦ã¼ã¹ã±ã¼ã¹å ã§è¤æ°ã®éç´ãå©ç¨ãããã¨ã¯åé¡ãªããã¨ãããå¿ è¦
- ãæ´æ°ãå¿ãã対çã¯ã»ã©ã»ã©ã«
- ååã¯ã¦ã¼ã¹ã±ã¼ã¹ã¯å¼±ãæ´åæ§ã®å¢çãéç´ã¯å¼·ãæ´åæ§ã®å¢çãååæ¸ããè¨äºã®ä¸»å¼µã©ããã§ã
- ããã»ã©ã³ã¹ãããããã«ã¦ã¼ã¹ã±ã¼ã¹ãçµææ´åã«ããæ¹æ³ã¯ãã
ãåèã¾ã§ã«ã
è£è¶³: 3/22
ãã®è¨äºã«æ¸ããèãæ¹ã¯ãã¤ã¯ããµã¼ãã¹ã¨ããã人åãã§ãã¨è¨ããããã¨ãããã¾ããããã¯ãã®ã¨ããã§ããããããªã«ãã¤ã¯ããµã¼ãã¹ã£ã¦ãã¼ãã«é«ãã§ããï¼ã¯ã©ã¦ãã¨DevOpsã§ç°¡åã«ãªã£ãã¯ãã§ãããã身è¿ãªãã®ã§ããã
ã¨ãããã¨ã§ãä½ãåèã«ãªãæ¸ç±ãæãã¦ã»ããã¨è¨ãããã®ã§ä»¥ä¸ã®æ¬ããªã¹ã¹ã¡ã§ãã
ã5.2 DDDã®Aggregateãã¿ã¼ã³ã使ã£ããã¡ã¤ã³ã¢ãã«ã®è¨è¨ãã§ç´¹ä»ããã¦ãããã«ã¼ã«3: 1ã¤ã®ãã©ã³ã¶ã¯ã·ã§ã³ã§1ã¤ã®ã¢ã°ãªã²ã¼ãã«ã¼ããä½æã¾ãã¯æ´æ°ãããããã²èªãã§ãã ããããã®è¨äºã¨å¯¸åéããªã解説ããªããã¦ãã¾ãã
- ä½è :Chris Richardson,é·å°¾é«å¼,樽澤åºäº¨
- çºå£²æ¥: 2020/03/23
- ã¡ãã£ã¢: Kindleç