é çªã«è¡ããŸãããããããŠããã«å°ããªå 責äºé ïŒãã®èšäºã¯ãããã³ããšã³ãéçºè åãã®Ya SubbotnikProã§ã®ç§ã®ã¹ããŒãã«åºã¥ããŠæžãããŸãããããã¯ãšã³ãã«é¢äžããŠããå Žåã¯ããããããèªåã«ãšã£ãŠæ°ããããšã¯äœãèŠã€ãããŸãããããã§ã¯ãå€§äŒæ¥ã§ã®ããã³ããšã³ãã®çµéšãèŠçŽããNode.jsã䜿çšããçç±ã𿹿³ã説æããŸãã
ãã®èšäºã§ããã³ããšã³ããšèŠãªããã®ãå®çŸ©ããŸããããã¿ã¹ã¯ã«é¢ããè«äºãèã«çœ®ããæ¬è³ªã«çŠç¹ãåœãŠãŸãããã
ããã³ããšã³ãã¯ãè¡šç€ºãæ åœããã¢ããªã±ãŒã·ã§ã³ã®äžéšã§ãããã©ãŠã¶ãŒããã¹ã¯ããããã¢ãã€ã«ãªã©ãç°ãªãå ŽåããããŸãããã ããåžžã«éèŠãªæ©èœããããŸããããã³ããšã³ãã«ã¯ããŒã¿ãå¿ èŠã§ãããã®ããŒã¿ãæäŸããããã¯ãšã³ãããªããã°ãããã¯åœ¹ã«ç«ã¡ãŸãããããã¯ããªãæç¢ºãªå¢çç·ã§ããããã¯ãšã³ãã¯ãããŒã¿ããŒã¹ã«ã¢ã¯ã»ã¹ããåä¿¡ããããŒã¿ã«ããžãã¹ã«ãŒã«ãé©çšããçµæãããã³ããšã³ãã«æäŸããæ¹æ³ãç¥ã£ãŠããŸããããã³ããšã³ãã¯ãããŒã¿ãåä¿¡ãããã³ãã¬ãŒãåããŠããŠãŒã¶ãŒã«çŸãããäžããŸãã
æŠå¿µçã«ã¯ãããã³ããšã³ããããŒã¿ãåä¿¡ããã³ä¿åããããã«ããã¯ãšã³ããå¿ èŠã§ãããšèšããŸããäŸïŒã¯ã©ã€ã¢ã³ããµãŒããŒã¢ãŒããã¯ãã£ãåããå žåçãªææ°ã®ãµã€ãããã©ãŠã¶ã®ã¯ã©ã€ã¢ã³ãïŒã·ã³ãšåŒã¶ãšãèšèªã¯å転ããªããªããŸãïŒã¯ãããã¯ãšã³ããå®è¡ãããŠãããµãŒããŒãããã¯ããŸãããããŠãã¡ãããã©ãã«ã§ãäŸå€ããããŸãããµãŒããŒãå¿ èŠãšããªãè€éãªãã©ãŠã¶ãŒã¢ããªã±ãŒã·ã§ã³ãããïŒãã®å Žåã¯èæ ®ããŸããïŒããµãŒããŒäžã§ããã³ããšã³ããå®è¡ããå¿ èŠããããŸããããã¯ãµãŒããŒãµã€ãã¬ã³ããªã³ã°ãŸãã¯SSRãšåŒã°ããŸãããããæãåçŽã§æãçè§£ããããã±ãŒã¹ãªã®ã§ãããããå§ããŸãããã
SSR
ããã¯ãšã³ãã®çæ³çãªäžçã¯æ¬¡ã®ããã«ãªããŸããããŒã¿ãå«ãHTTPèŠæ±ã¯ã¢ããªã±ãŒã·ã§ã³ã®å ¥åã«å°çããåºåã«ã¯äŸ¿å©ãªåœ¢åŒã®æ°ããããŒã¿ãå«ãå¿çããããŸããããšãã°ãJSONã HTTP APIã¯ããã¹ããšéçºæ¹æ³ã®çè§£ãç°¡åã§ãããã ãã人çã¯èª¿æŽãè¡ããŸããAPIã ãã§ã¯äžååãªå ŽåããããŸãã
ãµãŒããŒã¯æ¢è£œã®HTMLã§å¿çããŠãæ€çŽ¢ãšã³ãžã³ã¯ããŒã©ãŒã«ãã£ãŒããããããœãŒã·ã£ã«ãããã¯ãŒã¯ã«æ¿å ¥ããããã®ã¡ã¿ã¿ã°ã䜿çšããŠãã¬ãã¥ãŒãã¬ã³ããªã³ã°ããããããã«éèŠãªããšã«ã匱ãããã€ã¹ã§ã®å¿çãé«éåãããããå¿ èŠããããŸããæã®ããã«ãPHPã§Web2.0ãéçºããŸããã
ãã¹ãŠãããç¥ãããŠãããé·ãé説æãããŠããŸããããã¯ã©ã€ã¢ã³ãã¯å€åããŸãã-å¿ é ã®ã¯ã©ã€ã¢ã³ãåŽãã³ãã¬ãŒããšã³ãžã³ãããã«ãã£ãŠæ¥ãŸãããçŸä»£ã®Webã§ã¯ãJSXãããŒã«ãæ¯é ããŠããããã®é·æãšçæã«ã€ããŠã¯é·ãéè°è«ã§ããŸããã1ã€åŠå®ããããšã¯ã§ããŸããããµãŒããŒã¬ã³ããªã³ã°ã§ã¯ãJavaScriptã³ãŒããªãã§ã¯å®è¡ã§ããŸããã
ããã¯ãšã³ãéçºã«ãã£ãŠSSRãå®è£ ããå¿ èŠãããå ŽåãããããŸãã
- 責任ç¯å²ã¯ãŸã¡ãŸã¡ã§ããããã¯ãšã³ãããã°ã©ããŒãã¬ã³ããªã³ã°ãæ åœãå§ããŠããŸãã
- èšèªãæ··åšããŠããŸããããã¯ãšã³ãããã°ã©ããŒã¯JavaScriptã䜿ãå§ããŸãã
解決çã¯ãSSRãããã¯ãšã³ãããåé¢ããããšã§ããæãåçŽãªã±ãŒã¹ã§ã¯ãJavaScriptã©ã³ã¿ã€ã ã䜿çšããå¿ èŠãªJavaScriptãã³ãã¬ãŒããšã³ãžã³ã§åäœããèªäœã®ãœãªã¥ãŒã·ã§ã³ãŸãã¯ãã¬ãŒã ã¯ãŒã¯ïŒNextãNuxtãªã©ïŒããã®ã©ã³ã¿ã€ã ã«é 眮ãããã©ãã£ãã¯ãééãããŸããçŸä»£ã®äžçã§ããªãã¿ã®ãã¿ãŒã³ã
ãã®ããããµãŒããŒäžã®ããã³ããšã³ãéçºè ã«å°ãã ãèš±å¯ããŸããããã£ãšéèŠãªåé¡ã«ç§»ããŸãããã
ããŒã¿åä¿¡äž
äžè¬çãªè§£æ±ºçã¯ãæ±çšAPIãäœæããããšã§ãããã®åœ¹å²ã¯ãã»ãšãã©ã®å Žåãè€æ°ã®ãã€ã¯ããµãŒãã¹ãããŒãªã³ã°ã§ããAPIGatewayã«ãã£ãŠåŒãåããããŸãããã ããããã§ãåé¡ãçºçããŸãã
ãŸããããŒã ãšè²¬ä»»ç¯å²ã®åé¡ãå€§èŠæš¡ãªææ°ã®ã¢ããªã±ãŒã·ã§ã³ã¯ãå€ãã®ããŒã ã«ãã£ãŠéçºãããŠããŸããåããŒã ã¯ããžãã¹ãã¡ã€ã³ã«éç¹ã眮ããŠãããããã¯ãšã³ãã«ç¬èªã®ãã€ã¯ããµãŒãã¹ïŒãŸãã¯è€æ°ïŒãæã¡ãã¯ã©ã€ã¢ã³ãã«ç¬èªã®ãã£ã¹ãã¬ã€ãåããŠããŸãããã€ã¯ãããã³ããšã¢ãžã¥ãŒã«æ§ã®åé¡ã«ã€ããŠã¯è§ŠããŸãããããã¯å¥ã®è€éãªãããã¯ã§ããã¯ã©ã€ã¢ã³ããã¥ãŒãå®å šã«åé¢ãããŠããã1ã€ã®å€§ããªãµã€ãå ã®ããSPAïŒã·ã³ã°ã«ããŒãžã¢ããªã±ãŒã·ã§ã³ïŒã§ãããšããŸãã
åããŒã ã«ã¯ãããã³ããšã³ããšããã¯ãšã³ãã®éçºè ãããŸãã誰ããèªåã®ã¢ããªã±ãŒã·ã§ã³ã«åãçµãã§ããŸãã APIGatewayãåé¡ã«ãªãå¯èœæ§ããããŸãã誰ã責任ãè² ããŸããïŒèª°ãæ°ãããšã³ããã€ã³ãã远å ããŸããïŒãããžã§ã¯ãã®ä»ã®ãã¹ãŠã®äººã®åé¡ã解決ããã®ã«åžžã«å¿ããå°çšã®APIã¹ãŒããŒããŒã ïŒééãã®ä»£åã¯äœã§ããïŒãã®ã²ãŒããŠã§ã€ã厩å£ãããšãã·ã¹ãã å šäœãããŠã³ããŸãã
第äºã«ãåé·/äžååãªããŒã¿ã®åé¡ã 2ã€ã®ç°ãªãããã³ããšã³ããåãæ±çšAPIã䜿çšãããšã©ããªãããèŠãŠã¿ãŸãããã
ãããã®2ã€ã®ããã³ããšã³ãã¯å€§ããç°ãªããŸããå¿ èŠãªããŒã¿ã»ããã¯ç°ãªãããªãªãŒã¹ãµã€ã¯ã«ãç°ãªããŸããã¢ãã€ã«ããã³ããšã³ãã®ããŒãžã§ã³ã®å€åæ§ã¯æå€§ã§ãããããåŸæ¹äºææ§ãæå€§ã«ãªãAPIãèšèšããå¿ èŠããããŸãã Webã¯ã©ã€ã¢ã³ãã®å€åæ§ã¯äœããå®éããªãªãŒã¹æã®ãã°ã®æ°ãæžããããã«ã以åã®ããŒãžã§ã³ã1ã€ãµããŒãããã ãã§æžã¿ãŸãããã ãããæ±çšãAPIãWebã¯ã©ã€ã¢ã³ãã®ã¿ã«ãµãŒãã¹ãæäŸããŠããå Žåã§ããããŒã¿ãåé·ãŸãã¯äžååã§ãããšããåé¡ã«çŽé¢ããŠããŸãã
åãããã³ã°ã«ã¯åå¥ã®ããŒã¿ã»ãããå¿ èŠã§ããã1ã€ã®æé©ãªã¯ãšãªã§ååŸã§ããŸãã
ãã®å ŽåããŠãããŒãµã«APIã¯æ©èœããªããããã€ã³ã¿ãŒãã§ã€ã¹ãåé¢ããå¿ èŠããããŸããããã¯ãããããã«ç¬èªã®APIã²ãŒããŠã§ã€ãå¿ èŠã§ããããšãæå³ããŸãããã³ããšã³ããããã§ã®ãããããããšããèšèã¯ãç¬èªã®ããŒã¿ã»ããã§åäœããäžæã®ãããã³ã°ã瀺ããŸãã
ãã®ãããªAPIã®äœæã¯ãããã³ããšã³ããšé£æºããŠåžæãå®è£ ããå¿ èŠãããããã¯ãšã³ãéçºè ã«ä»»ããããšãã§ããŸãããŸãã¯ãã¯ããã«è峿·±ããå€ãã®ç¹ã§ããå¹ççã«ãããã³ããšã³ãããŒã ã«APIã®å®è£ ãæäŸããããšãã§ããŸããããã«ãããSSRã®å®è£ ã«ããåé¡ãè§£æ¶ãããŸããAPIãããã¯ããã¬ã€ã€ãŒãã€ã³ã¹ããŒã«ããå¿ èŠããªããªãããã¹ãŠã1ã€ã®ãµãŒããŒã¢ããªã±ãŒã·ã§ã³ã«çµ±åãããŸããããã«ãSSRãå¶åŸ¡ããããšã«ããããµãŒããŒã«è¿œå ã®èŠæ±ãè¡ãããšãªããã¬ã³ããªã³ã°æã«å¿ èŠãªãã¹ãŠã®ãã©ã€ããªããŒã¿ãããŒãžã«é 眮ã§ããŸãã
ãã®ã¢ãŒããã¯ãã£ã¯ãããã³ããšã³ãã®ããã¯ãšã³ããŸãã¯BFFãšåŒã°ããŸããèãæ¹ã¯åçŽã§ããã¯ã©ã€ã¢ã³ãèŠæ±ããªãã¹ã³ããããã¯ãšã³ããããŒãªã³ã°ããŠãæé©ãªå¿çãè¿ãæ°ããã¢ããªã±ãŒã·ã§ã³ããµãŒããŒã«è¡šç€ºãããŸãããããŠãã¡ããããã®ã¢ããªã±ãŒã·ã§ã³ã¯ããã³ããšã³ãéçºè ã«ãã£ãŠå¶åŸ¡ãããŸãã
ããã¯ãšã³ãã«è€æ°ã®ãµãŒããŒããããŸããïŒåé¡ãªãïŒ
ããã¯ãšã³ãéçºãã©ã®éä¿¡ãããã³ã«ã奜ããã«é¢ä¿ãªããWebã¯ã©ã€ã¢ã³ããšéä¿¡ããããã«ä»»æã®äŸ¿å©ãªæ¹æ³ã䜿çšã§ããŸãã RESTãRPCãGraphQL-ç§ãã¡ã¯èªåã§éžæããŸãã
ããããGraphQLèªäœã¯ãåäžã®ã¯ãšãªã§ããŒã¿ãååŸããåé¡ã®è§£æ±ºçã§ã¯ãããŸãããïŒãã¶ããäžéãµãŒãã¹ããã§ã³ã¹ããå¿ èŠã¯ãããŸãããïŒ
æ®å¿µãªãããGraphQLã广çã«äœ¿çšããã«ã¯ãå¹ççãªããŒã¿ããŒã¹ã¯ãšãªã®éçºãæ åœããããã¯ãšã³ãéçºè ãšã®ç·å¯ãªååãå¿ èŠã§ãããã®ãããªãœãªã¥ãŒã·ã§ã³ãéžæããããšã§ãããŒã¿ãåã³å¶åŸ¡ã§ããªããªããæåã®å Žæã«æ»ããŸãã
ãã¡ããå¯èœã§ãããé¢çœããããŸããïŒããã³ããšã³ãã®å ŽåïŒ
ã§ã¯ãBFFãå®è£ ããŸãããããã¡ãããNode.jsã§ã¯ãã©ãããŠïŒããã³ããšã³ãéçºè ã®çµéšãšJavaScriptãåå©çšããŠãã³ãã¬ãŒããæäœããã«ã¯ãã¯ã©ã€ã¢ã³ããšãµãŒããŒã«åäžã®èšèªãå¿ èŠã§ããä»ã®ã©ã³ã¿ã€ã ç°å¢ã¯ã©ãã§ããïŒ
GraalVMããã³ãã®ä»ã®ãšããŸããã¯ãªãœãªã¥ãŒã·ã§ã³ã¯ãããã©ãŒãã³ã¹ãV8ããå£ããå ·äœçãããŸãã Denoã¯ãŸã å®é𿮵éã§ãããæ¬çªç°å¢ã§ã¯äœ¿çšãããŠããŸããã
ãããŠäžç¬ã Node.jsã¯ãAPIGatewayãå®è£ ããããã®é©ãã»ã©åªãããœãªã¥ãŒã·ã§ã³ã§ããããŒãã¢ãŒããã¯ãã£ã§ã¯ãã·ã³ã°ã«ã¹ã¬ããã®JavaScriptã€ã³ã¿ãŒããªã¿ãŒãlibuvãšçµã¿åãããŠäœ¿çšââã§ããŸããlibuvã¯éåæã®I / Oã©ã€ãã©ãªã§ãããã¹ã¬ããããŒã«ã䜿çšããŸãã
JavaScriptåŽã§ã®é·ãèšç®ã¯ãã·ã¹ãã ããã©ãŒãã³ã¹ã«åœ±é¿ãäžããŸãããããåé¿ã§ããŸããå¥ã ã®ã¯ãŒã«ãŒã§å®è¡ãããããã€ãã£ããã€ããªã¢ãžã¥ãŒã«ã®ã¬ãã«ã«ããŸãã
ãã ããåºæ¬çãªã±ãŒã¹ã§ã¯ãNode.jsã¯CPUãéäžçã«äœ¿çšããæäœã«ã¯é©ããŠããŸãããåæã«ãéåæI / Oã§ããŸãæ©èœããé«ãããã©ãŒãã³ã¹ãæäŸããŸããã€ãŸãããŠãŒã¶ãŒã«é¢ä¿ãªããåžžã«è¿ éã«å¿çã§ããã·ã¹ãã ãåŸãããŸããããã¯ãšã³ããã©ãã ãå¿ãããã«ã€ããŠãæäœã®çµäºãåŸ ã€ããã«ãŠãŒã¶ãŒã«å³åº§ã«éç¥ããããšã§ããã®ç¶æ³ã«å¯ŸåŠã§ããŸãã
ããžãã¹ããžãã¯ãä¿åããå Žæ
çŸåšãã·ã¹ãã ã«ã¯ãããã¯ãšã³ããããã³ããšã³ããBFFã®3ã€ã®å€§ããªéšåããããŸããåççãªïŒã¢ãŒããã¯ãã«ãšã£ãŠïŒè³ªåãçºçããŸãïŒããžãã¹ããžãã¯ãã©ãã«ä¿æãããïŒ
ãã¡ãããã¢ãŒããã¯ãã¯ã·ã¹ãã ã®ãã¹ãŠã®ã¬ã€ã€ãŒã«ããžãã¹ã«ãŒã«ãå¡ãã€ã¶ãããã¯ãããŸãããçå®ã®æºã¯1ã€ã§ãªããã°ãªããŸããããããŠããã®ãœãŒã¹ã¯ããã¯ãšã³ãã§ããããŒã¿ã«æãè¿ãã·ã¹ãã ã®éšåã§ãªãå Žåãé«ã¬ãã«ã®ããªã·ãŒãä¿åããä»ã®å Žæã¯ãããŸããïŒ
ãããå®éã«ã¯ãããã¯åžžã«æ©èœãããšã¯éããŸãããããšãã°ãBFFã¬ãã«ã§å¹ççãã€è¿ éã«å®è£ ã§ããããžãã¹äžã®åé¡ãçºçããŸããå®ç§ãªã·ã¹ãã èšèšã¯çŽ æŽãããã§ãããæã¯éãªãã§ããã¢ãŒããã¯ãã£ã®ã¯ãªãŒã³ããç ç²ã«ããªããã°ãªããªãå Žåããããã¬ã€ã€ãŒããªãŒã¯ãå§ããŸãã
ãå®å šãªãNode.jsããã¯ãšã³ããåªå ããŠBFFãæšãŠãããšã§ãå®ç§ãªã¢ãŒããã¯ãã£ãå®çŸã§ããŸããïŒãã®å ŽåãæŒãã¯ãªãããã§ãã
äºå®ã§ã¯ãããŸããããµãŒããŒã«è»¢éãããå Žåãã€ã³ã¿ãŒãã§ãŒã¹ã®å¿çæ§ã«åœ±é¿ãäžããããžãã¹ã«ãŒã«ããããŸããããã«æåŸãŸã§æµæããããšã¯ã§ããŸãããå®å šã«åé¿ããããšã¯ã§ããªãã§ããããã¢ããªã±ãŒã·ã§ã³ã¬ãã«ã®ããžãã¯ãã¯ã©ã€ã¢ã³ãã«æµžéããŸããææ°ã®SPAã§ã¯ãBFFãããå Žåã§ããã¯ã©ã€ã¢ã³ããšãµãŒããŒã®éã«ã¹ãã¢ãçºçããŸãã
ã©ããªã«é 匵ã£ãŠããããžãã¹ããžãã¯ã¯Node.jsã®APIã²ãŒããŠã§ã€ã«æµžéããŸãããã®çµè«ãä¿®æ£ããŠãæãããããå®è£ ã«ç§»ããŸãããïŒ
æ³¥ã®å€§ããªããŒã«
è¿å¹Žã®Node.jsã¢ããªã±ãŒã·ã§ã³ã§æã人æ°ã®ãããœãªã¥ãŒã·ã§ã³ã¯Expressã§ããå®èšŒæžã¿ã§ãããã¬ãã«ãäœãããŠãåªããã¢ãŒããã¯ãã£ã¢ãããŒããæäŸããŠããŸãããäž»ãªãã¿ãŒã³ã¯ããã«ãŠã§ã¢ã§ããæ³¥ã®å€§ããªå¡ã®ãããªExpressã®å žåçãªã¢ããªã±ãŒã·ã§ã³ïŒååãåŒã¶ããšãã¢ã³ããã¿ãŒã³ã§ã¯ãããŸããïŒã
const express = require('express');
const app = express();
const {createReadStream} = require('fs');
const path = require('path');
const Joi = require('joi');
app.use(express.json());
const schema = {id: Joi.number().required() };
app.get('/example/:id', (req, res) => {
const result = Joi.validate(req.params, schema);
if (result.error) {
res.status(400).send(result.error.toString()).end();
return;
}
const stream = createReadStream( path.join('..', path.sep, `example${req.params.id}.js`));
stream
.on('open', () => {stream.pipe(res)})
.on('error', (error) => {res.end(error.toString())})
});
ãã¹ãŠã®ã¬ã€ã€ãŒãæ··åšããŠããã1ã€ã®ãã¡ã€ã«ã«ã³ã³ãããŒã©ãŒããããã€ã³ãã©ã¹ãã©ã¯ãã£ããžãã¯ãæ€èšŒãããžãã¹ããžãã¯ãªã©ãã¹ãŠãå«ãŸããŠããŸãããããæ±ãã®ã¯èŠçã§ããããªãã¯ãã®ãããªã³ãŒããç¶æããããããŸãããNode.jsã§ãšã³ã¿ãŒãã©ã€ãºã¬ãã«ã®ã³ãŒããèšè¿°ã§ããŸããïŒ
ããã«ã¯ãä¿å®ãšéçºã容æãªã³ãŒãããŒã¹ãå¿ èŠã§ããèšãæããã°ãã¢ãŒããã¯ãã£ãå¿ èŠã§ãã
Node.jsã¢ããªã±ãŒã·ã§ã³ã¢ãŒããã¯ãã£ïŒæçµçã«ïŒ
ããœãããŠã§ã¢ã¢ãŒããã¯ãã£ã®ç®æšã¯ãã·ã¹ãã ã®æ§ç¯ãšä¿å®ã«äŒŽã人çåŽåãåæžããããšã§ããã
ãããŒãããããããããããŒãã£ã³
ã¢ãŒããã¯ãã£ã¯ãã¬ã€ã€ãŒãšãããã®éã®æ¥ç¶ãšãã2ã€ã®éèŠãªèŠçŽ ã§æ§æãããŠããŸããã¢ããªã±ãŒã·ã§ã³ãã¬ã€ã€ãŒã«åå²ããçžäºã®ãªãŒã¯ãé²ããã¬ã€ã€ãŒã®éå±€ãšã¬ã€ã€ãŒéã®æ¥ç¶ãé©åã«æŽçããå¿ èŠããããŸãã
ã¬ã€ã€ãŒ
ã¢ããªã±ãŒã·ã§ã³ãã¬ã€ã€ãŒã«åå²ããã«ã¯ã©ãããã°ããã§ããïŒããŒã¿ãããžãã¯ããã¬ãŒã³ããŒã·ã§ã³ãšããå€å žçãª3å±€ã®ã¢ãããŒãããããŸãã
ãã®ã¢ãããŒãã¯çŸåšã廿¢ããããšèŠãªãããŠããŸããåé¡ã¯ãããŒã¿ãåºæ¬ã§ãããšããããšã§ããã€ãŸããã¢ããªã±ãŒã·ã§ã³ã¯ãåå ããããžãã¹ããã»ã¹ã§ã¯ãªããããŒã¿ããŒã¹ã§ã®ããŒã¿ã®è¡šç€ºæ¹æ³ã«å¿ããŠèšèšãããŸãã
ããçŸä»£çãªã¢ãããŒãã§ã¯ãã¢ããªã±ãŒã·ã§ã³ã«ããžãã¹ããžãã¯ãšé£æºããã³ãŒãã§å®éã®ããžãã¹ããã»ã¹ã衚çŸããå°çšã®ãã¡ã€ã³ã¬ã€ã€ãŒãããããšãåæãšããŠããŸãããã ããEric Evansã®åŸæ¥ã®ãã¡ã€ã³é§ååèšèšã«ç®ãåãããšã次ã®ã¢ããªã±ãŒã·ã§ã³å±€ã¹ããŒã ãèŠã€ãããŸãã
ããã§äœãåé¡ã«ãªã£ãŠããŸããïŒDDDã䜿çšããŠèšèšãããã¢ããªã±ãŒã·ã§ã³ã®åºç€ã¯ããã¡ã€ã³ãã€ãŸãæãéèŠã§äŸ¡å€ã®ããããžãã¯ã§ããé«ã¬ãã«ã®ããªã·ãŒã§ããå¿ èŠãããããã«æãããŸãããã ãããã®å±€ã®äžã«ã¯ãããŒã¿ã¢ã¯ã»ã¹å±€ïŒDALïŒããã®ã³ã°ãç£èŠãªã©ã®ã€ã³ãã©ã¹ãã©ã¯ãã£å šäœããããŸããã€ãŸããã¯ããã«äœãã¬ãã«ã§éèŠæ§ã®äœãããªã·ãŒã§ãã
ã€ã³ãã©ã¹ãã©ã¯ãã£ã¯ã¢ããªã±ãŒã·ã§ã³ã®äžå¿ã§ããããã¬ãŒã®å¹³å¡ãªäº€æã¯ããã¹ãŠã®ããžãã¹ããžãã¯ã®ã·ã§ã€ã¯ã¢ããã«ã€ãªããå¯èœæ§ããããŸãã
ããäžåºŠRobertMartinã«ç®ãåãããšããClean Architectureããšããæ¬ã®äžã§ã圌ã¯ã¢ããªã±ãŒã·ã§ã³å ã®ç°ãªãã¬ã€ã€ãŒéå±€ãä»®å®ããŠããããã¡ã€ã³ãäžå€®ã«ããããšãããããŸãã
ãããã£ãŠã4ã€ã®ã¬ã€ã€ãŒãã¹ãŠãç°ãªãæ¹æ³ã§é 眮ããå¿ èŠããã
ãŸããã¬ã€ã€ãŒãéžæãããããã®éå±€ãå®çŸ©ããŸãããããã§ã¯ãæ¥ç¶ã«ç§»ããŸãããã
æ¥ç¶
ãŠãŒã¶ãŒããžãã¯åŒã³åºãã®äŸã«æ»ããŸããããã€ã³ãã©ã¹ãã©ã¯ãã£ãžã®çŽæ¥ã®äŸåãåãé€ããæ£ããã¬ã€ã€ãŒéå±€ã確ä¿ããã«ã¯ã©ãããã°ããã§ããïŒäŸåé¢ä¿ãå ã«æ»ãç°¡åã§ããç¥ãããæ¹æ³ãã€ãŸãã€ã³ã¿ãŒãã§ã€ã¹ããããŸãã
çŸåšãé«ã¬ãã«ã®UserEntityã¯äœã¬ãã«ã®ãã¬ãŒã«äŸåããŠããŸãããããã©ããããããã¯ãã¬ãŒãã·ã¹ãã ã«å«ããããã«å®è¡ãããªããã°ãªããªãå¥çŽãæç€ºããŸãããã®å Žåã®ãã¬ãŒã®äº€æã¯ãåãå¥çŽãéµå®ããæ°ããå®è£ ãæ¥ç¶ããããšã«ãªããŸããéèŠãªè³ªåã¯ãããã©ã®ããã«æ¥ç¶ãããã§ãã
import {Logger} from â../core/loggerâ;
class UserEntity {
private _logger: Logger;
constructor() {
this._logger = new Logger();
}
...
}
...
const UserEntity = new UserEntity();
ã¬ã€ã€ãŒã¯ãã£ãããšæ¥ç¶ãããŠããŸãããã¡ã€ã«ã®æ§é ãšå®è£ ã«ã¯çµã³ã€ãããããŸããäŸåé¢ä¿ã®å転ãå¿ èŠã§ããããã¯ãäŸåé¢ä¿ã®æ¿å ¥ã䜿çšããŠè¡ããŸãã
export class UserEntity {
constructor(private _logger: ILogger) { }
...
}
...
const logger = new Logger();
const UserEntity = new UserEntity(logger);
ããã§ãããã¡ã€ã³ãUserEntityã¯ãã¬ãŒã®å®è£ ã«ã€ããŠäœãç¥ããŸãããå¥çŽãæäŸããå®è£ ããã®å¥çŽã«æºæ ããããšãæåŸ ããŸãã
ãã¡ãããã€ã³ãã©ã¹ãã©ã¯ãã£ãšã³ãã£ãã£ã®ã€ã³ã¹ã¿ã³ã¹ãæåã§çæããããšã¯æã楜ããããšã§ã¯ãããŸããããã¹ãŠãæºåããã«ãŒããã¡ã€ã«ãå¿ èŠã§ããäœæãããã¬ãŒã®ã€ã³ã¹ã¿ã³ã¹ãã¢ããªã±ãŒã·ã§ã³å šäœã«ãã©ãã°ããå¿ èŠããããŸãïŒå€ããäœæããã®ã§ã¯ãªãã1ã€æã€æ¹ãæå©ã§ãïŒãç²ããŸãããããŠãããã§IoCã³ã³ãããæŽ»èºãããã®ãã©ãŒãã¬ãŒãã®äœæ¥ãåŒãç¶ãããšãã§ããŸãã
ã³ã³ããã®äœ¿çšã¯ã©ã®ããã«èŠããã§ããããïŒããšãã°ã次ã®ããã«ãªããŸãã
export class UserEntity {
constructor(@Inject(LOGGER) private readonly _logger: ILogger){ }
}
äœãèµ·ããŠãïŒãã³ã¬ãŒã¿ã®éæ³ã䜿çšããŠã次ã®ããã«èª¬æããŸããããUserEntityã®ã€ã³ã¹ã¿ã³ã¹ãäœæãããšãã¯ããã®ãã©ã€ããŒããã£ãŒã«ã_loggerã«ãLOGGERããŒã¯ã³ã®äžã®IoCã³ã³ããã«ãããšã³ãã£ãã£ã®ã€ã³ã¹ã¿ã³ã¹ãæ¿å ¥ããŸããILoggerã€ã³ã¿ãŒãã§ãŒã¹ã«æºæ ããããšãæåŸ ãããŠããŸããããããŠãIoCã³ã³ããã¯ããèªäœã§ãã¹ãŠãå®è¡ããŸãã
ã¬ã€ã€ãŒãéžæããããããã©ã®ããã«è§£ãããæ±ºå®ããŸããããã¬ãŒã ã¯ãŒã¯ãéžæããæãæ¥ãŸããã
ãã¬ãŒã ã¯ãŒã¯ãšã¢ãŒããã¯ãã£
質åã¯åçŽã§ããExpressãææ°ã®ãã¬ãŒã ã¯ãŒã¯ã«ä»»ããããšã§ãåªããã¢ãŒããã¯ãã£ãå®çŸã§ããã§ãããããNestãèŠãŠã¿ãŸãããïŒ
- TypeScriptã§æžããã
- Express / Fastifyã®äžã«æ§ç¯ãããŠãããããã«ãŠã§ã¢ã¬ãã«ã§ã®äºææ§ããããŸãã
- ããžãã¯ã®ã¢ãžã¥ãŒã«æ§ã宣èšãã
- IoCã³ã³ãããæäŸããŸãã
ããã«å¿ èŠãªãã®ã¯ãã¹ãŠæã£ãŠããããã§ãã圌ãã¯ãŸããã¢ããªã±ãŒã·ã§ã³ã®æŠå¿µãããã«ãŠã§ã¢ãã§ãŒã³ãšããŠæ®ããŸãããããããè¯ãã¢ãŒããã¯ãã£ã¯ã©ãã§ããïŒ
å·£ãžã®äŸåæ§æ³šå ¥
æç€º ã«åŸã£ãŠã¿ãŸããããNestã§ã¯ããšã³ãã£ãã£ãšããçšèªã¯éåžžORMã«é©çšããããããUserEntityã®ååãUserServiceã«å€æŽããŸãããã¬ãŒã¯ãã¬ãŒã ã¯ãŒã¯ã«ãã£ãŠæäŸãããããã代ããã«æœè±¡FooServiceãæ¿å ¥ããŸãã
import {FooService} from â../services/foo.serviceâ;
@Injectable()
export class UserService {
constructor(
private readonly _fooService: FooService
){ }
}
ãããŠ...ç§ãã¡ã¯äžæ©åŸéããããã§ãïŒã€ã³ãžã§ã¯ã·ã§ã³ã¯ãããŸãããå転ã¯ãã
ãŸãããäŸåé¢ä¿ã¯ãæœè±¡åã§ã¯ãªãå®è£ ãç®çãšããŠããŸãã
ãããä¿®æ£ããŠã¿ãŸãããããªãã·ã§ã³çªå·1ïŒ
@Injectable()
export class UserService {
constructor(
private _fooService: AbstractFooService
){ } }
ãã®æœè±¡çãªãµãŒãã¹ã«ã€ããŠèª¬æããè¿ãã®ã©ããã«ãšã¯ã¹ããŒãããŸãã
export {AbstractFooService};
FooServiceã¯AbstractFooServiceã䜿çšããããã«ãªããŸããããã®ãããIoCã«æåã§ç»é²ããŸãã
{ provide: AbstractFooService, useClass: FooService }
2çªç®ã®ãªãã·ã§ã³ãåè¿°ã®ã€ã³ã¿ãŒãã§ã€ã¹ã䜿çšããã¢ãããŒãã詊ããŠã¿ãŸããããJavaScriptã«ã¯ã€ã³ã¿ãŒãã§ãŒã¹ããªãããããªãã¬ã¯ã·ã§ã³ã䜿çšããŠå®è¡æã«å¿ èŠãªãšã³ãã£ãã£ãIoCããåŒãåºãããšã¯ã§ããŸãããå¿ èŠãªãã®ãæç€ºçã«è¿°ã¹ãå¿ èŠããããŸããããã«ã¯@Injectãã³ã¬ãŒã¿ã䜿çšããŸãã
@Injectable()
export class UserService {
constructor(
@Inject(FOO_SERVICE) private readonly _fooService: IFooService
){ } }
ãããŠããŒã¯ã³ã§ç»é²ããŸãïŒ
{ provide: FOO_SERVICE, useClass: FooService }
ãã¬ãŒã ã¯ãŒã¯ãç²åŸããŸããïŒããããã©ã®ãããã®è²»çšãããããŸããïŒããªãã®ç ç³ãæ¢ããŸãããããã¯çãããããšã§ãããã¢ããªã±ãŒã·ã§ã³å šäœããã¬ãŒã ã¯ãŒã¯ã«ãã³ãã«ããã¹ãã§ã¯ãªãããšã瀺åããŠããŸããç§ããŸã ããªããçŽåŸãããŠããªãã®ãªããä»ã®åé¡ããããŸãã
äŸå€
ãã¹ãã¯äŸå€ãé€ããŠç¹æ» ããŸããããã«ã圌ã¯ãã¢ããªã±ãŒã·ã§ã³ã®åäœã®ããžãã¯ã説æããããã«äŸå€ã¹ããŒã䜿çšããããšãææ¡ããŠããŸãã
ã¢ãŒããã¯ãã£ã®èгç¹ãããããã§ã¯ãã¹ãŠåé¡ãããŸãããïŒåã³èå人ã«ç®ãåããŸãããïŒ
ããšã©ãŒãäºæ³ãããåäœã§ããå Žåã¯ãäŸå€ã䜿çšããªãã§ãã ããããäŸå€ã¯ãäŸå€çãªç¶æ³ã瀺åããŠããŸããããžãã¹ããžãã¯ãäœæãããšãã¯ãäŸå€ãã¹ããŒããªãããã«ããå¿ èŠããããŸããJavaScriptãTypeScriptãäŸå€ãåŠçãããããšãä¿èšŒããªããšããçç±ã ãã®å Žåãããã«ãå®è¡ã®æµãããããã«ãããªããGOTOã¹ã¿ã€ã«ã§ããã°ã©ãã³ã°ãéå§ããŸããã€ãŸããã³ãŒãã®åäœã調ã¹ãŠããéãèªè ã¯ããã°ã©ã å šäœããžã£ã³ãããå¿ èŠããããŸãã
ããŒãã£ã³ãã¡ãŠã©ãŒ
äŸå€ã®äœ¿çšãåæ³ã§ãããã©ãããçè§£ããã®ã«åœ¹ç«ã€ç°¡åãªã«ãŒã«ããããŸãã
ããã¹ãŠã®äŸå€ãã³ãã©ãŒãåé€ãããšãã³ãŒãã¯æ©èœããŸããïŒãçãããããããã®å ŽåãäŸå€ã§ã¯ãªãç¶æ³ã§äŸå€ã䜿çšãããå¯èœæ§ããããŸãããããžãã¹ããžãã¯ã§ãããåé¿ããããšã¯å¯èœã§ããïŒã¯ãïŒã¹ããŒããäŸå€ãæå°éã«æããè€éãªæäœã®çµæã䟿å©ã«è¿ãã«ã¯ãæåãŸãã¯ãšã©ãŒã®ç¶æ ïŒPromiseã«éåžžã«è¿ãæŠå¿µïŒã®ã³ã³ãããŒãæäŸããEitherã¢ããã䜿çšããå¿ èŠããããŸãã
å®çšçãªããã°ã©ããŒ
const successResult = Result.ok(false);
const failResult = Result.fail(new ConnectionError())
æ®å¿µãªãããNestãæäŸãããšã³ãã£ãã£å ã§ã¯ãä»ã®æ¹æ³ã§è¡åã§ããªãããšããããããŸããäŸå€ãã¹ããŒããå¿ èŠããããŸããããããã¬ãŒã ã¯ãŒã¯ã®ä»çµã¿ã§ãããããã¯éåžžã«äžå¿«ãªæ©èœã§ãããããŠåã³çåãçããŸãïŒå€åããªãã¯ãã¬ãŒã ã¯ãŒã¯ã§ã¢ããªã±ãŒã·ã§ã³ããã©ãã·ã¥ããã¹ãã§ã¯ãããŸãããïŒãã¬ãŒã ã¯ãŒã¯ãšããžãã¹ããžãã¯ãç°ãªãã¢ãŒããã¯ãã£ã¬ã€ã€ãŒã«åé¢ããããšã¯å¯èœã§ããããïŒ
確èªãããã
ãã¹ããšã³ãã£ãã£ãšã¢ãŒããã¯ãã£ã¬ã€ã€ãŒ
人çã®å³ããçå®ïŒNestã§æžããã®ã¯ãã¹ãŠ1ã€ã®ã¬ã€ã€ãŒã«ç©ã¿éããããšãã§ããŸããããã¯ã¢ããªã±ãŒã·ã§ã³ã¬ã€ã€ãŒã§ãã
ãã¬ãŒã ã¯ãŒã¯ãããžãã¹ããžãã¯ã«æ·±ãå ¥ã蟌ãŸããããªãã®ã§ãäŸå€ããã³ã¬ãŒã¿ãããã³IoCã³ã³ãããé€ããŠãã¬ãŒã ã¯ãŒã¯ãæé·ããããšã¯ãããŸããããã¬ãŒã ã¯ãŒã¯ã®äœæè ã¯ããã®ç ç³ã䜿çšããŠããžãã¹ããžãã¯ãäœæããããšãã©ãã»ã©çŽ æŽãããããæããã«ããŸããã圌ãã®ä»äºã¯ããªããæ°žé ã«èªåèªèº«ã«çµã³ä»ããããšã§ãããã¬ãŒã ã¯ãŒã¯ã¯ãã¢ããªã±ãŒã·ã§ã³ã¬ãã«ã®ããžãã¯ã䟿å©ã«æŽçããã€ã³ãã©ã¹ãã©ã¯ãã£ãšUIãããã«æ¥ç¶ããããã®åãªãæ¹æ³ã§ããããšãå¿ããªãã§ãã ããã
ããã¬ãŒã ã¯ãŒã¯ã¯è©³çްã§ããã
ãããŒãããããããããããŒãã£ã³
ã³ã³ããŒãã³ããç°¡åã«çœ®ãæããããšãã§ããã³ã³ã¹ãã©ã¯ã¿ãŒãšããŠã¢ããªã±ãŒã·ã§ã³ãèšèšããããšããå§ãããŸãããã®ãããªå®è£ ã®äžäŸã¯ãå è§åœ¢ã®ã¢ãŒããã¯ãã£ïŒããŒãããã³ã¢ããã¿ã¢ãŒããã¯ãã£ïŒã§ãããã®ã¢ã€ãã¢ã¯è峿·±ããã®ã§ãããã¹ãŠã®ããžãã¹ããžãã¯ãåãããã¡ã€ã³ã³ã¢ã¯ãå€çãšéä¿¡ããããã®ããŒããæäŸããŸããå¿ èŠãªãã®ã¯ãã¹ãŠãã¢ããã¿ãŒãä»ããŠå€éšã«æ¥ç¶ãããŠããŸãã
Nestããã¬ãŒã ã¯ãŒã¯ãšããŠäœ¿çšããŠNode.jsã«ãã®ãããªã¢ãŒããã¯ãã£ãå®è£ ããããšã¯çŸå®çã§ããïŒããªããèå³ãããã°ãäŸãæããŠã¬ãã¹ã³ãè¡ããŸãããããã§èŠã€ããããšãã§ããŸãã
ãŸãšããŸããã
- Node.jsã¯BFFã«é©ããŠããŸããããªãã¯åœŒå¥³ãšäžç·ã«æ®ããããšãã§ããŸãã
- æ¢è£œã®ãœãªã¥ãŒã·ã§ã³ã¯ãããŸããã
- ãã¬ãŒã ã¯ãŒã¯ã¯éèŠã§ã¯ãããŸããã
- ã¢ãŒããã¯ãã£ãè€éã«ãªããããããå ¥åã«ééããããããšãééã£ãããŒã«ãéžæããå¯èœæ§ããããŸãã
ç§ã¯ãããã®æ¬ããå§ãããŸãïŒ
- ãããŒãã»ããŒãã£ã³ããã¯ãªãŒã³ã¢ãŒããã¯ãã£ãã
- Vaughn Vernon, Domain-Driven Design Distilled,
- Khalil Stemmler, khalilstemmler.com,
- Martin Fowler, martinfowler.com/architecture.