ã¯ãããŸããŠãããŒã¿&AIããŒã ã®oyabuã§ããããŒã¿ã¹ãã©ããžã¹ããšããããŒã¿ã¢ããªã¹ãã¿ãããªä»äºãããŠãŸã å
·äœçã«ã¯ãDELISH KITCHENãã¢ããªã®ããŒã¿ãæœåºãåæããŠé£åã¡ãŒã«ãŒãªã©ã®ã¯ã©ã€ã¢ã³ãããŸã®æœçãææ¡ã«ã掻çšé ãä»äºãããŠããŸã ä»åã¯LLM(ChatGPTãOpenInterpreter)ãããžãã¹ãµã€ãã«æŽ»çšããŠãããããã«ãã£ãããšã®è©±ãããŸã ãŸã å§ããã°ãããªã®ã§ãææèªäœã¯ãããªã«åºãŠãªãã§ãããèããããšããåŸãããç¥èŠãå
±æããããšæããŸã ãã£ãããšã¯ä»¥äžã§ã ChatGPTã®äœ¿ãæ¹ããã¥ã¡ã³ãã®äœæ(çŠå¿ãšãŠãŒã¹ã±ãŒã¹ã®æŽç) ChatGPTã®äœ¿ãæ¹ååŒ·äŒ OpenInterpreterãé£ã«åº§ã£ãŠãã«ã¹ã¿ããŒãµã¯ã»ã¹ã®æ¹ã«è©ŠããŠããã ãã£ãã(èª²é¡æ) ãããããããªããšãããå§ãããã£ãããšããŠã¯ä»¥äžãªæãã§ã 倧åæãšããŠLLMãçåšããµãã£ãŠãããèªåãšããŠãååãã®å©çã享åããŠãã ããžãã¹ãã³ã«ãšã£ãŠãChatGPTã¹ãã« = ä»ã®Excelã¹ãã«ãããã«ãªãããšã¯ç®ã«èŠããŠã ããžãã¹ãµã€ãã§ãChatGPTã䜿ã£ãŠã人ã¯ãããããããŸãäŒè©±ã«åºãŠããªã 瀟å
ã®SlackãæŒã£ãŠãChatGPTã®è©±ãããŠã人ã¯ã ããããšã³ãžã㢠貌ã£ãŠãã¢ã³ããçã«ãããããã®åšèŸºæ
å ±ããšã³ãžãã¢ã«ã¯éãŸã£ãŠæ¥ããã æ°ã«ãªã£ãŠã¯ããŠã1å詊ãããã®ã®ãæ¥åã«äœ¿ãã€ã¡ãŒãžãæ¹§ããŠãªãæ¹ããªãã ããã å€ãã®ããªãŒãšããåŠæ³ åãåãã®éšçœ²ãšãã°ããåããŠãæ¥åããªããšãªãããã£ãŠããŠã现ããæœçåäœã§ChatGPTã§è§£æ±ºåºæ¥ãããªãã®ãèŠããŠãã 瀟å
çšã®ChatããŒã« ãåºæ¥ãŠãçŽæ¥æ¥åã«é¢ããå
容ããã©ã³ã¯ã«èããç°å¢ãæŽã£ã 瀟å
ã®éçšã«ãŒã«/tipsãéããããã¥ã¡ã³ããããããäžåš ãã£ãããšãšãã®ç®çãææ/åŸãããç¥èŠ ç®ç ç®çã¯ChatGPTã«ãããããžãã¹ãµã€ãã®å·¥æ°åæž/ã¯ãªãªãã£ã¢ããã§ã ãšããããã¯å©çšç¿æ
£åãç®æšãšãããã®ããã«ä»¥äžã®2ç¹ãéæããããæœçãå®è¡ããŸãã ChatGPTã身è¿ãªããŒã«ã ãšæã£ãŠããã ChatGPTã§åºæ¥ãããš/èŠæãªããšãç¥ã£ãŠããã ç¿æ
£åã®åææ®µéã§éèŠãªã®ã¯ããªãŒã¯ãšã³ã·ãŒãæµã¯äœãã¢ãããŒã·ã§ã³ãšé«ãããŒãã«ãªã®ã§ ãšãããããããæ°ã«ããæœçã®èšèšãããŸãã å
·äœçã«ãã£ãããš ChatGPTã®äœ¿ãæ¹ããã¥ã¡ã³ãã®äœæ æäœéã®çŠå¿çãªã«ãŒã«ã¯æžãã€ã€ãæ¥åã«ãã£ããŠãŒã¹ã±ãŒã¹ãäžå¿ã«æžããŸãããããããçç±ã¯ä»¥äžã§ã åäººã®æ¥åã«è¿ãéšåã®ã³ã³ãã³ããæ¡å
ããããšã§ã倿§ãªå人ã®èå³ã«åŒã£ãããããããããã çæ³è«ã§ããã°ãæãç«ã¡ãçè«ãç¥ãããšã¯å€§äºã§ãããèå³ã®ãªã人ããããã ãŸãå®å
šã«ãã®æ¥åãChatGPTã§è§£æ±ºããããšã¯é£ãããããããŸããããä»åŸã®å·¥æ°ççž®ãã¯ãªãªãã£ã¢ãããèŠè¶ãã ããã³ããã®ã¿ã¿ããååšããããšèªäœãéèŠã ãšæã£ãŠããã®ã§ãã¡ãã£ãšã§ãè§£æ±ºåºæ¥ãããªããšããããªããšãããã ãŠãŒã¹ã±ãŒã¹ãšããŠå
¥ããŠãããŸãããããã³ããã®å€¢ãèŠãŸãã(倩åããããŸãã) ããã¥ã¡ã³ãåã«ããã£ãŠã¯ããªãã¹ããã©ãšãã£ã«å¯ãã ãŠãŒã¹ã±ãŒã¹ãçã蟌ãããã«ããŸãããããšãã°ä»¥äžã®ãããªã«ããŽãªã§ãæ¥åã«è¿ããŠãŒã¹ã±ãŒã¹ãçã蟌ã¿ãŸãã ãã¬ã¹ãç³» åŸæ¥ã®æ¥åã®å·¥æ°ãäžããç³» åŸæ¥ã®æ¥åã®ã¯ãªãªãã£ãäžããç³» çŽè¿ã®ChatGPT Plusã®æ©èœå
容 OpenInterpreterã§ããè€éãªããšãã§ãã話 ChatGPTã®äœ¿ãæ¹ååŒ·äŒ ããã¯äžèšã®ããã¥ã¡ã³ãããã®ãŸãŸãã¢çã«ç޹ä»ããŸãã ããã¥ã¡ã³ããèªãŸããªãã®ã¯äžã®åžžãããçšåºŠãæéããåãããŠ(ä»åã¯1æé)éäžããŠChatGPTã«ã€ããŠèããŠãããå¿
èŠããããŸã å
±éã®äœéšãéããŠã話é¡ã«ã®ãŒãããããè¿ãã®åžã§å£é ã§ã®ç¥èŠã®å
±æã«ã€ãªããã®ãå匷äŒã®å©ç¹ã ãšæããŸã ãã£ãçµæã¯ãšãããšããããŸãŸã§ChatGPTã«ã¯æ£è§£ã®ããçããèããŠåã€ãããŠäœ¿ããªããšæã£ãŠããã©ããã¬ã¹ãã«ãã£ã¡ã䜿ãã!ããªã© ã¡ããã¡ããè¯ãåå¿ã¯åŸãããŸãã äœæŠéããŠãŒã¹ã±ãŒã¹ãè²ã
玹ä»ããããšã§ãåã
ã®æ¥åã§ã®æŽ»çšã€ã¡ãŒãžãå
·äœçã«ãã£ãŠãããããã§ãã ãšã¯ããããããŸã§ãç¿æ
£åã®ããã®äžæ©ç®ãªã®ã§ããã¬ããžã·ã§ã¢ãOJTçãªåãã¯ç¶ç¶ããŠè¡ã£ãŠããå¿
èŠããããŸã OpenInterpreterãé£ã«åº§ã£ãŠãã«ã¹ã¿ããŒãµã¯ã»ã¹ã®æ¹ã«è©ŠããŠããã ç¶ç¶çã«ChatGPTã«èå³ããã£ãŠãããããã«ãäœãé£ã³éå
·çãªå®çžŸãå¿
èŠã ãšèããŸãã OpenInterpreterãŸãã§ããããšãã話ãèããã®ã§ãããã䜿ã£ãŠã¿ãããšã«ããŸãã ã¡ãªã¿ã«åãããŒã ã®furuhama-sanãOpenInterpreterã®å®è£
ãæ·±æãããŠãã®ã§ããèå³ã®ããæ¹ã¯èŠãŠã¿ããšé¢çœãã§ã tech.every.tv OpenInterpreterã®ã¡ãªããã®ç޹ä»ã¯furuhama-sanã®èšäºãèªãã§é ããšåãããŸãããä»åé
åã«æããã®ã¯ä»¥äžãªããšã§ãã GoogleColaboratoryãšããç°¡åã«çšæã§ããéããç°å¢ã§ã®å®è¡ããããã ããŒã«ã«ã®ãã¡ã€ã«ã®é²èЧ/ç·šéãã§ãã(ä»åã¯ããŠã³ãããGoogleDrive) äžèšã掻ãããŠããã¡ã€ã³ç¥èãæã€ããžãã¹ãµã€ããããçšåºŠã®ããŒã¿åæãŸã§èªç«çã«è¡ãããš ä»åŸã®åææ¥åã®ããŒãã«ãäžãããããæ¿ã瀺åãç¥èŠã財ç£ãšããŠå¹ççã«è²¯èãããã¡ãªããããããŸã ãã¡ããäžççžã§ãããšã¯æã£ãŠããŸãããããã®ç¬¬äžæ©ãšããŠãé£ã«ãã人ã«ç¡çãèšã£ãŠOpenInterpreterã䜿ã£ãŠé ããŸãã ããžæè¬ã§ããé£ã®äººãªã®ã§ä»®ã«TãããšåŒã³ãŸããããTããã¯ããã°ã©ãã³ã°ãã§ããªãã«ã¹ã¿ããŒãµã¯ã»ã¹ã£ãœãç«ã¡äœçœ®ã®ã²ãšã§ã ãã£ãããšã¯ä»¥äžã§ã CSV圢åŒã§åºåãããã¢ã³ã±ãŒãçµæãOpenInterpreterã§ã¯ãã¹éèšãã ããŸããªããããããæžããGoogleColaboratoryãäºåã«çšæ TããããããããããšãèããŠãææ³ã説æããªããä»®ã®ããã³ãããç®ã®åã§æžããŠã¿ã OpenInterpreterãã³ãŒãã®å®è¡èŠåŠãèããŠããã®ã§ãTããã«æ·±ãèããã«ã©ãã©ãå®è¡ã®æç€ºãåºããŠããã æå³ããçµæã§ã¯ãªããåŠçã«æéãããããªãå床ããã³ãããèŠã€ãçŽããç¹°ãè¿ã çµæãšããŠç¹å®ã®ã¢ã³ã±ãŒãé
ç®ããã®ä»ã®é
ç®ãšã¯ãã¹éèšãããã®ã20åãããåŸãããŸãã ãšã©ãŒãžã®å¯ŸåŠããåãColabã®ä»æ§ã«çãããšããããTããã®ãæéã¯ãããªãã«é ããŠããŸã£ãã®ã§ãã(4h+α)ã ãããšåãã§é ããŸãã ãšããã®ããããããä»åã®ã¢ã³ã±ãŒãçµæã®ã¯ãã¹éèšã¯åŸæ¥ä»¥äžã®åé¡ãæ±ããŠããããã§ãã æéãããã ã²ãšã€ã²ãšã€ã®ã¯ãã¹éèšã®ããã«éœåºŠæ°åŒãçµãå¿
èŠãããã®ã§ç²Ÿç¥çã«ã€ãã TãããšããŠã¯ãææç©ãåŸãããããšããã¡ããã§ãããäžèšãèªåã®æã§ãããªããŠããããšããããšã«å¥œå°è±¡ãæã£ãŠããããã§ãã ãŸãããšã©ãŒãåºããšãã«èœã¡ãã®ã§ã¯ãªãããšã©ãŒã®å
容ãçè§£ããäžã§å床修æ£ã®åŠçããããŠãããã®ã¯ãã£ã¡ãå¬ãããšãä»°ã£ãŠããŸãã æçµçã«ã¯æçã蚎ããŠãããã²ããããã¡ãããåœä»€ãäžããŠããã®ã§ãããèªå·±åçãããã ãã§èŠªè¿æãèœçããã®ã¯å€§å€è峿·±ãçŸè±¡ã§ãã ãããã«OpenInterpreterã¯å
çã«ãã«ãåŠçãç¹°ãè¿ãã®ãã²ãšã€ç¹åŸŽã§ããããæ©ãã§ããããã«èŠããã®ãäººéæ§ãæãããã€ã³ããªã®ãããããŸãã éã«ä»¥äžã®ç¹ãã€ãããã§ãã ã€ã³ã¿ã©ã¯ãã£ãã«åŠçå®è¡ã®æç¡ãèãããã®ã§ãåžžã«å€æãæ±ãããã ã³ãŒããã¬ã³ã¬ã³åºåããããæå³ããããã ãªãã ããã ããã©ããã ããã¯å®éšããåã«ããçšåºŠäºæž¬ã¯ããŠããã®ã§ãããã¯ããããããšããæãã§ã äºåã®auto_runã®èšå®ããtemperatureã®èª¿æŽ/ããã³ããã®ç²Ÿé¬ã§ããçšåºŠè§£æ±ºã§ãããã§ã¯ãããŸããã ç®ãŸããããåºåãããæ
å ±ã«ç¥ããç¥ããã®ãã¡ã«å¯åŠå粟ç¥ãæ¶è²»ãããŠããããã§ãã äŸãã°GASãæŽããã¹ãã¬ããã·ãŒããæäŸãããªã©ã§ã屿çãªè§£æ±ºã¯å¯èœãªèª²é¡ã§ããã OpenInterpreterã§ããçšåºŠæè»ã«èª²é¡ãè§£æ±ºåºæ¥ãããšã¯ããã£ãã®ã§ãåŒãç¶ããããããŸã䜿ã£ãŠããžãã¹ãµã€ãã®èª²é¡è§£æ±ºãç®æããŠããããã§ã â» äœè«ã§ããã¢ããããŒãåŸOpenInterpreterãããŸãåããªããªããŸãã(10/16æç¹, ver: 0.1.7) ãã®issueã®å¯Ÿå¿ãããããšã§è§£æ±ºããŸãã https://github.com/KillianLucas/open-interpreter/issues/637 ãŸãšã 以äžãããžãã¹ãµã€ãã«ChatGPTã®å©çšãç¿æ
£ã¥ãããããšãããªãŒãšæã£ãäžã§ è²ã
ãã£ãŠã¿ãè©±ãæžããŠã¿ãŸãã ãšããããç¬¬äžæ©ç®ãšããŠããã¥ã¡ã³ãã®äœæ/å匷äŒãªã©å®æœãããããªãã®åå¿ã¯é ããå€å°å©çšã¯ä¿é²ã§ãã宿ã¯ãããŸã ãšã¯ãããä»åŸç¿æ
£åã®ããã«ã¯èã®æ ¹éåãéèŠã«ãªã£ãŠããŸã ããžãã¹ãµã€ãã§è§£æ±ºããããããªèª²é¡ãèŠã€ããããã®å Žã§ChatGPTã«è§£ããŠããããªã© 现ããäœéšãç¹°ãè¿ããŠããããšã§ãåããŠç¿æ
£ãæåãšããŠæ ¹ä»ããã®ã ãšæã£ãŠããã®ã§ãå¿æŽãããããé¡ãããŸã
åããŸããŠãDELISH KITCHEN éçºéšã®åç°ãšç³ããŸãããã®èšäºã§ã¯AWS Elemental MediaConvertã䜿ã£ãŠã¬ã·ãåç»ã®ãµã ãã€ã«ãäœæããæ¹æ³ã玹ä»ããŸãã ãµã ãã€ã«äœæã®èæ¯ DELISH KITCHEN ã¯ã¬ã·ããåç»ã§ããããããåºæ¬çãªæçããã¢ã¬ã³ãžãŸã§æ§ã
ãªã¬ã·ããå
¬éããŠããŸãã ã¹ããã§ãã©ãŠã¶çã®DELISH KITCHENãã¿ãŠããã ããå Žåãã¬ã·ãã®åå·¥çšã¯æé ã®èª¬æãšãã€ã³ãã衚瀺ããŠããŸãã ä»åã¯ããå·¥çšãåããããããªãããããã«ç»åã远å ããéã³ãšãªããŸããã ã¢ããªãPCãã©ãŠã¶çã®DELISH KITCHENã§ã¯å·¥çšã®åç»ãæ¿å
¥ãããŠããããšãããåç»ã®ãµã ãã€ã«ãå·¥çšç»åãšããŠå©çšããããšã«ããŸããã ããããªããçŸåšèšå®ãããŠãããµã ãã€ã«ã¯åç»éå§æç¹ã®ãã£ããã£ã«ãªã£ãŠããŸãã ãã®ãããåç»éå§æç¹ã®ãã¬ãŒã ã«ãªã£ãŠãããµã ãã€ã«ããã§ã«åç»ã®å€æåŠçã§å©çšããŠããAWS Elemental MediaConvertãçšããŠã¬ã·ãããšã«é©åãªãã¬ãŒã ã§èšå®ã§ããããå®è£
ãé²ããŸããã AWS Elemental MediaConvertãšã¯ AWS Elemental MediaConvertïŒä»¥äžãMediaConvertãšããŸãïŒã¯ãã¡ã€ã«ããŒã¹ã®åç»åŠçãµãŒãã¹ã§ãåŸæ¥ã®ãããŒããã£ã¹ãããã³ãã«ãã¹ã¯ãªãŒã³ããã€ã¹ãžã®ã€ã³ã¿ãŒãããã¹ããªãŒãã³ã°ã«å¿
èŠãªåœ¢åŒã«ã¡ãã£ã¢ã倿ããããšãã§ããŸããåºç€ãšãªãã€ã³ãã©ã®ã»ããã¢ããã管çãã¡ã³ããã³ã¹ã¯äžèŠã§ãå¿
èŠãªãããªåŠçèšå®ã§ãžã§ããéä¿¡ããã ãã§äœ¿çšãéå§ããããšãã§ããŸãããžã§ãã¯ãã©ã³ã¹ã³ãŒãäœæ¥ãè¡ããã®ã§ãå
¥åãã¡ã€ã«ãšåºåãã¡ã€ã«ãæå®ããã©ã®ãããªãã¡ã€ã«ãäœæãããããã©ã®ãããªãã©ãŒãããã§äœæããããçãèšå®ããŸãã 詳ããã¯ãã¡ã åãçµãã ããš ãµã ãã€ã«ã®äœæã«ã¯MediaConvertã®ãã¬ãŒã ãã£ããã£æ©èœãå©çšããŸããã ãã¬ãŒã ãã£ããã£æ©èœã¯åç»ã®éæ¢ç»ãäœæããããã®æ©èœã«ãªããŸãã ãµã ãã€ã«äœæã«ããã£ãŠã¯æ¢åã§1æ¬ã®ã¬ã·ãåç»ãæå®ããç§æ°ã§ã¯ãªããã³ã°ããŠãããžã§ããããã®ã§ããã«ãã¬ãŒã ãã£ããã£ãçµã¿èŸŒãããšã«ããŸããã åç»ã®ãã£ããã£ã¿ã€ãã³ã°ã«ã¯ãã¬ãŒã ã¬ãŒããæå®ããå¿
èŠããããŸããããã¥ã¡ã³ãã§ã¯ã³ã³ãœãŒã«ã«ããèšå®ãäŸã«ããŠããŸããããã³ã³ãœãŒã«ã§ã¯éçãªå€ããæã€ããšãã§ããŸããããã®ãããã¬ã·ãããšã«æå®ããããã¬ãŒã ãç°ãªãä»åã®å Žåãã³ã³ãœãŒã«ã«ããèšå®ã§ã¯ãªãåçãªå€ãå©çšã§ãã圢ã§å®è£
ããå¿
èŠããããŸããã åçãªå€ãå©çšããããã®å®è£
æ¹æ³ã¯2ã€ã§ããAWS CLIã䜿çšããŠJSONã«ãã£ãŠãžã§ã仿§ãèšå®ããæ¹æ³ããããã¯SDKãäœ¿ãæ¹æ³ã§ããä»åã¯æ¢åã®å®è£
ãAWS CLIãçšããŠããããããã¬ãŒã ãã£ããã£ã®ãžã§ã仿§ãJSONã§å®è£
ããããšã«ããŸããã ä»åã¯åŒç€Ÿã§MediaConvertãæ¢ã«å©çšãããŠããããšãããã以äž1-3ã®æé ã¯ç¹ã«è¡ããŸããã§ããããåããŠå©çšããå Žåã¯ä»¥äžã®æé ãèžãå¿
èŠããããŸãã ãã¡ã€ã«çšã®ã¹ãã¬ãŒãžãäœæãã Amazon S3 ã³ã³ãœãŒã«ã䜿çšããŠãã±ãããäœæããŸããMediaConvert ã¯ãAmazon S3 ãŸã㯠HTTP ã HTTPS ã䜿çšãããµãŒããŒããã®å
¥åãã¡ã€ã«ãåãå
¥ããŸãã IAM ã®ã¢ã¯ã»ã¹èš±å¯ãã»ããã¢ãããã MediaConvert ã S3 ãã±ããã«å¯Ÿããèªã¿èŸŒã¿ãšæžã蟌ã¿ãå®è¡ã§ããããã«ããã«ã¯ããããæ
ã Identity and Access Management (IAM) ããŒã«ãäœæããŸãã 笊å·åãããœãŒã¹ãã¡ã€ã«ãã¢ããããŒããã Amazon S3 ã³ã³ãœãŒã«ã䜿çšããŠãAmazon S3 ãã±ããã«ãœãŒã¹ãã¡ã€ã«ãã¢ããããŒãããŸãã ãžã§ããäœæãã ãããªãã¡ã€ã«ã 1 ã€ããŸãã¯è€æ°ã®åºåã«å€æããããã® MediaConvert ãžã§ããäœæããŸãã åŒçšå
: AWS Elemental MediaConvert å
¬åŒããŒãž ãã¡ããäœæããJSONã§ããäžéšã®èšå®ã¯çç¥ããŠããŸãã { " Settings ": { " OutputGroups ": [ { ... " Name ": " File Group ", " Outputs ": [ { " ContainerSettings ": { " Container ": " RAW " } , " VideoDescription ": { " Width ": <åºåãã£ããã£ã®å¹
>, " Height ": <åºåãã£ããã£ã®é«ã> " CodecSettings ": { ... " Codec ": " FRAME_CAPTURE ", " FrameCaptureSettings ": { " FramerateNumerator ": < fps >, " FramerateDenominator ": <ãã£ããã£ãããã¬ãŒã çªå·>, " MaxCaptures ": 2 , ... } } , ... } , " Extension ": " jpg ", " NameModifier ": <åå修食å> } ] , " OutputGroupSettings ": { " Type ": " FILE_GROUP_SETTINGS ", " FileGroupSettings ": { " Destination ": <åºåãã¡ã€ã«ã®æ ŒçŽå
> } } } ] , ... " Inputs ": [ { " FileInput ": <å
¥åãã¡ã€ã«ã®æ ŒçŽå
> } ] } } åºæ¥äžãã£ããµã ãã€ã«ããã¡ãã§ãã å®è£
ã«ãããã€ãŸã¥ãããšãã æ¬å®è£
ã«ãããŠã¯3ç¹ã€ãŸã¥ãããšããããããŸããã ãã¬ãŒã ã®ãã£ããã£ã¿ã€ãã³ã°ã¯ç§æ°ã§æå®ã§ããªã åœåããã£ããã£ã®ã¿ã€ãã³ã°ã¯åç»ã®ã¯ãªããã³ã°ãšåæ§ã«ã¿ã€ã ã³ãŒãã§æå®ã§ããã®ããšæã£ãŠããã®ã§ããããã¬ãŒã ãã£ããã£ã§ã¯ã¿ã€ã ã³ãŒãã§ã®æå®ãã§ããªã仿§ãšãªã£ãŠããŸããã æ¬¡ã«æãã€ããæ¹æ³ããµã ãã€ã«ã«ãããç§æ°ãåç»ã®ã¹ã¿ãŒãæç¹ãšãªãããå
ã®åç»ãã¯ãªããããŠ0ãã¬ãŒã ç®ããµã ãã€ã«ã«æå®ããæ¹æ³ã§ãïŒä»¥äž3.åç
§ïŒãããããã¡ãã«ã€ããŠãMediaConvertã¯åç»ãããã¯ãªãŒãã£ãªã®åºåããããžã§ãã«ãããŠã®ã¿ãã¬ãŒã ãã£ããã£ãäœæããããšãã§ããã¬ãŒã ãã£ããã£ã®ã¿ã®åºåãžã§ããäœæããããšã¯ã§ããŸãããæ¯åäžèŠãªåç»ãäœæãããŠããŸãã®ã§æå¿µããŸããããããã£ãŠä»åã¯ä»¥äž2ã§ç޹ä»ããframerateã«ããèšå®ãæ¡çšããŸããã framerateã®èšå® ãã£ããã£ã®ã¿ã€ãã³ã°ãæå®ããã«ã¯ãframerateãèšå®ããŸããå
·äœçãªèšå®ã¯ãframerate = framerateDenominator / framerateNumeratorããšãªããframerateDenominatorã«ã¯FPSïŒãã¬ãŒã ã¬ãŒãïŒãframerateNumeratorã¯ãã£ããã£ããããã¬ãŒã çªå·ãæå®ããŸãã ãµã ãã€ã«äœææã¯ãã£ããã£å¯Ÿè±¡ã®åç»ã確èªããªããç§æ°ã§ãã£ããã£ã®ã¿ã€ãã³ã°ãæå®ããŠãããããããããã¬ãŒã çªå·ã«å€æããå¿
èŠãããã®ã§ããã©ãããã°é©åã«æå®ããç§æ°ããã¬ãŒã çªå·ã«æå®ã§ããã®ãèŠæ
®ããŸããã ã³ã³ãœãŒã«ã§ç¢ºèªãããšframerateã¯ä»¥äžã®ããã«èšå®ããããšã«ãªããŸãããã®å Žåã¯ãããªã®ãã¬ãŒã ã¬ãŒãã30FPSã§ã50ãã¬ãŒã ããšã«1ãã¬ãŒã ãJPEGãã¡ã€ã«ã«ãã£ããã£ããŸãã (åè: AWS for M&E Blog ) æå€§ãã£ããã£æ°ã¯2ã«ããå¿
èŠãããããš MediaConvertã¯åžžã«åç»éå§æç¹ã®ãã¬ãŒã ããã£ããã£ããããã2æã§èšå®ããŠãããªããšæ¬²ãããã£ããã£ã¯ååŸã§ããŸããã ãžã§ããå®äºãããšãåºåã®S3ãã±ããã«2ã€ã®ãã¹ã¿ãŒãã¬ãŒã JPGç»åãèŠã€ããã®ã§2ã€ç®ã®ç»åãã¡ã€ã«ïŒ clip-poster.0000001.jpg ïŒãæå®ãããã¬ãŒã çªå·ã®ãã£ããã£ç»åã«ãªããŸãã çµããã« æ¬èšäºã§ã¯AWS Elemental MediaConvertãå©çšããŠåç»ã®ãµã ãã€ã«ãäœæããæ¹æ³ã玹ä»ããŸããããããŸã§ãèªã¿ããã ãããããšãããããŸããã
ã¯ããã« ã¯ãããŸããŠã2023 幎 4 æããæ°åå
¥ç€Ÿã retail HUB ã§ Software Engineer ãããŠããã»ãã ( @hon_d7174 )ã§ããGo ã奜ãã§ãïŒ çŸåšãç§ãã¡ã¯ Next.js ã䜿çšããŠæ°èŠãããã¯ããéçºããŠããŸãããã®ããã°ã§ã¯ãç§ãã¡ãåãçµãã§ãããããžã§ã¯ãã®äžã§å·¥å€«ããç¹ã«ã€ããŠã話ãããããšæããŸãã ãŸããæ¢åã®ãããã¯ãã Next.js 13 ãžç§»è¡ããéã®æµãã工倫ã«ã€ããŠã¯ãã¡ãã®èšäºãã芧ãã ãã: Next.js ã® Pages Router ãã App Router ãžã®ç§»è¡ã«ææŠããŠã¿ã ãããã¯ãæŠèŠ åœç€Ÿã®ãããã¯ãã¯ãå°å£²æ§åãã«ã¢ããªãæäŸããŠããŸãããã®ã¢ããªã«ã¯ãã¯ãŒãã³ããç¥ãããã¢ããªãŠãŒã¶ãŒã®ååã管çããããã·ã¥ããŒããå«ãŸããŠãããå°å£²æ§ã¯ãã®ããã·ã¥ããŒãã䜿çšããŠã¢ããªã®ãŠãŒã¶ãŒãã³ã³ãã³ãã®ç®¡çãç°¡åã«è¡ãããšãã§ããŸãã åœç€Ÿã®ãããã¯ãã¯ã以äžã®ãããªç¹åŸŽãæã£ãŠããŸãã ãã«ãããã³ãã¢ãŒããã¯ã㣠åå°å£²æ§ã¯ãããããç¬èªã®ããã³ããšããŠã·ã¹ãã ãå©çšããŸããããã«ãããç°ãªãå°å£²æ§éã§ã®ããŒã¿ããªãœãŒã¹ã®åé¢ãå®çŸãããŠããŸãã ã¢ã¯ã»ã¹å¶åŸ¡ åããã³ãããŠãŒã¶ãŒã«ã¯ãé²èŠ§ã»æäœå¯èœãªãªãœãŒã¹ãå©çšå¯èœãªãµãŒãã¹ãç°ãªããŸããã¢ã¯ã»ã¹å¶åŸ¡ã«ãããã»ãã¥ãªãã£ã匷åããæ
å ±ã®æŒæŽ©ãäžæ£ãªæäœãé²ããŸãã ã·ã¹ãã æ§æ ã·ã¹ãã æ§æå³ ç§ãã¡ã®äœæããŠãããããã¯ãç°¡åãªã·ã¹ãã æ§æå³ã¯äžèšã®ããã«ãªã£ãŠããŸãããã®äžã® web client ãš BFF ã« Next.js ãçšããŠããŸãã Library 以äžã¯ä»å説æããå
容ã«ç»å Žãã䞻㪠Library ã«ãªããŸãã SWR Auth.js(æ§ NextAuth) å®è£
ãããã¯ãæŠèŠã§è¿°ã¹ãã¢ã¯ã»ã¹å¶åŸ¡ã«ã€ããŠäžéšå®è£
ã«ã€ããŠèª¬æããŸãã Auth.js ãçšããèªèšŒã»èªå¯ã®å®è£
ã¯ããã«èªèšŒã»èªå¯ã«ã¯ Auth.js ãçšããŠããŸããAuth.js ã® interface ãäžèšã®ããã«æ¡åŒµããŠãŒã¶ãŒæ
å ±ã Token ã管çããŠããŸããAuth.js ã® cookie ã§ç®¡çããããšã«ãã client side, server side ã§å
±éã®ç¶æ
管çãå¯èœã«ãªããŸããäžèšã§ã¯æ¬ãããã¯ãã§å®éã« client side, server side ã§å©çšãããµãŒãã¹ãããã³ãã«é¢ããæ
å ±ãèšå®ããŠããŸãã declare module 'next-auth' { interface User extends User { services: string[]; chain: string; chains: string[]; access_token: string; expires_at: number; } interface Session extends Session { user: { id: string; services: string[]; chain: string; chains: string[]; } & DefaultSession.user; access_token: string; expires_at: number; } } declare module 'next-auth/jwt' { interface JWT { services: string[]; chain: string; chains: string[]; access_token: string; expires_at: number; error?: 'RefreshAccessTokenError'; } } 次㫠client side ã«ãã㊠Auth.js ã§äœæãã JWE ã®ããŒã¿ã«ã¢ã¯ã»ã¹ããæ¹æ³ã«ã€ããŠã§ãã client side ããã¢ã¯ã»ã¹ããéã«ã¯ useSession() ãçšããŸããclient side ãã JWE ã®æŽæ°ãå¿
èŠãªéã«ã¯ useSession() ã® update ãš Auth.js ã® jwt callback ãäžèšã®ããã«å®è£
ããå¿
èŠããããŸãã const { data: session } = useSession(); <Menu mode="horizontal" items={chains} onClick={({ key }) => update({ chain: key })} {...props} /> jwt callback ãäžèšã®ããã«ããããšã«ãã update ã§æŽæ°ããã session ã®å
容ã jwt ã«ãåæ ããããšãå¯èœã«ãªããŸãã callbacks: { async jwt({ token, user, session, trigger }) { if (user && trigger === 'signIn') { token.sub = user.id; token.email = user.email; token.name = user.name; token.services = user.info['services']; token.chain = user.info['mart'][0]; token.chains = user.info['mart']; } // sessionãæŽæ°ãããéã«tokenãæŽæ°ããã trigger === 'update' && session.chain && (token.chain = session.chain); return token; }, middleware ã®å®è£
middleware ã§ã¯äž»ã«èªèšŒã»èªå¯ç¶æ
ã®æ€èšŒãš HTTP ãªã¯ãšã¹ããããã®å
±éåãã¢ã¯ã»ã¹å¶åŸ¡ã®å®è£
ãè¡ãªã£ãŠããŸãã Next.js 13 ã® middleware 㯠page é·ç§»æãš route handler ãžã®ã¢ã¯ã»ã¹æã®äž¡æ¹ã§åäžã® middleware ã䜿ãããŸãã middleware ã§ã¯ hooks ã®ãã㪠client side ã§ãã䜿ããªãåŠçã¯è¡ããªãããšã«æ³šæããå¿
èŠããããŸãã èªèšŒã»èªå¯ç¶æ
ã®æ€èšŒã¯ client side ã§çšããŠãã useSession() ã§ã¯ãªã Auth.js ã«ãã£ãŠçæããã JWE ãååŸããããšãã§ãã getToken() ãçšããŠæ€èšŒããŸãã export default async function middleware(req: NextRequest) { const newRequest = new NextRequest(req, req); const { pathname } = req.nextUrl; const token = await getToken({ req: req }); const accessToken = token.access_token; // tokenã®æç¡ãæ€èšŒãã const isAuthenticated = !!token; -------------------------------------çç¥-------------------------------------- // èªèšŒãå¿
èŠãªããŒãžãžã®é·ç§»ãBFFãžãªã¯ãšã¹ãã®éã«æ€èšŒãè¡ã if (!isAuthenticated) { return NextResponse.redirect(`${process.env.BASE_URL}/signIn`); } -------------------------------------çç¥-------------------------------------- } 次㫠HTTP ãªã¯ãšã¹ããããã®å
±éåã«ã€ããŠã§ãã æ¬ãããã¯ãã§ã¯ä»¥äžã®äºã€ã® header ãäž»ã«å
±éã§äœ¿ãããŠããŸãã äžã€ç®ã¯èªèšŒãå¿
èŠãª page, BFF ãžãªã¯ãšã¹ãããéã«å¿
èŠãª Authorization header ã§ãã // AccessTokenãAuthorization headerã«è¿œå ããã newRequest.headers.set('Authorization', `${accessToken}`); äºã€ç®ã¯åçš®ãªãœãŒã¹ãµãŒããŒã§ããã³ãããšã«ç°ãªãåŠçãè¡ãéã«å¿
èŠãªããã³ã header ã§ãã // ããã³ãæ
å ±ãå¿
èŠãªãšã³ããã€ã³ãã確èªãå¿
èŠãªå Žåã¯headerã远å ããã if (isMartAPIRoute(pathname)) { const chain = token.chain; newRequest.headers.set('X-Mart-Chain', chain); } SWR ãçšãã repository ã®å®è£
äžèšã BFF ãžã®ãªã¯ãšã¹ããè¡ã client ã®å®è£
ã«ãªããŸãã ãŠãŒã¶ãŒèå¥å( userID )ãšããã³ãæ
å ±( chain )ã Auth.js ã® useSession() ãçšããŠååŸããããšã§èªèšŒã»èªå¯ç¶æ
ã®æ€èšŒãè¡ããŸãããŸããããã cache key ã«å«ããããšã§åäžããã€ã¹ã§ç°ãªããŠãŒã¶ãŒãã¢ã¯ã»ã¹ããç¶æ
ããŠãŒã¶ãŒãè€æ°ã®ããã³ããè·šãã§å©çšããã±ãŒã¹ã§äžæŽåãèµ·ããªãããã«ããŠããŸããå ã㊠userID ãŸã㯠chain ã falsy ãªå€ã®å Žå null ã key ãšããŠæž¡ãããšã§èªèšŒã»èªå¯ç¶æ
ãæ£ãããªããšãã«ãªã¯ãšã¹ããè¡ãããªãããã«ããŠããŸãã function useCoupon(id: string) { // Auth.jsããèªèšŒã»èªå¯æ
å ±ããŠãŒã¶ãŒé¢é£æ
å ±ãååŸããã const { data: session } = useSession(); const chain = session?.user?.chain; const userID = session?.user.id; return useSWR(chain && userID ? [`/api/coupons/${id}`, chain, userID] : null, getCouponFetcher, { suspense: true, revalidateOnMount: false, }); } async function getCouponFetcher([url]: [string]): Promise<Coupon> { const res: Coupon = await fetch(url, { }).then(async (res) => { if (!res.ok) { const { message }: ErrorMessage = await res.json(); throw { message: message, code: res.status }; } return res.json(); }); return res; } çµããã« ãã«ãããã³ãã®ã¢ããªã±ãŒã·ã§ã³ãšããããšã§ãŠãŒã¶ãŒã«çŽã¥ãæ
å ±ã ãã§ãªãçŸåšãã®ãŠãŒã¶ãŒãã©ã®ããã³ãã«é¢é£ãããªãœãŒã¹ãæäœããŠããããšããããšãèæ
®ããå¿
èŠãããç¹ãç¹ç°ã§ãããšæããŸããããŸãè©³çŽ°ãªæš©éèšå®ã¯ãŸã å®è£
ããŠããªãã®ã§ããããããèæ
®ãããšããã«è€éæ§ãå¢ãã®ã§ããäžå±€å·¥å€«ãå¿
èŠã ãšæããŸããã ãã«ãããã³ãã»ãã«ããµãŒãã¹ã®éçºãè¡ãããšèããŠãã人ã®åèã«ãªãã°å¹žãã§ãã ãããŸã§èªãã§ããã ãããããšãããããŸããïŒ
ãšããªãŒã§CTOãããŠãã imakei ã§ãã ãšããªãŒã§ã¯å®æçã«CEOã®åç°ããã¹ããŒã¬ã³ãæ²ããããŸãã 仿ã®ã¹ããŒã¬ã³ã¯ ãææŠãã§ããã CEOã®ãã¬ãŒã³ããæå (â»äžéšç€Ÿå
åãã®å
容ãããã®ã§æ¶ããŠãŸã) ãã®èšäºã§ã¯ãéçºéšã»ãšã³ãžãã¢ã«ãšã£ãŠã®ãææŠããšã¯äœãªã®ãã ãšããªãŒã®éçºéšã§ã®è§£éãå
±æã§ããã°ãšæããŸãã ãŸããå®ã¯ãã®ã¹ããŒã¬ã³ã決ãŸãåããéçºéšã§åãçµãã§ãã ãææŠWEEKãã«é¢ããŠãè§Šããããã°ãšæããŸãã ãšããªãŒã®éçºéšã«ãããææŠã®èãæ¹ 詳现ã¯åŸè¿°ããŸããããšããªãŒã®éçºéšã§ã¯ã4åæããšã«ãææŠWEEKãã宿œããŠããŸãã ä»å¹Ž3æããå§ããã§ã«2å宿œããŠããã®ã§ããããã®äžã§ã¢ã³ã±ãŒããªã©ããæãããã課é¡ã«ã äºæ¥éšã®ããŒãããããæ¢ããŠãŸã§ãå¥ã®ããšããæå³ãããããªã ããŸããææŠãçãªå
容ã宿œã§ããªãã£ã ãªã©ãææŠãšã¯äœãªã®ãã人ã«ãã£ãŠéãããšã§çãŸãããã®ããããŸããã ããã§ãèªåã®æ¹ã§èšèªåããã®ãäžèšã«ãªããŸãã éçºéšã«ããããææŠããšã¯ äºæ¥ã«ãããæŠç¥ã®å®çŸ æè¡çãªèгç¹ããããäžèšãæšé²ããããã®ææŠ äžé·æçãªç®ç·ã§ã®åŒ·ãéçºçµç¹ã®å®çŸ ã§ãã (â»äžéšç€Ÿå
åãã®å
容ãããã®ã§æ¶ããŠãŸã) 1. äºæ¥ã«ãããæŠç¥ã®å®çŸãžã®ææŠ ããã«åçŽã«ãããšããŒããããã®å®çŸã»éæã«ãªãããšæããŸãã åŒç€Ÿã«éããããã³ãã£ãŒäŒæ¥ã§ã¯åžžã«é«ãæé·çãæ±ããããŸãã ãã®äžã§ç«ãŠãããããŒããããã¯ããªãã¢ã°ã¬ãã·ããªãã®ãå€ãã ä»ãŸã§éãã®éçºãããŠããŠã¯éæã§ããªããã®ãå€ãã§ãã ãã®äžã§æŠç¥ãçè§£ãã€ã€ããããæéã§å®çŸããããã®è©Šè¡é¯èª€ãéçºãææŠã®1ã€ãšããŠããŸãã 2. æè¡çãªèгç¹ããããäžèšãæšé²ããããã®ææŠ 1ã€ç®ãšè¢«ããšããããããŸãããããã§ã¯æŠç¥ãå®çŸããã ãã§ã¯ãªãã ãããããã«é²ããããšã«çŠç¹ãåœãŠãŠããŸãã LLMãã¯ãããAIãæ©æ¢°åŠç¿ããŸãåŒç€Ÿã§ããã°OMOã«é¢é£ããæè¡ãªã©ã æšä»ã®ãããã¯ãã®ã³ã¢ãæè¡ãæ
ã£ãŠããããæè¡ã䜿ãããšã§ããžãã¹ã®å¹
ãåºããªã£ããã èªãæãåãããªããšãããªããšæã£ãŠããæ®æ®µã®æ¥åã®ã»ãšãã©ãæè¡ã§å¹çåã§ããæä»£ã«ãªããŸããã ãããã¯æè¡ãç¥ããªããšæ°ä»ããªãããšãå€ãããšã³ãžãã¢ããã®çºä¿¡ãå«ã åžžã«æ°ããæè¡ã«å¥œå¥å¿ãæã¡ããããã©ã䜿ãããèããããšãéèŠã«ãªã£ãŠããŸãã 3. æç¶å¯èœãª 匷ãéçºçµç¹ ãžã®ææŠ ããã§ãã 匷ãéçºçµç¹ ãšã¯ãããããã«ã¡ã³ããŒãåçŽã«é«ãã¹ãã«ãæã¡åãããã ãã§ãªãã ãã®ã¹ãã«ãçºæ®ããäºæ¥ã䌞ã°ããçµç¹ãæããŠããŸãã 匷ãçµç¹ ã®ããã«ã¯ãŸããä»ãŸã§äžããŠãããããªææŠãã§ããå¿
èŠãããã®ã¯ãã¡ããã ãããæç¶å¯èœãªç¶æ
ã«ãªããšãããŸããã æç¶å¯èœã§ããããã«ãåã
ã®ææŠãåçºã§çµããã®ã§ã¯ãªãã ç¶ç¶çã«ææŠã§ãããããªä»çµã¿ã¥ããã倱æãæããææŠãè®ããããæåã¥ãããå¿
èŠã§ãã ãã®èгç¹ããã ãšããææŠWEEKãèªäœãããããææŠãªã®ãããããŸããã ãŸããæç¶å¯èœãªçµç¹ãäœã£ãŠããäžã§ æ¡çš ã倧åã«ãªã£ãŠããŸãã çµç¹ã¯åžžã«ã¹ã±ãŒã«ããŠããããŸãäºæ¥ãã©ãã©ãæ¡å€§ãããªãã§ãã£ãŠãã ææŠããç¶ããããã«ã¯ä»²éãæ¡çšããŠããã»ãã«ãããŸããã é¶åµãªéšåããããŸããã匷ãçµç¹ã»åããããšæããçµç¹ã¥ãããããŠããããšã§ã 匷ã仲éãæ¡çšã§ãã匷ã仲éãæ¡çšããããšã§ãã匷ãçµç¹ã«ãªã£ãŠãããšããè¯ã埪ç°ãçã¿ããã§ãã ææŠWEEK ããŠããããªåŒç€Ÿã§ãããä»å¹ŽãããææŠWEEKããšãããã®ã宿œããŠããŸãã ææŠWEEKãšã¯éåžžã®åäºæ¥éšã®ããŒããããããé¢ããæè¡çã«äœãã«éäžããŠææŠãã1é±éãæããŠããŸãã äžèšã®ãææŠããèžãŸãããšã ãšããªãŒã® ææŠ ãæšé²ããããã« ãšã³ãžãã¢ãªã³ã°ãäžæ©åã«é²ããããã® WEEK ãšèšããã§ãããã ææŠWEEK ååæããšã«å®æœããŠãããéœåºŠäºæ¥éšã®æ¹ã«ãé¡ãããŠã 宿œé±ã¯å¯èœãªéãããŒãã£ã³ã°çã0ã«ããŠãããã ãŸãšãŸã£ãæéãéçºã«åœãŠãããããã«èª¿æŽããŠããã£ãŠããŸãã ïŒå¯å®¹ãªã¿ãªããã«ãŸãã§æè¬:pray:ïŒ åè¿°ããããã«ãã§ã«2åéå¬ãããŠããã11æã«3åç®ãæ§ããŠããŸãã 第äžåã§ã¯ãŸã ãŸã ãææŠããæµžéããã«ãæ¥ã
ã®æ¹åãããã ãŸãšãŸã£ãŠéçºã§ããé±ãšããŠäœ¿ã£ãŠããŸãããšããããŸãããã (ãããäºæ¥éšã®ããã ã£ããããã®ã§ããã¡ããã¿ããªåããã§ããã) åŸã
ã«åæãæŽããŠããŠããã®ãã11æåã«åããŠã¯è¯ãææŠå
容ãéãŸã£ãŠãããŸãã ãŸã ãŸã æ¹åç¹ãå€ãã®ã§ãããéœåºŠã¢ããããŒããããŠããã®ã楜ããã ä»åŸãäŒç€Ÿã®ææŠãçœåŒããå¶åºŠãšãªãããããã«è¯ããã®ã«ããŠããããã§ãã ãŸã第1åã®æ§åã¯every.thingã§èšäºã«ããªã£ãŠããŸãã®ã§ããã²èŠããŠãã£ãŠãã ããïŒ https://everything.every.tv/20230428 ãããã« ãšããªãŒã®éçºéšã«ããããææŠãããŸãšããŠã¿ãŸããã æè¡çãªææŠã ãã§ãªããäºæ¥ã䌞ã°ãããã仲éãéããããã®ææŠããç¶ããŠããäŒç€Ÿã§ãã ãããªãšããªãŒã§ã¯ãäžç·ã«ææŠããŠããã仲éãå
šæ¹äœã§åéããŠãããŸãã ãã®ããã°ã§å°ãã§ããããããããã ãªããšæã£ãŠãããæ¹ã¯äžç·ã«åããŸãããïŒ https://corp.every.tv/recruits#position-list
ã¯ãããŸããŠãæ ªåŒäŒç€ŸãšããªãŒã®éçºæ¬éšã®ããŒã¿&AIããŒã ã§ããŒã¿ãµã€ãšã³ãã£ã¹ããããŠãã倿¿µã§ãã æè¿è©±é¡ã®Open Interpreterã«ã€ããŠãå®è£
ã®äžèº«ã远ã£ãã®ã§ç°¡åãªè§£èª¬ãšææã«ã€ããŠãŸãšããŸããã Open Interpreter Open Interpreterãšã¯ãLLMã«æç€ºãåºããããŒã«ã«ç°å¢ã§ã³ãŒããå®è¡ããããŒã«ã§ãã å
¬åŒã®README ã«ãããšãChatGPTã®æ©èœãšããŠäœ¿ããOpenAI Code Interpreterãšã¯ç°ãªããOpen Interpreterã®å£²ãã¯ããŒã«ã«ç°å¢ã§å®è¡ã§ããããšããšæããŸãã èªç¶èšèªãéããŠã察話çã«PCã®äžè¬çãªæ©èœã®æäœãããã¡ã€ã«ã®äœæã»ç·šéãããŒã¿åæãªã©ãããŒã«ã«ã§å®çŸå¯èœã§ãã ãã£ãããããŒã«ã«ãã¡ã€ã«ã«å¯ŸããŠãèªç¶èšèªã§ã©ã®çšåºŠã¿ã¹ã¯ãæç€ºã§ããã®ã詊ããŠã¿ãŸããã ç°¡åãªã¿ã¹ã¯ïŒç»åãã¡ã€ã«ã®ç§»åæäœãäŸã«ïŒ Macã§ã¹ã¯ãªãŒã³ã·ã§ãããæ®ããšãããã©ã«ãã§ã¯Desktopã«æºãŸããšæããŸãã ãã®ã¹ã¯ãªãŒã³ã·ã§ãããã¡ãæç€ºéãåŒã£è¶ãã§ããã詊ããŠã¿ãŸãã æç€ºãšããŠæåã«äžããå
¥åã¯ä»¥äžã§ãã Desctopé
äžã®ã¹ã¯ãªãŒã³ã·ã§ãããDocumentsé
äžã«screenshotãšãããã£ã¬ã¯ããªãäœã£ãŠç§»åã㊠å
·äœçãªã³ãã³ãã¯äžåæããã«è©ŠããŸããã çµæã¯ä»¥äžã«ãªããŸããã ããã§ãå人çã«è¡æçã ã£ãã®ã¯ãããŒã«ã«ãã¡ã€ã«ã«å¯ŸããŠLLMã§æäœã§ããŠããããšã§ã¯ãªãã èªåã§åé¡ã«æ°ã¥ããŠè§£æ±ºã§ããŠãã ããšã§ãã mvã³ãã³ããæ£åžžã«åäœããŠããªãããšãçè§£ããäžã§ãlsã³ãã³ããå®è¡ããå®è¡çµæãããšã«Screen Shotã§ã¯ãªãã¹ã¯ãªãŒã³ã·ã§ããã§ããããšæ°ã¥ããŠèªå·±è§£æ±ºããŠããŸããŸãããé©ãã§ãã å®è£
ã®è§£èª¬ ãããããæ¬é¡ã§ãã èªåã§åé¡ã«æ°ã¥ããŠèªå·±è§£æ±ºã§ããããšãã©ãå®çŸããŠããã®ããOpen Interpreterã®å®è£
ã®äžèº«ã远ã£ãŠã¿ãŸããã 説æã®ããæ£ç¢ºæ§ãããããããããéèŠããŠããŸãããçæãã ããã github.com å
šäœå å
šäœåãšããŠã¯ã以äžã®ãããªåŠçã®æµãã§ãã ãŸãããŠãŒã¶ã®æç€ºïŒããã§ã¯ããã³ãããšåºå¥ããããã«æç€ºãšè¡šçŸããŸãïŒãåãåããLLMã«æž¡ãããã³ãããäœæããŸãã æ¬¡ã«ãLLMãããã³ãããããšã«ããŠãŒã¶ã®æç€ºã«æ²¿ãããã°ã©ã ãäœæããŸãã æåŸã«äœæããã³ãŒããå®è¡ããŸãããããŠå®è¡çµæãããã¯ãšã©ãŒæãå床LLMã«æž¡ãããã³ããã«å ããŠäœæãçŽããŸãã ããããŠãŒã¶ãæ¢ãããŸã§ç¹°ãè¿ããŸãã æ·±æã ããã§æ³šç®ãããã®ã¯ãããã³ããäœæéšåã§ãã æ°ã«ãªã£ãã®ã¯ä»¥äžã®3ç¹ã§ããã configã®system message åèããã¹ãã®æäŸïŒopen proceduresïŒ æå€§tokenãè¶
ãããšãåŠç äžèš3ç¹ãå
šäœåã«åæ ããããšä»¥äžã®ããã«ãªããŸãã ãããã詳现ãè¿°ã¹ãŠãããŸãã configã®system message OpenAIã®apiã䜿çšããéãå
éšã§ã¯ä»¥äžã®messegesã®ãããªæ§é ãçšããŠãããã³ãããäœæããŸãã response = openai.ChatCompletion.create( model= "gpt-3.5-turbo" , messages=[ { "role" : "system" , "content" : "You are a helpful assistant." }, { "role" : "user" , "content" : "Who won the world series in 2020?" }, { "role" : "assistant" , "content" : "The Los Angeles Dodgers won the World Series in 2020." }, { "role" : "user" , "content" : "Where was it played?" } ] ) roleã«ã¯ãsystemãuserãassistantã®ãããããå
¥ããŸãã userã«ã¯ãŠãŒã¶ãŒãåºããæç€ºãassistantã¯LLMã®åçãsystemã¯assistantã®åçå«ããåäœãèšå®ããããã«äžããŸãã system messageã¯å¿
é ã§ã¯ãããŸããããåçã®å質ãé«ããããã«ã¯éèŠãªèŠçŽ ã§ãã ååããã³ããã®æåã«å
¥ããŸãã 詳ãã㯠OpenAIã®Chat completions APIã®ããã¥ã¡ã³ã ã«æžãããŠããŸãã Open Interpreterã«æåã«äžããsystem messageããconfigå
ã«æžãããŠããã以äžã«å人çã«æ°ã«ãªã£ããã®ãæç²ããŸããã æç²ã¯ç¿»èš³ãããããã®ã貌ã£ãŠããããåæã¯ ãªããžã㪠ããåç
§ãã ããã ããªãã¯ãªãŒãã³ã»ã€ã³ã¿ãŒããªã¿ãŒãã³ãŒããå®è¡ããããšã§ã©ããªç®æšãéæã§ããäžçäžæµã®ããã°ã©ããŒã ã ããããLLMã«å¯ŸããŠãããŒã«ãæç¢ºã«ããããã³ãããæžãããŠããŸãã ãŸããèšç»ãæžããŠãã ããã åã³ãŒããããã¯ã®éã«å¿
ãèšç»ãå確èªããŠãã ãã ã (ããªãã¯æ¥µåºŠã®çæèšæ¶åªå€±ãªã®ã§ãèšç»ãä¿æããããã«åã¡ãã»ãŒãžãããã¯ã®éã§èšç»ãå確èªããå¿
èŠããã)ã Open Interpreterã¯å®è¡åã«æé ãæžããŠãããã®ã¯ããã®ããã³ãããå¹ããŠããã§ãã ãŸããã³ãŒãã®å
容ãå¿ããªãããã«åŒ·èª¿ããŠãŸããã©ã®å€æ°ã«äœã®å€ãå
¥ããŠããããªã©ãå¿ããªãããã«ããããããªãšæããŸãã ããªããã³ãŒããå®è¡ãããšãããã㯠ãŠãŒã¶ãŒã®ãã·ã³ äžã§å®è¡ãããããŠãŒã¶ãŒã¯ããªãã«ãã¿ã¹ã¯ãå®äºããããã«å¿
èŠãªã³ãŒããå®è¡ãã å®å
šãã€å®å
šãªèš±å¯ ãäžããŠããŸããããªãã¯ããã®ãŠãŒã¶ãŒãå©ããããã«ããã®ãŠãŒã¶ãŒã®ã³ã³ãã¥ãŒã¿ãã³ã³ãããŒã«ããããã®å®å
šãªã¢ã¯ã»ã¹æš©ãæã£ãŠããŸãã ã³ãŒããå®è¡ã§ããããšãOpen Interpreterã®åãã®ã²ãšã€ãªã®ã§ãå®è¡ã§ããããã«åŒ·èª¿ããŠããã®ãããããŸããã ã€ã³ã¿ãŒãããã«ã¢ã¯ã»ã¹ã§ãããç®æšãéæããããã« ããããã³ãŒã ãå®è¡ããæåã¯æåããªããŠããäœåºŠã詊ããŠãã ããã æè¿ã®ãã¥ãŒã¹ã«ã€ããŠèããªã©ããå Žåãã¯ããŒãªã³ã°ããŠæ
å ±ãåŸãããšããã®ã¯ããã®ããã³ãããå¹ããŠããã§ãã äžè¬çã«ãã§ããã ãå°ãªãã¹ãããã§ èšç»ãç«ãŠã ããã®èšç»ãå®è¡ããããã«å®éã«ã³ãŒããå®è¡ããããšã«é¢ããŠã¯ã 1ã€ã®ã³ãŒããããã¯ã§ãã¹ãŠãè¡ãããšããªãããšãéèŠã§ãã äœãã詊ããããã«é¢ããæ
å ±ãå°å·ããããããå°ããªãæ
å ±ã«åºã¥ããã¹ãããã§ç¶ããã¹ãã§ããäžåã§ã§ããããã«ãªãããšã¯ãªãããäžåã§ããããšãããšãç®ã«èŠããªããšã©ãŒã«ã€ãªããããšãå€ãã ããã§æžãããŠããããã«ãäžåºŠã«ã³ãŒãã¯æ°è¡çšåºŠã§çæã»å®è¡ããŠãããŸãã ä»®ã«ãšã©ãŒãåºãŠããªã«ããªãããããOpen Interpreterãªãã§ã¯ã®ããã³ããããªãšæããŸããã ããªãã«ã¯ ã©ã㪠ä»äºãã§ããã æåŸã«å±ãŸãã ãã®ããã³ãããããã®ã§è峿·±ãã§ãã åèããã¹ãã®æäŸïŒopen proceduresïŒ ãã®åŠçã§ã¯ããŠãŒã¶ãæç€ºããã¿ã¹ã¯ã解決ããäžã§åèã«ãªãããã¹ããæäŸããŠããŸãã åèããã¹ãããsystem messageãšããŠå
¥åããŠããŸãã github.com ãŸãããããããã¿ã¹ã¯ãšã¿ã¹ã¯ã«é¢é£ããããã¹ããçŽã¥ããæ§é ããŒã¿ïŒtext_dbïŒãçšæããŸãã ãã®ããŒã¿ããã¯ãã«åããŠãvector_dbå
ã«embeddingsãä¿åããŠãããŸãã æ¬¡ã«Open Interpreterããæç€ºãpostããããšãsearch apiå
ã§æç€ºããã¯ãã«åããŸãïŒquery_embeddingsïŒã æåŸã«ãembeddingsãšquery_embeddingsã®ã³ãµã€ã³é¡äŒŒåºŠãèšç®ãã䌌ãŠããäžäœ2ä»¶ã®ããã¹ããè¿ããŸãã åèããã¹ããå®éã«åœ¹ç«ã€ã®ã¯ããŠãŒã¶ãæç€ºããã¿ã¹ã¯ããtext_dbå
ã®å
容ãšé¢é£ãããšãã®ã¿ã§ãã åèããã¹ããåã蟌ãã§ããŸã£ããæåŸãããã³ããå
ã«ãã€ãºãšããŠå
¥ã£ãŠããŸãã®ã§ã¯æããŸãããã以äžã®ãããªããã³ãããåæã«æ·»ããŠå¶åŸ¡ããŠããããã§ãïŒ åè ïŒã èšç»ã®äžã§ãããã¿ã¹ã¯ã«é¢é£ããã®ã§ããã°ãäžèšã®æé ããã¹ããããšãããããã®ã§ããã°ã æ£ç¢ºãªã³ãŒãã®æç ïŒç¹ã«éæšå¥šã®éç¥ã®å Žåã¯ã --åçªå·ã®ã€ããã¹ãããã®äžã«ãããèšç»ã«æžã蟌ãã§ãã ãã ïŒãå«ããŠãã ããã ç¹°ãè¿ããŸãããããã¿ã¹ã¯ã«é¢é£ããã®ã§ããã°ãäžèšã®æé ãã éèªç㪠ã³ãŒãã®æç ããçŽæ¥ããªãã®èšç»ã«å«ããŠãã ããã çµæ§åŒ·åŒã ãªãšæããŸãããã OpenAI apiã®ããã¥ã¡ã³ã ã«ã䌌ããããªããšãæžãããŠãããããããã³ãããšã³ãžãã¢ãªã³ã°ã§ã¯ããããå¶åŸ¡æ¹æ³ãªã®ãããããŸããã æå€§tokenæ°ãè¶ãããšãã®å¶åŸ¡ tokenãšã¯ãæç« ãæå³ãæã€æå°åäœã«ãããã®ã§ãã Open Interpreterã§çšããããšãã§ããLLMã«ã¯ããã€ãã®éžæè¢ããããåã¢ãã«ããšã«æå€§tokenæ°ãèšå®ãããŠããŸãã gpt-4ã¯8192ãããå®äŸ¡ãªgpt-3.5-turboã¯4096ãããŒã«ã«ã§äœ¿ããCode Llamaã¯1048ãšãã£ãå
·åã§ãïŒ åè ïŒã ãã®tokenæ°ãè¶ããªãããã«å¶åŸ¡ããå¿
èŠãããã OpenAIã®å¯ŸåŠæ³ ãšããŠã¯ã以äžã®æ¹æ³ãæããããŠããŸãã åã®äŒè©±ã®èŠçŽorãã£ã«ã¿ãªã³ã° åã®äŒè©±ãåºåçã«èŠçŽããŠé£çµããèŠçŽã®èŠçŽãäœæ ããããOpen Interpreterã§ã¯ã以äžã®ææ³ããšã£ãŠããŸãã tokenæ°ã®å²åãçšããŠãæé ãšææ«ããããããæåãååŸããéã ... ã§é£çµ ãŸãã(å¿
èŠtokenæ° / 䜿çštokenæ°) * ã¡ãã»ãŒãžæåæ°ã§ãããã³ãããšããŠäœ¿çšããæåæ°ã決ããŸãã æ¬¡ã«ã決ããæåæ°ã2ã§å²ã£ãæåæ°ïŒ=half_lengthïŒãèµ·ç¹ãšããŠãæé ããhalf_lengthæ°ã®æåãšææ«ããhalf_lengthæ°ã®æåãååŸããŸãã æåŸã«ãæé + ... + ææ«ãšããããã«é£çµããŠãtokenæ°ãè¶ããªãããã«å¶åŸ¡ããŸãã github.com Open Interpreterå
ã®ããŒã¿æ§é ãããŸã§ã®èª¬æã§ãããã³ãããäœæã§ããŸããã ãããããã®ããã³ãããLLMã«æž¡ããã³ãŒããå®è¡ããŸã ãã®åŠçã®æµãã®äžã§ãOpen Interpreterã¯äžèšãã©ãŒãããã®ããŒã¿æ§é ã管çããŠããŸãã messages: List[Dict[ str , Any]] ãã®ãã©ãŒãããã§æç³»åé ã«äœæãããã€ã¡ãŒãžã以äžã«ãªããŸãã ãŠãŒã¶ãã³ãŒãå®è¡ã®éã¯ã«ãŒããç¶ãããããäŒè©±ãç¶ãã° {role: user} ãš {role: assistant} ã亀äºã«ç¶ããŠãããŸãã Open Interpreterãå©çšããäžã§ã®èª²é¡ Open Interpreterã®å®è£
ã远ãããšã§ããããã®åããé®®æã«ãªã£ãŠããŸããã ãããã詊ãäžã§ä»¥äžã®ãããªåé¡ç¹ãèŠããŠããŸããã ã³ã¹ã Open Interpreterã¯ããã³ããã«æ§ã
ãªå·¥å€«ããããŸããããã®å·¥å€«ãå®çŸããŠãããããã«ãinputãšoutputã®tokenæ°ãè¥å€§åããŠããŸããŸãã çµæãšããŠãã³ã¹ããå¢å ããŠãããŸãã 粟床 ã³ã¹ããåæžããããã«ãLLMã¢ãã«ãšããŠå®äŸ¡ãªgpt-3.5-turboãããŒã«ã«ã§Code Llamaã䜿ãããšãã§ããŸãããgpt-4ãšæ¯ã¹ããšæ£çŽç²ŸåºŠã埮åŠã§ããã Open Interpreterã«éããŸããããæå€§tokenæ°ãããããLLMãšã®äŒè©±ã¯ç¡å¶éã«ç¶ããããŸããã Open Interpreterã¯tokenã®äœ¿çšéãå¢å ããããäžã«ãæå€§tokenæ°ãè¶ãããšãã®å¶åŸ¡ãèŠçŽã§ã¯ãªãéã ... ã§è£éãããããæ°åã®äŒè©±ã§éå»ã®äŒè©±å
容ãå¿ããå¿
èŠãªæ
å ±ãæãèœã¡ãå¯èœæ§ããããŸãã ãããå°ãªããã粟床ã«åœ±é¿ããããããããŸããã ã³ãŒãã®å®è¡ãæåŸ
ããªãå Žåã¯ãã¹ããã Open Interpreterã¯åºæ¬ã©ããªåé¡ã«å¯ŸããŠããã³ãŒããäœæã»å®è¡ããŠè§£æ±ºããããšããŸãã ãã®ãããã³ãŒããäœæãããç®çã ãšéåžžã«è¯ãããŒã«ã§ããããã以å€ã®ç®çã ãšåããã©ãæããŸãã äŸãã°ãpdfãèŠçŽããŠã»ãããšæç€ºãããšãããšããŠãŒã¶ã欲ããã®ã¯èŠçŽããããã¹ãã ãã§ããOCRãèŠçŽçšã®ã©ã€ãã©ãªãã€ã³ã¹ããŒã«ããŠå®è¡ããã³ãŒããæ±ããŠããŸããã ãŸãšã Open Interpreterã«é¢ããŠãå®è£
ã®ç°¡åãªè§£èª¬ãšææããŸãšããŸããã Open Interpreterã«è§Šããäºã§ããã®åããäœæããããšãã§ããããã³ãããšã³ãžãã¢ãªã³ã°ã«ã€ããŠãçè§£ãæ·±ããããšãã§ããŸããã ä»åŸã®ã¢ããããŒããåŒãç¶ããã£ããã¢ãããç¶ããããšæããŸãã
ã¯ããã« ããã«ã¡ã¯ãDELISH KITCHEN éçºéšã§å°å£²åãåãã®éçºãããŠããæ± ã§ãã åŒç€Ÿã§ã¯å°å£²äºæ¥è
ãèªç€Ÿãããã¹ãŒããŒã¢ããªãã¹ããŒãå°å
¥ã§ãããã©ãããã©ãŒã ãæäŸããŠããŸãã https://biz.delishkitchen.tv/retailhub ãããã¹ãŒããŒã¢ããªã®éçºã« Flutter ãå©çšããŠãããæ¥ã
äºæ¥æ¡å€§ã«åããŠéçºãé²ããŠããŸãã æ¬èšäºã§ã¯ãæè¿éçºãé²ããŠããäžã§äžèš 2 ã€ã®ããã©ãŒãã³ã¹æ¹åã«ç¹ãã£ãäºäŸã«ã€ããŠãDevTools ã® Performance View ã亀ããªããã玹ä»ããŸãã Flutter 3.10 ã¢ããããŒãã«äŒŽã Shader compilation jank è§£æ¶ GridView ã®ããã©ãŒãã³ã¹æ¹å ããã©ãŒãã³ã¹æ¹åã®åæç¥è DevTools Performance View Flutter ã«ã¯ DevTools ãšããããã©ãŒãã³ã¹ããã³ãããã°ããŒã«ãæšæºã§åãã£ãŠããããã®äžã®äžã€ã®æ©èœã« Performance View ãšããæ©èœããããŸãããã®æ©èœã¯ããã¬ãŒã ããšã®ããã©ãŒãã³ã¹ã¡ããªã¯ã¹ããã£ããã£ããŠèŠèŠåããæ©èœã§ãããã®æ©èœãå©çšããããšã§åŸè¿°ãããžã£ã³ã¯ãšããäœããã©ãŒãã³ã¹ãªãã¬ãŒã ãšããã«é¢é£ããåŠçãæ€åºããããšãã§ããŸãã ãã¬ãŒã ãã£ãŒã ãã¬ãŒã ãã£ãŒãã§ã¯ããã¬ãŒã ããšã®æç»ã®åŠçæéã衚瀺ãããŸããè²ã®ã€ããããŒã®åã»ãã㯠1 ãã¬ãŒã ã®åŠçæé衚ããŠãããè²ã«ãã£ãŠ UI åŠçæéãRasterïŒGPUïŒåŠçæé çã衚ããŠããŸãã ã¿ã€ã ã©ã€ã³ã€ãã³ããã£ãŒã ã¿ã€ã ã©ã€ã³ã€ãã³ããã£ãŒãã§ã¯ããã¬ãŒã ãã£ãŒãã§ããŒãéžæãããšã察å¿ãããã¬ãŒã ã®è©³çްã衚瀺ãããŸããUI ã¹ã¬ãããš RasterïŒGPUïŒã¹ã¬ããã®äž¡æ¹ã®ãã¬ãŒã ãæ§ç¯ããå
šãŠã®ã€ãã³ãã確èªããããšãã§ããŸãã ãžã£ã³ã¯ãšã¯ ç»é¢ã®æç»ã«ã€ããŠã1 ãã¬ãŒã ãæç»ããã®ã« 1 ãã¬ãŒã 以äžã®æç»æéãããã£ãŠããŸããšã該åœã®ãã¬ãŒã ã¯æç»ãããã¹ããããããŸãããã®å Žåãã¢ããªç»é¢ã¯ã³ãé£ã³ã®ããã«ã¬ã¿ã€ãã衚瀺ãšãªããŸãããã®ãããªäœããã©ãŒãã³ã¹ãªãã¬ãŒã ããžã£ã³ã¯ãšãããŸãã 1 ãã¬ãŒã ã¯ã60fps ããã€ã¹ã ãš 1/60 â 16 ããªç§ãªã®ã§ãåãã¬ãŒã ã®æç»æéã 16 ms 以äžã§ãªããã°ãUI ãä¹±ãããããã¬ãŒã ãèœã¡ããããããšããããŸãã ãã®ãããªãžã£ã³ã¯ãã¬ãŒã 㯠Performance View ã®ãã¬ãŒã ãã£ãŒãã§ã¯ãªã¬ã³ãžè²ãšããŠè¡šç€ºãããããããã¬ãŒã ãã£ãŒããå©çšããããšã§æ€åºããããšãã§ããŸããäžèšãã¬ãŒã ãã£ãŒãç»åãã¿ããšããªã¬ã³ãžè²ã«ãªã£ãŠããããŒã確èªã§ãããšæããŸãã Flutter 3.10 ã¢ããããŒãã«äŒŽã Shader compilation jank è§£æ¶ åŒç€Ÿãããã¹ãŒããŒã¢ããªã§ã¯çŸåš Flutter 3.10 ãžã®ã¢ããããŒã察å¿ãé²ããŠããŸããFlutter 3.10 ã§ã¯ Impeller ãšããæ°ããã¬ã³ããªã³ã°ãšã³ãžã³ã iOS ã®ããã©ã«ãã®ãšã³ãžã³ãšããŠèšå®ãããŸãããImpeller ã«ãã åŸè¿°ã® Shader compilation jank ãšããèµ·åæã®ããã©ãŒãã³ã¹äœäžã®åé¡ãè§£æ¶ãããã®ã§ããã®å
容ã«ã€ã㊠Performance View ãå©çšããŠç¢ºèªããŠãããŸãã Shader compilation jank ãšã¯ Shader compilation jank 㯠åè¿°ãããžã£ã³ã¯ã®äžçš®ã§ãã Flutter ã®ããã©ãŒãã³ã¹åé¡ã®äžã€ã«ãååã¢ãã¡ãŒã·ã§ã³æã«å€§ããã¬ã¿ã€ãåé¡ããããŸããã·ã§ãŒããŒã¯ GPU äžã§åäœããã³ãŒãã®äžéšã§ãFlutter ãåŸæ¥ã¬ã³ããªã³ã°ã«äœ¿çšããŠãã Skia ã°ã©ãã£ãã¯ã¹ã©ã€ãã©ãªã¯ãæ°ããæç»ã®ã³ãã³ããåããŠèŠããšããã«ã¹ã¿ã GPU ã·ã§ãŒããçæããŠã³ã³ãã€ã«ããããšããããŸãããã® Skia ã«ããã·ã§ãŒããŒçæãšã³ã³ãã€ã«ã¯ããã¬ãŒã ã®ã¯ãŒã¯ããŒããšé ã«è¡ãããŸããã³ã³ãã€ã«ã«ã¯ã«ã¹ã¿ã GPU ã·ã§ãŒãã«ãã£ãŠã¯æ°çŸããªç§ãããå¯èœæ§ãããããã®éããã³ã³ãã€ã«ã«ãã£ãŠãã¬ãŒã ãæ¬ èœãã倧ããã¬ã¿ã€ããããªåäœãšãªããŸããããã Shader compilation jank ã§ãã Shader compilation jank è§£æ¶ç¢ºèª Flutter 3.3.10 ããŒãžã§ã³ã¢ããåã® Flutter 3.3.10 ã§ Shader compilation jank ã®çºçã確èªããŸãã ã¢ããªã®ååã¢ãã¡ãŒã·ã§ã³ãåäœãããéã® Performance View ãæ¬¡ã®ç»åã§ããèµ€é»ã衚瀺ãããŠããç®æã Shader Compilation ã®åŠçæéãšãªããŸãã 4.4ms ãšåœã¢ããªã§ã¯åœ±é¿ã¯å°ãªãã§ãããçºçããŠããããšã確èªã§ããŸãã Flutter 3.10.6 次ã«ãFlutter 3.10.6 ã«ã¢ããããŒãããç¶æ
ã§ãåæ§ã« Performance View ã確èªããŸãã èµ€é»ã衚瀺ãããŠãã Shader Compilation ããªããªã£ãŠããããšã確èªã§ããŸããã GridView ã®ããã©ãŒãã³ã¹æ¹å 次ã«ãGridView ã®ããã©ãŒãã³ã¹æ¹åã«ã€ããŠã玹ä»ããŸãã åŒç€Ÿãããã¹ãŒããŒã¢ããªã«ã¯ãã«ããŽãªã«æå±ããååãã°ãªãã圢åŒã§è¡šç€ºããç»é¢ããããŸããç¡éã¹ã¯ããŒã«æ©èœã«ããç»é¢ãã¹ã¯ããŒã«ããŠã³ããŠãããšã次ã
ã«èŠçŽ ãèªã¿èŸŒãããã«ãªã£ãŠããŸãããã®ç»é¢ã«ãããŠããã©ãŒãã³ã¹ã®äœãå®è£
ãšãªã£ãŠããããããããã説æããæ¹åæ¹æ³ã詊ããŸããã GridView ãšã¯ GridView ã¯äžèšã¢ããªç»é¢ã®ããã«ã°ãªãã圢åŒã§èŠçŽ ã衚瀺ããéã«äœ¿çšãã Widget ã§ãã åŒç€Ÿãããã¹ãŒããŒã¢ããªã®ããã«å€§éã®èŠçŽ ã衚瀺ããã°ãªããã§ã¯ GridView.builder ã³ã³ã¹ãã©ã¯ã¿ã䜿çšããããšãå
¬åŒã«æšå¥šãããŠããŸããGridView.builder ã³ã³ã¹ãã©ã¯ã¿ã䜿çšããããšã§ãç»é¢ã®è¡šç€ºé åã«å¿
èŠãªèŠçŽ ã®ã¿ããã«ããããé åå€ã®èŠçŽ ã¯é åå
ã«å
¥ã£ãã¿ã€ãã³ã°ã§åçã«æç»ããããããªãé
å»¶æç»ãå®çŸããããšãã§ããŸãã æ¬¡ã®ãµã³ãã«ã§ç»é¢ãã¹ã¯ããŒã«ãããšãconsole ã«ãã«ããããã¿ã€ãã³ã°ã§æåã衚瀺ãããé
å»¶æç»ãããŠããããšã確èªã§ããŸãã GridView ã®ããã©ãŒãã³ã¹ãäœäžããå®è£
äŸ GrieView ãä»ã® Widget ãšäžç·ã«çžŠæ¹åã«äžŠã¹ãŠã¹ã¯ããŒã«ããããã±ãŒã¹ãèããŸãã ãã®å®è£
ã« Column ãš SingleChildScrollView ãçµã¿åãããæ¬¡ã®ãµã³ãã«ã®ãããªå®è£
ã詊ããŠã¿ãŸããããå
ã»ã©ãšåæ§ã« console ã§ãã«ããããã¿ã€ãã³ã°ã確èªãããšãé
å»¶æç»ãããã«å
šãŠã®èŠçŽ ãåæã«ãã«ããããŠããããšãããããŸãã ãã㯠shrinkWrap ã true ã®å Žåã«ãããŠãGridView ãèªèº«ã®å Widget ã«åãããŠé«ãã調æŽããããã§ãã芪ã§ãã SingleChildScrollView ãš Column ã¯é«ããç¡å¶éã§ãããããGridView ã¯äºåã«å
šãŠã®åèŠçŽ ã®é«ããèšç®ãããã®é«ãã«åºã¥ããŠã¹ã¯ããŒã«ãèšå®ããŸãããã®ããå
šãŠã®èŠçŽ ãåæã«ãã«ãããå¿
èŠããããé
å»¶æç»ãããããã©ãŒãã³ã¹ãäœäžããŸãããŸããshrinkWrap ã false ã«ãããšãç¡å¶éã®é«ããšèªèããããšã©ãŒãšãªããŸãã åŒç€Ÿãããã¹ãŒããŒã¢ããªã§ãåæ§ã®å®è£
ãšãªã£ãŠããã衚瀺é åå€ã®èŠçŽ ãåæã«ãã«ããããŠããŸãããPerformance View ã§ç¢ºèªãããšã次ã®ç»åã®ããã« StaggeredGrid ã®äžã§å€§éã®èŠçŽ ãçæãããŠããŸãã GridView ã®ããã©ãŒãã³ã¹æ¹åã®å®è£
äŸ ãã®åé¡ã¯ CustomScrollView ãš SliverGrid ã䜿çšããããšã§åé¿ããããšãã§ããŸãã ãã®ã³ãŒãã§ã¯ãCustomScrollView å
ã« SliverToBoxAdapter ã§ ListTile ãé
眮ããããã« SliverGrid ãé
眮ããŠããŸããSliverGrid å
ã§ã¯ãSliverChildBuilderDelegate ã䜿çšããŠåèŠçŽ ãåçã«çæããŠããŸããããã«ããè€æ°ã® Widget ã瞊ã«äžŠã¹ãã¹ã¯ããŒã«ç»é¢ã«ãããŠãGrid ã®èŠçŽ ã®é
å»¶æç»ãå®çŸããããšãã§ããŸããã åŒç€Ÿãããã¹ãŒããŒã¢ããªã®è©²åœå®è£
ãåæ§ã«ä¿®æ£ãããšãGridView ã«ããçæãããèŠçŽ æ°ã倧å¹
ã«åæžãããã¹ã¯ããŒã«ã§åçã«é
å»¶æç»ãããããã«ãªããŸããã ãããã« ä»åã¯ããã©ãŒãã³ã¹æ¹åã«ç¹ããäºäŸã 2 ã€ãPerformance View ã亀ããªãã玹ä»ããŸããã Performance View ãå©çšããããšã§ãæ®æ®µéçºããŠããäžã§ã¯æ°ä»ãã«ããäœããã©ãŒãã³ã¹ãã¬ãŒã ããã®åŠçã®ããã«ããã¯ãæ€åºããããšãã§ããŸãã ä»åã玹ä»ããæ¹åã¯å€§ããªæ¹åã§ã¯ãªãã§ãããå°ããæ¹åã®ç©ã¿éãããŠãŒã¶ããªãã£ã®é«ãã«ç¹ãããšæãã®ã§ãä»åŸãããã©ãŒãã³ã¹ãæèããªããéçºãç¶ããŠãããã°ãšæããŸãã ãã®èšäºãå°ãã§ã Flutter éçºã®åèã«ãªãã°å¹žãã§ããããããšãããããŸããã åè https://docs.flutter.dev/tools/devtools/performance https://docs.flutter.dev/perf/shader https://docs.flutter.dev/perf/best-practices#be-lazy https://youtu.be/LUqDNnv_dh0?feature=shared
åããŸããŠïŒãã¢ããéçºéšã§Software Engineer(SE)ãããŠããéŽæšã§ãïŒ SEããŒã ã¯APIéçºãããã®APIãå©çšããwebéçºãŸã§å¹
åºãé åãæ
åœããŠããïŒãã¢ããéçºéšã®webéçºã«ã¯ Next.js ãæ¡çšããŠããŸãïŒ ãŸãïŒãšããªãŒã®éçºéšã§ã¯å®æçã«ææŠweek(â»)ãªããã®ãéå¬ãïŒæè¡ç芳ç¹ããäºæ¥è²¢ç®ãè¡ã1é±éãèšããŠããïŒãã®äžã§Next.jsã® Pages Router ã App Router ã«ç§»è¡ããæ©äŒãé ããã®ã§ç޹ä»ãããŠããã ããŸãïŒ â» ææŠweekã«ã€ããŠã¯ä»¥äžã®ãªãŠã³ãã¡ãã£ã¢ã§èšäºã«ããŠããŸãïŒä»åã®ææŠweekã¯äºæ¥éšã®å£æ ¹ãè¶
ããããŒã ç·šæã§è¡ãïŒå€§å€é¢çœããã®ã§ããïŒ エンジニアが楽しみながら開発体験を向上させる「挑戦week」を実施しました! èæ¯ Next.jsã§ã«ãŒãã£ã³ã°ãè¡ãéïŒ v13以å㯠Pages Router ãå©çšããå¿
èŠããããŸãããïŒv13以é㯠App Router ãšããä»çµã¿ãéžæè¢ã«å ãããŸããïŒ App Router㯠React ã®ææ°æ©èœïŒ React Server Components ã Suspense ãªã©ïŒã«è¿œåŸããã«ãŒãã£ã³ã°ã·ã¹ãã ã§ããããšããïŒNext.jså
¬åŒã«ã¯ æ°ããã¢ããªã±ãŒã·ã§ã³ãäœæããéã«ã¯App Routerã®å©çšãæšå¥š ãããŠããïŒæ¢ã«App Routerã§ããå©çšåºæ¥ãªãæ©èœã®éçºãèŠåããããŸãïŒ ãããã®ããšããïŒå¹Ÿã€ãã®ã¡ãžã£ãŒã¢ããããŒããçµãŠApp RouterãNext.jsã®ã«ãŒãã£ã³ã°ã·ã¹ãã ã®äž»æµã«ãªãããšãäºæ³ãããããïŒé·æã«ãããNext.jsã®ææ°æ©èœã«è¿œåŸããŠããããã«ã¯Pages RouterããApp Routerãžã®ç§»è¡ãå¿
èŠã ãšå€æãææŠããéã³ã«ãªããŸããïŒ ç§»è¡å¯Ÿè±¡ 圱é¿ã®å€§ãããéã¿ãŠïŒç§»è¡å¯Ÿè±¡ã«ã¯ãã¢ããã§å©çšããŠããdashboardãæ¡çšããŸããïŒ ç§»è¡ã®æµã 1. Pages Routerã®åããŒãžãApp Routerã®ããŒãžã«å€æããã¹ã¯ãªããã®äœæ åœç¶ã§ããïŒApp Routerãžç§»è¡ããããã«ã¯Pages Routerã®ããŒãžãç§»è¡ããããšãå¿
é ã§ãïŒ Pages RouterãšApp Router㯠å
±åãå¯èœ ãªããïŒ1ããŒãžãã€ç§»è¡ããŠããããšãåºæ¥ãã®ã§ããïŒäžã€ãã€çœ®æããŠãããšç§»è¡ãçµãããŸã§ã«ããªãã®æéãèŠããŠããŸãããšãïŒdashboard以å€ã«ãApp Routerã«ç§»è¡ããã察象ãããããïŒäžæ¬ã§çœ®æããã¹ã¯ãªãããäœæããããšã«ãªããŸããïŒ å
¬åŒãã㯠Codemods ã®çœ®æã¹ã¯ãªããã¯æäŸãããŠããªãããïŒPages Routerã®åããŒãžã«å¯Ÿã以äžã®ã«ãŒã«ã«åºã¥ãã倿ãããã¹ã¯ãªãããèªäœããŸãã(â»)ïŒ æéã¯èŠããŸããå®è£
ã«å°é£ãªç¹ã¯ããã»ã©ç¡ãããšæããŸãïŒ use client ã®ä»äž [xxxx].tsx ã [xxxx]/page.ts ã«å€æ xxxx/index.tsx ã xxxx/page.tsx ã«å€æ xxxx.tsx ã xxxx/page.tsx ã«å€æ â»åèçšåºŠã«ãªããŸãã Gist ã§å
¬éããŠããŸã 2. ãã°ã€ã³ååŸã®ã¬ã€ã¢ãŠãã®äœæ ãã¢ããã®dashboardã¯ãã°ã€ã³ååŸã§ã¬ã€ã¢ãŠããç°ãªãããïŒããããã®ã¬ã€ã¢ãŠããäœæããŸããïŒ dashboardã¯ãã°ã€ã³åã«ããã¢ã¯ã»ã¹åºæ¥ãªãããŒãžãšãã°ã€ã³åŸã«ããã¢ã¯ã»ã¹åºæ¥ãªãããŒãžã«äºåãããŠããããïŒ Route Groups ãšããæ©èœãçšããããšã§æ¯èŒçç°¡åã«ã¬ã€ã¢ãŠãã®åºãåããå®çŸåºæ¥ãŸããïŒ ä»¥äžã®ããã«æ¬åŒ§ã§å²ãŸãããã£ã¬ã¯ããªåãã€ããããšã§Route Groupsãå©çšåºæ¥ãŸã. app âââ ( loggined ) â âââ layout.tsx â ... âââ ( unloggined ) âââ layout.tsx ... 3. _app.tsx åã³ _document.tsx ãšç䟡ãªåŠçã®åçŸ App Routerã§ã¯ _app.tsx ãš _document.tsx ã廿¢ãããããïŒããããè¡ã£ãŠããããšãšç䟡ãªããšã file conventions ã middleware ãçšããŠåçŸããå¿
èŠããããŸãïŒ ãã¢ããã®dashboardã§ã¯ _app.tsx ã§sessionã®ç®¡çãã¬ã€ã¢ãŠãã®åºãåããªã©ãïŒ _document.tsx ã§ã¯ããããŒã®ç®¡çãªã©ãè¡ã£ãŠããããïŒmiddlewareãš layout.tsx ãçšããŠåçŸããŸããïŒ æ³šæç¹ãšããŠïŒApp Routerã§ã¯ Header ã³ã³ããŒãã³ãã廿¢ ãããŠããïŒä»£ããã« layout.tsx ãã Metadata ãªããžã§ã¯ã ãexportããããã«ãªã£ãŠããŸãïŒãã®Metadataãªããžã§ã¯ãã§ããïŒHeaderã³ã³ããŒãã³ããçšããŠå®çŸããŠããããšå
šãŠãåçŸåºæ¥ãèš³ã§ãªãïŒäŸãã° CDNããstylesheetãèªã¿èŸŒãããšãåºæ¥ãªã ãªã£ãŠããŸãïŒãã®ç¹ã«ã€ããŠã¯ïŒcloseã¯ãããŠããŸãã issue ã«ããªã£ãŠãã解決ããã®ã«ã¯æéããããããã§ããããšãšïŒå¹žããªããšã«ãã¡ã€ã«ã®importã§è§£æ±ºã§ãããã®ä»¥å€ã¯åœ±é¿ãå°ããã£ãããåŸåãã«ããããšã«ãªããŸããïŒ 4. ã«ãŒãã£ã³ã°ã«é¢ããhooksã®ç§»è¡ App Routerã§ã¯ã«ãŒãã£ã³ã°ã«é¢ããhooksã next/router ã§ã¯ãªã next/navigation ããimportããããã«å€æŽ ãããŠããïŒ useRouter hookãæã£ãŠãã圹å²ã useRouter ãš usePathname ïŒ useSearchParams ã®3ã€ã®hooksã«åè§£ãããŠããŸãïŒåŸã£ãŠïŒç»åã®ããã«ïŒnext/routerãçšã㊠router.push ãšèšè¿°ããŠããã³ãŒãã¯next/navigationã®useRouterãïŒ router.query ãšèšè¿°ããŠããã³ãŒãã¯useSearchParamsãçšããŠçœ®æããå¿
èŠããããŸãïŒ useRouterã®å©çšç®æèªäœã¯å€å²ã«æž¡ã£ãŠããããïŒä¿®æ£ã«ã¯ã ãã¶æéãå¿
èŠãšãªããŸããïŒ ãŸãïŒãã®éïŒåŸæ¥ã®useRouterãæã£ãŠãã events çã®äžéšã®æ©èœãnext/navigationã§ã¯å®è£
ãããŠããªãããšã«æ³šæãå¿
èŠã§ãïŒeventsãå®è£
ãããŠããªãããšããïŒPages Routerã§ç°¡åã«å®çŸåºæ¥ãŠããããŒãžé·ç§»äžã®åŠçãApp Routerã§ã¯ç°¡åã«ã¯å®çŸåºæ¥ãªããªããŸããïŒ å
¬åŒãã㯠usePathnameãšuseSearchParamsãå©çšããã³ã³ããŒãã³ããäœæããããšã«ããåçŸæ¹æ³ ãæç€ºãããŠããïŒãããçšããã°åçŸå¯èœããšæãããŸããïŒãã¢ããã®dashboardã§ã¯ããŒãžé·ç§»ã®é²æã衚瀺ããããã®ããã°ã¬ã¹ããŒã«ããçšããŠãããïŒé²æã確èªããããŒãºã®æãçšéãããŒãžãååšããªãã£ãããïŒåçŸããã«å
ã«é²ãããšã«ãªããŸããïŒ ã«ãŒãã£ã³ã°ã«é¢ããhookã®é·ç§» 5. ãã®ä» React Server Componentsã§ã¯Runtime Configãå©çšåºæ¥ãªã ããïŒç°å¢å€æ°ã§çœ®ãæãããªã©ã®ç§»è¡äœæ¥ãããŸããïŒ ç§»è¡äœæ¥ãéããŠæãããã€ã³ã ç§»è¡äœæ¥ãéããŠïŒ _app.tsx åã³ _document.tsx ã®å€§ãããç§»è¡ã³ã¹ãã®å€§éšåãæ±ºå®ããããã«æããŸããïŒ ãããã®ãã¡ã€ã«ã§è¡ã£ãŠããäºã倧ããã»ã©App Routerã®file conventionsãmiddlewareã«å¯Ÿããç¥èãšå®è£
çµéšãæ±ããããããã§ãïŒ ãŸãåºæ¥ãªããªãããšãïŒåçŸã«äžæéãå¿
èŠã«ãªãããšãæŽçããäžã§ç§»è¡ã«æããšèŠéããã€ããããããã«æããŸãïŒ ãŸãšã ãNext.jsã®Pages RouterããApp Routerãžã®ç§»è¡ã«ææŠããŠã¿ãããšé¡ãïŒå®éã«ææŠweekäžã«è¡ã£ãç§»è¡äœæ¥ã«ã€ããŠç޹ä»ãããŠããã ããŸããïŒ åŸåãã«ãããã®ãªã©äžéšããæ®ãã¯ããã€ã€ãïŒäž»èŠéšã®ç§»è¡èªäœã¯åºæ¥ãã®ã§ã¯ãªãããªãšæã£ãŠãããŸãïŒ äœããïŒç§»è¡äœæ¥ãéããŠfile conventionsãRoute Groupsãªã©ã®App Routerã§ã®ã¿å©çšåºæ¥ãæ©èœãåŠã³ïŒå©çšããããšãåºæ¥ïŒç¥ç奜å¥å¿ãåºæ¿ãããäžé±éã§ããïŒ ã¢ããªã±ãŒã·ã§ã³ã®èŠæš¡ãå©çšããŠããæ©èœã«äŸåããŸããïŒç§»è¡ããéã«ã¯ããããåæ§ã®æµããåãã®ã§ã¯ãªãããšæããŠããïŒãã®èšäºãPages RouterããApp Routerãžã®ç§»è¡ãæ€èšãããŠããéçºè
ã®æ¹ã
ã®ã圹ã«ç«ãŠãã倧å€å¬ããã§ãïŒ ãããŸã§ãèªã¿ããã ãããããšãããããŸããïŒ
DELISH KITCHEN ã¯ã¬ã·ããåç»ã§ããããããåºæ¬çãªæçããã¢ã¬ã³ãžãŸã§æ§ã
ãªã¬ã·ããå
¬éããŠããŸãã å®ã¯ã¬ã·ãåç»ä»¥å€ã«ããå£ç¯ã«ãã£ãããããã¬ã·ããçŽ æã«ã€ããŠã®è§£èª¬ãæçã«åœ¹ç«ã€æ
å ±ãªã©ãèšäºã«ãŸãšãããå
¬éãããŠããŸãããåç¥ã§ãããïŒ äŸãã°ãããã£ãèšäºã§ãã 飿¬²ã®ç§ã«ããã¿ãªïŒç§ãæ¬ã®éèã䜿ã£ãã¬ã·ã6éž ãªãïŒãªãã³ïŒåŒã³æ¹ã®ç±æ¥ã«ã€ããŠè§£èª¬ããŸãïŒ åã¡ããããŒã¡ãã詳ãã解説ã»ç¹åŸŽãã¬ã·ããã玹ä»âª ã ãæ±ãšã¯ïŒç°¡åãªã ãã®äœãæ¹ãã玹ä»ïŒ ä»åã¯ããã®èšäºã Android ã¢ããªã§é²èЧã§ããããã«ãã話ãããããšæããŸãã èšäºãšã¯ ãŸãã¯äžäŸãèŠãŠããã ããã°ãšæããŸãã ç®æ¬¡ æ¬æ èšäºã®æŠèŠãšèŠåºã ããããããªåºæ±âŠ ã¬ã·ãåç»ã¯æçã®æé ãç°¡åã«ææ¡ããããã®ã§ãããäžæ¹ã§çŽ æã®é
åã«ãµããã«ã¯ããŸãé©ããŠããªãè¡šçŸæ¹æ³ããšæããŸããèšäºã§ã¯ããããã£ãçŽ æã®é
åã§ãã£ããããã詳现ãªè§£èª¬ãæçã«åœ¹ç«ã€æ
å ±ãªã©ã玹ä»ããŠããŸãã ç²æ«ã ããšã¯ãã®åã®éããé°¹ç¯ãæåžãªã©ã®çŽ æã也ç¥ãããŠç²æ«ç¶ã«å å·¥ãããã®ã§ãã補é éçšã§ç±ãå ããŠããªããããããçŽ æã®èªç¶ãªé¢šå³ãæããããŸãã ãªãã»ã©âŠãµã ãã¯é¡ç²ã ãã䜿ã£ãŠããã®ã§ãããä»åºŠã¯ç²æ«ã ãã䜿ã£ãŠã¿ããããªïŒ èšäºã®ããŒã¿ æ©éã§ããèšäºã«ã€ããŠæè¡é¢ã®è©±ãããããšæããŸãã ãŸãã¯èšäºãæ§æããããŒã¿ã®æ§é ã«ã€ããŠã§ãã ⻠以éã®å
容ã¯å
·äœçãªåŠçã«ã€ããŠã¯å²æããæ²èŒããããŒã¿ãã€ã¡ãŒãžãšãªããŸã å
ã«ç޹ä»ããèšäºã®å
容ã¯èšäº API ãä»ã㊠JSON 圢åŒã§ããŒã¿ãååŸããŸãã { " article_id ": 123456 , " title ": " ã ãæ±ãšã¯ïŒç°¡åãªã ãã®äœãæ¹ãã玹ä»ïŒ ", " description ": " åé£ã«ãããã ãæ±ã®åœ¹å²ã¯ãšãŠã倧ãã⊠", " thumbnail ": " https://tech.blog.com/images/header.png ", " created_at ": " 2022-06-02T16:00:00Z ", " contents ": [ { " type ": " image ", " image_url ": " https://tech.blog.com/images/main.jpeg " , } , { " type ": " header1 ", " text ": " åé£ã«æ¬ ãããªãã ãæ±ãšã¯ïŒ " } , { " type ": " paragraph ", " text ": " ã ãã«ã¯ããŸããŸãªçš®é¡ããããŸãããäžã§ãäžè¬çã«ãã䜿ãããŠããçŽ æãé°¹ç¯ãæåžâŠ " } , ... } èšäºã¯ title ã description ãªã©èšäºå
±éã®èŠçŽ ã®ä»ã«ãæ¬æãªã©ãå«ãŸãã contents ã§æ§æãããŠããŸãã contents ã¯èšäºã®å
容ãæè»ã«è¡šçŸã§ããããå¯å€é·ã«ãªã£ãŠããŸãããã®äžèº«ã¯ãèŠçŽ ãåºå¥ãã type ãšå
容ïŒããã¹ãã URL ãªã©ïŒã®çµã¿åããã§æ§æããããªããžã§ã¯ãã§ãã ãããã®ããŒã¿ã¯ã¢ããªåŽã§æ±ããããããã« type ã§åºå¥ããŠåèŠçŽ ã«å€æããŸãã sealed class Content { // èŠåºãã®å±æ§ãšã㊠sealed class Headline : Content() { abstract val headline: String abstract val subHeadline: String ? } // èŠåºãïŒ data class Headline1( override val headline: String , override val subHeadline: String ?, ) : Headline() // èŠåºãïŒ data class Headline2( override val headline: String , override val subHeadline: String ?, ) : Headline() // æ®µèœ data class Paragraph( val text: String , ) : Content() // ç»å data class Image( val imageUrl: String , ) : Content() ... } ããŒã¹ãããèŠçŽ ã¯ãªã¹ãïŒRecyclerViewïŒã«è¿œå ããŸãã ãªã¹ããžã®è¿œå åèŠçŽ ã RycyclerView ã« add ããã¿ã€ãã³ã°ã§ type ã«å¿ãã ViewHolder ã«å€æããŠè¿œå ããŸãã 以äžãGroupie ã䜿ã£ãŠäœæãã Adapter ãš ViewHolder ã®äžéšã§ãã â» Groupie ã«é¢ãã詳现㯠github ãåç
§ããŠãã ãã class ArticleAdapter( private val listener: Listener ) : GroupAdapter<GroupieViewHolder>() { ... interface ContentItem interface SectionItem : ContentItem interface TitleItem : ContentItem interface SubTitleItem : ContentItem interface DescriptionItem : ContentItem interface OtherItem : ContentItem private class ContentHeadline1Item( private val item: Content.Headline1 ) : BindableItem<ItemContentHeadline1Binding>(), TitleItem { override fun getLayout() = R.layout.item_content_headline1 override fun initializeViewBinding(view: View) = ItemContentHeadline1Binding.bind(view) override fun bind(viewBinding: ItemContentHeadline1Binding, position: Int ) { viewBinding.title.text = item.headline } } ... } ContentHeadline1Item 㯠ViewHolder ã§ãããã®ããã«ãèŠçŽ ã«åããã ViewHolder ãçšæããŠåèŠçŽ ã倿ããŸãã ããã§ ContentItem ã SectionItem ãªã©ã® interface ãæ°ã«ãªã£ãæ¹ãããã£ããããããããŸããããã® interface ã«ã€ããŠã¯åŸã»ã©è§ŠããããšæããŸãã èŠçŽ éã®ããŒãžã³ ViewHolder ã«å€æããèŠçŽ ã¯ ViewHolder å
ã§æå®ããã¬ã€ã¢ãŠããé©çšãããŸããäžå³ã®ããã«ã¬ã€ã¢ãŠãå
ã§ããã°ç®æ¬¡ã®ã¿ã€ãã«ããªã¹ããªã©ããŒãžã³ã®èª¿æŽã¯å®¹æã§ãããã§ã¯ãèŠçŽ éã®ããŒãžã³ã¯ã©ãã§ããããïŒ ç®æ¬¡ã¯éåžžã® layout.xml å
ã§å®çµã§ããã®ã§ç°¡åã§ã èŠåºããªãäžéšã« 24 dpãç»åãªãäžäžã« 16 dp ã®ããã«èŠçŽ ããšã«åºå®ã®ããŒãžã³ãªãåçŽã ã£ãã®ã§ãããèšäºã®å Žåã¯åã®èŠçŽ ã«ãã£ãŠããŒãžã³ã倿Žããå¿
èŠããããŸãããã²ãšæéãããå¿
èŠãããããã§ãã çµè«ããèšãã°ãä»åã®èŠçŽ éã®ããŒãžã³ã¯ RecyclerView ã® ItemDecoration ã䜿ã£ãŠè§£æ±ºããŸãããItemDecoration ã¯ãªã¹ãã«è¿œå ãããã¢ã€ãã ã«ãªãã»ããã远å ãã䟿å©ãªä»çµã¿ãæã£ãŠããŸãã ãã® ItemDecoration ã®å®è£
ã§å
ã»ã©è§Šãã ContentItem ãªã©ã® interface ã圹ã«ç«ã¡ãŸãã æºåãšããŠãå ViewHolder ã«é©ãã interface ãé¢é£ä»ããŠãããŸãã 以äžãå®è£
ã®äžéšã§ãã class MarginDecoration( resources: Resources, @IdRes private val space: Int ) : RecyclerView.ItemDecoration() { // space ãå
ã«å¿
èŠãª marginXX ãå®çŸ© ... override fun getItemOffsets(outRect: Rect, view: View, parent: RecyclerView, state: RecyclerView.State) { val itemCount = parent.adapter?.itemCount?.let { it - 1 } ?: 0 val position = parent.getChildAdapterPosition(view) // æåŸã®èŠçŽ ã¯äžã«ãããŒãžã³ãèšãã val bottom = if (itemCount == position) margin40 else 0 // æåã®èŠçŽ ã¯äžã®ããŒãžã³ãåºå® val top = if (position == 0 ) margin24 else null // äžã®ããŒãžã³ã¯åã®èŠçŽ ãšã®é¢ä¿ã«ãã£ãŠæ±ºå®ãããããäžã€åã® ViewHolder ãååŸãã val previousHolder = if (position > 0 ) (parent.adapter as? ArticleAdapter)?.findContentItemBy(position - 1 ) else null val currentHolder = parent.getChildViewHolder(view) as? GroupieViewHolder // åã®èŠçŽ ãšã®é¢ä¿ã§ããŒãžã³ãå€ããå€å®ãããã§è¡ã when ( val item = currentHolder?.item) { is TitleItem -> outRect. set ( 0 , top ?: margin40, 0 , bottom) is SubTitleItem -> when (previousHolder) { is SectionItem -> margin40 else -> margin24 }.let { outRect. set ( 0 , top ?: it, 0 , bottom) } ... is OtherItem -> outRect. set ( 0 , top ?: margin24, 0 , bottom) else -> { // nothing } ... } getItemOffsets() ã¯ãªã¹ãã«èŠçŽ ã远å ãããã¿ã€ãã³ã°ã§èŠçŽ ã«ãªãã»ããã远å ããããšãå¯èœã§ãããã©ã¡ãŒã¿ã® outRect ã« set(left, top, right, bottom) ããããšã§èŠçŽ ã«ããŒãžã³ãé©çšããŸãã outRect.set() ããéã«çŸåšã®èŠçŽ ã SubTitleItem ã§åã®èŠçŽ ã SectionItem ãªã 40 dp âŠãšèããããçµã¿åãããæ¡ä»¶ã§å®çŸ©ããŠé©åãªããŒãžã³ãèšå®ããŸããã 以äžãèšäºãå®è£
ããçµæã§ãã ç®æ¬¡ æ¬æ ã¢ããªçã®ç®æ¬¡éšå ã¢ããªçã®æ¬æ ContentItem ãªã©ã® interface ãçšæããããšã§5çš®é¡ã® interface ãšããã€ãã®èŠçŽ ãèæ
®ããã ãã§æžã¿ãŸãããæ°ããèŠçŽ ã远å ããå Žåãé©ãã interface ãé¢é£ä»ããã ãã§æžã¿ãŸããèšäºã®èŠçŽ ãšããŠçšæããã type ã¯10çš®é¡ä»¥äžããã®ã§ãåå¥ã«å¯Ÿå¿ããããšãèãããšâŠè³ãéããŸãã æåŸã« ããã㊠DELISH KITCHEN ã® Android ã¢ããªã§ãèšäºãé²èЧã§ããããã«ãªããŸãããäžçæžåœäœã£ãæ©èœã§ãããèªã¿ç©ãšããŠãé¢çœããšæãã®ã§ããã²è²ã
ãªèšäºãèªãã§ã¿ãŠã»ããã§ãã
ã¯ããã« iOSã«ã¯ããã©ã«ãã§ããã«ã¹ã±ã¢ããšããã¢ããªãååšããããšããåç¥ã§ããããã åŒç€Ÿã®DELISH KITCHENã¢ããªã§ã¯æšå¹Žãã«ã¹ã±ã¢ãšããæ°æ©èœããªãªãŒã¹ããŸããããæ¥ã
æ¹ä¿®ãéããŠããäžã§ãã«ã¹ã±ã¢ã¢ããªã«ãçç®ããè²ã
ãšèª¿æ»ãè¡ããŸããã ä»åã¯ãã®èª¿æ»å
容ã«ã€ããŠçºããŠãããããšæããŸãã ãã«ã¹ã±ã¢ã¢ããªãšã¯ 赀䞞ã§å²ã£ããã®ããã«ã¹ã±ã¢ã¢ããªã§ãã ãã¡ãã®ã¢ããªã§ã¯ãæ©æ°ãªã©ã®ã¢ã¯ãã£ããã£æ
å ±ããè¡å§ãªã©ã®ãã€ã¿ã«æ
å ±ãšãã£ãå¥åº·ã»å»çæ
å ±ãäžã€ã®ã¢ããªã§ç®¡çã§ãããã®ãšãªã£ãŠãããç°¡åã«æ
å ±ãé²èЧã»ç·šéããããšãã§ããŸãã ç§ã®å ŽåãApple Watchã§æ©æ°ãèšé²ãããã«ã¹ã±ã¢ã¢ããªã§äžé±éã®å¹³åæ©æ°ã確èªããããšãã£ãäœ¿ãæ¹ãããŠããŸãã ãŸã 䜿çšãããããšããªãæ¹ã¯äžåºŠè§ŠããŠã¿ãŠã¯ãããã§ããããã HealthKitã«ã€ã㊠https://developer.apple.com/jp/health-fitness/ ããã°ã©ã ãããã«ã¹ã±ã¢ã¢ããªã®æ
å ±ã«ã¢ã¯ã»ã¹ããå Žåã HealthKit ã䜿çšããŸãã HealthKitã䜿çšããããšã§å®¹æã«ãã«ã¹ã±ã¢ã¢ããªã®æ
å ±ã«ã¢ã¯ã»ã¹ããããšãã§ããŸãã https://www.proofpoint.com/jp/threat-reference/hipaa-compliance äœè«ã«ã¯ãªããŸãããå»çåéã§æ¥åãè¡ãç«å Žã®å Žå㯠HIPAA ãšããæ³åŸã«åŸãããšã«ãªããŸãã ä»åã¯HIPAAã«ã€ããŠæ·±ãã¯è§ŠããŸããããå¥åº·æ
å ±ãèšé²ããã¢ããª(éHIPAAã¢ããª)ãšå»çè¡çºã«é¢ããã¢ããª(HIPAA察象ã¢ããª)ã§äœæãããã©ã€ãã·ãŒããªã·ãŒãã¢ããªç³è«å
容ãç°ãªããŸãã®ã§ãããå
容ãçè§£ããŠããå®è£
ããããšããå§ãããŸãã ãã«ã¹ã±ã¢é£æºæé ããããã¯å®éã«ããã°ã©ã ãããã«ã¹ã±ã¢ã«é£æºããæ¹æ³ãçºããŠãããããšæããŸãã ä»åã¯HealthKitã䜿ã£ãŠæ©æ°ã®æ
å ±ãååŸããæ¹æ³ãçºããŸãã éçºç°å¢ Xcode Version 14.3.1 (14E300c) éçºèšèª : swift Capability远å TARGETS > Signing & Capabilities ã«ãŠãHealthKitã远å ä»åãèšåºèšé²ã®ããŒã¿ã«ã¢ã¯ã»ã¹ãããã³ããã¯ã°ã©ãŠã³ãé
ä¿¡ã¯è¡ããªãããã以äžã®ãã§ãã¯ã¯äžèŠã§ãã info.plistæŽæ° info.plistã«ãŠã以äž2é
ç®ã远å - Privacy - Health Update Usage Description ⊠ãã«ã¹ã±ã¢ã®ããŒã¿ãæŽæ°ããããã®èš±å¯ãæ±ããæã«è¡šç€ºãããæèš - Privacy - Health Share Usage Description ⊠ãã«ã¹ã±ã¢ã®ããŒã¿ãååŸããããã®èš±å¯ãæ±ããæã«è¡šç€ºãããæèš Valueã«æžãããæååããåŸè¿°ããæš©é確èªãã€ã¢ãã°ã«è¡šç€ºãããŸãã èªèšŒåŠçå®è£
ããããã¯å®è£
ã«å
¥ããŸãã let healthStore: HKHealthStore init() { healthStore = HKHealthStore() } HKHealthStore ã®ã€ã³ã¹ã¿ã³ã¹ãä»ããŠèªèšŒãååŸãæŽæ°ãè¡ããŸãã®ã§ããŸãã¯ã€ã³ã¹ã¿ã³ã¹ã®çæãããŠãããŸãã func auth() { // æŽæ°ãããããŒã¿ let shareTypes = Set([ // æ©æ° HKQuantityType.quantityType(forIdentifier: HKQuantityTypeIdentifier.stepCount)! ]) // ååŸãããããŒã¿ let readTypes = Set([ // æ©æ° HKQuantityType.quantityType(forIdentifier: HKQuantityTypeIdentifier.stepCount)! ]) // èªèšŒå®æœ healthStore.requestAuthorization( toShare: shareTypes, read: readTypes, completion: { success, error in if success { print("èš±å¯ãããŸãã") } else { print("åŽäžãããŸãã") } } ) } 次ã«èªèšŒåŠçãšãªããŸãã requestAuthorization ã§ãŠãŒã¶ã«å¯ŸããŠã¢ã¯ã»ã¹ããæ
å ±ã®æš©é確èªãã€ã¢ãã°ã衚瀺ããŸãã toShare ã«ã¯æŽæ°ãããããŒã¿ãèšå®ã read ã«ã¯ååŸãããããŒã¿ãèšå®ããŸãã â»plistã§èšå®ããæ
å ±ãšshareã®æå³ãç°ãªãã®ã§æ³šæãå¿
èŠã§ãã å®è¡ãããšäžèšã®ãããªæš©é確èªãã€ã¢ãã°ã衚瀺ãããŸãã ãã®ãã€ã¢ãã°ã«ã¯åè¿°ããplistã«èšå®ããæèšã衚瀺ãããŸãã ååŸåŠçå®è£
ãã«ã¹ã±ã¢ã¢ããªããããŒã¿ãååŸããåŠçãå®è£
ããŸãã func getStepCount(fromDate: Date, endDate: Date) { let query = HKSampleQuery( // ååŸãããããŒã¿ã®çš®å¥ sampleType: HKSampleType.quantityType(forIdentifier: .stepCount)!, // ããŒã¿ã®æé predicate: HKQuery.predicateForSamples(withStart: fromDate, end: endDate), // ååŸä»¶æ°ã®äžé limit: HKObjectQueryNoLimit, // ãœãŒã sortDescriptors: [NSSortDescriptor(key: HKSampleSortIdentifierEndDate, ascending: true)], resultsHandler: { (query, results, error) in guard error == nil else { return } // ååŸããçµæããµã³ããªã³ã°ããŒã¿ã®åã«å€æ if let itemList = results as? [HKQuantitySample] { for item in itemList { print("èšé²æ¥æ : \(item.endDate)") print("æ©æ° : \(String(item.quantity.doubleValue(for: .count())))") } } } ) healthStore.execute(query) } HKSampleQuery ã§ã¯ãšãªã®æ
å ±ãäœæãã execute ã¡ãœããã«æµããšããå®è£
ãšãªããŸãã æŽæ°åŠçå®è£
ãã«ã¹ã±ã¢ã¢ããªããããŒã¿ãæŽæ°ããåŠçãå®è£
ããŸãã func updateStepCount(targetData: Date, stepCount: Double) { // æŽæ°ãããããŒã¿ã®çš®å¥ let type = HKObjectType.quantityType(forIdentifier: .stepCount)! // èšå®ããããŒã¿ let quantity = HKQuantity(unit: .count(), doubleValue: stepCount) // ãµã³ããªã³ã°ããŒã¿äœæ let sample = HKQuantitySample(type: type, quantity: quantity, start: targetData, end: targetData) healthStore.save(sample, withCompletion: { (success, error) in if success { print("æå") } else { print("倱æ") } }) } HKQuantitySample ã§ãµã³ããªã³ã°ããŒã¿ãäœæãã save ã¡ãœããã«æµããšããå®è£
ãšãªããŸãã ååŸã»æŽæ°æã®æ³šæç¹ ååŸã»æŽæ°åŠçãåè¿°ããŸããããããŒã¿ãåãæ±ãéã®æ³šæç¹ããããŸãã // èšå®ããããŒã¿ let quantity = HKQuantity(unit: .count(), doubleValue: stepCount) æŽæ°åŠçã®ãã¡ãã®éšåã§ãããã€ã³ã¹ã¿ã³ã¹ãçæããéã«ç¬¬1åŒæ°ã« HKUnit ãèšå®ããŠããŸãã https://developer.apple.com/documentation/healthkit/hkunit HKUnitã¯ãåäœãã®ã¯ã©ã¹ã«ãªããŸãããå®è£
ããéã¯èšå®ããããŒã¿ãšåäœãäžèŽããªããšExceptionãçºçããŠããŸããŸãã ä»åã¯æ©æ°ã®ãããã«ãŠã³ãã®åäœãè¿ã.count()ãèšå®ããŠããŸããã let quantity = HKQuantity(unit: .kilocalorie(), doubleValue: stepCount) ã®ããã«ãæ©æ°ã«ããã«ããªãŒã®åäœãè¿ã.kilocalorie()ãèšå®ããŠããã«ãæã«ã¯ãšã©ãŒãæ€ç¥ã§ãããå®è¡ã§ããŠããŸããŸãã ãã«ã¹ã±ã¢ã¢ããªã§ã¯è€æ°ã®æ
å ±ã管çããéœåäžãåäœã®çš®é¡ãå€ãã®ã§ãããé©åãªåäœãèšå®ããå¿
èŠãããç¹ã«æ³šæããŠãã ããã ãããã« HealthKitã䜿çšãããã«ã¹ã±ã¢ã¢ããªãšã®é£æºæ¹æ³ãçºããŸããããåè¿°ã®èšå®ãå®è£
ã®ã¿ã§ã¢ã¯ã»ã¹ã§ãããããæ·å±
ã¯äœããç°¡åã«å®è£
ãã§ããŸããã è¿å¹ŽãUIUXãåäžãããããã«ã¯ç°¡åã«ããŒã¿ãååŸã»ç·šéãã§ãããå¥ã¢ããªãšé£æºã§ããããšãå¿
é ã ãšæããŠããŸãããå¥åº·å¿åã®æ¹ãå€ããªãããŸãã¹ããŒããŠã©ãããæ®åããããšãããããã«ã¹ã±ã¢ã¢ããªã§ããŒã¿ãèšé²ããŠãããŠãŒã¶ãå¢ããŠããå°è±¡ãªã®ã§ãå¥åº·æ
å ±ãªã©ãã«ã¹ã±ã¢ã¢ããªã§ã管çããŠããæ
å ±ãæ±ãéã¯HealthKitãå°å
¥ããããšã§ååãªå¹æãèŠèŸŒãããšæããŸãã ä»åã¯HealthKitã®è§Šãéšåã®ç޹ä»ãšãªããŸããããã«ã¹ã±ã¢é£æºã®å®è£
ãèããŠããæ¹ã«ãšã£ãŠå°ãã§ãåèã«ãªãã°å¹žãã§ãã
ã¯ããã« åè²ãŠã¡ãã£ã¢ããã¢ãããã§ããã¯ãšã³ããããã³ããšã³ãã®èšèšã»éçºãæ
åœããŠããæ¡æã§ãã 2023幎8æ1æ¥ãMAMADAYSã¯ãã¢ããã«çãŸãããããŸããã tomonite.com ã¢ããªã®ã¡ã€ã³æ©èœã§ãããè²å
èšé²ããåŠåš 鱿°ç®¡çãã飿ãªã¹ããã軞ãšããŠãå®¶æãããŒãããŒãå®¶æä»¥å€ã®äººã瀟äŒãšã®æ¥ç¹ãäœãããã®ã·ã§ã¢æ©èœãã³ãã¥ããã£æ©èœãªã©ã®æ¡å
ãããããŠãããŸãã ä»åã¯ãContinuous Profiling ã宿œããããšãã§ãã Pyroscope ã䜿çšããŠããã¢ããã§éçšããŠãã Go ãµãŒããŒã®ã¡ã¢ãªãªãŒã¯ã調æ»ã»æ¹åãã話ãããããšæããŸãã 以åã ãã¢ããã§EKSããECSã«ç§»è¡ãã話 ãšããèšäºã«ãããŠãEKS on EC2 ãã ECS Fargate ãžã®ç§»è¡ã«äŒŽããå³å¯ãªãªãœãŒã¹ç®¡çã®å¿
èŠæ§ãçããã¡ã¢ãªãªãŒã¯ãæ€åºããä»¶ã®å¯Ÿå¿ã«ãªããŸãã tech.every.tv Pyroscope ã«ã€ã㊠Pyroscope ãšã¯ Continuous Profiling ã宿œããããšãã§ãããªãŒãã³ãœãŒã¹ã®ãã©ãããã©ãŒã ã§ãã Continuous Profiling ãšã¯ããœãããŠã§ã¢ãã¢ããªã±ãŒã·ã§ã³ãå®è¡ãããŠããéããªã¢ã«ã¿ã€ã ã§ããã©ãŒãã³ã¹ããŒã¿ãå®è¡æ
å ±ãåéããCPUãã¡ã¢ãªçã®ãªãœãŒã¹ãã©ãã§å€ãæ¶è²»ããŠãããåæã»ãã¥ãŒãã³ã°ããææ³ã§ãã 2023幎3æã«ããŒã¿å¯èŠåããŒã« Grafana ãªã©ãéçºããŠãã Grafana Labs ã Pyroscope ãè²·åãã ãªãŒãã³ãœãŒã¹ Grafana Pyroscope ãšããŠçµ±åãããŸããã æ¬èšäºã§ã¯ Grafana Pyroscope ã®æ
å ±ã«ãè§Šãã€ã€ãPyroscope ã§ Go ãµãŒããŒã®ã¡ã¢ãªãªãŒã¯ã調æ»ã»æ¹åãã話ãšãªããŸãã Pyroscope ã§ã§ããããš ã³ãŒãå
ã®ããã©ãŒãã³ã¹ã«é¢é£ããåé¡ãããã«ããã¯ãèŠã€ããããšãã§ããŸããäŸãã°ãCPU䜿çšçã®äžæãã¡ã¢ãªãªãŒã¯ã®çºççã§ãã pyroscope ã® Single View ç»é¢ ã¿ã°æ©èœ Tags ãæéæå®ã«ãããUIäžã®ãããã¡ã€ãªã³ã°ããŒã¿ãçµã蟌ã¿ã§ããŸãã pyroscope ã® Tags ã§ã®ãã£ã«ã¿ãªã³ã°ç»é¢ ãã¥ãŒæ©èœ Comparison View ã«ããã2ã€ã®æéåºéã䞊ã¹ãŠæ¯èŒåæã§ããŸãã pyroscope ã® Comparison View ç»é¢ ãã¥ãŒæ©èœ Diff View ã«ããã2ã€ã®æéåºéã®å·®åãååŸããŠããŒããããã®ããã«è²ä»ãããŠæ¯èŒåæã§ããŸãã pyroscope ã® Diff View ç»é¢ åè: demo.pyroscope.io Pyroscope ã®ä»çµã¿ Pyroscope Agent ãšããèšèªããšã«çšæãããŠããããã»ã¹ããã¢ããªã±ãŒã·ã§ã³ã®åäœã宿çã«èšé²ã»éèšãããã®ããŒã¿ã Pyroscope Server ã«éä¿¡ããŸãã Pyroscope Server ããã®ããŒã¿ãåŠçã»éçŽããããšã§ããŠãŒã¶ãŒããããã¡ã€ãªã³ã°ã®çµæã WEB UI ãã Flame Graph (ãã¬ãŒã ã°ã©ã)ãé²èЧããããšãå¯èœã«ãªããŸãã ãªã®ã§ãPyroscope ã§ Continuous Profiling ã宿œããã«ã¯ã Pyroscope Agent ãš Pyroscope Server ã®èšå®ãå¿
èŠã«ãªããŸãã pyroscope ã®å
šäœå åè: pyroscope.io Grafana Pyroscope ã«ã€ã㊠2023幎3æã«ããŒã¿å¯èŠåããŒã« Grafana ãªã©ãéçºããŠãã Grafana Labs ã Pyroscope ãè²·åãã ãªãŒãã³ãœãŒã¹ Grafana Phlare ãšçµ±åããã Grafana Pyroscope ã«ãªããŸããã åè: grafana.com ãŸãã2023幎8ææ«ã«ãGrafana Pyroscopeããšã㊠version 1.0 ãå
¬éãããŸããã ãã®ããŒãžã§ã³ã§ã¯ã以äžãã¯ãããšããæ¹åãè¡ãããŸããã Grafana ãšå®å
šã«çµ±åãããGrafana ããã·ã¥ããŒãã§ã¡ããªã¯ã¹ããã°ããã¬ãŒã¹ãªã©ä»ã®å¯èŠ³æž¬æ§ã®ææšãšäžç·ã« Profiling ã®ããŒã¿ã衚瀺å¯èœã«ãªããŸããã æ§ã
ãªãªããžã§ã¯ãã¹ãã¬ãŒãžãµãŒãã¹ (ex. AWS S3, Google Cloud Storage) ãšã®çµ±åããµããŒãããããããã¡ã€ã«ããŒã¿ãã¹ãã¬ãŒãžãµãŒãã¹ã«ä¿åå¯èœã«ãªããŸããã æ°Žå¹³æ¹åã®ã¹ã±ãŒã«ã¢ãŠãããµããŒããããããããèŠæš¡ã®ãããžã§ã¯ãã§æé©ãªããã©ãŒãã³ã¹ãåºãããšãå¯èœã«ãªããŸããã åè: github.com Pyroscope ãæŽ»çšãããã©ãã«ã·ã¥ãŒãã£ã³ã° åé¡ã ã£ãããš ãã¢ããã§å©çšããŠãã Go ãµãŒããŒã®åºç€ã§ãã ECS ã®ã¡ã¢ãªäœ¿çšçãæéã®çµéãšãšãã«äžæãç¶ãããšããåé¡ããããŸããã ãããµãŒããŒã®ã¡ã¢ãªè§£æŸããé·æéçµéããå ŽåããµãŒããŒã®äžæåæ¢ãšãã£ããªã¹ã¯ããã£ãããã調æ»ã»æ¹åãæ±ããããŠããŸããã ECS ã¡ã¢ãªäœ¿çšç æ¹åå Pyroscope ã®å°å
¥ â Pyroscope Server ã®èµ·å Pyroscope Server ããµãŒããŒäžã§ Docker çµç±ã§èµ·åããŸããã Pyroscope ã«ãããªãœãŒã¹æ¶è²»ã®æé©åã®ãããããŒã¿ã®ä¿ææé retention ã exemplars-retention ã調æŽãããã以å€ã®èšå®å€ã¯ãããã©ã«ãã®å€ãå©çšããŸããã â¡ Pyroscope Server ãš Go ãµãŒããŒã®ãããã¯ãŒã¯èšå® ããããã§AWSã¢ã«ãŠã³ããç°ãªãæ§æã ã£ãã®ãããããããã¯ãŒã¯ã®çéã®ãããVPCãã¢ãªã³ã°æ¥ç¶ãã«ãŒãã£ã³ã°ããŒãã«ãžã®ã«ãŒãã®èšå®ãããŸããã ⢠Pyroscope Agent ã®èµ·å Profiling ããããµãŒããŒã¯ Go 補ãªã®ã§ãåæ§ã« Go ã® Pyroscope Agent ãå©çšããŸããã Pyroscope Server åŽã®ãªãœãŒã¹æ¶è²»ã®æé©åã®ããã SampleRate ã調æŽããŸããã ãŸããã¢ããªã±ãŒã·ã§ã³ãµãŒããŒåŽã®åºç€ã ECS ãªã®ããããããŒãžã§ã³åäœã§ãã詳现ã«åæã§ããããã«ã Tags ã«ã¿ã¹ã¯å®çŸ©ã®ããŒãžã§ã³ãèšå®ããŸããã // Init initialize func Init() { address := conf.PyroscopeAddress() if address == "" { return } pyroscopeConfig := pyroscope.Config{ ApplicationName: "tomonite-server" , ServerAddress: address, SampleRate: conf.PyroscopeSampleRate(), Tags: map [ string ] string { "taskArn" : ecs.TaskARN(), "taskDefinitionVersion" : ecs.TaskDefinitionVersion(), }, } if _, err := pyroscope.Start(pyroscopeConfig); err != nil { log.Alert(fmt.Errorf( "failed to start profiling for pyroscope. err: %w" , err)) } } Profiling ã®çµæ æéã®çµéãšãšãã« Go ãµãŒããŒå
šäœã«å¯ŸããŠã¡ã¢ãªã®äœ¿çšçãèããäžæããŠããåŠçãç¹å®ããããšãã§ãããã®åŠçã¯ã grpc-go ãšããã¢ãžã¥ãŒã«ã§ããããšãåãããŸããã ããæç¹A grpc-go ã®ã¡ã¢ãªäœ¿çšçã¯ãµãŒããŒå
šäœã®15%ã»ã© ããæç¹Aãã12æéåŸ grpc-go ã®ã¡ã¢ãªäœ¿çšçã¯ãµãŒããŒå
šäœã®30ïŒ
ã»ã© ãããªã調æ»ã»æ¹ä¿®å¯Ÿå¿ grpc-go 㯠Go ãµãŒããŒåŽã§æç€ºçã«å©çšãããŠããå®è£
ç®æãçºèŠã§ããªãã£ããããã¡ã€ã³ã®ã¢ãžã¥ãŒã«ãšã®äŸåé¢ä¿ã調æ»ããŸããã ãããšãCloud Firestore ããŒã¿ããŒã¹ã®èªã¿åããšæžã蟌ã¿ã®ããã®ã¯ã©ã€ã¢ã³ããæäŸãã cloud.google.com/go/firestore ãäŸåããŠããããšã倿ããŸããã $ go mod why -m google.golang.org/grpc github.com/everytv/tomonite-server/db cloud.google.com/go/firestore google.golang.org/grpc å®éã« firestore åšãã®ã³ãã¯ã·ã§ã³ãä¿æãããŠãã®ãŸãŸã«ãªã£ãŠããåŠçããã£ãã®ã§ãã³ãã¯ã·ã§ã³ãè§£æŸããããã (*firestore.Client).Close() ã远èšããŠãªãªãŒã¹ããŸããã firestore ã®ã³ãã¯ã·ã§ã³ãè§£æŸããä¿®æ£ ãã®çµæãGo ãµãŒããŒå
šäœã«å¯Ÿããã¡ã¢ãªã®äœ¿çšçã®å¢å ãé¡èã«ç·©ããã«ãªããç¡äºã«ã¡ã¢ãªãªãŒã¯ã®åé¡ã解決ããããšãã§ããŸããã ECS ã¡ã¢ãªäœ¿çšç æ¹ååŸ ãããã« ä»å㯠Pyroscope ãš Continuous Profiling ãPyroscopeãæŽ»çšãããã©ãã«ã·ã¥ãŒãã£ã³ã°ã®äºäŸã«ã€ããŠç޹ä»ããŸããã Pyroscope ãå©çšããã¡ãªãããšããŠãWEB UIã§çŽæçã«æäœã§ãããããã¥ãŒæ©èœã§ãã Comparison View ã Diff View ã§ããå¹ççãªåæãå¯èœãªãšããã ãšèããŠãŸãã Continuous ProfilingãããŠããããšã§ãåé¡çºçåŸã« Profiling çµæãåŸãŠãå³åº§ã«èª¿æ»ãå¯èœã«ãªããŸããä»åŸã Pyroscope ãããŸã掻çšããŠãµãŒãã¹ã®å®å®çšŒåãå®çŸããŠãããŸãã ãŸããGrafana Labs ã«ããè²·åã»çµ±åã«äŒŽãããããªãæ©èœéçºãèŠèŸŒãŸãããããä»åŸã®éçºã®ååãæ³šèŠãã€ã€ææ°ããŒãžã§ã³ãžã®ã¢ããã°ã¬ãŒããæ€èšã§ããã°ãšèããŠããŸãã
ã¯ããã« DELISH KITCHENã§äž»ã«iOSã®éçºããããžã¡ã³ããæ
åœããŠããä¹
ä¿ã§ãã 以åã DELISH KITCHEN iOSã¢ããªéçºã®CIç°å¢ã«ã€ã㊠ãšããèšäºã§CIç°å¢ã玹ä»ããŸããã ä»åã¯ãXcode Cloudã®å°å
¥çµç·¯ãšCI/CDç°å¢ã®å€åã«ã€ããŠã玹ä»ããŸãã Xcode Cloudãžç§»è¡ããçç± Xcode Cloud ã®çºè¡šä»¥éãããŸããŸãªè©Šè¡ãè¡ã£ãŠããŸããããç¹ã«ä»¥äžã®çç±ããå
šé¢çãªå°å
¥ã決å®ããŸããã ä»ã®ãµãŒãã¹ãšæ¯èŒããŠæ©èœãå°ãªããããåŠç¿ã³ã¹ããäœã TestFlightãApp Store Connectãžã®ã¢ããããŒãæã«èšŒææžã®ç®¡çãäžèŠ XcodeãmacOSã®ã¢ããããŒããžã®è¿œåŸãéã ãã«ãçªå·ã®ç®¡çãäžèŠ Firebase App DistributionããTestFlightã«ç§»è¡ããçç± ã¢ããªé
åžã«äœ¿ããµãŒãã¹ãã Firebase App Distribution ããTestFlightã«ç§»è¡ããŸãããApp DistributionãçšããŠAdHocé
ä¿¡ãããŠããéã«ã¯ã以äžã®äœæ¥ãçºçããŠããŸããã ã€ã³ã¹ããŒã«ããã端æ«ã®UUIDãç»é² Provisioning profileã®æŽæ° ãããã®äœæ¥ã¯fastlaneã䜿ã£ãŠåèªååããŠããã®ã§ãããŸã§æéã§ã¯ãªãã£ãã®ã§ãããTestFlightãå©çšããããšã«ãã£ãŠãããã®éåããè§£æŸãããŸããã Xcode Cloud以å€ãå©çšããŠããå Žåã¯ãApp Store Connect APIãå©çšãããããªã¹ã¯ãªãããçµãããšã«ãªããšæãã®ã§ãããXcode Cloudã¯ããããããªã«åŠçããŠããããšããã¡ãªããããããŸãã æ§æ Xcode Cloudå°å
¥åŸã®ã¢ããªã®ç€Ÿå
åãé
åžããã³App Store Connectãžæåºãè¡ãå
šäœã®ãããŒå³ã以äžã«ç€ºããŸãã ååã®èšäºã§ã¯fastlaneãè²ã
ãªåœ¹å²ãæãããŠããã®ã§ãããä»åã®çšéã«éããšfastlaneã¯äžèŠã«ãªããŸããã Releaseçã®ã¯ãŒã¯ãã㌠App Store Connectãžã®æåºãšæçµçãªåäœç¢ºèªã®ããã®é
åžãè¡ããŸãã ç¹å®ã®ãã¬ãã£ãã¯ã¹ãå«ãã¿ã°ãGitHubã«ããã·ã¥ããããšã次ã®ã¯ãŒã¯ãããŒãå®è¡ãããŸãã TestFlightã§å
éšãã¹ã¿ãŒã«é
åž App Store Connectãžã®æåº æåãŸãã¯å€±æãSlackãã£ã³ãã«ã«éç¥ Developçã®ã¯ãŒã¯ãã㌠䞻ã«ç€Ÿå
é¢ä¿è
ãžã®é
åžãè¡ããŸããå¥ã¢ããªãšããŠæ±ããããããReleaseçãšã¯å¥ã®ãã³ãã«IDãèšå®ããŠããŸãã ãã¡ããåæ§ã«ãç¹å®ã®ãã¬ãã£ãã¯ã¹ãå«ãã¿ã°ãGitHubã«ããã·ã¥ããããšã次ã®ã¯ãŒã¯ãããŒãå®è¡ãããŸãã TestFlightã§å
éšã»å€éšãã¹ã¿ãŒã«é
åžãã æåãŸãã¯å€±æãSlackãã£ã³ãã«ã«éç¥ å
éšã»å€éšãã¹ã¿ãŒã®äœ¿ãåã å
éšãã¹ã¿ãŒãšå€éšãã¹ã¿ãŒã®äœ¿ãåãã«é¢ããŠã以äžã«ç°¡åãªéãããŸãšããŸããã å
éšãã¹ã¿ãŒ (Internal Testers) å€éšãã¹ã¿ãŒ (External Testers) Apple ID App Store Connectã§ç®¡çãããApple IDãå¿
èŠ ç¹ã«å¶éãªã é
åžãŸã§ã®æé ã¢ããããŒãåŸå³æ 審æ»ééåŸ ãã¶ã€ããŒããããã¯ããããŒãžã£ãŒãªã©ãããã«ç¢ºèªããŠãããããå Žåã¯å
éšãã¹ã¿ãŒããæè»œã«ç¢ºèªãããå©çšè
åãã«ã¯å€éšãã¹ã¿ãŒãå©çšããŠããã£ãŠããŸãã ãŸãšã Xcode Cloudã®å°å
¥ã«ãããç¹ã«ãããã€ã«é¢é£ããäœæ¥ãã·ã³ãã«ã«ãªããŸããã ãããŠæ°ã«ãªãç¹ãæãããš èšå®ãGUI App Store Connectã«ååšããªãã¢ããªã«å¯ŸããŠã¯ãŒã¯ãããŒãèšå®ã§ããªã ä»»æã®ã¹ã¯ãªãããå®è¡ããæ©æ§ ã¯ããããå®è¡ã¿ã€ãã³ã°ãéå®ç ãã£ãã·ã¥ã®èšå®ãªã©ãäžæç ãªã©ãèããããŸãã ä»åã¯ãããã€ã«çŠç¹ãåœãŠãå
容ã«ãªããŸããããiOSéçºã®åãçµã¿ã«é¢ããŠå°ãã§ãç¥ã£ãŠããã ããã°å¹žãã§ãã
Google Cloudã®Data Analytics Workshopã«åå ããŠããŸãã! ããã«ã¡ã¯ã æ ªåŒäŒç€ŸãšããªãŒã®éçºæ¬éšããŒã¿&AIããŒã (DAI)ã§ããŒã¿ãšã³ãžãã¢ãããŠããåç°ã§ãã ä»åã¯ãå
æ¥åå ããGoogle Cloudã®Data Analytics Workshopã«ã€ããŠç޹ä»ããŸãã ã¯ããã« ãšããªãŒã§ã¯ãåãµãŒãã¹ããã®ãã°ãããŒã¿åºç€ã«éçŽãããããããŒã¿åæãæ©æ¢°åŠç¿ã®ããã«æŽ»çšããŠããŸãã ããŒã¿åºç€ã®æ§æã¯ãDatabricksãTreasureDataããããŠRedashãçµã¿åããããã®ã§ãã å
·äœçã«ã¯ãDatabricksã§ETLåŠçãè¡ãããã®ããŒã¿ãTreasureDataã«ä¿åããŸãã ãããŠãRedashãçšããŠããŒã¿ã®å¯èŠåãè¡ã£ãŠããŸãã çŸåšã®ããŒã¿åºç€ã«ã¯ãæŽå²çãªçµç·¯ããçããããŒã¿åŠçãããŒã®è€éãããå
šäœçãªã³ã¹ãæé©åãšãã£ã課é¡ãååšããŠããŸãã ãã®ãããªç¶æ³ã§ããŒã¿åºç€ã®æ§æãèŠçŽããŠããäžãGoogle Cloudã®æ¹ããData Analytics Workshopã®æ¡å
ãé ããåå ãããŠããã ããŸããã Data Analytics Workshopãšã¯ Data Analytics Workshopã¯ãGoogle Cloudã®ã¹ãã·ã£ãªã¹ãã«çŸç¶ã®ããŒã¿åºç€/ããŒã¿æŽ»çšã®èª²é¡ããã¢ãªã³ã°ããŠããã ããGoogle Cloudã®é¢é£ãµãŒãã¹ãçšãããœãªã¥ãŒã·ã§ã³ã»ã¢ãŒããã¯ãã£ãææ¡ããŠããã ãã¯ãŒã¯ã·ã§ããã§ãã ã¯ãŒã¯ã·ã§ããã®æµã ä»åã®ã¯ãŒã¯ã·ã§ããã§ã¯ãGoogle CloudããData Analytics Specialistãäžå¿ã«ãCustomer EngineerãSalesã®æ¹ã
ãå«ã3åã®æ¹ãæ
åœããŠãã ãããŸããã ãšããªãŒããã¯ãCTOãšDAIã¡ã³ããŒããã¢ããã®ããã¯ãšã³ããšã³ãžãã¢ãåå ããŸããã ã¯ãŒã¯ã·ã§ããã¯å
š2æ¥ããã以äžã®ãããªæµãã§é²ããããŸããã Day 1 ãšããªãŒã®çŸç¶ã®ããŒã¿åºç€ãšèª²é¡ã®èªèåãã äž»èŠãããã¯ãã®ãçŽ¹ä» äºåãã¢ãªã³ã°ãå
ã«ãããã€ãã®Google Cloudã®ãµãŒãã¹ã玹ä»ããŠããã ããŸããã Day2 ã¢ãŒããã¯ãã£æ¡ã®æ€èš æã
ã®èª²é¡ã解決ããããã®ã¢ãŒããã¯ãã£æ¡ãææ¡ããã ããããã«ã€ããŠã®ãã£ã¹ã«ãã·ã§ã³ãè¡ããŸããã ãã³ãºãªã³ ããã€ãã®Google Cloudã®ãµãŒãã¹ãçšãããã³ãºãªã³ãè¡ããŸããã ã¯ãŒã¯ã·ã§ããã§ã®åŠã³ 以äžã«ã¯ãŒã¯ã·ã§ããã§åŠã³ãæ°ä»ããèšèŒããŸãã ããŒã¿åºç€ã®èª²é¡ãšã¢ãŒããã¯ãã£ãã£ã¹ã«ãã·ã§ã³ Day1ã§ã¯ããšããªãŒã®çŸç¶ã®ããŒã¿åºç€ãšèª²é¡ã®èªèåãããè¡ããŸããã çŸè¡ã®ã¢ãŒããã¯ãã£ã®å
±æã ãã§ãªãããã®ã¢ãŒããã¯ãã£ããªããã®ãããªåœ¢ã«ãªã£ãã®ããAI掻çšã«åããåãçµã¿ã®é²æãBIããŒã«ãããŒã¿ã¬ããã³ã¹ã«é¢ãã課é¡ãªã©ãããŒã¿ã«é¢é£ããåé¡ç¹ãå¹
åºããã¢ãªã³ã°ããŠããã ããŸããã ãšããªãŒã®ããŒã¿åºç€ã«ã¯ã以äžã®ãããªèª²é¡ãååšããŠããŸãã DatabricksãšTreasureDataã®2ã€ã®åºç€ã«ããããããŒã¿åŠçãããŒãååšããããããããŒãè€éåããŠãã ããŒã¿æŽ»çšãä¿é²ããããã®ããŒã¿ã«ã¿ãã°ã®æŽåãšããŒã¿ã¬ããã³ã¹ã®åŒ·åãå¿
èŠã§ãã æ©æ¢°åŠç¿ããããã¯ãã«é©çšããããã®MLOpsã®æŽåãæ±ããããŠãã ãã¢ããã®ããŒã¿åºç€ã§ããBigQueryã®ã³ã¹ããå¢å åŸåã«ãã ãããã®èª²é¡ãèæ
®ããäžã§ãDay2ã§ã¯Google Cloudã®ãµãŒãã¹ã掻çšããã¢ãŒããã¯ãã£æ¡ãææ¡ããã ããŸããã ææ¡ããã ããã¢ãŒããã¯ãã£æ¡ã§ã¯ãåºæ¬çã«BigQueryãäžå¿ãšããæ§æãšãªã£ãŠããŸãã ããã«ããã以äžã®ãããªã¡ãªãããåŸããããšèããããŸãã ããŒã¿åŠçãããŒãåçŽåã§ãã Google Cloudã®ä»ã®ãµãŒãã¹ãšã®é£æºã容æã«ãªããGoogle Cloudã®åãµãŒãã¹ãæå€§é掻çšã§ãã MLOpsåºç€ãšããŠBigQueryãšé£æºã容æãªVertexAIãå©çšã§ãã ããŒã¿ã«ã¿ãã°ãšããŠBigQueryããèªåçã«ã¡ã¿ããŒã¿ãåéå¯èœãªDataplexãå©çšã§ãã BigQueryã®åŒ·åãªèšç®è³æºã掻çšã§ãã ææ¡ããããã©ã³ã§ã¯ãPlan3ããPlan1ã«åããŠGoogle Cloudã®ãµãŒãã¹å©çšçãé«ããŠããæ³å®ãããŠããŸãã Plan3ã§ã¯çŸè¡ã®DWHã§ããTreasureDataãBigQueryã«ç§»è¡ããPlan2ã§ã¯DatabricksãGoogle Cloudã®Sparkåºç€ã§ããDataProcã«ç§»è¡ããŸãã ãããŠãPlan1ã§ã¯ãã¹ãŠã®åŠçãBigQueryã«éçŽããŸãã Google Cloudäžã«ããŒã¿åºç€ãæ§ç¯ãããšãBigQueryã®èšç®è³æºã掻çšãã€ã€çŸè¡ã¢ãŒããã¯ãã£ã«å¯ŸããŠã³ã¹ããæããããšãå¯èœãšãªããŸãã ãŸããBigQuery MLãªã©ã®æ©èœã䜿çšãå¯èœãšãªããŸãã ããã«ãGoogle Cloudã®ä»ã®ãµãŒãã¹ãšã®é£æºã容æã«ãªãããã«ãããŒãžãã®ããŒã¿ã«ã¿ãã°ãMLåºç€ãBIããŒã«ãªã©ãå°å
¥ãããããªããŸãã ææ¡ãããã¢ãŒããã¯ãã£æ¡ãæ€èšããçµæãçŸè¡ã®ã¢ãŒããã¯ãã£ãšåçã®æ§èœãç¶æãã€ã€ã³ã¹ããæããããšãå¯èœã ãšå€æããŸããã ããããç§»è¡ã³ã¹ãã®å€§ãããã¢ããªåºç€ãšã®é£æºãªã©ã解決ãã¹ã課é¡ãå€ãååšããŸãã ä»åã®ã¯ãŒã¯ã·ã§ããã§ã¯æéã®å¶çŽãããã¢ãŒããã¯ãã£æ¡ã®è©³çްãªãã£ã¹ã«ãã·ã§ã³ãè¡ããŸããã§ããã ããããã¯ãŒã¯ã·ã§ããçµäºåŸããªãã£ã¹ã¢ã¯ãŒãšãã圢ã§ãGoogle Cloudã®ã¹ãã·ã£ãªã¹ãã®æ¹ã
ãšãªã³ã©ã€ã³ã§ãã£ã¹ã«ãã·ã§ã³ããæéãããã ããŠããŸãã äž»èŠãããã¯ãã®ãçŽ¹ä» äž»èŠãããã¯ãã®ã玹ä»ã§ã¯ãäºåãã¢ãªã³ã°ã®éã«äŒããLLMãšããŒã¿ã¬ããã³ã¹ãäžå¿ã«Google Cloudã®ãµãŒãã¹ãã玹ä»ããã ããã®ã§äžéšã以äžã§ç޹ä»ããŸãã VertexAI ( https://cloud.google.com/vertex-ai?hl=ja ) èšç·ŽçšããŒã¿ã®æºåãã¢ãã«ã®ãã¬ãŒãã³ã°ããããã€ã¡ã³ããäºæž¬ã®ç£èŠãã¢ãã«ã®æ¹åãŸã§ããã¹ãŠã®ã¹ããããå®è¡ã§ããæ©æ¢°åŠç¿ãã©ãããã©ãŒã Generative AI Studio ( https://cloud.google.com/generative-ai-studio?hl=ja ) çæAIã¢ãã«ã®ãã¡ã€ã³ãã¥ãŒãã³ã°ãããã³ããèšèšãªã©ãè¡ããããŒã« Dataplex ( https://cloud.google.com/dataplex?hl=ja ) 忣ããããŒã¿ã«å¯ŸããŠäžå
åããã管çãšããŒã¿ã¬ããã³ã¹ãæäŸããããã®ãã©ãããã©ãŒã VertexAIã®å©ç¹ãšããŠãã¢ãã«ã®ãã¬ãŒãã³ã°ãããããã€ãŸã§ã®äžè²«ããæäœãå¯èœã§ãããšããç¹ã§ãã ããã«ãããMLOpsã®å®è¡ãå¹çåãããŸãã ããã«ãGenerative AI Studioã®äœ¿çšã«ãããèªåã§ãã¡ã€ã³ãã¥ãŒãã³ã°ãè¡ãã³ã¹ããåæžã§ãããšèããããŸãã Dataplexã¯ãããŒã¿ã¬ããã³ã¹ã®éçšããµããŒãããããã«ãè€æ°ã®ãµãŒãã¹ã«åæ£ããŠååšããããŒã¿ã«å¯ŸããŠãããŒã¿ã®ç®¡çåäœãäœæãã管çåäœã§ã®æš©é管çãè¡ãªããŸãã ããã«ããã«ãããŒãžãã§ãããGoogle CloudãµãŒãã¹ãšã·ãŒã ã¬ã¹ã«é£æºã§ããããŒã¿ã«ã¿ãã°ãšããŠãããŒã¿ã«ã¿ãã°ã®ç®¡çã»éçšã³ã¹ããåæžã§ãããšèããããŸãã äžæ¹ããšããªãŒã§ã¯ããŒã¿ã«ã¿ãã°ãšããŠOpenMetadataãã»ã«ããã¹ãã§äœ¿çšããŠããŸãã OpenMetadataã¯ãGCP/GCP以å€ãå«ããæ§ã
ãªããŒã¿ãœãŒã¹ããã®æšªæçãªã¡ã¿ããŒã¿åéã容æã«ã§ããç¹ãé
åçã§ã¯ãããŸãããã»ã«ããã¹ãã£ã³ã°ç±æ¥ã®éçšã³ã¹ããªã©ã®èª²é¡ãããã€ãååšããŠããŸãã ãã®ããã䜿ãããããéçšã³ã¹ããå«ããDataplexãéžæè¢ã®äžã€ãšããŠæ€èšããŠãããããšèããŠããŸãã Google CloudãµãŒãã¹ã®ãã³ãºãªã³ ãã³ãºãªã³ã§ã¯ã2ã°ã«ãŒãã«å¥ããŠä»¥äžã®ãµãŒãã¹ãçšãããã³ãºãªã³ãè¡ããŸããã - BigQuery ML ( https://cloud.google.com/bigquery/docs/bqml-introduction?hl=ja ) - BigQuery Interactive SQL Translator ( https://cloud.google.com/bigquery/docs/interactive-sql-translator?hl=ja ) BigQuery MLã§ã¯ãBigQueryäžã«ããDELISH KITCHENã®ã€ãã³ããã°ã察象ã«ãã¢ãã«ã®ãã¬ãŒãã³ã°ãšäºæž¬ãè¡ããŸããã BigQuery SQL倿ã¯ãä»ã®SQLèšèªãGoogle SQLã«å€æãå¯èœãªãµãŒãã¹ã§ãã ãšããªãŒã§ã¯ãRedashããTreasureDataãžã®ã¯ãšãªã«Presto SQLã䜿çšããŠãããããBigQueryåºç€ãžã®ç§»è¡ãèãããšãPresto SQLããGoogle SQLãžã®å€æãå¿
èŠãšãªããŸãã çŸåšãRedashäžã«ã¯çŽ17,000ä»¶ã®ã¯ãšãªãååšããŠãããããããGoogle SQLã«å€æããç§»è¡ã³ã¹ãã¯å€§ããªèª²é¡ãšãªããŸãã ãã®åé¡ã解決ããããã«ãBigQuery SQL倿ã玹ä»ããã ããå®éã«å€æã詊ã¿ãŸããã æé ãšããŠWebãã©ãŠã¶äžã§å€æåã®èšèªãéžæããåŸãSQLãå
¥åããŠãã¿ã³ãæŒãã ãã§ãã ãã®çµæãæšæºçãªé¢æ°ã¯ãšã©ãŒãªã倿ã§ããç§»è¡ã³ã¹ãã®å€§å¹
ãªåæžãæåŸ
ã§ãããšæããŸããã ããããTreasureDataã®ç¬èªé¢æ°ã«ã€ããŠã¯å€æãè¡ããªããããç§»è¡ã³ã¹ããå®å
šã«ãŒãã«ããããšã¯é£ãããšæããŸããã ç§»è¡ãè¡ãéã¯ç¬èªé¢æ°ã®å€æã«ã®ã¿æ³šåããæšæºçãªé¢æ°ã«ã€ããŠã¯èªå倿ãè¡ãããšã§ãã³ã¹ããæãã€ã€ç§»è¡ãé²ãããããšèããããŸãã ä»åŸã®åãçµã¿ ä»åææ¡ããã ããã¢ãŒããã¯ãã£æ¡ãåèã«ããšããªãŒã®ããŒã¿åºç€ã®æ¹åãé²ããŠããäºå®ã§ãã ããŒã¿åºç€ã®å€§èŠæš¡ãªå·æ°ã¯ããšã³ãžãã¢ãªã³ã°ãªãœãŒã¹ã®ç¢ºä¿ãæ¢åã®ããŒã¿åŠçãããŒã®ç§»è¡ãªã©ãå€ãã®èª²é¡ã䌎ããŸãã ãã®ãããå°èŠæš¡ãªPoCã宿œãããªã©ããŠãç§»è¡ã®èŠç©ãããç§»è¡åŸã®ã¢ãŒããã¯ãã£ã®éžå®ãè¡ã£ãŠããäºå®ã§ãã ãŸããMLåšãã®ãµãŒãã¹ãªã©ãéšåçã«å°å
¥å¯èœãªãµãŒãã¹ãååšããããããããã®ãµãŒãã¹ã掻çšããPoCã宿œããŠããäºå®ã§ãã ãããã« ä»åã®ã¯ãŒã¯ã·ã§ããã§ã¯ãGoogle Cloudã®ã¹ãã·ã£ãªã¹ãã®æ¹ã
ã«ãšããªãŒã®ããŒã¿åºç€ã®èª²é¡ããã¢ãªã³ã°ããŠããã ãããã®äžã§Google Cloudã®ãµãŒãã¹ã掻çšããã¢ãŒããã¯ãã£æ¡ãææ¡ããã ããŸããã ããã«ãæ§ã
ãªãµãŒãã¹ã®ç޹ä»ãè¡ã£ãŠããã ããããããå©çšããŠã©ã®ãããªããŒã¿æŽ»çšåºç€ãæ§ç¯ãããã«ã€ããŠæ§ã
ãªã¢ã€ãã¢ãæ¹§ããŸããã ã¯ãŒã¯ã·ã§ããã®éå¬ã«ããããå€ãã®ãªãœãŒã¹ãæäŸããŠããã ããGoogle Cloudã®çæ§ã«å¿ããæè¬ç³ãäžããŸãã
ã¯ãããŸããŠãæ ªåŒäŒç€ŸãšããªãŒã®éçºæ¬éšã®ããŒã¿&AIããŒã ã§ãããŒãžã£ãŒå
ŒããŒã¿ãµã€ãšã³ãã£ã¹ããããŠããäŒè€ã§ãã ä»åã¯ããšããªãŒã®ããŒã¿çµç¹ãæ®æ®µã©ããã£ãåãçµã¿ãè¡ãªã£ãŠãããããç°¡åã«ã玹ä»ããããšæããŸãã ãšããªãŒã«ã€ããŠ æ ªåŒäŒç€ŸãšããªãŒã¯ããDELISH KITCHENãããã¢ããããTIMELINEããšãã3ã€ã®ã¡ãã£ã¢ãéå¶ããŠããŸãã åã¡ãã£ã¢ã¯ããããäž»åãšãªããµãŒãã¹ããããããããèµ·ç¹ã«å€å²ã«æž¡ãäºæ¥ãå±éããŠããŸãã ã©ã®ã¡ãã£ã¢ãæŠç¥äžãããŒã¿ããäžå¯æ¬ ãšãªã£ãŠããŸãã ãµãŒãã¹ã®ã°ããŒã¹ã®ããã®KGIã»KPIã®ã¢ãã¿ãªã³ã°ã¯ãã¡ããã§ããã åºåäºæ¥ã§ã®ã¯ã©ã€ã¢ã³ãæ§åãã®åªäœè³æããOMOäºæ¥ã«ããããªãã©ã€ã³ããŒã¿ã®æŽ»çšãªã©ã ããŒã¿ãèµ·ç¹ãšããåãçµã¿ã¯æ°å€ã宿œãããŠããŸãã ããŒã Objective ããŒã¿&AIããŒã ã§ã¯ããããŒã¿è³ç£ãæå€§é掻çšããäºæ¥éå¶ã®å®çŸããObjectiveã«æ²ããŠããŸãã ãã®Objectiveãéæãããç¶æ
ã¯ã2ã€ã«åããããŸãã ããŒã¿è³ç£ãé©åã«äœ¿ããç¶æ
ã«ãªã£ãŠãã ããŒã¿è³ç£ã®æŽ»çšãäºæ¥æ¹åã«è²¢ç®ããŠãã åè
ã¯ããµãŒãã¹ã®åãããµãŒãã¹å
å€ã§çºçãããŠãŒã¶ãŒã®è¡åãæ£ããåéãããå©çšããã人ã誰ã§ãå©çšã§ããããã«ãªã£ãŠããç¶æ
ã§ã ããŒã¿åºç€ãBIããŒã«ã®æäŸã»ããŒã¿ã¬ããã³ã¹ãªã©ãé¢é£ããŸãã åŸè
ã¯ãããŒã¿ã«ãã£ãŠé©åãªæææ±ºå®ããªãããããããŒã¿ã䜿ã£ãŠäºæ¥äŸ¡å€ãåµåºãããŠããç¶æ
ã§ã ããŒã¿åæã广æ€èšŒã»çµ±èšã¢ãã«ã»æ©æ¢°åŠç¿ãªã©ãé¢é£ããŸãã ããã2ã€ã®ç¶æ
ã¯ãã©ã¡ããçæ¹ã ãã§ã¯äžååã§ãäž¡æ¹ãæ©èœããŠåã㊠data-driven / data-informed ãªæææ±ºå®ã«ã€ãªããããã ããããäž¡ç«ãããã®ãããŒã¿&AIããŒã ãšããŠã®ããã·ã§ã³ã ãšèããŠããŸãã éçºäœå¶ 2023幎9ææç¹ã§ãããŒã¿&AIããŒã ã¯ãããŒã¿ãšã³ãžãã¢ã1åããããŒã¿ãµã€ãšã³ãã£ã¹ãã3åããããŒã¿ã¹ãã©ããžã¹ãã1åãåšç±ããŠããŸãã ããããã®å®çŸ©ãæ
åœé åã¯è«žèª¬ãããŸããããšããªãŒã§ã¯äž»ã«ä»¥äžã®ããã«ãªã£ãŠããŸãã ããŒã¿ãšã³ãžãã¢: ããŒã¿åéã»åæåºç€ã®æ§ç¯ãšæ¹åãããŒã¿ã¬ããã³ã¹ã®åŒ·å ããŒã¿ãµã€ãšã³ãã£ã¹ã: ã°ããŒã¹æœçã®åæã»å¹ææ€èšŒãããžãã¯æ¹å ããŒã¿ã¹ãã©ããžã¹ã: ããŒã±ãã£ã³ã°ãœãªã¥ãŒã·ã§ã³ã«ãããå¶æ¥æ¯æŽ ãããã¯å€§ããªæ¬ããšããŠã¯åå²ãããŠããŸãããä»ã®é åã«ãŸããã£ãåãçµã¿ãè¡ãå Žé¢ãå€ããããŸãã äŸãã°ãããŒã¿ãµã€ãšã³ãã£ã¹ãã»ããŒã¿ã¹ãã©ããžã¹ãããã¢ãã¿ãªã³ã°ãåæã®ããã«æ°ããããŒã¿ãå¿
èŠã«ãªã£ããã åºæ¬çã«ã¯ããŒã¿ååŸåŠçã®å®è£
ãŸã§å«ããŠæ
åœããŸãã 忥äœå¶ã«ã§ããã»ã©ã®äººæ°ãããªããšããåŽé¢ããããŸããã ã¹ãã«ã®å±äººæ§ãç·©åãã€ã€ã 倧å
ã®ããŒã¿ã掻çšã§ããç¶æ
ã«å å·¥ããçµéšãéããŠããŒã¿ã«å¯Ÿããè§£å床ãäžããããããšãã£ãã¡ãªããããããšèããŠããŸãã æè¡ã¹ã¿ãã¯ã¯ãäž»èŠãªãã®ãæãããšãããã以äžã®ããã«ãªã£ãŠããŸãã ã€ã³ãã©ç³»: AWSãGCPãterraform ããŒã¿åºç€ç³»: DatabricksãTreasureDataãFivetran ããŒã¿åæç³»: Redashãstreamlit ããã°ã©ãã³ã°èšèª: PythonãScalaãSQL (SparkSQLãPrestoãªã©) MLç³»: MLflowãFastAPI (ML API) AIããŒã«ç³»: Github CopilotãOpenAI API äž»ãªæ¥åå
容 ããã§ã¯ãããŒã¿&AIããŒã ãæ¥é åãçµãã§ããæ¥åã®ãã¡ãçŽè¿ã®ãã®ãããã€ããããã¯ã¢ããããŠç޹ä»ããŸãã ããŒã¿ã«ã¿ãã°æ§ç¯ çŸåšããŒã¿åºç€ã¯æ§ã
ãªå©çšè
ã«äœ¿ã£ãŠããã ããŠããŸããã ãæ¬²ããããŒã¿ãã©ãã«ãããåããã¥ããããããŒãã«ã®ã«ã©ã ã®å®çŸ©ãåãããªãããšãã£ã課é¡ããã³ãã³æããããŠããŸããã ããã§ãããŒã¿ãšã³ãžãã¢äžå¿ã«ããŒã¿ã«ã¿ãã°ã®æ§ç¯ãé²ããŸããã ããã€ãã®å®çŸæ¹æ³ã«é¢ããŠPoCãè¡ããçµæçã«ããã€ãã®ããŒã«ãè·šãã§ã¡ã¿ããŒã¿ãåéã§ããOpenMetadataãæ¡çšããŸããã ã€ã³ãã©ã¯AWSäžã«æ§ç¯ããŠãããçŸåšã¯ããŒã¿ã«ã¿ãã°ã®æ®åã«åããåãçµã¿ã宿œããŠããŸãã 广æ€èšŒ äž»ã«ããŒã¿ãµã€ãšã³ãã£ã¹ãããPdMããšã³ãžãã¢ãšé£æºããæ¥ã
ã®æœçã®å¹ææ€èšŒãæ
åœããŠããŸãã 广æ€èšŒã¯A/Bãã¹ããéžæããããšãå€ããå®éšèšèšã®éšåããæåŸã®æææ±ºå®ã®éšåãŸã§ãããŒã¿ãµã€ãšã³ãã£ã¹ãã䞊走ããã±ãŒã¹ãå€ã
ãããŸãã çŽè¿ã§ã¯ã现ããã¯ãªãšã€ãã£ãã®æ¹åã«å²ãå·¥æ°ãåæžããããããã³ãã£ããã¢ã«ãŽãªãºã ã®å°å
¥ãé²ããŠããŸãã PR匷åãããžã§ã¯ã ãããŸã§ãããŒã±ãã£ã³ã°ãœãªã¥ãŒã·ã§ã³ã®èª²é¡ã®1ã€ã«ããã¬ã³ãäºæž¬ãªã©ã®ãã¬ã¹ãªãªãŒã¹ã®å°ãªãããããŸããã ãã¬ã¹ãªãªãŒã¹ã¯å
¬éãŸã§ã«å°ãªããªãåŽåãå¿
èŠã§ãããå¶æ¥ã¡ã³ããŒã®æ¹ãçŽè¿ã®ãã¬ã³ããæ£ããææ¡ããã®ã«æå¹ãªåŽé¢ã«å ãã ã¡ãã£ã¢ãšããŠããŒã¿è³ç£ãæ¥é å©çšããã ããŠãããŠãŒã¶ãŒæ§ã«éå
ã§ãããšãã瀟äŒè²¢ç®ãšããŠã®åŽé¢ããããŸãã ãã®ãããžã§ã¯ãã¯ããŒã¿ã¹ãã©ããžã¹ããšåºå ±ã»ç®¡çæ é€å£«ã飿ºããŠé²ããŠããã ããŒã¿ã¹ãã©ããžã¹ããæ¢çŽ¢çãªåæãã§ããããã·ã¥ããŒããäœæ åºå ±ã»ç®¡çæ é€å£«ã亀ããŠè°è«ãã€ã€ããã¬ã³ãã®æ¢çŽ¢ã©ããã·ã¥ããŒãã®èª¿æŽãé²ãã çºä¿¡ã®æ¹åæ§ã決ãŸããšããŒã¿ã®æŽåœ¢ãšçºä¿¡å
容ã®èª¿æŽã宿œ ãšãã£ãæµãã§ãããŒã¿ã¹ãã©ããžã¹ããèµ·ç¹ã«åèªã®æã€ãã¡ã€ã³ç¥èãããŸãéçŽããããããžã§ã¯ãã«ãªã£ãŠããŸãã çŽè¿ã¯ãã§ã³ãã³ãã«é¢ãããã¬ã¹ãªãªãŒã¹ãçºä¿¡ãããããã€ãã®ã¡ãã£ã¢ã§ãåãäžããŠããã ããŠãããŸãã ããŒã¿çµç¹ãšããŠã®çŽè¿ã®åãçµã¿ ãŸããããŒã¿çµç¹ãšããŠãçŽè¿ã¯ä»¥äžã®ãããªåãçµã¿ãè¡ã£ãŠããŸãã å匷äŒã®å®æœ ããŒã¿åæãæ©æ¢°åŠç¿ãªã©ã®ã¹ãã«ã身ã«ã€ããäžã§ã¯ãå®è·µçãªçµéšã«å ããŠãæ°åŠãªã©ã®åºç€ç¥èã®ç¶ç¶çãªåŠç¿ãéèŠã«ãªããŸãã ããã§ããŒã¿&AIããŒã ã§ã¯ãæ°åŒã«åãåãæéãäœãããšããåç®ã§ãæå¿ã®ã¡ã³ããŒã§èŒªèªäŒãéå¬ããŠããŸãã éå»äœåºŠã瀟å
ã§å匷äŒãéå¬ãããåå ãããããŠããŸããããäºç¿ãšçºè¡šè³æã®æºåã¯ããããã®è² æ
ã«ãªã£ãŠããããã ãã®èŒªèªäŒã¯æ
åœè
ããã®å Žã§ãã¯ã€ãããŒãã«æžããªããèªã¿é²ããããšãã圢åŒããšã£ãŠããŸã ïŒãã®ãããå
容ãé£ããå Žåã«ã¯åå è
å
šå¡ãé ãæ±ããŠã»ãšãã©é²ãŸãªããŸãŸçµããåããããŸãïŒã çŸåšã¯ãçµ±èšçæ©æ¢°åŠç¿ã®æ°ç100å with Pythonããšããæžç±ãæ±ã£ãŠããŸãã é±ã«1æéã®ããŒã¹ã§ã2023幎9ææç¹ã§éå§ãã1幎å以äžïŒæè¿ããããæçµç« ã«å
¥ããŸããïŒç¶ããŠãããä»ã§ã¯æ¯èŒçå€åã®åãçµã¿ã«ãªã£ãŠããŸãã 瀟å
ChatAppäœæ æè¿ChatGPTã®ãããªçæAIãçµã¿èŸŒãã ãµãŒãã¹ãããŒã«ãæ¥ã
å¢å ããŠããäžã§ãããããæ¥åžžçã«è§ŠããŠèæãæŽã¿ã ããè¯ã掻çšã®ä»æ¹ãèãæ¥åæ¹åã«æŽ»ãããŠããã¹ãã«ãæ±ãããã€ã€ãããŸãã ãã®ãããªåãã瀟å
ã§é«ããŠãããããããŒã¿&AIããŒã ãšããŠç€Ÿå
ChatAppãäœæã»æäŸããåãçµã¿ãè¡ããŸããã ãªãªãŒã¹æã®Slackã¡ãã»ãŒãž ChatAppã¯OpenAI APIãããŒã¹ã«åããŠãããå
¥åããæ
å ±ãåŠç¿ã«äœ¿ãããªãããèšå®ã§ãããããChatGPTãããæ¥åå©çšã®æ·å±
ãäžãã£ãŠããŸãã ãŸããGPT-4ã瀟å¡ã¯èª°ã§ãç¡æã§äœ¿çšã§ããããã«ãªã£ãŠããŸãã ChatAppã®äœæã¯ãããŒã ã§äœã£ãŠã¿ãããšãã話é¡ãåºãç¿é±ã«ã1æ¥æéããšã£ãŠããŒã¿ãšã³ãžãã¢ã»ããŒã¿ãµã€ãšã³ãã£ã¹ãã®2åã§äžæ°ã«äœãäžããã ãšããç¹ã¯å°å³ãªã¢ããŒã«ãã€ã³ãã«ãªã£ãŠããŸãã ãŸããäœæã«ãããŠã¯ä»¥äžã®èšäºãåèã«ãããŠããã ããŸããã ãã®ãããªãã¡ã³ããŒã®çµéšå€ã«ãªãããã€æ¥åã«ã圹ç«ã€ãããªåãçµã¿ãç±éãæã£ãŠéè¡ãããããªåãã¯ãä»åŸãããŒã ãšããŠå¢ãããŠãããããšèããŠããŸãã ä»åŸã®åãçµã¿ æåŸã«ãããŒã¿çµç¹ãšããŠã®ä»åŸã«åããåãçµã¿ã玹ä»ããŸãã ããŒã¿åºç€ã®ç¶ç¶çãªæ¹å çŸåšã®ããŒã¿åºç€ã¯å¹
åºãäºæ¥éšã«ããŒã¿ãæäŸãå©çšããã ããŠããç¶æ
ã§ããã ã³ã¹ããã¯ãããå質ãæäŸé床ãªã©ãããæ¹åã§ããéšåã¯å€ã
ååšããŠããŸãã ãŸããå©çšè
ã䜿ããããBIããŒã«ã®èšèšããèŠãããªããªã£ãŠããŸãããã·ã¥ããŒãã®ç®¡çæ¹æ³ãªã©ããåãçµãã¹ã課é¡ãšããŠæãã£ãŠããŸãã çŽè¿ã§ã¯OpenMetadataã䜿ã£ãããŒã¿ã«ã¿ãã°ãäœæããŸãããããããããã«ç€Ÿå
æ®åãããŠããããããããªèª²é¡ã§ãã ãããã¯äžæ°ã«è§£æ±ºã§ãããã®ã§ã¯ãªãã§ããã ããŒã ãšããŠã¯ç¶ç¶çã«éžæè¢ãæ€èšãç¶ããç¶æ
ãäœããå°ãã§ãè¯ãç¶æ
ãç®æããããšèããŠããŸãã ããŒã¿ã«ããæè¡æŽæ°ã®æšé² çŸç¶DELISH KITCHENãåãããµãŒãã¹å
éšã«ã¯æ§ã
ãªããžãã¯ïŒæ€çŽ¢ãã¬ã³ã¡ã³ããªã©ïŒãåã蟌ãŸããŠããŸãã ãããã®ã»ãšãã©ã¯ããµãŒãã¹åæã®é ã«äœæãããã«ãŒã«ããŒã¹ã®ã¢ã«ãŽãªãºã ãã粟床ãç¶ç¶çã«è©äŸ¡ãããŠããªãã¢ãã«ã«ãªã£ãŠããã æ¹åã®äœå°ãå€ãæ®ãããŠããç¶æ
ã§ãã ãŠãŒã¶ãŒæ§ã®å©çšäœéšãå°ãã§ãåäžãããããã«ãçŸåšã¯ãµãŒãã¹ãšããžãã¯ãé©åã«åé¢ãããç¶æ
ãå°å
¥ããåãçµã¿ãå§ããŠããŸãã ãµãŒãã¹ãšããžãã¯ã®åé¢ããªãããããšã§ãããŒã¿ãµã€ãšã³ãã£ã¹ããããžãã¯ã®æ¹åã«éäžã§ããç°å¢ã«ãªãã€ã€ã å¿
èŠã§ããã°ããžãã¯ãåæãšããUXã®èšèšã«ãåãçµããããã«ãªããšèããŠããŸãã ä»ã¯å°ããã€å°å
¥äºäŸãå¢ãããŠããæ®µéã§ãããå°æ¥çã«ã¯ã€ã³ãã©ãæŽåãã€ã€ããã¹ã±ãŒã«ããåºç€ãæ§ç¯ããŠãããããåãçµãã§ããããã§ãã ãããã« ããŒã¿&AIããŒã ã®çŽè¿ã»å°æ¥ã«åããåãçµã¿ããç°¡åã«ã玹ä»ããŸããã ãšããªãŒã®ããŒã¿çµç¹ã«èå³ãæã£ãŠããã ããæ¹ã®è§£å床ãå°ãã§ãäžãããããªå
容ã«ãªã£ãŠãããšå¹žãã§ãã ãã詳ãã話ãèãããæ¹ã¯ãã«ãžã¥ã¢ã«é¢è«ããç³ã蟌ã¿ããã ãããšå¬ããã§ãïŒ corp.every.tv
ããã«ã¡ã¯ããã¢ããã§iOSã¢ããªãéçºããŠããååã§ããã ãã¢ããã§ã¯ãµãã©ã€ããå«ããè€æ°ã®ã¢ããªããªãªãŒã¹ããŠããŸããããããã¢ããªã®ãªãªãŒã¹ãçµããŠããã°ããŒã¹ããããã«æ¹å/éçšãè¡ã£ãŠããŸãããN1ã€ã³ã¿ãã¥ãŒçã§ãŠãŒã¶ãŒã®å£°ãèããŠã¿ããšããããªæ©èœããã£ããã§ããïŒç¥ããªãã£ãã§ãããšããæèŠãã¡ãã»ãèŠåããããŸããæã
æ©èœãæäŸããŠããåŽãšããŠã¯ãã§ããã ãæ©èœèªç¥ããŠããããããã«ãã¶ã€ã³ã工倫ããŠæäŸããŠããŠãäžå®æ°ã¯æ©èœã«ãã©ãçãåã«é¢è±ããŠããŸãå¯èœæ§ããããŸããã ããã§ä»åã¯iOS17ã§è¿œå ãããTipKitãçšããŠãæ©èœèªå°ã§ããªããæ€èšŒããŠãè§ŠããŠãããããšæããŸãïŒã TipKitãšã¯ ãŸãTipKitã®æŠèŠãã話ãããŸãã TipKitã¯ã¢ããªäžã§ãã³ãã衚瀺ããŠãŒã¶ãŒã«æ©èœ/æäœæ¹æ³ãç¥ã£ãŠãããããã®ææ®µãšããŠæäŸãããŠããŸããã ããã«ãããã¢ããããŒãã§è¿œå ããæ©èœãç¥ã£ãŠããã£ããããªã³ããŒãã£ã³ã°ã§ã¢ããªã®ã³ã¢ãšãªãæ©èœãç¥ã£ãŠãããããšãã§ããŸãã ãã ãããŠãŒã¶ãŒã¢ã¯ã·ã§ã³ãä¿ãäžã§ãâãã³ããã©ã®ã¿ã€ãã³ã°ã§è¡šç€ºãããââã©ã®ãããªã¡ãã»ãŒãžã§ã¢ãããŒããããâãèããã®ãé£ãããèšèšãããã倧äºã«ãªããšæããŸããã å®è£
ã æ©éå®è£
ã«åãæãããŸããä»åã¯UIKitã§è¡šç€ºãããšããŸã§ã玹ä»ããŸãããSwiftUIã§ãå®è£
ã¯ãããç°¡åã§ããã ãŸãã¯AppDelegateã§TipKitã䜿ãèšå®ã ãããŠãããŸããã import TipKit func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool { Task { try? await Tips.configure() } /* ..... */ } 次ã«ãã³ãã衚瀺ãããViewControllerã§åŠçãèšè¿°ããŠãããŸãã äžèšã§ã¯ãã³ãã§è¡šç€ºããTipã®äžèº«ãå®çŸ©ããŠããŸãã import TipKit struct StartButtonFeatureTip: Tip { var title: Text { Text("é£çãå§ãŸã£ããšæã£ããã¿ãã!!") } var message: Text? { Text("é£çããããŸã£ãŠãããããããŸã£ãããããã¿ã³ãã¿ããããŠèšæž¬ãçµäºããŸããã") } var image: Image? { Image(systemName: "hand.tap.fill") } } åäœæ€èšŒã§ã¯ç»é¢è¡šç€ºã¿ã€ãã³ã°ã§ãã³ãã衚瀺ãããã£ãã®ã§ãviewDidAppearã§è¡šç€ºç»é²ãããŠããŸãã ç»é¢ããé¢ããéã«ãã€ã³ã¹ã¿ã³ã¹ãè§£æŸã§ããããã«nilã代å
¥ããŠããŸãã // ã¯ã©ã¹ãããã㣠private var startButtonFeatureTip = StartButtonFeatureTip() private var tipObservationTask: Task<Void, Never>? private weak var tipPopoverController: TipUIPopoverViewController? override func viewDidAppear(_ animated: Bool) { super.viewDidAppear(animated) /* ... */ tipObservationTask = tipObservationTask ?? Task { @MainActor in for await shouldDisplay in startButtonFeatureTip.shouldDisplayUpdates { if shouldDisplay { let popoverController = TipUIPopoverViewController(startButtonFeatureTip, sourceItem: contractStartButton) present(popoverController, animated: animated) tipPopoverController = popoverController } else { if presentedViewController is TipUIPopoverViewController { dismiss(animated: animated) tipPopoverController = nil } } } } } override func viewWillDisappear(_ animated: Bool) { super.viewWillDisappear(animated) tipObservationTask?.cancel() tipObservationTask = nil } ãããŸã§ã®èšè¿°ã§ã·ãã¥ã¬ãŒã¿ãŒãèµ·åãããšãã³ãã衚瀺ãããããã«ãªããŸãã ãããç°¡åã§ãããæ¬¡ã¯ããã¹ããªã©ã«ã¹ã¿ãã€ãºã§ãããšãã¯èª¿æŽãã¢ããªã«éŠŽæãããã«ããŠãããããšæããŸãïŒ ããã¹ãã«ã©ãŒããã©ã³ããªã©ã¯Tipã®äžèº«ãå®çŸ©ããŠãããšãã§èšè¿°ããã¢ã€ã³ã³ã®è²ã«ã€ããŠã¯TipUIPopoverViewControllerã®äžã«ããViewã®tintColorã倿Žããããšã§æå®ã§ããŸãã struct StartButtonFeatureTip: Tip { var title: Text { Text("é£çãå§ãŸã£ããšæã£ããã¿ãã!!") .foregroundStyle(Color(uiColor: .defaultTint)) } var message: Text? { Text("é£çããããŸã£ãŠãããããããŸã£ãããããã¿ã³ãã¿ããããŠèšæž¬ãçµäºããŸããã") .foregroundStyle(Color(uiColor: .defaultTint)) } var image: Image? { Image(systemName: "hand.tap.fill") } } override func viewDidAppear(_ animated: Bool) { super.viewDidAppear(animated) /* ... */ tipObservationTask = tipObservationTask ?? Task { @MainActor in for await shouldDisplay in startButtonFeatureTip.shouldDisplayUpdates { if shouldDisplay { let popoverController = TipUIPopoverViewController(startButtonFeatureTip, sourceItem: contractStartButton) popoverController.view.tintColor = .defaultTint present(popoverController, animated: animated) tipPopoverController = popoverController } else { if presentedViewController is TipUIPopoverViewController { dismiss(animated: animated) tipPopoverController = nil } } } } } ãã³ãã®backgroundColorãæå®ããããšãã§ããã®ã§ãããéããã¢ã€ã³ã³ã®è²ã®æå®ã¯çŸç¶äžæãªã®ã§ã泚æãå¿
èŠããã§ãã(iOS17ãæ£åŒãªãªãŒã¹ããããUIKitããã§ãéããã¢ã€ã³ã³ã®è²ãæå®ã§ããããã«ãªãããšãé¡ããŸããã) ãã³ãã®äžã«ã¢ã¯ã·ã§ã³ãªã³ã¯ãä»äžããããšãå¯èœã§ãã Tipã®äžèº«ã®å®çŸ©ã«Actionã远å ããŸããTipUIPopoverViewControllerã®ã€ãã·ã£ã©ã€ã¶ã«actionHandlerãããã®ã§ããã³ãã©ãŒå
ã§ActionåŠçãèšè¿°ããŠãããŸãã struct StartButtonFeatureTip: Tip { var title: Text { Text("é£çãå§ãŸã£ããšæã£ããã¿ãã!!") .foregroundStyle(Color(uiColor: .defaultTint)) } var message: Text? { Text("é£çããããŸã£ãŠãããããããŸã£ãããããã¿ã³ãã¿ããããŠèšæž¬ãçµäºããŸããã") .foregroundStyle(Color(uiColor: .defaultTint)) } var image: Image? { Image(systemName: "hand.tap.fill") } var actions: [Action] { [Action(id: "start_button", title: "詳现ã¯ãã¡ã")] } } override func viewDidAppear(_ animated: Bool) { super.viewDidAppear(animated) Tracker.track(event: .counterScreen) AdjustTracker.track(event: .counterScreen) let statusBarHeight = self.view.window?.windowScene?.statusBarManager?.statusBarFrame.height ?? 0 headerViewHeightConstraint?.constant = 44 + statusBarHeight tipObservationTask = tipObservationTask ?? Task { @MainActor in for await shouldDisplay in startButtonFeatureTip.shouldDisplayUpdates { if shouldDisplay { let popoverController = TipUIPopoverViewController(startButtonFeatureTip, sourceItem: contractStartButton, actionHandler: { action in guard action.id == "start_button" else { return } /* ã詳现ã¯ãã¡ãããã¿ããåŸã®åäœ */ }) popoverController.view.tintColor = .defaultTint present(popoverController, animated: animated) tipPopoverController = popoverController } else { if presentedViewController is TipUIPopoverViewController { dismiss(animated: animated) tipPopoverController = nil } } } } } ã«ãŒã«ãã€ãã ãã³ãã衚瀺ãããæã«ããŠãŒã¶ãŒãXXXXãããããããŠãŒã¶ãŒããã°ã€ã³ããããçã
æ¡ä»¶ãæºãããæã«è¡šç€ºãããå ŽåããããšæããŸããããã§äœ¿çšããã®ãã«ãŒã«ã§ãã ã«ãŒã«ã¯2çš®é¡ãããŸãã ãã©ã¡ãŒã¿ããŒã¹ æèŠçã«ã¯âãã°ã€ã³ããŠãããâçBoolã§ç®¡çã§ãããã®ã ãšæããŸãã ã€ãã³ãããŒã¹ ãXXXãããããçã®ã€ãã³ãããªã¬ãŒãæå®ã§ããŸãã ä»åã¯ã詊ãã§ã€ãã³ãããŒã¹ã®ã«ãŒã«ã䜿çšããããããããButtonã2åã¿ãããããããããŸã£ããããButtonã«ãã³ãã衚瀺ããåŠçãæžããŠãããŸãã ãŸãã¯ãTipã®äžèº«ã®å®çŸ©ã«EventãšRuleãšèšè¿°ããŸãã viewDidAppearå
ã¯ç¹ã«å€ãããããŸããã ããããããButtonãã¿ãããããã¿ã€ãã³ã°ã§ãstartButtonTappedCountãã€ã³ã¯ãªã¡ã³ãããå¿
èŠããããŸãã struct StopButtonFeatureTip: Tip { static let startButtonTappedCount = Event(id: "start_button_tapped_count") var title: Text { Text("é£çããããŸã£ããã¿ãã!!") .foregroundStyle(Color(uiColor: .defaultTint)) } var message: Text? { nil } var image: Image? { Image(systemName: "hand.tap.fill") } var rules: [Rule] { #Rule(Self.startButtonTappedCount) { $0.donations.count >= 2 } } } private lazy var contractStartButton: ContractStartButton = { let button = ContractStartButton() button.configure(tapped: { [weak self] in guard let self = self else { return } Task { try? await StopButtonFeatureTip.startButtonTappedCount.donate() } /* ... */ }) return button }() ãã®ä» ä»ã«ã1æ¥1åã®ãã³ããã衚瀺ããªããåããã³ããåºç¶ããªãããã«åºçŸåæ°ãå¶éãããçã®ãªãã·ã§ã³ããããŸãããã²èª¿ã¹ãŠã¿ãŠãã ããã ãŸããèŠãç®ã®ç¢ºèªããããªã©åžžã«ãã³ããåºãããæããããšæããŸããããã®æã¯ãã®ããã«èšè¿°ããããšã§å
šãŠã®ãã³ãã衚瀺ããããšãã§ããŸãã Tips.showAllTipsForTesting() æåŸã« ä»åã¯iOS17ã§è¿œå ãããTipKitãè§Šã£ãŠã¿ãŸãããææ³ãšããŠã¯ãªã³ããŒãã£ã³ã°ã«çµã¿èŸŒãããšã§åæ¥ã®æ©èœå©çšãä¿ãããšãã§ãã现ãããšããŸã§æ©èœèªç¥ã«ç¹ããããã ãšæããŸããã ãŸã倧ãããªæ©èœã远å ãã¢ããããŒãã宿œããéã«ãåæ§ã«äŸ¡å€ãæãããã§ãã ãã ãããŒã¹ã®ã¬ã€ã¢ãŠãã¯OSãæäŸãããã®ã«åãå¿
èŠããããããããããªãããªèŠãç®ã§è¡šç€ºãããèŠæãããå Žåã«ã¯äœ¿ããªãããã§ãã ãã¢ããã§ã¯ãµãã©ã€ãã¢ããªã§æ€èšŒãããŠãŒã¶ãŒã®åå¿ãè¯ããã°éæãä»ã®ã¢ããªã«ã¯å±éããŠãããããªãšèããŠããŸãã åè https://developer.apple.com/videos/play/wwdc2023/10229/ https://developer.apple.com/documentation/tipkit/highlightingappfeatureswithtipkit
èæ¯ DELISH KITCHEN éçºéšã§å°å£²åãåãã®éçºã«æºãã£ãŠãã倧æ ( @kosukeohmura ) ãšãããŸãã ãšããªãŒã§ã¯ ãªããŒã«ã¡ãã£ã¢ã®æ§ç¯ã»æäŸãéããŠå°å£²æ§ãæ¯æŽããŠãã æ§æ³ãæ²ããŠããã retail HUB ãšããæ çµã¿ã§ããã€ãã® SaaS ãããã¯ããéçºã»æäŸããŠããŸããéçºã®ãã§ãŒãºãšããŠã¯ãŸã ãŸã æªæçãªéšåãå€ãã®ã§ãããä»åã¯ãã®äžã§ããã«ãããã³ã㪠SaaS ã«æ³å®ãããèŠæ±ã«çç®ããŠããããæºããããã«èããŠããããšãã話ãããŸãã ãã«ãããã³ããªã·ã¹ãã ãšã¯ ãšããªãŒã§ã¯åå°å£²ïŒäž»ã«ã¹ãŒããŒããŒã±ããïŒæ§ãããããããã³ããšãªãã·ã¹ãã ãå
±çšããããããããã«ãããã³ããªãããã¯ããäœã£ãŠããŸãããã«ãããã³ããªã·ã¹ãã ã¯ãããã³ããšããæŠå¿µèªäœãååšããªãã·ã¹ãã ããããã³ãããšã«ç¬èªã®ã·ã¹ãã ãååšããå Žåã«æ¯ã¹ãŠã©ã®ãããªæã«åããŠãããã®ãªã®ã§ãããããããããã®å Žåã«ã€ããŠãç§ãªãã®çè§£ãæžããŠã¿ãŸãã ããã³ããšããæŠå¿µãç¡ãã·ã¹ãã ããã§æãããªãã§æãã·ã³ãã«ãªã±ãŒã¹ãšããŠãããã³ããšããæŠå¿µããªããå䜿çšè
ãç¬ç«ããŠããã·ã¹ãã ããããŸããåŒç€Ÿãéå¶ããã¬ã·ãåç»ã¡ãã£ã¢ DELISH KITCHEN ããã®ã¢ãã«ã§ãã ïŒåœããåãªè©±ã§ããïŒçµç¹ã§äœ¿çšãããªããããªã·ã¹ãã ã§ã¯ãããã³ãã䜿ã£ãŠãªãœãŒã¹ãæãããåæ©ãçãŸããŸããã äžèšã®ãããªèŠæ±ãçãŸãããã·ã¹ãã ã§ã¯ãããã³ããšããåäœã§åçš®ãªãœãŒã¹ãæããããšãæ€èšããå¿
èŠãåºãŠããŸãã èªçµç¹ã®ã¡ã³ããŒã確èªããã èªçµç¹ã«å±ãããªãœãŒã¹ã®å€æŽãè¡ããã ç¹å®ã®çµç¹ã«å±ãããŠãŒã¶ãŒçŸ€ã®ããããã¯ãã®äœ¿çšç¶æ³ã確èªããã ç¹å®ã®ããã³ãåãã®ã·ã¹ãã æ¬¡ã«ããæ¥µç«¯ãªäŸãšããŠãããã³ãããããã«èŠæ±ã现ããèŽåãããã®éœåã«ããããŠããããå¶äœã»æ§ç¯ã»æäŸãããã·ã¹ãã ãèããŠã¿ãŸããã³ã¹ããèããªãå Žåã«ã¯æãããã³ãã®èŠæ±ãæºããããææ³ã§ãããããã³ãããšã«ã·ã¹ãã ã«å¯ŸããèŠæ±ãç°ãªãå Žåãæãæè»ã«å¯Ÿå¿ã§ããææ³ã§ãã äžæ¹ã§ãåããããªèª²é¡ã倿°ã®ããã³ããæ±ããäžã§ãã®ææ³ãåã£ãå Žåã«ã¯ãã·ã¹ãã ããšã«äœãæ¿ãããªãªãŒã¹äœæ¥ã仿§çå®ãªã©ã®ã³ã¹ãããããããã®ã³ã¹ãã¯å¿
èŠä»¥äžã«å€ããªããŸããè€æ°ã®ã·ã¹ãã ã«åã倿Žãé©çšãç¶ããããšããããã³ããå¢ããã«é£ããŠé£ãããªããŸãã ãã«ãããã³ããªã·ã¹ãã ãã«ãããã³ããªã·ã¹ãã ã§ã¯ããœãŒã¹ã³ãŒãããã®ä»ãµãŒããŒçã®ãªãœãŒã¹ãããã³ãéã§å
±çšããŸããããã³ãã®å¢å ã«å¯ŸããŠéçºãéçšã«æããã³ã¹ããïŒçŽæ¥ã¯ïŒæ¯äŸããªãã®ã§ãã¹ã±ãŒã«ããããã·ã¹ãã ãšãªããŸããäœããã®çµç¹ã衚ããããªããŒã¿æ§é ãå¿
èŠã§ãåããããªèª²é¡ãæã£ãããã³ããå€ãååšããå Žåã«ã¯æåãªéžæè¢ãšãªããŸããç§éã®ããŒã ã§ããå€ãã®å°å£²æ§ã®æ±ãã課é¡ãå
±éã®ãããã¯ãã§è§£æ±ºããŠãããããšèãããã®ææ³ããšã£ãŠããŸãã çæããŠããã¹ãããšãšããŠãããã³ãããšã®èª²é¡ã倧ããç°ãªãå Žåããåããã³ãããã®èŠæ±ãå®çŽã«åãåãæ©èœæ¡åŒµãç¶ãããããªå Žåã«ã¯ãç¹å®ã®ããã³ãåãã®ç¹å¥ãªå®è£
ãä¹±ç«ããããã·ã¹ãã ã®å¿
èŠä»¥äžãªå€æ©èœåãèµ·ããåŸãŸãããããªããšãããã¯ãã¯è€éæ§ãå¢ããŠãããéçºé床ã®äœäžããã°ã®é »åºãæãã§ãããã ããã³ãããšã®èŠæ±ã¯å€å°ãªããšãç°ãªããã®ã§ããããããã®èŠæ±ãæã«ã¯åãæšãŠã€ã€ãã©ãããã³ãå
±éã®èª²é¡ã解決ã§ãããããã¯ãã«èœãšã蟌ãã§ãããããšããé£ããã«åãåãããšãå¿
èŠãšãªããŸãããã«ãããã³ããªã·ã¹ãã ã¯å€ãã®å Žå to B ã§ãããã客æ§ãšã®é¢ä¿ã to C ãšæ¯ã¹ãŠè¿ããã·ã¹ãã 䜿çšè
ã®çã®å£°ãéè¿ã§èããããšãããããšæããŸãããã®äžã§ãæªæ¥ãèŠæ®ããŠãããã¯ããã©ããããã®ã«ããŠããããèããæææ±ºå®ãè¡ãç¶ããããšã倧åã ãšæããŸãã ãã«ãããã³ããªãããã¯ãã«ãããèŠæ± è€æ°ã®ããã³ãããªãœãŒã¹ãå
±çšããéœåäžãããã³ãããšã®ããŒã¿ã®åé¢ã«ãããã©ã€ãã·ãŒã®ç¢ºä¿ãèŠæ±ã®çé ãšããŠæããããŸããç°ãªãããã³ãã®ããŒã¿ããããã¯ãäžã§èŠããŠããŸããšããããã¯ãã®ä¿¡é Œã¯å€±ããäºæ¥èªäœã®åç¶ãå±ãããªã£ãŠããŸããŸãã 仿¹ã§ããããã¯ããéå¶ã»æ¹åããŠããäžã§ã¯ããã³ããæšªæããããŒã¿ãèŠãŠåæãè¡ãã»æ¬¡ã®æœçãžç¹ããŠãããããšããããŒãºãããããŸãéå¶åŽã®ã¡ã³ããŒãåããã³ãã®ä»£ããã«ãããã¯ãã®ããŒã¿ãé²èŠ§ã»æäœããã±ãŒã¹ãèããããŸãã ãã«ãããã³ããªãããã¯ãéçºã§èããããš ããŒã¿ã®åé¢ RDB ãããã¯ãããã®ç®¡çç»é¢ã«è¡šç€ºãããã»ãšãã©ã®ããŒã¿ãå
¥ã£ãŠããããŒã¿ããŒã¹ã§ããééçãªã³ã¹ããš DB ãžã®è² è·ãšãèããããŒã¿ããŒã¹ã®ã€ã³ã¹ã¿ã³ã¹ã¯å
±éãšããããã³ãããšã«è«çããŒã¿ããŒã¹ãåé¢ãã圢ã«ããŠããŸããå ããŠãããã³ãå
±éã®ã¬ã³ãŒãã«ã€ããŠã¯å
±çšã®ã¹ããŒããäœæããããã«ä¿åããŠããŸããRDB ãŠãŒã¶ãŒãããã³ãããšã«äœæãããããã察å¿ããããã³ãã®ããŒã¿ä»¥å€ã«ã¢ã¯ã»ã¹ã§ããªãããã«ããŠããŸãã ç»åãªã©ã®ãã¡ã€ã« åçš®ãã¡ã€ã«ãä¿åããã¹ãã¬ãŒãžãµãŒãã¹ (Amazon S3 ã䜿çšããŠããŸã) ã«ã€ããŠããRDB ãšåæ§ã«ããã³ãããšã®ããŒã¿ã®åé¢ãå¿
èŠã§ãããããã³ãããšã«ãã±ãããåããŠãã¡ã€ã«ãä¿ç®¡ããŠããŸãããã¡ããããã³ãå
±éã®ãã¡ã€ã«ã«ã€ããŠã¯å
±çšã®ãã±ããã䜿çšããŠããŸãã åçš®ã€ãã³ããã°ãã¢ã¯ã»ã¹ãã° åçš®åæã«äœ¿ãã¯ã©ã€ã¢ã³ãã¢ããªäžã§ã®ã€ãã³ããã°ããµãŒããŒã»ããŒããã©ã³ãµãžã®ã¢ã¯ã»ã¹ãã°ã«ã€ããŠã¯ãã»ã³ã·ãã£ããªæ
å ±ã¯å
¥ããªãããšãšããã³ã暪æã§çµ±èšçãªèŠããã±ãŒã¹ãå€ããšèããããã³ãããšã«åããã«ä¿åããŠããŸããããã³ãã®èå¥åããã°ã«å«ããããšã§ãããã³ãããšã®ãã°ãæœåºããããšãã§ããŸãã API ãµãŒããŒã»ããŒããã©ã³ãµãŒ ããããããã³ãå
±éã®ãã®ã䜿çšããŠããŸãããAPI ãªã¯ãšã¹ãã®å
容ããããã³ããèå¥ããä»ããã³ãçšã® RDB ãã¹ãã¬ãŒãžãžã®æ¥ç¶ãèµ·ãåŸãªãããã«ããŠããŸãã éçºçšã®ããã³ã 现ãã話ã§ãããéçºæã瀟å
ã§ã®ãã¢ã«äœ¿ãããã³ãã©ãããã®ïŒãšãã話ããããŸããåŒç€Ÿã§ã¯ããŒã«ã«ç°å¢ãéçºçšã®ç°å¢ã«ã¯ç€Ÿå
å
±éã®æ¶ç©ºã®ããã³ãã®ç°å¢ãçšæããéçºã瀟å
çšãã¢ã¢ããªã§ã®åäœç¢ºèªã«ããã䜿çšããŠããŸãã éå¶ã¡ã³ããŒã®ãŠãŒã¹ã±ãŒã¹ã®èæ
® éå¶åŽã®ã¡ã³ããŒãåããã³ãã®ä»£ããã«ãããã¯ãã®ããŒã¿ãé²èŠ§ã»æäœããããšããå Žåã«ãåããã³ãããšã®ãŠãŒã¶ãŒã¢ã«ãŠã³ããããã€ãæã€åœ¢ã ãšããã°ã€ã³ã»ãã°ã¢ãŠããç¹°ãè¿ããããè€æ°ã®ãµã€ããæž¡ãæ©ããªã©é¢åãªããšãæ³å®ã§ããŸãããã®ããšãé²ããããã¢ã«ãŠã³ãã«è€æ°ã®ããã³ããçŽã¥ããããªåœ¢ãšããé²èŠ§ã»æäœå¯Ÿè±¡ã®ããã³ããéžæã§ãããããªåœ¢ãšããŠããŸãã ãµãŒãã¹ããµãŒããŒã® Endpoint ã® URL ãããã³ãããšã«åããã äžã®äžã® SaaS ãããã¯ãã䜿ã£ãŠãããšããã³ãããšã«ãµããã¡ã€ã³ãä»äžã㊠{tenant}.example.com ã®ãããªåœ¢ãšããã±ãŒã¹ããããŸããåºæ¬çã«ã¯ããã³ãããšã«ä»äžããã»ãããªãœãŒã¹ã®ç«¶åã®å¯èœæ§ããªããªããšèããŠããããŠããŸãããããã³ããåãæ¿ãããããªãŠãŒã¹ã±ãŒã¹ãããå Žåã«ã¯ãµããã¡ã€ã³ãå€ãã«ããã§ãã ãããã« ãã«ãããã³ããªã·ã¹ãã ã®éçºãå§ããŠããäžã§èããŠããããšãæããŠã¿ãŸããïŒçŸåšã¯ããããŠããããšãããã®ã§ãä»åŸå€ãããšãããåºãŠãããšæããŸãïŒããã«ãããã³ãã§ã¯ãªãã·ã¹ãã ã«æ¯ã¹ãŠãåºæ¬çãªãšããã§ãæ³å以äžã«èããããšãå€ãããŸããã®èŸºã®èšèšãã»ãã¥ãªãã£ã䜿ãåæã®åäžã«å€§ããå¹ããŠãããšæããŠããŸããéçºãé²ãã§ããããå®è·µçãªè©±ã«ãèžã¿èŸŒãã 話ããããã§ãã
æŠèŠ TIMELINEéçºéšã®å
åã§ãã æ ªåŒäŒç€ŸãšããªãŒã§ã¯ãããã¯ãšã³ãç³»ãœãããŠã§ã¢ãGoèšèªã§èšè¿°ããããšãå€ãã§ãããŸããäœæããããã°ã©ã ã«ã€ããŠã¯ãgo testã³ãã³ããçšããŠãã¹ããèšè¿°ããããã«ããŠããŸãã ä»åã¯ãgo testæã«çºçããäžèŠåããã¥ãããšã©ãŒãã©ã®ããã«èª¿æ»ã察çãããã«ã€ããŠå
±æããŸãã ç°å¢ Goèšèª Test Frameworkãšã㊠Convey DBã¯MySQL ãšã©ãŒçºçæã®ç¶æ³ ããæããããŒã«ã«ç°å¢ã«ãŠãã¹ããå®è¡ãããšããã以äžã®ãããªãšã©ãŒãçºçããããã«ãªããŸããã $ go test ./repository/*.go ... Line 30: - Error 1062: Duplicate entry '1' for key 'PRIMARY' ... äžèŠããŠããã¹ãäžã«ã¬ã³ãŒããç»é²ããããšããéã«ããªãããã®çç±ã§Primary Keyã®éè€ãçºçãããšããããšãåãããŸãã ãã ããã®æã¯ develop ãã©ã³ãã®å
é ã§ãã¹ããå®è¡ããŠãããåãã³ããããCIç°å¢ã§ã¯æ£åžžã«ãã¹ããæåããŠããã®ã§äžæè°ã«æããŸããã ãã¹ãã³ãŒããèŠãŠã¿ããšä»¥äžã®ãããªå®è£
ã«ãªã£ãŠããŸããã import ( . "github.com/smartystreets/goconvey/convey" ) func setup() { err := insertRecord( 1 ) // ID:1ã§ã¬ã³ãŒããç»é² if err != nil { panic (err) } } func teardown() { err := cleanupTable() // ããŒãã«ã®ã¬ã³ãŒããå
šåé€ if err != nil { panic (err) } } func Test_Find(t *testing.T) { Convey( "Find" , t, func () { setup() repo := NewRepository() Convey( "æ£åžžç³»" , func () { record, err := repo.Find( 1 ) // ID:1ã§ã¬ã³ãŒããæ€çŽ¢ So(err, ShouldBeNil) // ãšã©ãŒã¯çºçããªãããšãæ€èšŒ So(record.ID, ShouldEqual, 1 ) // ID:1ã®ã¬ã³ãŒããååŸã§ããããšãæ€èšŒ }) Convey( "ç°åžžç³»" , func () { _, err := repo.Find( 0 ) // ID:0ã§ã¬ã³ãŒããæ€çŽ¢ So(err, ShouldEqual, ErrNotFound) // NotFoundãšã©ãŒãçºçããããšãæ€èšŒ }) Reset( func () { teardown() }) }) } conveyã®äœ¿ãæ¹ã«ã€ããŠç°¡åã«èª¬æããŸãã Convey() 颿° ãã¹ãã®ã³ã³ããã¹ãã衚çŸãã颿° 第äžåŒæ°ã«ã¯ã³ã³ããã¹ãã®èª¬æãã第äºåŒæ°ã«ã¯ãã¹ã察象ã®é¢æ°ãæž¡ã ã³ã³ããã¹ãã¯ãã¹ãããããšãã§ãã ã³ã³ããã¹ãå
éšã®ãã¹ãã³ãŒãã§panicãçºçããå Žåãã³ã³ããã¹ãåäœã§ãã¹ãã¯å€±æãããã®ãšã¿ãªããäžäœã®ã³ã³ããã¹ãã¯å®è¡ãããªããªã So() 颿° assertionãè¡ã颿° ShouldBeNil , ShouldEqual ãšãã£ããããã£ãŒãçšããŠèšè¿°ããããšãã§ãã Reset() 颿° ã³ã³ããã¹ãåäœã§ã®ãã¹ãã®åŸåŠçã衚çŸãã颿° ãã¹ãããã³ã³ããã¹ãã®å Žåãäžäœå±€ãå«ããŠå®è¡ããã èª¿æ» å®éã«ããã¹ãå®è¡åã®ç¶æ
ã§ãã¹ãçšDBã«æ¥ç¶ããŠããŒãã«ã®äžèº«ã確èªããŠã¿ããšããããã«Primary Keyã1ã®ã¬ã³ãŒããååšããŠããŸããã ããã§ã¯åœç¶ setup() ã§éè€ãšã©ãŒãçºçããŸãã ãããã Reset() ã§ teardown() ãåŒã³åºãããã«å®è£
ããŠããã®ã§ããã¹ãçµäºæã«ã¯ããŒãã«ã®äžèº«ã¯ç©ºã«ãªã£ãŠããã¯ãã§ããã ãã®åŸèšæ¶ãé Œãã«åå ã調ã¹ãŠã¿ããšããããã¹ãçµäºæã«ãã¬ã³ãŒããæ®ã£ããŸãŸã«ãªã£ãŠããçç±ã¯åçŽãªãã®ã§ããã develop ãã©ã³ãã®å
é ã§ãã¹ããå®è¡ãã以åã«ãããŒã«ã«ç°å¢ã«ãŠäžèšã®ãã¹ãã³ãŒããšåãããŒãã«ãæäœããå¥ã®ãã¹ãã³ãŒããå®è£
ããŠããŸããããã®éã誀ã£ãŠ teardown() ã®åŒã³åºããããªãç¶æ
ã§ãã¹ããå®è¡ããŸããã func Test_Other(t *testing.T) { Convey( "Other" , t, func () { setup() repo := NewRepository() _, err := repo.DoSomething() So(err, ShouldBeNil) // ãšã©ãŒã¯çºçããªãããšãæ€èšŒ }) } ãã®ãã¹ããå®è¡ããããšã§ãã¹ãçµäºæã«ã¬ã³ãŒããæ®ã£ããŸãŸã«ãªããŸããã ãã®åŸdevelopãã©ã³ãã«ç§»åããéãDBã¯ãã®ãŸãŸã®ç¶æ
ã§ãã£ãããã setup() ã«ãŠéè€ãšã©ãŒãçºçããããã«ãªã£ãŠããã®ã§ããã ããŒã¿ãæ®ã£ããŸãŸã§ãã¹ãå®è¡ setup() ã倱æ Reset() ãç»é²ãããªã teardown() ãåŒã³åºãããªã ããŒã¿ãæ®ã£ããŸãŸã§ãã¹ãå®è¡ setup() ã倱æ ... ãšããã«ãŒãã«é¥ã£ãŠãããšããããšã§ãã å¯Ÿå¿æ¡ èŠããã«ã1åã§ãã¬ã³ãŒããæ®ã£ããŸãŸã«ãªã£ãŠãããšãã®åŸãã¹ãããŒã¿ã®ç»é²ã§å¿
ã倱æãããŸããã®ç¶æ
ããèªåã§åŸ©åž°ã§ããªããšãããã¹ãã³ãŒãã«ãªã£ãŠããŸããã ãã®ãã¹ãã³ãŒãã«ãããåé¡ç¹ãšããŠã¯ä»¥äžãæããããŸãã setup() ã倱æããããšããã setup() ãš teardown() ã1察1ã§å¯Ÿå¿ãããšã¯éããªãããããã¹ãçµäºæã«ãã¹ãããŒã¿ãæ®ã£ããŸãŸã«ãªãããšããã ãããã解決ããæ¡ãšããŠã¯ä»¥äžãèããããŸãã ããŒãã«ã®ã¬ã³ãŒããåé€ããåŠçã setup() ãå®è¡ããåã«ç§»åãã setup() ã倱æããªãããã«ããã¢ãããŒãã§ãããããããããŒãã«ãåæåããŠãããã®åŸã«ç»é²ãšããå®è£
ã«ãªãããããã®å Žå Reset() èªäœäžèŠã«ãªããŸãã ç»é²ã®å
ã«åé€ãããåŸã«åé€ãããã¯ã©ã¡ããããåŸãå®è£
ã ãšæãã®ã§ããããã§ã«äžèšã®ãããªã³ãŒãã倧éã«ååšããããããã¹ãŠä¿®æ£ããã®ã¯é¿ããããšèããŸããã Reset() ã®åŒã³åºãã setup() ãå®è¡ããåã«ç§»åãã setup() ãš teardown() ãå¿
ã1察1ã§å®è¡ãããããã«ããã¢ãããŒãã§ãã setup() å
ã§panicããããšãããã§ã« Reset() ã§ç»é²ãããŠããã°ãã¹ãçµäºæã« teardown() ãå®è¡ãããããšã«ãªããŸãã func Test_Find(t *testing.T) { Convey( "Find" , t, func () { Reset( func () { teardown() }) setup() repo := NewRepository() ... }) } ãã ãconvey ã®ããã¥ã¡ã³ããèªããš Reset() 㯠Convey() ã®æ«å°Ÿã§å®è¡ããäŸãèšèŒãããŠãããconveyåŽã®æ³å®ãšããŠã¯çŸç¶ã®å®è£
ã®ã»ãããããããŠããããã«èŠåããããŸãã ãŸãåè¿°ã®çç±ãšåæ§ã«ãä¿®æ£ç®æãå€ããªãããšã¯é¿ããããšèããŸããã ãããã setup() å
ã§panicããªãããã«ãã setup() ã倱æããªãããã«ããã¢ãããŒãã§ãã setup() ã§ããŒã¿ç»é²ã倱æããå Žåã§ãã Reset() ãŸã§åŠçãç¶ç¶ãããããªå®è£
ã«ããŸãã äŸãã° setup() ã以äžã®ããã«ä¿®æ£ããŸãã func setup(t *testing.T) { err := insertRecord( 1 ) // ID:1ã§ã¬ã³ãŒããç»é² if err != nil { t.Error(err) } } ... func Test_Find(t *testing.T) { Convey( "Find" , t, func () { setup(t) ... Reset( func () { teardown() }) }) } ãããªããã¬ã³ãŒããæ®ã£ãŠã㊠setup() ã§ãšã©ãŒãçºçããå Žåã§ããã¹ãã¯ç¶ç¶ããã®ã§ teardown() ãå®è¡ãããããšã«ãªãã以éã®ãã¹ãã§ã¯æ£åžžã« setup() ãæåããããã«ãªããŸãã ãã ããã¹ãããŒã¿ç»é²åŠçã®ãšã©ãŒå€å®ã¯éåžžã®ãã¹ããšã¯åºå¥ããŠãããããšèããŸããããã®å®è£
ã ãšãã¹ãã«å€±æããã®ãããããšããã¹ãã®åæåŠçã§å€±æããã®ããäŒããã¥ãããªãã®ã§ã¯ãšæããŸããã ãŸãããã¡ããåæ§ã«ä¿®æ£ç®æãå€ããªãããšãé£ç¹ã§ããã ãã¹ãå®è¡æã«1åã ãããŒãã«ãåæåãã setup() ã倱æããªãããã«ããã¢ãããŒãã§ããå°ãªããšãããã¹ãå®è¡åã«ããŒãã«ãåæåãããŠããã°ãã¹ãã³ãŒããééã£ãŠããªãéããšã©ãŒãçºçããããšã¯ãªããªããšããçºæ³ã§ãã æžå¿µãšããŠã¯ããã¹ãã«å¯Ÿãç¡é¢ä¿ã®ããŒãã«ãåæåãããããå®è¡ããã©ãŒãã³ã¹ã®æªåãèããããŸãã ãã ãGoã®testã¯ããã±ãŒãžåäœã§å®è¡ãããããããã®åäœã§åæåããã ããªãããã©ãŒãã³ã¹ãžã®åœ±é¿ã¯ãããŸã§å€§ããã¯ãªããªããšèããŸããã DBã«çŽæ¥äŸåããrepositoryç³»ããã±ãŒãžã®ã¿ã察象ãšããã°ãããå
šäœããã¿ããšãã®å²åã¯é«ããªãããã§ãã ãã¡ããrepositoryç³»ããã±ãŒãžã«äŸåããŠããããã±ãŒãžèªäœã¯å¥ã«ååšããŠããããããã¯éæ¥çã«DBã«äŸåããŠãããšèšããã®ã§ããããããããã±ãŒãžã®å€§éšåã¯repositoryãmockãšããŠæ±ã£ãŠãããçŽæ¥DBã«äŸåããŠããããã§ã¯ãªãã£ãã®ã§ããŒãã«ã®åæååŠçã¯äžèŠã§ããã ããã§ããã¹ãå®è¡æã«1åã ãããŒãã«ãåæåãããããrepositoryç³»ããã±ãŒãžã«ãããŠä»¥äžã®ãããªã³ãŒããå®è£
ããŸããã import ( "github.com/khaiql/dbcleaner" "github.com/khaiql/dbcleaner/engine" ) func TestMain(m *testing.M) { CleanupAllTables() os.Exit(m.Run()) } func CleanupAllTables() { tables := allTables() dbCleaner := dbcleaner.New() dbCleaner.Clean(tables...) } func allTables() [] string { tables := make ([] string , 0 ) row, err := db.Query( "SHOW TABLES" ) if err != nil { panic (err) } for row.Next() { var table string if err := row.Scan(&table); err != nil { panic (err) } if table == "migrations" { // DB migrationçšããŒãã«ã¯é€å€ continue } tables = append (tables, table) } return tables } ããŒãã«ã®åæåã«ã¯ dbcleaner ã䜿çšããŸããã ããŒãã«æ°ã«ããããŸããã100åçšåºŠã®ããŒãã«ãåæåããã®ã«èŠããæéã¯1ç§çšåºŠã§ããã åè¿°ã®éãã圱é¿ãåããã®ã¯DBã«äŸåããããã±ãŒãžã®ã¿ã§ããããã蚱容ç¯å²ãšããŸããã ãŸãšã ä»åã¯Goèšèªã®ãã¹ãã³ãŒãã«ãããŠãã¹ãããŒã¿ç»é²ã«å€±æãããããªã±ãŒã¹ã§ã®å¯Ÿå¿ã«ã€ããŠå¯Ÿå¿ããçµæããŸãšããŸããã åèã«ãªããŸããã幞ãã§ãã
ã¯ããã« ããã«ã¡ã¯ãDELISH KITCHENéçºéšã®æäžã§ãã ãšããªãŒãéå¶ããŠãããµãŒãã¹ã®DELISH KITCHENããã¢ããã§ã¯ãã¬ãŒã³ããã£ã³ããŒã³ã宿çã«è¡ãããŠããããŠãŒã¶ãŒããã¯éå¬äžã®è€æ°ã®ãã£ã³ããŒã³ããæ°ã«ãªããã®ãéžãã§ããã€ãã®èšåã«çããããšã§å¿åããããšãã§ããããã«ãªã£ãŠããŸãã ä»åã¯ãã®ãã¬ãŒã³ããã£ã³ããŒã³ã®ETLåºç€ãStep Functionsãå©çšããŠãµãŒããŒã¬ã¹ã§æ§ç¯ãã話ã玹ä»ãããŠããã ããŸãã Step Functionså°å
¥ã®èæ¯ åœæã®æè¡éžå®ã§æèããããšã¯æ¬¡ã®ãããªããšã§ããã éçšé¢ãšè²»çšé¢ã§äœã³ã¹ãã§å®çŸã§ãã ããŒã¿ãšã³ãžãã¢ä»¥å€ã§ãéçºã»éçšã§ãã å°æ¥çãªããŒã¿ã®å¢å ãå®è¡é »åºŠã®å€æŽã«å¯Ÿå¿ããŠã¹ã±ãŒã«ã§ãã ç¹ã«ãã®åºç€ã«ãããŠã¯åãã¯å°äººæ°ã§éçšã³ã¹ããããã«äžããŠPoCããŠãããããéèŠã ã£ãã®ã§éçšã³ã¹ãã¯éèŠãªå€æåºæºã«ãªã£ãŠããŸããããã®äžã§AWSã§ã¯ã¯ãŒã¯ãããŒãšã³ãžã³ã®éžæè¢ãšããŠGlue WorkflowãMWAAããããŸããããAWSãµãŒãã¹ãšã®é£æºãè±å¯ã§jobã®å®è¡åºç€ãçžããããåœæã¯ããŒã¿éãåŠçè² è·ããããŠjobãšããŠlambdaãæ¡çšããããšã§ã³ã¹ããæå°éã«ã§ããStep Functionsãéžã³ãŸããããŸããStep Functionsã¯Glue jobãšãæ¥ç¶å¯èœãªã®ã§ãããŒã¿éã®å¢å ã«ããåŠçè² è·ãé«ããªã£ãŠããã°ãå·®ãæ¿ããæ€èšã§ããæè»æ§ãé«ãããšã決ãæãšãªããŸããã ã¹ããŒããã·ã³ã®æ§æ Step Functionsã®ã¯ãŒã¯ãããŒã¯ã¹ããŒããã·ã³ãšåŒã°ããŠããŸããããããã¯ãšããªãŒã§äœ¿ã£ãŠããã¹ããŒããã·ã³ã®æ§æãšStep Functionsã®æ©èœã䜿ã£ãŠã©ããããµãã«ETLãå®çŸããŠãããã説æãããŠããã ããŸãã å
šäœ å
šäœãšããŠã¯çŸç¶ã¯å€§ããåããŠãããŒã¿å€æãšã«ã¿ãã°æŽæ°ã®äºã€ã«åãããŠãããã¹ããŒããã·ã³ã®å®è¡ã¯EventBridgeããã¹ã±ãžã¥ãŒã«ããŠå®æçã«è¡ã£ãŠããŸãããªã³ã¿ã€ã ã§ã®å¥ããŒã¿åºç€ãžã®è»¢éãããå Žåã¯ãã®ã¹ããŒããã·ã³ãæ¡åŒµããããšã«ãã£ãŠäŸåé¢ä¿ãå¶åŸ¡ããããšãã§ããŸããæ¬¡ã«ããããã®åŠçã®è©³çްã説æããŸãã ããŒã¿å€æ ãã¬ãŒã³ããã£ã³ããŒã³ã®èŠä»¶ãšããŠãããããã®ãã£ã³ããŒã³ã¯ç¬èªã®ããŒã¿ãæã£ãŠããŠããã®ããŒã¿å€æã®èŠä»¶ããã£ã³ããŒã³ããã®å®æœæéã«ãã£ãŠç°ãªããŸãããŸããéå¬ããããã£ã³ããŒã³æ°ã次第ã«å€ããªã£ãŠããããšãæ³å®ãããŠããã®ã§Step Functionsã§æäŸãããŠããMapã¹ããŒããçšããåç䞊ååãããŠããããã®å€æåŠçããS3ã®æ ŒçŽãŸã§ãè¡ãªã£ãŠãããããçšåºŠããŒã¿éãå€ããªã£ãŠããæã«ã§ãlambdaã®å®è¡æéã®å¶éãåé¿ã§ããããã«ããŠããŸããMapã¹ããŒãã«å¯ŸããŠãããããç»é²ããŠãããã£ã³ããŒã³å
容ã以äžã®ãããªæ§é ã§æž¡ããŠäžŠåå®è¡ãè¡ãªã£ãŠãããèªèº«ã§æå®ããããšã§ç¹å®ã®ãã£ã³ããŒã³ã®åå®è¡ãå¯èœã§ãã { " campaigns ": [ { " platform ": " service1 ", " campaign ": " campaign1 " } , { " platform ": " service2 ", " campaign ": " campaign2 " } ] } ã«ã¿ãã°æŽæ° åã®ãããŒã§æ±ããããèŠä»¶ã§ã®ããŒã¿å€æãŸã§ã¯æºãããŠããŸããããã®ãŸãŸã ãšä»ã®åºç€ãžã®ããŒã¿è»¢éãåæãå°é£ãªãããAthenaã§æœåºã§ããããã«ããŠããŸãããã ãå
ã»ã©èª¬æãããŠããã ããéãããã£ã³ããŒã³ã¯ããããç¬èªã®ã¹ããŒããæã£ãŠãããèªåã§ããããšãããšæ¯åèªåã§ããŒã¿ã«ã¿ãã°ã®ã¹ããŒãå®çŸ©ãããªããšãããŸãããããã§ãã®éçšã³ã¹ããçãããã«Glue Crawlerã§å€æããS3ã®ããŒã¿ãèªã¿èŸŒãŸããŠèªåã§ã«ã¿ãã°ãäœãããããã«ããŠããŸããStep Functionsã«ã¯éåæãªåŠçãWaitã¹ããŒããšChoiceã¹ããŒããæŽ»çšããŠåŸ
ãŠãããã«ãªã£ãŠãããå®è¡çµæãè¿ã£ãŠãããChoiceã¹ããŒãã䜿ã£ãŠã¹ããŒããã·ã³ãçµäºã§ããããã«ãªã£ãŠããŸãã æŽ»çšããäžã§ã®Tips ãã®ãããªã¹ããŒããã·ã³ãæ§ç¯ããŠããäžã§Step FunctionsãæŽ»çšããäžã§ã®Tipsãããã€ããã£ãã®ã§ç޹ä»ãããŠããã ããŸãã ãšã©ãŒéç¥ Step Functionsã¯ã¹ããŒããã·ã³èªäœããšã©ãŒã«ãªã£ãæãçºç«ã¿ã€ãã³ã°ãšããŠEventBridgeãšé£æºããããšãã§ããããã«ãªã£ãŠããã®ã§ãããçµã¿åãããããšã§ç°¡åã«éç¥èªäœã¯ã§ããŠããŸããŸãããEventBridgeãåãåããæ
å ±ã«ã¯å¶çŽããããã¹ããŒããã·ã³ã®äœãã©ããªçç±ã§å€±æããã®ããã³ã³ãœãŒã«ã«è¡ããŸã§ããããŸããããŸãåŸè¿°ããŸãããäžéšåŠçã倱æãããšãã«ã¹ããŒããã·ã³èªäœã倱æãšã§ããªãã±ãŒã¹ãããã®ã§EventBridgeã ãã§ã¯æºãããªãããšããããEventBridgeã«å ããŠä»ã®éç¥ææ®µãçšæããªããšãããªãç¶æ³ã§ããã ããã§å®è¡ãšã©ãŒããã³ããªã³ã°ããCatchãã£ãŒã«ãã䜿ã£ãŠããšã©ãŒæ
å ±ãååŸãããšã©ãŒéç¥ãéãlambdaãç¬èªã§çšæããŠããŸããåŸç¶ã®ã¿ã¹ã¯ã«ä»¥äžã®æ
å ±ãlambdaã§ããã°eventãšããŠåãåããã®ã§ãããéç¥ãããå
容ã«ãã£ãŠå å·¥ããããšã§çŽ æ©ããšã©ãŒå
å®¹ãææ¡ã§ããäœå¶ãäœãããšãã§ããŸãã { " FunctionName ": " step functionsã®arn ", " Payload ": { " Execution ": { " Id ": " å®è¡ID ", " Input ": { // ããããã®ç°å¢ã§ã®jobã®çºç«å
容ã®è©³çްãå
¥ã } , " StartTime ": " å®è¡éå§æé ", " Name ": " å®è¡å ", " RoleArn ": " ããŒã«ã®arn " } , " param ": { " Error ": " Error ", " Cause ": " ãšã©ãŒå
容 " } } } 䞊åå®è¡æã®ãžã§ããã£ã³ã»ã«åé¿ å
ã»ã©ã®ããŒã¿å€æã®ãã§ãŒãºã§Mapã¹ããŒãã«ããåç䞊ååŠçãè¡ãªã£ãŠãããšèª¬æããŸããããå®ã¯Mapã¹ããŒãã䜿ã£ãã ãã ãšäžŠåããåŠçã®äžéšã倱æããæã«åŸç¶ã®åŠçã¯å
šãŠåæ¢ããŠããŸããŸããããã¯æ±ããããèŠä»¶ã«ããããšæããŸãããããäžéšã®åŠçã倱æããŠããã®ãšã©ãŒãéç¥ãã€ã€ããã以å€ã®åŠçã¯ç¶ããŠæ¬²ããã±ãŒã¹ã¯ãããšæããŸãã ãããã£ãå Žåã«äžŠååŠçã®äžã«ãšã©ãŒæã®äŸå€åŠçã远å ãããšã©ãŒéç¥ãè¡ã£ãäžã§æ£åžžçµäºãããããšã«ãã£ãŠå®çŸå¯èœã§ããããã«ããä»ã®åŠçã¯åŸç¶ã®ã¿ã¹ã¯ã«ç§»è¡ããã圱é¿ãæå°éã«ãšã©ããããšãã§ããŸãã ãã€ããŒããµã€ãºã®å¶éåé¿ Step Functionsã§ã¯ååŠçã§å®è¡ããçµæãåŸç¶ã®ã¿ã¹ã¯ã«æž¡ãããã«ããŒã¿ã®åãæž¡ããè¡ãã·ãŒã³ãå€ãããšæããŸãããã ããã€ããŒããµã€ãºã«ã¯å¶éããããé·ç§»æã«æž¡ããããŒã¿ã¯256KBãŸã§ã§ããäŸãã°ããMapã¹ããŒãã§ã®äžŠååŠçã®è¿ãå€ããµã€ãºãè¶
ããå Žåã以äžã®ãããªãšã©ãŒãåºãŠåŠçã¯äžæãããŠããŸããŸãã The state/task 'Map' returned a result with a size exceeding the maximum number of bytes service limit. ãããé²ãããã«ã¹ããŒããã·ã³ãäœãäžã§æèããã2ã€ã®ãã€ã³ãããããŸãã 倧ãããã€ããŒãã¯S3ãå€éšã¹ãã¬ãŒãžã䜿ã ããããã倧ãããªããšäºæ³ãããããŒã¿ã¯åŸç¶ã®ã¿ã¹ã¯ã«æž¡ãåã«ããŒã¿ãS3ãDBã«ä¿åããŠããã®æ ŒçŽå
ã®æ
å ±ãåŸç¶ã«æž¡ãããšã«ãããããŒã¿ãµã€ãºãå°ããããããšãã§ããŸãã ãŸããåãåé¡ã¯äžŠååŠçãå®è¡ããMapã¹ããŒãã«æž¡ãJSONé
åã§èµ·ããå¯èœæ§ããããŸããçŸåšã§ã¯Step Functionsã«Distributed Mapã¹ããŒããMapã¹ããŒããšã¯å¥ã§æäŸãããŠãããS3å
ã®å€§èŠæš¡ããŒã¿ãããšã«äžŠååŠçãå®è¡ã§ããããã«ãªã£ãŠããã®ã§ãäžŠåæ°ã䞊åæã«æž¡ãããããŒã¿éãå¢ããå Žåã«ã¯å©çšãæ€èšãããšè¯ããšæããŸãã åºåããã£ã«ã¿ãªã³ã°ããŠå¿
èŠãªããŒã¿ã«çµã£ãŠæž¡ã lambdaãªã©ã§æåãå¶åŸ¡ã§ããå Žåã«ã¯ãã®åŠçã®äžã§åºåãæå°éã«ãããšæããŸãããAWSã®ãµãŒãã¹ãšããŒã³ãŒãã§é£æºããå Žåã«ãã®åŠçãåºåããããŒã¿èªäœã¯å¶åŸ¡ããããšãã§ããŸãããäŸãã°ãã¹ããŒããã·ã³ã®äžã§athenaã®ã¯ãšãªçµæãååŸããããšãããšä»¥äžã®ãããªJSONãåºåãããŸãã { " QueryExecution ": { " EngineVersion ": { " EffectiveEngineVersion ": " Athena engine version 2 ", " SelectedEngineVersion ": " Athena engine version 2 " } , " Query ": " çºè¡ããã¯ãšãª ", " QueryExecutionContext ": { " Database ": " ããŒã¿ããŒã¹ " } , " QueryExecutionId ": " å®è¡ID ", " ResultConfiguration ": { " OutputLocation ": " s3ã®ãã±ãŒã·ã§ã³ " } , " ResultReuseConfiguration ": { " ResultReuseByAgeConfiguration ": { " Enabled ": false } } , " StatementType ": " DML ", " Statistics ": { " DataScannedInBytes ": 191831 , " EngineExecutionTimeInMillis ": 1704 , " QueryPlanningTimeInMillis ": 796 , " QueryQueueTimeInMillis ": 647 , " ResultReuseInformation ": { " ReusedPreviousResult ": false } , " ServiceProcessingTimeInMillis ": 85 , " TotalExecutionTimeInMillis ": 2436 } , " Status ": { " CompletionDateTime ": 1693159279869 , " State ": " SUCCEEDED ", " SubmissionDateTime ": 1693159277433 } , " SubstatementType ": " SELECT ", " WorkGroup ": " ã¯ãŒã¯ã°ã«ãŒãå " } } ãã ãå€ãã®å Žåã§æ¬²ããããŒã¿ã¯å®éã«ã¯ãšãªçµæãã©ãã®s3ã«ä¿åãããŠãããã ãšæããŸãããã®å Žåã«ã¯æ¬¡ã®ããã«å
¥åºåå¶åŸ¡ã®ããã®OutputPathãã©ã¡ãŒã¿ã䜿ã£ãŠãã£ã«ã¿ãªã³ã°ãããããšã«ãã£ãŠæ¬²ããããŒã¿ã ããåŸç¶ã«æž¡ãããšãã§ããŸãã $.QueryExecution.ResultConfiguration å®è¡çµæ { "OutputLocation": "s3ã®ãã±ãŒã·ã§ã³" } ä»ã«ãåºåå¶åŸ¡ã«ã¯ResultSelectorãResultPathãªã©åºåãã³ã³ãããŒã«ãããã©ã¡ãŒã¿ãæäŸãããŠãããããããæŽ»çšããããšã«ããæ¬²ããçµæã«çµã£ãããŒã¿ãäœãããšãã§ããŸãã çŸç¶ã®èª²é¡ ãããŸã§ãšããªãŒã«ãããStep Functionsã®æŽ»çšäºäŸã«ã€ããŠç޹ä»ãããŠããã ããŸãããããã°ããéçšããŠããäžã§æ¬¡ã®ãããªèª²é¡ãåºãŠããŸããã ã¹ããŒããã·ã³ã®IaCå ã¹ããŒããã·ã³èªäœã¯ASL(Amazon States Language)ã§èšè¿°ãããŠããã®ã§ã³ãŒãã§ç®¡çã§ããªãããã§ã¯ãããŸããããã ãå人çã«ãã®èšè¿°èªäœã®åŠç¿ã³ã¹ããé«ããã¹ããŒããã·ã³ãè€éã«ãªãã°ãªãã»ã©ã³ã³ãœãŒã«ã®ããžã¥ã¢ã©ã€ãºãããWorkflow Studioã§çµãã æ¹ãçŽæçãªã±ãŒã¹ãå€ããšæããŸãã ä»ã¯ããã»ã©ã¹ããŒããã·ã³èªäœã®å€æŽãè¡ãæ©äŒãå°ãªãã®ã§å€§ããªåé¡ã«ã¯ãªã£ãŠããŸããããä»åŸã®éçšãèãããšIaCåã¯è¡ãªã£ãŠãããæ¹ãè¯ãã®ã§ãAWS CDKãTerraformã§ã®ç®¡çæ¹æ³ãªã©ããŒã ã§PoCãè¡ã£ãŠãããããšæã£ãŠããŸãã ålambdaã®ç®¡ç Step Functionsã§ã¹ããŒããã·ã³ãäœãå Žåã«ãã€ããŒãã®ã¡ãã£ãšããå å·¥ãããŠåŸç¶ã®åŠçã«æž¡ãããã±ãŒã¹ãããŸã«ãããæäŸãããæ©èœã§ã¯è¶³ããªãå Žåã«åŸã
ã«lambdaã®æ°ãå¢ããŠãã£ãŠãŸãããç¹ã«ä»å玹ä»ããŠããã¹ããŒããã·ã³ä»¥å€ã«ããã€ãå¥ã§æ°ããã¹ããŒããã·ã³ãäœã£ãŠãããšãªã£ãæã«ã³ãŒãã管çããŠãããªããžããªã§ã©ã®lambdaãã©ã®ã¹ããŒããã·ã³ã«åœ±é¿ããŠããã®ãèŠéããæªããªã£ãŠããŠããŸãã ããã«ã€ããŠã¯å
±ééšåãšããããã®ã¹ããŒããã·ã³ç¬èªã«äœ¿ãããlambdaãéå±€ããããŠããŸãšããŠãããªãããåè¿°ããã¹ããŒããã·ã³ã®IaCåãæšé²ã§ããã°ãã®äŸåé¢ä¿ãæ°ããã¡ã³ããŒãçè§£ãããããªãã®ã§ã¯ãšèããŠããã®ã§ãããŒã ã§è©±ããªãããªãã¡ã¯ã¿ãªã³ã°ãé²ããŠããããã§ãã ãããã« ä»åã®Step Functionså°å
¥ã«ãããã³ã¹ããæå°éãŸã§åæžããªããETLåºç€æ§ç¯ãè¡ãããšãã§ããŸãããä»åŸãéçšããããŒã äœå¶ãæ±ãããŒã¿ã®èŠæš¡ã«ãã£ãŠã¯GlueãMWAAãä»ã®ããããŒã¿åŠçã«ç¹åãããµãŒãã¹ãéžæããæ¹ãè¯ãå Žåããããšæãã®ã§ãäºæ¥ã®ç¶æ³ã«åãããŠã·ã¹ãã æ¹åãã§ããã°ãšèããŠããŸãã ãŸããšããªãŒã§ã¯æ¥ã
ããããã®ãããåŠçãå®è¡ãããŠããŸããããã®äžã§ã¯äŸåé¢ä¿ãèµ·åã¿ã€ãã³ã°ã§æé»çã«å¶åŸ¡ããŠãããã®ããã£ããããã®ã§ããŒã¿ã®ETLã ãã§ã¯ãªãããããã£ããããåŠçã®å®è¡ã«ãä»åŸã¯ãŒã¯ãããŒãšã³ãžã³ã®å°å
¥ãèããŠããããã§ãã ãããŸã§ãèªã¿ããã ããããããšãããããŸããã
DELISH KITCHEN ã® Android çã§ã¯ãã©ã€ãã©ãªåã build.gradle ã«èšèŒããŠç®¡çããŠããŸããã // ãããªæã implementation "androidx.media3:media3-exoplayer:$MEDIA3_VERSION" implementation "androidx.media3:media3-exoplayer-hls:$MEDIA3_VERSION" implementation "androidx.media3:media3-ui:$MEDIA3_VERSION" ã©ã€ãã©ãªã®ããŒãžã§ã³ã ãã¯å®æ°åãããŠå¥éåããŸãšããŠç®¡çããŠããŸãããããããå
šãŠããŸãšãŸã£ãŠããããã§ã¯ãªãã£ããããçŸåšã©ã®ãããªã©ã€ãã©ãªãã©ã®ããŒãžã§ã³ã§å©çšãããŠããããäžç®ã§ããããªãç¶æ
ã§ããã ããã§ãä»åŸã©ã€ãã©ãªã®æ£åžããè¡ããããããã«ããŸãé¢ä¿ã©ã€ãã©ãªãæããŠæ±ããããã«ãããã Version Catalog ã§ãšããŸãšããããšã«ããŸããã ç°å¢ Android Studio Giraffe | 2022.3.1 Gradle 8.0 ãã£ãããš Android Developers ã«ç§»è¡ã«ã€ããŠã®èšäº(â»1)ãããããã¡ããåèã«äœæ¥ãè¡ããŸããã äœæ¥ã®æµãã¯ä»¥äžã®éãã§ãã libs.versions.toml ãã¡ã€ã«ãšã»ã¯ã·ã§ã³ã®äœæ libs.versions.toml ãã¡ã€ã«ãžã©ã€ãã©ãªã®æ
å ±ãèšèŒ èšèŒããæ
å ±ãå©çšã㊠gradle ãä¿®æ£ ãããã詳现ãèŠãŠãããŸãããã libs.versions.toml ãã¡ã€ã«ãšã»ã¯ã·ã§ã³ã®äœæ ãŸãã¯ã«ãŒãã® gradle ãã£ã¬ã¯ããªé
äžã« libs.versions.toml ãšããååã®ãã¡ã€ã«ãäœæããŸã(â»2)ã ç¶ããŠãã®ãã¡ã€ã«äžã« versions/libraries/bundles/plugins ãšãã 4 ã€ã®ã»ã¯ã·ã§ã³ãäœæããŸãã ãã®åŸããããã®ã»ã¯ã·ã§ã³ã§ã¯ä»¥äžã®ãããªå€ãèšèŒããŠãããŸãã versions ã©ã€ãã©ãªã®ããŒãžã§ã³å€ libraries ã©ã€ãã©ãªã®ãšã€ãªã¢ã¹å bundles é¢ä¿ããã©ã€ãã©ãªãã¡ãæãããšã€ãªã¢ã¹å plugins ãã©ã°ã€ã³ã®ãšã€ãªã¢ã¹å libs.versions.toml ãã¡ã€ã«ãžã©ã€ãã©ãªã®æ
å ±ãèšèŒ åã¢ãžã¥ãŒã«ãªã©ã«ãã gradle ãã¡ã€ã«ã確èªããèšèŒãããŠããã©ã€ãã©ãªãªã©ã®æ
å ±ã libs.versions.toml ãã¡ã€ã«ãžæžãåºããŠãããŸãã libs.versions.toml ãã¡ã€ã«ã®åã»ã¯ã·ã§ã³ã«å¯ŸããŠã以äžã®ããã«èšèŒããŠãããŸãã èšèŒããæ
å ±ãå©çšã㊠gradle ãä¿®æ£ libs.versions.toml ãã¡ã€ã«ãžæ
å ±ãéçŽããåŸã¯ãããã gradle ãã¡ã€ã«ãžé©çšããŠããããšã«ãªããŸãã apply plugin ã implementation ãªã©ããŽãªãŽãªæžãæããŠãããŸãããã before after ãã®éã«å©çšããå称㯠libs.{ã»ã¯ã·ã§ã³å}.{ãã€ãã³ããããã«å€æãããšã€ãªã¢ã¹å} ãšãªãç¹ã«æ³šæãå¿
èŠã§ãã ã©ããªã£ãã ããã§ libs.versions.toml ãã¡ã€ã«ãèŠãã ãã§ã©ããªã©ã€ãã©ãªãã©ããªããŒãžã§ã³ã§äœ¿ãããŠãããã確èªã§ããããã«ãªããŸããã ã¢ãžã¥ãŒã«ã«æ£ã£ã gradle ããã¡ãã¡éããªããŠãããªããä»åŸã®ã©ã€ãã©ãªæ£åžããæ¥œã«ãªããŸããã ãŸããbundles ã®ãããã§é¢é£ã©ã€ãã©ãªããŸãšããŠæ±ããããšã«ãããå¿
èŠãªã©ã€ãã©ãªã®èšèŒãæŒãããããŒãžã§ã³ã®æå®ã誀ã£ãããšãã£ããã¹ããªããªããŸãã ãŸãšã ããžãã£ããªæèŠãšããŠã Version Catalog 㯠Android ã¢ããªéçºã«å¿
é ãªå¯Ÿå¿ã§ã¯ãããŸãããã察å¿ããããšã§1ãã¡ã€ã«ã«ã©ã€ãã©ãªæ
å ±ãéçŽããããããä»åŸã®ã©ã€ãã©ãªç®¡çãæ¥œã«ãªããšæããŸãã Version Catalog ãçšããããšã§ã¯ãç¹ã«é¢é£ã©ã€ãã©ãªãbundleãšããŠæ±ããç¹ã䟿å©ãšæããŠããŸãã ä»åã libs.versions.toml ãã¡ã€ã«ãšããå°çšã®ãã¡ã€ã«ãžãŸãšããæ¹ã gradle ãšã¯åãåãã§ããŠãããšèããŠçæããŸããããä»ã«ã settings.gradle ãžãŸãšããæ¹æ³(â»3)ãååšããŠããŸãã ã©ã¡ãã®æ¹æ³ã§ã1ãã¡ã€ã«ã«éçŽããŠç®¡çã§ãããšããç¹ã¯ã¡ãªããã§ãããšæã£ãŠããŸãã ãã¬ãã£ããªæèŠãšããŠã¯ãã©ã€ãã©ãªã®ç®¡çã®éã«gradle以å€ã«ãtomlãšããç»å Žäººç©ãå¢ããããšãéã«ã¡ãã£ãšå«ã ãšããæèŠããããŸããã ãŸãããšã€ãªã¢ã¹åã®åœåã§åå被ããåé¿ããããã«ãã€ãã³å»ã¿ãšãããããããã«ãããšã€ãªã¢ã¹åãé·ããªãããšããã£ããšã®æèŠããããŸããã ä»ã«ã Version Catalog ã®è£å®ããžã£ã³ããè¡ããªãç¹ãäžäŸ¿ã»ã»ã»ã ã£ãã®ã§ããããã®ç¹å«ã Version Catalog ã«å¯ŸãããµããŒãã¯Android Studio Giraffeã§ã¯ãããããšæ¹å(â»4)ãããŠããŸããã æçµçã«ã¯ããŒã ã¡ã³ãã¿ããªã®çè§£ãåŸãŠã®æ¡çšãšãªããŸãããéçºäœæ¥ã楜ã«ããããšãã§ããæè¡ã¯ä»åŸãæ€èšããŠåãå
¥ããŠãããã°ãšæã£ãŠããŸãã åè â»1 ãã«ããããŒãžã§ã³ ã«ã¿ãã°ã«ç§»è¡ãã https://developer.android.com/studio/build/migrate-to-catalogs?hl=ja â»2 The libs.versions.toml file https://docs.gradle.org/current/userguide/platforms.html#sub:conventional-dependencies-toml â»3 Declaring a version catalog https://docs.gradle.org/current/userguide/platforms.html#sub:version-catalog-declaration â»4 Android Studio Giraffe ãå®å®çã« - Gradle ãã«ã ã¹ã¯ãªããã® Kotlin DSL https://android-developers-jp.googleblog.com/2023/08/android-studio-giraffe-is-stable.html
ã¯ããã« 2023幎8æ1æ¥ãMAMADAYSã¯ãã¢ããã«çãŸãããããŸããã tomonite.com iOSã¢ããªããã¢ããã«ååãå€ãããããŸã§ã®ã¡ã€ã³æ©èœã§ãããè²å
èšé²ããåŠåš 鱿°ç®¡çãã軞ãšããŠãå®¶æãããŒãããŒãå®¶æä»¥å€ã®äººã瀟äŒãšã®æ¥ç¹ãäœãããã®ã·ã§ã¢æ©èœãã³ãã¥ããã£æ©èœãªã©ã®æ¡å
ãããããŠãããŸãã ãã¢ããã®iOSã¢ããªã¯æ°èŠäœæç»é¢ãäžå¿ã«SwiftUIã®å°å
¥ãé²ããŠããŸããäžæ¹ãæ¢åã®ç»é¢ãå
šé¢çã«SwiftUIã«çœ®ãæããããšã¯èããŠããªããããä»åŸãUIKitã®ç»é¢ã®ã¡ã³ããã³ã¹ãç¶ç¶ããŠãããŸãã ä»åã¯UIKitã®ç»é¢ã«Result Buildersãå°å
¥ããŠã¡ã³ããã³ã¹æ§ãåäžããåãçµã¿ãã玹ä»ããŸãã Result Buildersãšã¯ Result Buildersã¯Swift 5.4ã§å°å
¥ãããŸããã Result Buildersã䜿ããšããªã¹ããããªãŒãªã©ã®æ§é åãããããŒã¿ããããèªç¶ã§å®£èšçãªæ§æã§äœæããããšãã§ããŸãã https://docs.swift.org/swift-book/documentation/the-swift-programming-language/advancedoperators/#Result-Builders Result Buildersã¯SwiftUIã®@ViewBuilderããRegexBuilderã§äœ¿ãããŠããŸãã ArrayBuilderãäœã Result Buildersã䜿ã£ãŠãä»»æã®åã®é
åãåºåãã颿°ã宣èšçã«æžããããã«ããArrayBuilderãšãããã®ãèããŠã¿ãããšæããŸãã 以äžã®ãããªIntã®é
åãåºåãã颿°ãã var numbers: [Int] { var numbers: [Int] = [ 1, 2 ] if xxxx { numbers.append(3) } return numbers } ArrayBuilderãçšããŠä»¥äžã®ããã«æžããããã«ããŸãã @ArrayBuilder<Int> var numbers2: [Int] { 1 2 if xxxx { 3 } } ArrayBuilderãé©çšããå Žåã以äžã®ãããªç¹ã§æ¹åãããŠãããšæããŸãã 倿°å®£èšãappendãreturnã®ãããªæç¶ãçãªèšè¿°ãäžèŠã§ãã³ãŒããç°¡æœã«ãªã£ã ã³ãŒãã®æ§é ãšåºåããå€ã®æ§é ãäžèŽããŠããŠçè§£ãããã å€ã®è¿œå ãåé€ãªã©ã®å€æŽããããã ArrayBuilderã®å®è£
ã¯ä»¥äžã®ããã«ãªããŸãã @resultBuilder struct ArrayBuilder<OutputModel> { static func buildBlock(_ components: [OutputModel]...) -> [OutputModel] { return components.flatMap { $0 } } static func buildExpression(_ expression: OutputModel) -> [OutputModel] { return [expression] } static func buildExpression(_ expression: ()) -> [OutputModel] { return [] } static func buildOptional(_ component: [OutputModel]?) -> [OutputModel] { return component ?? [] } static func buildEither(first component: [OutputModel]) -> [OutputModel] { return component } static func buildEither(second component: [OutputModel]) -> [OutputModel] { return component } static func buildArray(_ components: [[OutputModel]]) -> [OutputModel] { Array(components.joined()) } } UICollectionViewDiffableDataSource / UITableViewDiffableDataSourceã®snapshotã«é©ç𠿬¡ã«ãUICollectionViewDiffableDataSource / UITableViewDiffableDataSourceã«ãã¿ããŸããããã®snapshotãäœæããåŠçã«ArrayBuilderã䜿ãããšãèããŸããã snapshotãçæããåŠçã¯ä»¥äžã®ãããªã€ã¡ãŒãžã§ãã class ViewModel { enum Section: Hashable { case .section1 case .section2 } enum Row: Hashable { case .row1 case .row2 case .row3 case .row4 case .row5 } public var snapshot: NSDiffableDataSourceSnapshot<SectionType, RowType> { var snapshot = NSDiffableDataSourceSnapshot<SectionType, RowType>() snapshot.appendSections([.section1, .section2]) snapshot.appendItems([.row1, .row2, .row3], toSection: .section1) snapshot.appendItems([.row4, .row5], toSection: .section2) return snapshot } } ArrayBuilderã䜿çšããDiffableTableViewModelãããã³ã«ãäœæãã以äžã®ãããªæžãæ¹ãã§ããããã«ããŸãã class ViewModel: DiffableTableViewModel { typealias SectionType = Section typealias RowType = Row enum Section: Hashable { case .section1 case .section2 } enum Row: Hashable { case .row1 case .row2 case .row3 case .row4 case .row5 } // ãã®é¢æ°ãæ¹åãããŠããŸã var tableSections: [TableSection<Section, Row>] { TableSection(.section1) { .row1 .row2 .row3 } TableSection(.section2) { .row4 .row5 } } } ããã§ã¯äœ¿çšããŠããŸããããtableSections颿°ã®äžã§foræãifæãçšããããšãã§ããŸãã DiffableTableViewModelãå°å
¥ããããšã§ä»¥äžã®ãããªå¹æãåŸããããšæããŸãã æç¶ãçãªèšè¿°ãäžèŠã§ã³ãŒããç°¡æœ ç»é¢èŠçŽ ã®æ§é ãšã³ãŒãã®æ§é ãäžèŽããŠããŠçè§£ãããã ç»é¢èŠçŽ ã®è¿œå /åé€/äžŠã¹æ¿ããªã©ã«å®¹æã«å¯Ÿå¿ã§ãã DiffableTableViewModelãããã³ã«ã¯ä»¥äžã®ããã«å®çŸ©ããŠããŸãã import UIKit protocol DiffableTableViewModel { associatedtype SectionType: Hashable associatedtype RowType: Hashable @ArrayBuilder<TableSection<SectionType, RowType>> var tableSections: [TableSection<SectionType, RowType>] { get } } extension DiffableTableViewModel { var snapshot: NSDiffableDataSourceSnapshot<SectionType, RowType> { var snapshot = NSDiffableDataSourceSnapshot<SectionType, RowType>() snapshot.appendSections(tableSections.map {$0.sectionType}) tableSections.forEach { tableSection in snapshot.appendItems(tableSection.rowTypes, toSection: tableSection.sectionType) } return snapshot } } struct TableSection<SectionType, RowType> { let sectionType: SectionType let rowTypes: [RowType] init(_ sectionType: SectionType, @ArrayBuilder<RowType> rowsBuilder: () -> [RowType]) { self.sectionType = sectionType self.rowTypes = rowsBuilder() } } 以äžåèã«ãªãã°å¹žãã§ãã
ã¯ããã« ã¯ãããŸããŠãDELISH KITCHEN éçºéš ã® çŸœéŠ¬ïŒ @NaokiHaba ïŒãšç³ããŸãã ãã®èšäºã§ã¯ãDELISH KITCHEN éçºéš ã§ è¡ã£ãŠãã Node.js ã®ããŒãžã§ã³ã¢ããã®æé ãšããã®éã«çºçããåé¡ãšãã®å¯Ÿå¿ã«ã€ããŠã玹ä»ããŸãã 察象èªè
ãã®èšäºã¯ã Node.js ã®ããŒãžã§ã³ã¢ãããè¡ãããããã©ã®ãããªæé ã§è¡ãã°ãããããããªãæ¹ãã Node.js ã®ããŒãžã§ã³ã¢ãããè¡ã£ãéã«çºçããåé¡ã®å¯Ÿå¿æ¹æ³ãç¥ãããæ¹ã察象ãšããŠããŸãã ãã®èšäºã§ç޹ä»ããç°å¢ ãã®èšäºã§ç޹ä»ããç°å¢ã¯ä»¥äžã®éãã§ãã Node.js v16.13.1 npm v8.1.2 nodenv v1.4.1 ããŒãžã§ã³ã¢ããã®èæ¯ DELISH KICTHEN WEB ã§ã¯ ããã³ããšã³ãã®ã©ã³ã¿ã€ã ãšã㊠Node.js ãæ¡çšããŠããŸãã tech.every.tv çŸåšå©çšããŠãã Node.js ã®ããŒãžã§ã³ã¯ v16.13.1 ã§ããã 2023 幎 9 æ 11 æ¥ ã« EOL ãäºå®ãããŠãããããä»å Node.js ã®ããŒãžã§ã³ã¢ãããè¡ãããšã«ããŸããã ããŒãžã§ã³ã¢ããã®æé ãªãªãŒã¹ããŒãã®ç¢ºèª Node.js ã®ããŒãžã§ã³ã¢ãããè¡ãéã¯ããªãªãŒã¹ããŒãã確èªããããŒãžã§ã³ã¢ããã«ãã£ãŠçºçããå¯èœæ§ã®ããåé¡ãäºåã«ææ¡ããå¿
èŠããããŸããã nodejs.org nodejs.org OpenSSL ã«é¢ãã倿Žãå€ãå«ãŸããŠããããšããã Node.js ã®ããŒãžã§ã³ã¢ããã«ãã£ãŠçºçããå¯èœæ§ã®ããåé¡ãšããŠã以äžã®ãããªãã®ãèããããŸããã 倿Žåã®ããŒãžã§ã³ã® Node.js ã§å©çšããŠãã OpenSSL ã®ããŒãžã§ã³ãšã倿ŽåŸã®ããŒãžã§ã³ã® Node.js ã§å©çšããŠãã OpenSSL ã®ããŒãžã§ã³ãç°ãªãããšã«ãã£ãŠã OpenSSL ã«é¢ããåé¡ãçºçããå¯èœæ§ããã Node.js ã®ããŒãžã§ã³ã¢ãã Node.js ã®ããŒãžã§ã³ã¢ããã¯ã nodenv ã® install ã³ãã³ããå©çšããŠè¡ããŸãã # çŸåšã®ããŒãžã§ã³æ
å ±ãç¢ºèª $ node -v 16.18.0 # .node-version ãæŽæ° $ vi .node-version # .node-version 18.16.1 # nodenv ã§ 18.16.1 ãã€ã³ã¹ããŒã« $ nodenv install $(cat .node-version) # 18.16.1 $ node -v 18.16.1 .node_modulesã» package-lock.json ãåäœæãã Node.js v16.18.0 ã§ã€ã³ã¹ããŒã«ãã node_modules ãã Node.js v18 ã§å©çšãããšäŸåé¢ä¿ã®äžæŽåçãçºçããå¯èœæ§ãé«ãããšããã node_modules ãåé€ãã package-lock.json ãåäœæããŸãã $ rm -rf node_modules package-lock.json # npm ã®ãã£ãã·ã¥ã§å€ãããŒãžã§ã³ã®ããã±ãŒãžãæ®ã£ãŠããå¯èœæ§ãããããããã£ãã·ã¥ãåé€ $ npm cache clean --force # ãã£ãã·ã¥ãã¯ãªã¢ããããã©ãããç¢ºèª $ npm-cache verify # package-lock.json ãåäœæ $ npm install OpenSSL ã® äºææ§ãšã©ãŒ Node.js v18 ã§ã¢ããªã±ãŒã·ã§ã³ãæ£åžžã«åäœããã確èªãããšã以äžã®ãããªãšã©ãŒãçºçããŸããã $ npm run dev # 以äžã®ãããªãšã©ãŒãçºçããå Žåã¯ãåŸè¿°ã®ã`Node.js` v18 ã§ã® `crypto` ã¢ãžã¥ãŒã«ã®å€æŽããã確èªãã ããã Error: error:0308010C:digital envelope routines::unsupported at new Hash (node:internal/crypto/hash:71:19) at Object.createHash (node:crypto:133:10) Node.js v18 ã§ã® crypto ã¢ãžã¥ãŒã«ã®å€æŽ Node.js v18 ã§ã¯ã crypto ã¢ãžã¥ãŒã«ã®ããã©ã«ãã®æå·åæ¹åŒã倿Žãããããšã«ããã Node.js v16 ã§æ£åžžã«åäœããŠããã¢ããªã±ãŒã·ã§ã³ãæ£åžžã«åäœããªããªãå¯èœæ§ããããŸãã å¯Ÿè±¡æ¹æ³ãšããŠã¯ã以äžã® 2 ã€ãèããããŸãã webpack ã®ããŒãžã§ã³ã¢ãã æ«å®æªçœ®ãšã㊠package.json ã® scripts ã« NODE_OPTIONS=--openssl-legacy-provider ã远å ãã æ¬æ¥ã¯ webpack ã®ããŒãžã§ã³ã¢ãããè¡ãããšãæãŸããã§ããã webpack ã®ããŒãžã§ã³ã¢ããã«ã¯æéãããããããæ«å®æªçœ®ãšã㊠package.json ã® scripts ã« NODE_OPTIONS=--openssl-legacy-provider ã远å ããããšã§å¯Ÿå¿ããŸããã Error when running build-storybook with Node 17 · Issue #16555 · storybookjs/storybook · GitHub nodejs.org { " scripts ": { " dev ": " NODE_OPTIONS=--openssl-legacy-provider app/server/index.js --watch " } } äžèšã®èšå®ã远å ããããšã§ã Node.js v18 ã§ã® crypto ã¢ãžã¥ãŒã«ã®ããã©ã«ãã®æå·åæ¹åŒã倿Žããããšãã§ããŸãã 以äžã®æé ã§ã Node.js v18 ãžã®ããŒãžã§ã³ã¢ãããå®äºããããšãã§ããŸããã Dockerfile ã®å€æŽ Node.js ã®ããŒãžã§ã³ã¢ããã«äŒŽãã Dockerfile ã® FROM ã§æå®ããŠãã Node.js ã®ããŒãžã§ã³ã倿ŽããŸãã # 倿Žå FROM node:14.17.3-alpine3.14 # 倿ŽåŸ FROM node:18-alpine3.16 æåŸã« Node.js ã®ããŒãžã§ã³ã¢ããã¯ã Node.js ã®ããŒãžã§ã³ã¢ããã«ãã£ãŠçºçããå¯èœæ§ã®ããåé¡ãäºåã«ææ¡ãã察å¿ããå¿
èŠããããŸãã ãã®èšäºãã Node.js ã®ããŒãžã§ã³ã¢ãããè¡ãéã®åèã«ãªãã°å¹žãã§ãã