ã¯ããã« ããã«ã¡ã¯ïŒã¹ã¿ã¡ã³ã§ãšã³ãžãã¢ã€ã³ã¿ãŒã³ãããŠããæŸå±±ã§ããçŽå幎éã€ã³ã¿ãŒã³ãããŠããŸãããä»åã¯ã€ã³ã¿ãŒã³ã®æ¯ãè¿ããæžããŠããããšæããŸãã èªå·±çŽ¹ä» ç§ã¯çŸåšãæç¥çã®å€§åŠ2幎çã§ãã倧åŠã§ã¯ç€ŸäŒçŠç¥ãå°æ»ããŠããŠãã®äžã§ãç¹ã«ç€ŸäŒçŠç¥äºæ¥ã®æé©åã«ã€ããŠç ç©¶ããŠããŸãã ã¹ã¿ã¡ã³ã«ã¯2020幎ã®ïŒæããã€ã³ã¿ãŒã³ãšããŠåç»ããŸãããæ¥åã§ã¯äž»ã«iOSã¢ããªã®éçºãè¡ã£ãŠããŸãã ã¹ã¿ã¡ã³ã§ã®ã€ã³ã¿ãŒã³ä»¥å€ã«å®åçµéšã¯ãªããæç³»ã®åŠéšã«éã£ãŠããã®ã§ãåç»æã¯æ£çŽå³ãå·Šãåãããªããšãããããªç¶æ
ã§ããããããå幎éã®ã€ã³ã¿ãŒã³ãçµãŠTUNAGã®æ°æ©èœéçºã»æ©èœæ¹åãè¡ãããŸã§æé·ããŸããã äžèšã§ã¯ã€ã³ã¿ãŒã³ãšããŠã©ã®ãããªæ¥åãããŠãã£ãã®ããæžããŠããããšæããŸãã ãããŸã§ã®æ¥åå
容 æåã®äžã¶æé ãŸãåãã®ïŒã¶æã¯å°ããªäžå
·åä¿®æ£ã现ããã¿ã¹ã¯ãããªããªããTUNAGã®ã³ãŒããçè§£ããŠãããŸãããã¡ããã©èªåãã€ã³ã¿ãŒã³ãå§ãããšãã«ã³ãããŠã€ã«ã¹ã®åœ±é¿ã§ãªã¢ãŒãã¯ãŒã¯ãé²ã¿ä»äºã®ããã¥ããããããŸãããããããéçºããŒã ã®ã¿ãªãããDiscordã®é話ãåžžæç¹ãã£ã±ãªãã«ããããããªããšãããæ°è»œã«èããç°å¢ãäœã£ãŠãã ãã£ãã®ã§ããªããšãã¿ã¹ã¯ã朰ããŠããããšãã§ããŸãããã€ã³ã¿ãŒã³ã§ã®åããŠã®ã¿ã¹ã¯ã¯ããã¿ã³ã®æåããå®äºãâšãéãããã«å€æŽãããã®ã§ãããç°¡åãªã¿ã¹ã¯ã§ããããåããŠPRãæåºãããšãã¯ç·åŒµããŸããã 2ã¶æç®ã ãããããã°ããããŠãTUNAGã®ã³ãŒãã«ãæ
£ããŠããé å°ãè€éãªæ©èœã®éçºãä»»ãããŸãããã¿ã€ã ã©ã€ã³ã®ã³ã¡ã³ãå
¥åç»é¢ããªãã¥ãŒã¢ã«ãããšããã¿ã¹ã¯ã§ããããããŸã§ã®æ¥åã§ã¯ãã³ãã€ã³ãã§ç¹å®ã®ç®æãä¿®æ£ããã°æžããã®ã§ããããããä»åã¯èªåã®æžããã³ãŒããä»åŸã©ã®ããã«äœ¿ãããã®ããªã©ãæ³å®ããªããã°ãããªãã£ããããã¢ãŒããã¯ãã£ã®çè§£ããªããžã§ã¯ãæåã®çè§£ã«èŠãã¿ãŸããããããéçºãé²ããŠãããã¡ã«èªåã®äžã§æ®µã
èŠããã§ããããšãè
ã«èœã¡ãããã«ãªã£ãŠããããããã§å€§ããæé·ã§ãããšæããŸãã çŸåš ããããã¯OSã®ã¢ããããŒãã®å¯Ÿå¿ãããã«ä»éããŠå¿
èŠã«ãªã£ãã©ã€ãã©ãªã®å°å
¥ãªã©ãè¡ãçŸåšã¯æ¯èŒçå€§èŠæš¡ãªãããžã§ã¯ãã«æºãã£ãŠããŸããã€ã³ã¿ãŒã³ã§ã¯ãããªãããã瀟å¡ãšåãæ¥åãä»»ããŠããã£ãŠããŸãã ãªãæªçµéšã®æç³»å€§åŠçã瀟å¡ãšåããããªæ¥åãã§ãããŸã§æé·ã§ããã®ã å幎éã®ã€ã³ã¿ãŒã³ãçµãŠèŠéããã»ã©æé·ããããšãã§ããŸãããäžçªåã®æé·ãåŸæŒãããŠãããã®ã¯TUNAGãæ¥æé·äžã®ãããã¯ãã§ãããšããããšã ãšæããŸããæé·äžã®ãããã¯ãã¯ã課é¡ãå€ãããããã®åãããžã§ã¯ããå€ãçšæãããŸãããã®ã©ãããéåãªéçºçµéšãç©ãããã®ã°ããã§ãã£ããããèªåã®æé·ã«å€§ããèµ·å ãããšæããŸãã ãŸããã¹ã¿ã¡ã³ã§ã¯ã»ãã¥ãªãã£å匷äŒããã³ã³ãã¥ãŒã¿ãŒãµã€ãšã³ã¹å匷äŒãªã©ãåå¿è
ãšäžçŽè
ã®ç¥èã®æºãåããŠããããããªå匷äŒãéå¬ãããŠããã®ã§ãããã«ç©æ¥µçã«åå ããŠãã£ãã®ãèªåã®åãåºäžãããèŠå ã«ãªã£ãã®ã§ã¯ãªãããšæããŸãã ãããã« ã¹ã¿ã¡ã³ã¯åšãã«åªç§ãªãšã³ãžãã¢ãå€ãéåžžã«åç£ç¢ç£šã§ããç°å¢ã§ããããã«è¥æã«ãå€ãã®ãã£ã³ã¹ãéã£ãŠããŸããèªåã¯ãã®å幎éã§å€ããä»»ããŠããã ãæé·ããããšãã§ããŸãããä»åŸãè¯ããããã¯ããäœãéçšã§èªèº«ãæé·ããŠããããšæããšã¯ã¯ã¯ã¯ããŸãã æåŸã«ãæ ªåŒäŒç€Ÿã¹ã¿ã¡ã³ã§ã¯äžç·ã«åããšã³ãžãã¢ãåéããŠããŸãããèå³ã®ããæ¹ã¯ãã² ãšã³ãžãã¢ãµã€ã ãã芧ãã ããã
ã¹ã¿ã¡ã³ãšã³ãžãã¢ã®äºæ¬ã§ãã æ®æ®µã®æ¥åã§ã¯Ruby on Railsãçšããæ©èœéçºãæ
åœããŠããŸãã åè·ã§ãã黿°åè·¯ã®èšèšãšã³ãžãã¢ããWebãšã³ãžãã¢ã«è»¢èº«ãã11æããåããŠããŸãã ã¹ã¿ã¡ã³ã§ã¯ããšã³ãžãã¢ã®æè¡ååäžã«åãå
¥ããŠããã瀟å
å匷äŒãç©æ¥µçã«å®æœããŠããŸãã ä»åã¯ãç§ã11æã12æã«åå ãããã¿ããªã®ã³ã³ãã¥ãŒã¿ã»ãµã€ãšã³ã¹å匷äŒãã«ã€ããŠã®èšäºã§ãã åœèšäºã®ãããã¯ã¯å€§ãã2ã€ã 1. å匷äŒã®ã¬ããŒã 2. å匷äŒã®äžã§Rubyã§å®è£
ããã¢ã«ãŽãªãºã ã«ã€ã㊠1ã«ãããŠã¯ããšã³ãžãã¢ãšããŠã¹ã¿ã¡ã³ã§åãããšã§ãã©ã®ãããªç°å¢ã§ã©ãæé·ã§ãããïŒã€ã¡ãŒãžããäžå©ãšãªãã°å¹žãã§ãã 2ã¯ãRubyãªãããæžãããšãã£ãæè¡å¯ãã®ã³ã³ãã³ãã§ãã å匷äŒã¬ããŒã ããã¹ã ã¿ããªã®ã³ã³ãã¥ãŒã¿ãµã€ãšã³ã¹(ç¿æ³³ç€Ÿ) å
容 èšç®é ããŒã¿æ§é ã¢ã«ãŽãªãºã (ãœãŒããæ¢çŽ¢) ããŒã¿ããŒã¹(ãªã¬ãŒã·ã§ãã«ãéãªã¬ãŒã·ã§ãã«ã忣ããŒã¿ããŒã¹ãããŒã¿ã®äžè²«æ§) ã³ã³ãã¥ãŒã¿(ã¢ãŒããã¯ãã£ãã³ã³ãã€ã©) ææ å€§åŠæä»£ã®å°æ»ãåè·ã§ãã¢ã«ãŽãªãºã ãããŒã¿ããŒã¹ã«ã€ããŠã¯ãåŠã¶æ©äŒããããŸãããããããŸã§ç¥èãšããŠæã£ãŠããã«éããŸããã§ããã ä»åã®å匷äŒã§äœããè¯ãã£ãããšã¯ãå
茩ãšã³ãžãã¢ã«è³ªåããªããçè§£ãæ·±ããããšãã§ããç¹ã§ãã ãã®ãããä»åã®å匷äŒãéããŠãWebãšã³ãžãã¢ã®ç«å Žã§ã©ãå®çŸããã®ããéžæããŠããã®ãçã以åãããå®åãã€ã¡ãŒãžããªããåŠã¶ããšãã§ããŸããã æ¥åã«æŽ»ãããŠããããš èšç®éãæèã§ããããã«ãªã£ã æããã«èšç®éãå¢ãããããªæ§é ã«æ³šæãåãããã«ãªããŸããã äŸãã°ã each ãªã©ãªã¹ããæ±ãã¡ãœããããã¹ãããããšãã£ãã³ãŒãããWebãšã³ãžãã¢ããã¥ãŒããåã«ã¯æ°ã«ããæžããŠãããã®ã§ãâŠã Rubyãªãã§ã¯ã®æžãæ¹ã«é¢å¿ãåããã£ãããšãªã£ã ææã®æžç±ã«ãããŠã¯ãäŸã§æ²èŒãããŠããã³ãŒãã¯ãæ¬äŒŒã³ãŒããçšããŠãããããçµéšã®æµ
ãç§ã«ã¯å°ã
ã€ã¡ãŒãžããã¥ãããšããããããŸããã ããã§ã¢ã«ãŽãªãºã ã®ç« ã§ã¯ãèªãRubyã§å®è£
ããŸããã å®éã«åããããšã§ã¢ã«ãŽãªãºã ã®åããæèŠçã«çè§£ãã§ããã ãã§ãªããã³ãŒãã¬ãã¥ãŒããããããšã§ãRubyãããã·ã³ãã«ãªå®è£
ãåŠã¶ããšãã§ããŸããã Rubyã§æžãã³ãŒãã®æå¿«ããšãèªèº«ãæžãã³ãŒãã®äžæçãã«æ°ã¥ãããšãã§ããŸããã ãã®æã«æžããã³ãŒãã«é¢ããã³ãŒãã«ã€ããŠã¯ã次ã®ãããã¯ã§å®éã«è§ŠããŠåããŸãã Rubyã«ããåçš®ã¢ã«ãŽãªãºã ã®å®è£
ãã¹ãŠèŒããŠããŸããšãçžåœãªæéãšãªã£ãŠããŸãã®ã§ãRubyã§å®è£
ããããšã§éããé¡èã ã£ãã³ãŒãã®ãã¡2ã€ãããã¯ã¢ããããŸãã æ¿å
¥ãœãŒã ããã¹ãã®ã³ãŒã function insertion_sort(list) for i â 2 ... list.length j â i while j and list[j- 1 ] > list[j] list.swap_items(j, j- 1 ) j â j - 1 Rubyã§åäœã®ã¿ãåçŸããã³ãŒã def swap (ary, x, y) ary[x], ary[y] = ary[y], ary[x] end def insert_sort (ary) for i in 1 ..(ary.length - 1 ) j = i while j > 0 && ary[j- 1 ] > ary[j] swap(ary, j- 1 , j) j = j - 1 end end end ãªãã¡ã¯ã¿ãªã³ã°åŸ ary = # ã©ã³ãã æ°å module Sortable def swap! (i, j) self [i], self [j] = self [j], self [i] end def insert_sort 0 .upto self .size- 1 do | i | i.downto 1 do | j | break if self [j- 1 ] < self [j] swap!(j- 1 , j) end end end end ary.extend Sortable ary.insert_sort Rubyã§ã¯ for æã䜿ããªãããšããããšã§ upto ã¡ãœããã§ä»£æ¿ããŸããã åãã㊠while æã«ã€ããŠã down_to ã§çœ®ãæããŠããŸãã ã€ãã¬ãŒã¿ã®å¶åŸ¡ãã¡ãœããèªèº«ã«ä»»ããç¹ã§RubyããããšãããŸãã ä»ã«ã¯Arrayãªããžã§ã¯ãã«ãŠ extend ããŠçšããããšã§ã颿°ã§ã¯ãªãã¡ãœãããšã㊠swap ã insert_sort ã宿œã§ããããã«ããŸããã DFSãšBFS DFSãšBFSãšã¯ DFS(Depth First Search)=æ·±ãåªå
æ¢çŽ¢ã BFS(Breadth First Search)=åºãåªå
æ¢çŽ¢ ãšåŒã°ããã¢ã«ãŽãªãºã ã®ããšã§ãã ã°ã©ããæ¢çŽ¢ããã«ããã£ãŠãã©ã®ãããªé åºã§ããŒããå·¡åããŠãããïŒãæããã®ãšæã£ãŠããã ããã°ãå·®ãæ¯ãããããŸããã å
·äœçã«ã¯æ¬¡ã®2ã€ã®å³ã®ãããªé çªã§æ¢çŽ¢ãé²ããŸãã DFSã®å Žå æ°åã®é çªã«æ¢çŽ¢ãè¡ãããŸãã ããŒã0ããæ¢çŽ¢ãéå§ãã ããŒã1, 5, 6ãçºèŠãã ããŒã1ãæ¡ä»¶ã«åèŽããã確èªãã ããŒã1ã«æ¥ç¶ãããããŒããæ¢ã ããŒã2ãçºèŠãã ããŒã2ãæ¡ä»¶ã«åèŽããã確èªãã ããŒã2ã«æ¥ç¶ãããããŒããæ¢ã ããŒã3, 4ãçºèŠãã ããŒã3ãæ¡ä»¶ã«åèŽããã確èªãã (以äžãåæ§) ãã®ããã«ãæ°ããçºèŠããããŒãããå
ã«æ¢çŽ¢ãé²ããŠããæ¹åŒãBFS(åºãåªå
æ¢çŽ¢)ã§ãã BFSã®å Žå ããŒã0ããæ¢çŽ¢ãéå§ãã ããŒã1, 2, 3ãçºèŠãã ããŒã1ãæ¡ä»¶ã«åèŽãããç¢ºèª ããŒã1ã«æ¥ç¶ãããããŒããæ¢ã ããŒã4ãçºèŠãã ããŒã2, 3ã1ãšåæ§ã«ãæ¡ä»¶ã確èªããäžã§æ¥ç¶ããŒããèŠã€ãã ããŒã1, 2, 3ã®æ¢çŽ¢ãå®äºãã æ°ããçºèŠããããŒã4, 5ã®æ¡ä»¶ã確èªãã (以äžãåæ§) ãã®ããã«ãå
ã«çºèŠããããŒãããå
ã«æ¢çŽ¢ãé²ããŠããæ¹åŒãBFS(åºãåªå
æ¢çŽ¢)ã§ãã æ©éãã³ãŒããèŠãŠãããŸãããã ããã¹ãã®ã³ãŒã function DFS(start_node, key) next_nodes <- Stack. new () seen_nodes <- Set. new () next_nodes.push(start_node) seen_nodes.add(start_node) while not next_nodes.empty node <- next_nodes.pop() if node.key = key return node for n in node.connected_nodes if not n in seen_nodes next_nodes.push(n) seen_nodes.add(n) return null function BFS next_nodes <- Queue. new () seen_nodes <- Set. new () next_nodes.enqueue(start_node) seen_nodes.add(start_node) while not next_nodes.empty node <- next_nodes.dequeue() if node.key = key: return node for n in node.connected_nodes if not n in seen_nodes next_nodes.enqueue(n) seen_nodes.add(n) return null Rubyã«ããå®è£
ã¯ã©ã¹å®è£
class Graph attr_accessor :nodes def initialize (nodes = []) @nodes = nodes end def initialize_search_memory @next_nodes = [] @seen_nodes = [] end def push_memory (node) @next_nodes .push(node) @seen_nodes .push(node) end alias :queue_memory :push_memory def pop_next_nodes @next_nodes .pop end def dequeue_next_nodes @next_nodes .shift end def saw? (node) @seen_nodes .include?(node) end def next_nodes_exist? @next_nodes .any? end def connect (key1, key2) if (v1 = find_node(key1)) && (v2 = find_node(key2)) v1.connect(key2) v2.connect(key1) else false end end def find_node (key) nodes.find{| v | v.key == key } end def get_connected_nodes (node) keys = node.connected_nodes nodes = keys.map{| k | find_node(k)} end end class Node attr_accessor :key , :value , :connected_nodes def initialize (key, value) @key = key @value = value @connected_nodes = [] # Nodeãªããžã§ã¯ãã®keyãæ ŒçŽãã end def connect (key) connected_nodes.push(key) end end DFS class Graph def dfs (start_key, key) initialize_search_memory start_node = find_node start_key push_memory start_node while next_nodes_exist? node = pop_next_nodes return node if node.key == key get_connected_nodes(node).each do | n | push_memory n unless saw? n end end end end BFS class Gragh def bfs (start_key, key) initialize_search_memory start_node = find_node start_key queue_memory start_node while next_nodes_exist? node = dequeue_next_nodes return node if node.key == key get_connected_nodes(node).each do | n | queue_memory n unless saw? n end end end end å®è¡çµæ @graph = ' ã°ã©ãã®çæ ' @gragh .dfs( 0 , 3 ) => #<Node:0x00007fd68e85a7e8 key: 3, value: 35, connected_nodes: [4, 5, 8, 9]> @gragh .dfs( 0 , 3 ) => #<Node:0x00007fd68e85a7e8 key: 3, value: 35, connected_nodes: [4, 5, 8, 9]> ããã¹ãã®ã³ãŒãã§ã¯ã stack ã set ãªã©äžè¬çãªããŒã¿æ§é ãçšããŠæžãããŠããŸããã Rubyã«ããå®è£
ã§ã¯ã¯ã©ã¹å®çŸ©ãçšããããšã§ãåŒæ°ãæå°éã«æããããšãã§ãããããã·ã³ãã«ãªã³ãŒãã§æžãããšãã§ããŸããã ãããã« ååã§ã¯ãå匷äŒãã©ã®ããã«é²ããããŠãããïŒå匷äŒã§äœãåŸãŠãæ¥åã«æŽ»ããããšãã§ããŠãããïŒã«ã€ããŠè¿°ã¹ãŸããã èªå·±ç éœããŠé£ããã€ããŠããããšã¯åæã§ã¯ãããŸãããã¹ã¿ã¡ã³ã«ã¯ãããããµããŒãããç°å¢ããããŸãã åŸåã§ã¯ãããæè¡çãªå
容ãšããŠããã¹ãã®ç䌌ã³ãŒããRubyã§å®è£
ããã³ãŒãã玹ä»ããŸããã ããªãšãŒã·ã§ã³è±ããªã€ããŒã¬ãŒã·ã§ã³ã¡ãœããããã¯ã©ã¹å®çŸ©ãçšããããšã§ãããã·ã³ãã«ã«æžããRubyã®è¯ããå確èªããŸããã ä»åã¯ä»¥äžã§ãã æåŸãŸã§ã芧ããã ãèª ã«ããããšãããããŸããã ã¹ã¿ã¡ã³ã§ã¯äžç·ã«ãããã¯ãéçºãé²ããŠããã仲éãåéããŠããŸãïŒ èå³ãæã£ãŠããã ããæ¹ã¯ãæ¯éäžèšã®åéããŒãžã埡芧ãã ããã Webã¢ããªã±ãŒã·ã§ã³ãšã³ãžãã¢åéããŒãž
ç®æ¬¡ ã¯ããã« HTTPããããŒãšã¯ Content-Typeã®æŠèŠ æ€èšŒå
容 ãããã« ã¯ããã« ããã«ã¡ã¯ãã¹ã¿ã¡ã³ã§ãšã³ãžãã¢ãããŠããæå¶ã§ããæ®æ®µã¯React+TypeScriptã§ããã³ããšã³ããéçºããããRailsã§APIãäœæããŠããŸããã¯ã©ã€ã¢ã³ããµã€ããããµãŒããŒãµã€ããžãªã¯ãšã¹ãããã«åœãããHTTPããããŒã®Content-Typeãæè»ã«å€ããäºã§ãªã¯ãšã¹ãã®èšè¿°ãã·ã³ãã«ã«åºæ¥ãã®ã§ãä»å玹ä»ããããšæããŸãã HTTPããããŒãšã¯ ãŸãHTTPããããŒã«ã€ããŠã§ããã以äžã®ããã«å®çŸ©ãããŠããŸãã HTTPããããŒã¯ãèŠæ±ãŸãã¯å¿çã«é¢ãã远å ã®ã³ã³ããã¹ãåã³ã¡ã¿ããŒã¿ãæž¡ãHTTPèŠæ±ãŸãã¯å¿çã®ãã£ãŒã«ã HTTPããããŒã¯ä»¥äž3ã€ã«ã«ããŽã©ã€ãºããã ãªã¯ãšã¹ãããããŒïŒãã§ãããããªãœãŒã¹ãŸãã¯ã¯ã©ã€ã¢ã³ãèªäœã«é¢ãã詳现æ
å ±ãå«ãããããŒã å¿çããããŒïŒå ŽæããµãŒããŒèªäœïŒååãããŒãžã§ã³ãªã©ïŒãªã©ãå¿çã«é¢ããè¿œå æ
å ±ãå«ãããããŒã 衚çŸã¡ã¿ããŒã¿ããããŒïŒã¡ãã»ãŒãžæ¬æã®ãªãœãŒã¹ã«é¢ããã¡ã¿ããŒã¿ïŒèšèªãé·ããã¡ãã£ã¢ã¿ã€ããªã©ïŒ Content-Type㯠ãªã¯ãšã¹ãããã£ã®ã¡ãã£ã¢ã¿ã€ããæå® ãã圹å²ãæã€ã®ã§ã衚çŸã¡ã¿ããŒã¿ããããŒã«è©²åœããŸãã Content-Typeã®æŠèŠ äžè¿°ã®éããContent-Typeã¯ãªã¯ãšã¹ãæã«ã¡ãã£ã¢ã¿ã€ããæå®ãã圹å²ãæãããŸãã ã¡ãã£ã¢ã¿ã€ãã¯ãMIMEã¿ã€ããèŠçŽ ã¿ã€ããšãèšãããã€ã³ã¿ãŒãããäžã§è»¢éããã ã³ã³ãã³ãã®åœ¢åŒã衚çŸããèå¥å ã衚ããŸãã å
·äœçãªçš®é¡ã®äŸãšããŠä»¥äžãæããããŸãããã¡ã€ã«ã¯ã圢åŒããšé©å®èªã¿æããŠãã ããã MIMEã¿ã€ã ææžã®çš®é¡ text/plain ããã¹ããã¡ã€ã« text/csv CSVãã¡ã€ã« text/html HTMLãã¡ã€ã« text/css CSSãã¡ã€ã« text/javascript JavaScriptãã¡ã€ã« application/json JSONãã¡ã€ã« application/pdf PDFãã¡ã€ã« image/jpeg JPEGãã¡ã€ã«(.jpg, .jpeg) image/png PNGãã¡ã€ã« image/gif GIFãã¡ã€ã« image/svg+xml SVGãã¡ã€ã« application/zip Zipãã¡ã€ã« video/mpeg MPEGãã¡ã€ã«ïŒåç»ïŒ æ€èšŒå
容 ä»åæ€èšŒããå
容ã¯ä»¥äžã§ãã åæãšããŠReactã¢ããªã±ãŒã·ã§ã³ã¯POST(PATCH)ãã©ã¡ãŒã¿(params)ããªããžã§ã¯ããšããŠç®¡çããŠããŸãããããŠAPIã«ãªã¯ãšã¹ããããã¡ã€ã«ã§ã¯ä»¥äžã®ããã«ãã©ã¡ãŒã¿ãå±éããŸãã ãã©ã¡ãŒã¿ã¯å
šãŠãå¿
é é
ç®ã§ã¯ãªããååšããå Žåã®ã¿ãªã¯ãšã¹ãã«å«ããæ³å®ã§ãã æ¹åå // type type UserParamsType = { name: string email: string address: string phone: number gender: string } // useræŽæ°çšã®é¢æ°ã å¥é¢æ°ã«ãšã³ããã€ã³ãurlãšãªã¯ãšã¹ãbodyãæž¡ã export const requestUpdateUser = async ( userId: number , params: UserParamsType ) => { // ãšã³ããã€ã³ã const url = `api/v1/user/${userId}` // ãã©ã¡ãŒã¿çæ const { name , email , address , phone , gender , } = params let body = '' if ( name ) body += `&[name]=${encodeURIComponent(name)}` if ( email ) body += `&[email]=${encodeURIComponent(email)}` if ( address ) body += `&[address]=${encodeURIComponent(address)}` if ( phone ) body += `&[phone]=${encodeURIComponent(phone)}` if ( gender ) body += `&[gender]=${encodeURIComponent(gender)}` const response = await fetchPatchTemplate ( url , body ) return response } // HEADERS // Content-Typeã«ã¯application/x-www-form-urlencoded; charset=utf-8ãæå® const HEADERS = { Accept: 'application/json' , 'Content-Type' : 'application/x-www-form-urlencoded; charset=utf-8' , } // apiãå©ã颿° export const fetchPatchTemplate = async ( url: string , body: string ) => { try { const response = await fetch ( url , { credentials: 'same-origin' , method: 'PATCH' , headers: HEADERS , body , } ) if ( !response.ok ) { throw Error ( response. statusText ) } const resJson = await response.json () return { payload: resJson } } catch ( error ) { return { error: 'ãšã©ãŒã¡ãã»ãŒãž' } } } äžèšã®éãContent-Typeã«ã¯ application/x-www-form-urlencoded; charset=utf-8 ãæå®ããŠããŸãã ãã®Typeã¯ã ãããŒãšå€ã '=' ãæãã§çµã«ãªãã '&' ã§åºåãããŠãšã³ã³ãŒããããã ãšããç¹åŸŽãæã¡ãŸãã ãã£ãŠãã®Typeãæå®ããå Žåã¯ãäžèšã®èšè¿°ã§paramsãçæãããªã¯ãšã¹ãbodyã«å«ããäºãã§ããŸãã æ¹åæ¡ ããããäžèšã®èšè¿°ã§ã¯paramsã®æ°ã ãå±éã®èšè¿°ãããåæ°ãå¢ããŠããŸããŸãã ãã®å Žåã¯ã以äžã®ããã« paramså±ééšå ãš ContentType ãæžãæããäºã§èšè¿°éãæžããäºãå¯èœã§ãã paramså±ééšå => JSON.stringify(params) JSON.stringify() ã¡ãœããã¯ãããJavaScript ã®ãªããžã§ã¯ããå€ãJSONæååã«å€æããã¡ãœããã§ãã ContentType => 'application/json' application/jsonã«å€æŽãJSON圢åŒãæ±ãããã倿ŽããŸãã // type type UserParamsType = { name: string email: string address: string phone: number gender: string } // useræŽæ°çšã®é¢æ°ã å¥é¢æ°ã«ãšã³ããã€ã³ãurlãšãªã¯ãšã¹ãbodyãæž¡ã export const requestUpdateUser = async ( userId: number , params: UserParamsType ) => { // ãšã³ããã€ã³ã const url = `api/v1/user/${userId}` // ãªããžã§ã¯ã圢åŒã®paramsãJSON.stringifyã®åŒæ°ã«æž¡ããã©ã¡ãŒã¿çæ const body = JSON.stringify ( params ) const response = await fetchPatchTemplate ( url , body ) return response } // HEADERS // Content-Typeã«ã¯application/jsonãæå® const HEADERS = { Accept: 'application/json' , 'Content-Type' : 'application/json' } // apiãå©ã颿° export const fetchPatchTemplate = async ( url: string , body: string ) => { try { const response = await fetch ( url , { credentials: 'same-origin' , method: 'PATCH' , headers: HEADERS , body , } ) if ( !response.ok ) { throw Error ( response. statusText ) } const resJson = await response.json () return { payload: resJson } } catch ( error ) { return { error: 'ãšã©ãŒã¡ãã»ãŒãž' } } } ãããã« ä»åã¯HTTPéä¿¡ã«ãããããããŒåã³Content-Typeã«ã€ããŠç޹ä»ãããŠããã ããŸããã paramsã®éã«ããããŸãããã¯ã©ã€ã¢ã³ãã®èšè¿°ã倧å¹
ã«æžããããšãã§ããå Žåãããã®ã§ããããããContent-Typeãæè»ã«æ±ã£ãŠãããã°ãšæããŸãã ä»åã®å
容ãå°ãã§ãåèãšãªãã°å¹žãã§ãã ã¹ã¿ã¡ã³ã§ã¯äžç·ã«ãããã¯ãéçºãé²ããŠããã仲éãåéããŠããŸãïŒ èå³ãæã£ãŠããã ããæ¹ã¯ãæ¯éäžèšã®åéããŒãžã埡芧ãã ããã Webã¢ããªã±ãŒã·ã§ã³ãšã³ãžãã¢åéããŒãž åè HTTPããã㌠Content-Type MIME ã¿ã€ã
ã¯ããã« ããã«ã¡ã¯ãã¹ã¿ã¡ã³ã§ãšã³ãžãã¢ãããŠããæ¢
æã§ãã20åãšããŠæšå¹Žã®4æããæ£åŒã«å
¥ç€Ÿãããããã1幎ãçµãšããšããŠããŸãããããªèªåãã é人ããã°ã©ã㌠ããèªãã§ã¿ãææ³ãšãèªåã«ã©ã®éšåãæŽ»çšã§ãããã玹ä»ããŠããããšæããŸãã æ°è£
ç é人ããã°ã©ã㌠è·äººããåå ãžã®é äœè
: ïœïœïœïœ
ïœïŒšïœïœïœ , ïœïœïœïœïŒŽïœïœïœïœïœ çºå£²æ¥: 2017/07/14 ã¡ãã£ã¢: Kindleç ãªãèªãã ã ããã°ã©ããŒãšããŠã®å¿åŸãåŠã³ãèªåèªèº«ã1段ã¬ãã«ã¢ãããããããšæã£ãããã§ãã äžèšã«ãæžããŸããããã¹ã¿ã¡ã³ã«å
¥ç€ŸããŠ1幎匱ãçµã¡ãŸãããæ¥åã§ã¯äž»ã« Ruby on Rails ã§ FANTS ã®éçºãè¡ã£ãŠãããããçšåºŠã®ç¥èã¯èº«ã«ã€ããŠããŸããããã ãæè¡ã¯èº«ã«ã€ããŠãããã®ã®ããã®ä»ã®ããšã«é¢ããŠã¯ãŸã ãŸã æªçã§ããããã§ã瀟å
ã®æšèŠå³æžã«ãäžãã£ãŠãããé人ããã°ã©ããŒããèªã¿ãå®è·µããããšã§æé·ããããšèããŸããã é人ããã°ã©ããŒãšã¯ã©ããªæ¬ã ãã£ãããšèª¬æãããšããããè¯ãããã°ã©ããŒã«ãªãããã»ããè¯ãä»äºãè¡ãããããæäŒããããæ¬ãã§ããçãã»ã¯ã·ã§ã³ãéããããã¡ã§æ§æãããŠãããåã»ã¯ã·ã§ã³ã§ç¹å®ã®è©±é¡ãæ±ã£ãŠããŸããæè¡ã ãã§ãªããããã°ã©ããŒãšããŠã®ä»äºã®é²ãæ¹ãªã©ã話é¡ã«ããå¹ççã»çç£çã«è¡åããã«ã¯ã©ããããããããèšè¿°ãããŠããæ¬ã§ãã ããã§ãããã€ãã®ã»ã¯ã·ã§ã³ãæç²ããŠãå
å®¹ãææ³ã»èªåã«æŽ»ããã«ã¯ã©ãããããããã玹ä»ããŠãããŸãã 第1ç« ïŒé人ã®å²åŠ ~ãœãããŠã§ã¢ã®ãšã³ããããŒ~ ãšã³ããããŒãšã¯ç©çåŠã®çšèªã§ãç¡ç§©åºãªåºŠåããè¡šãææšã®ããšã§ãããã®ã»ã¯ã·ã§ã³ã§ã¯å
šå®å®ã®ãšã³ããããŒãå¢å ããŠããã®ãšåæ§ã«ããœãããŠã§ã¢ãæéãšãšãã«ç¡ç§©åºã«ãªã£ãŠãããšèª¬æããŠããŸãã ç¡ç§©åºã«ãªãçç±ãšããŠãå²ãçªçè«ããäžããŠãããæªãèšèšãè³ªã®æªãã³ãŒããæ®ããŠãããšããèªåãé©åœã«äœæ¥ããã ãã ããšããèãæ¹ãå¿ã³èŸŒã¿ããããªãããšèšèŒãããŠããŸãã èªåèªèº«ãã鲿ã«ãã£ãŠã¯æ·±ãèããã«ã³ãŒããæžããŠããŸã£ãããšãããããããçµæãšããŠæªãã³ãŒããšãªãããã®åŸã®äœæ¥ã«æªåœ±é¿ãåãŒãããšããçµéšãããããšããããŸãã ãŸãã¯èªåã®æãã€ããéšåãããå²ããçªã§ã¯ãªã(é©åãªã¡ãœããåãèšè¿°ã»è²¬ä»»ãæç¢ºã«ããèšèš)ã³ãŒããèšè¿°ãããšã³ããããŒãæããŠãããããšæããŸãã 第2ç« ïŒé人ã®ã¢ãããŒã ~äºéåã®éã¡~ ãã®ã»ã¯ã·ã§ã³ã§ã¯äºéåãèµ·ããåå ãäºéåã«ããåé¡ã説æããŠããŸãã ãããèªãã§ããçããããäºéåã«æ©ãŸãããçµéšãããã®ã§ã¯ãªãã§ãããããã³ãŒãäžã§åãç¥èãïŒç®æä»¥äžã«èšè¿°ããŠããããã§ãè€æ°ç®æãä¿®æ£ããªããã°ãããªãã£ããã仿§ãè€æ°ç®æã«ãŸãšãŸã£ãŠããããšã§ãã©ããæ£ãšããããããããããªãããªã©ã¯ãããã¡ãªåé¡ã ãšæããŸããæ§ã
ãªäºéåã®è§£æ±ºæ¹æ³ã瀺ãããŠããŸãããäžã§ããåå©çšããããããã«ããŠããããšãã¯äžã€ã®è§£æ±ºæ¹æ³ã§ããã³ãŒãäžã®è©±ã§ã¯ãDRYãå¿ããã©ãããã§ãå©çšã§ããã¡ãœããã«ããŠããã仿§äžã®è©±ã§ã¯ã仿§ããŸãšããäžã€ã®ããã¥ã¡ã³ããäœæãéäžå±¥æŽã远ããããã«ããŠæŽæ°ããŠããããªã©ãããŠãäºéåããéæŸãããŸãããã 第6ç« ïŒã³ãŒãã£ã³ã°æ®µé ~ãªãã¡ã¯ã¿ãªã³ã°~ ãã®ã»ã¯ã·ã§ã³ã¯ãªãã¡ã¯ã¿ãªã³ã°ãšã¯äœããã©ããã£ãŠãªãã¡ã¯ã¿ãªã³ã°ããããã説æããŠããŸãã ãã®æ¬ã§ã¯ãã³ãŒãã®èšè¿°ã®ããçŽããåäœæ¥ãåèšèšããç·ç§°ããŠããªãã¡ã¯ã¿ãªã³ã°ããšåŒãã§ããŸãããŸãããªãã¡ã¯ã¿ãªã³ã°ãè¡ãã¿ã€ãã³ã°ã¯ãã³ãŒãããªããã§ããªããšæãããããŸãšããã¹ã2ã€ã®äºæãèŠã€ããå ŽåããšããŠããŸãããŸãã«ã³ãŒããæžããŠããéã«ãäžèšã®ããšãæããå Žé¢ã¯å€ãã§ãããããªãªãŒã¹ãçŽæã®ããšãèãããšã宿ã«ãªãã¡ã¯ã¿ãªã³ã°ã«çæã§ããªãã§ãããæŸçœ®ããŠãããšãå°æ¥åé¡ãçºçããå Žåãäœèšã«ä¿®æ£ã®ããã«å€§éã®æéãå¿
èŠã«ãªããŸãããªã®ã§ãæ°ã¥ããã¿ã€ãã³ã°ã§ãªãã¡ã¯ã¿ãªã³ã°ã»ããŸããªãªãã¡ã¯ã¿ãªã³ã°ãè¡ããå°æ¥ã®åé¡ã«å¯ŸåŠããŠããããã§ããã 第8ç« ïŒé人ã®ãããžã§ã¯ã ~ã©ãã§ãèªåå~ ãã®ã»ã¯ã·ã§ã³ã¯ãã«ãããªãªãŒã¹æç¶ãããã¹ããªã©ã®äœæ¥ã®èªååã«ã€ããŠèª¬æããŠããŸãã 人éã¯ã³ã³ãã¥ãŒã¿ã»ã©ç¹°ãè¿ãäœæ¥ãåŸæã§ã¯ãªãã®ã§ããã¥ãŒãã³ãšã©ãŒã«ããåé¡ãæäœæ¥ã«ããå·¥æ°ãå€ããªããŸããããã§äœæ¥ãèªååããããšã§ããã¥ãŒãã³ãšã©ãŒãç¡ããªããæäœæ¥ããªãããŠä»ã®äœæ¥ãè¡ãçç£æ§ãäžããããšãã§ããŸãããŸãããã®æŠå¿µã¯ããã°ã©ããŒä»¥å€ã§ãéèŠãªèãã§ãããæ¥ã
ã®æ¥åãæ¯ãè¿ããç¹°ãè¿ãäœæ¥ããããªãããããèªååããŠã¿ãããšããããšãå®è·µããŠããããšæããŸããã ãããã« ä»åã¯ãé人ããã°ã©ããŒããèªã¿ãæ¬ã®å
å®¹ã»ææ³ã»èªåã«æŽ»ããã«ã¯ããšããããšãäžå¿ã«ç޹ä»ããŸãããæ¬ã®äžã§ç޹ä»ãããŠããããŒã«ãªã©ã¯å°ãå€ãã®ã§ãå©çšã¯é£ãããããããŸããããæŠå¿µãšããŠã¯ãšãŠãéèŠãªããšèšè¿°ãããŠããŸããããã ãèªåã¯2016幎ã«çºå£²ããããã®ãèªã¿ãŸããããå»å¹Žã®11æã« 第2çãšããŠæ°ããããŒãžã§ã³ ãçºå£²ãããŠãããããªã®ã§ããã¡ãã§ã¯ä»ã«å³ããããŒã«ã玹ä»ãããŠããã®ã§ã¯ãªãããšæããŸãã é人ããã°ã©ã㌠âçéã«åããããªãã®æ
â 第2ç äœè
: ãã€ãããã»ããŒãã¹ , ã¢ã³ããªã¥ãŒã»ãã³ã çºå£²æ¥: 2021/01/18 ã¡ãã£ã¢: Kindleç åã»ã¯ã·ã§ã³ã§å®çµããŠãããšã¯ãããååãæ¬ãªã®ã§ãèªåèªèº«ãŸã ãŸã çè§£ã§ããŠããªãéšåããããŸããããã°ã©ããŒãšããŠè¿·ã£ããšãã«èªã¿è¿ããªã©ããŠãçè§£ãæ·±ããŠããããã§ãã æ ªåŒäŒç€Ÿã¹ã¿ã¡ã³ã§ã¯äžç·ã«åããšã³ãžãã¢ãåéããŠããŸãããèå³ã®ããæ¹ã¯ãã² ãšã³ãžãã¢æ¡çšãµã€ã ãã芧ãã ããã
ã¢ãã€ã«ã¢ããªã°ã«ãŒãã§ããã«Androidã¢ããªã®éçºãè¡ã£ãŠãã @sokume ã§ãã Androidéçºè
ã®æ¹ã§ããã°èå³é¢å¿ã®å°œããªãã Android OS 12 Developer Preview 1 ã2/18æ¥ã«å
¬éãããŸãããã æ¯å¹Žã®äºã§ã¯ãããŸããã2021å¹Žã®æ°OS Android 12ãžã®å¯Ÿå¿ã«ãããŠå°ããã€æ€èšãããããŠãããªããšãªããªãææããã£ãŠããŸããã ãã®èšäºã§ã¯ãæ°OS Android 12ãžã®å¯Ÿå¿ãã2021幎平è¡ã«ããŠæ°ã«ãªãæŽæ°ãªã©ãããã¯ã¢ããããŠããããšæããŸãã Android12 å
Œξ
å ± 以äžã«å
Œξ
å ±ãèšèŒãããŠããŸãã Android 12 Developer Preview Android 12 Behavior changes: all apps Android 12 Features and APIs Overview ã¹ã±ãžã¥ãŒã« Android 12 ã®ãªãªãŒã¹ã¹ã±ãžã¥ãŒã«ã¯ä»¥äžã®ããã«ãªãããã§ãã https://developer.android.com/about/versions/12 ãã äžæšå¹ŽãŸã§ã¯ 5æã® Google I/O ã 10æã® made by Google ãšãã£ã倧ãããªãªãã©ã€ã³ã軞ãšããã€ãã³ãããããŸããã®ã§ããªãªãŒã¹ææãã€ãã³ããšé£åããŠããæããããŸããã æšå¹Žãšåæ§ã®ã¹ã±ãžã¥ãŒã«ã«ãªããããšããã ãšæããã®ã§ãä»å¹Žã8ææ«ã9æã«ãªãªãŒã¹ãããæµãã«ãªãããã§ãã ã¢ããªãžã®å€æŽç¹ OSãé²åããã®ã§ããã®ç°å¢ãå©çšããã¢ããªãé²åãä¿ãããŸãã targetSDK Update to Android 12 ã¢ããªã® targetSdkVersion ã Android12çšã«å€æŽããéã®å€æŽç¹ã«ã€ããŠã¯ä»¥äžã®èšäºã«ãªããŸãã https://developer.android.com/about/versions/12/behavior-changes-12 ããŒãšãªãã®ã¯ä»¥äžã®ç¹ã«ãªãããã§ãã Foreground service launch restrictions App components containing intent filters must declare exported attribute Unsafe launches of nested intents å
容ãšããŠã¯ãã¢ããªã®Launchéšåã«é¢ããã»ãã¥ãªãã£ãŒããã©ã€ãã·ãŒã®å€æŽãã¯ããããã§ãããªã³ã¯å
ã«è©³çްããããŸãã®ã§ãéçºäžã®ã¢ããªããã®å€æŽç¹ã®å¯Ÿè±¡ãšãªãã¢ããªãã©ãããã§ãã¯ããŠãããŸãããã Update all Apps Android OS 12 äžã§åäœãããã¹ãŠã®ã¢ããªã«å¯ŸããŠã®èšäºã¯ä»¥äžã«ãªããŸãã https://developer.android.com/about/versions/12/behavior-changes-all UXã«é¢ããç¹ãããã©ã¢ã°ã©ãŠã³ãPushã«é¢ããç¹ã®å€æŽãªã©ãOSå
šäœã§ã®å€æŽãããããã§ãããã®ç¹ããã£ããææ¡ããªããšã§ããã Android 12 ããã€ã¹ ä»åã®çºè¡šã«ããããŠãAndroid 12ã®éçºè
åããã¬ãã¥ãŒçããªãªãŒã¹ãããŠããŸãã https://developer.android.com/about/versions/12/download#flash æŽæ°ã§ããæ©çš®ã¯ä»¥äžã«ãªããŸãã Pixel 3 and 3 XL Pixel 3a and 3a XL Pixel 4 and 4 XL Pixel 4a and 4a (5G) Pixel 5 æŽæ°æ¹æ³ã Android Flash Tool ãå©çšããæŽæ°ãšãèªåã®adbç°å¢ãå©çšããæŽæ°ã®2ãã¿ãŒã³ãçšæãããŠããŸãã https://developer.android.com/about/versions/12/download 泚æã§ãïŒãã€ãã®ããšã§ãããèªèº«ã®å€æã§ããã€ã¹ã®ããã¯ã¢ãããåã£ãåŸã«æŽæ°ãè¡ãããã«ããŸããããã¯ãªãŒã³ã€ã³ã¹ããŒã«ããå®è¡ãããŸãã ç§ãPixel 4 XL ã Android 12éçºè
ãã¬ãã¥ãŒç ã«æŽæ°ããŠã¿ãŸãããå©çšããæãã¯å€§ããAndroid 11ããã®å€§ããªå€æŽã¯ãããŸã§æããŸããã§ããããä»åŸãããããšäœ¿ã£ãŠäœããã®éããããã£ãŠããã®ããªãšæã£ãŠããŸãã çŽè¿ã®åé¡ã¯ããã¯ãåããªããªã£ãäžéšã®ã¢ããªãã©ãããããŒãšããç¹ã§æ©ãã§ãããŸãã Jetpack Compose ã¯ïŒ Android ç°å¢ã®å®£èšåUIéçºãã¬ãŒã ã¯ãŒã¯ãšããŠãJetpack Compose ãæšå¹Žã¯è©±é¡ã«ãªããŸããã Jetpack Composeã®ããŒããããçã«ã¯ä»å¹ŽããªãªãŒã¹ã®å¹Žãšãªãäºå®ã§ãã æ£åŒã«ãªãªãŒã¹ãšãªãããšã§ãAndroidã®éçºãã¬ãŒã ã¯ãŒã¯ãšããŠãŸã倧ããªå€åãããããäºãèããããŸããã æ©ã段éããæè¡çãªãã£ããã¢ãããããããŠçœ®ãå¿
èŠãããã§ãããã Jetpack Compose https://www.youtube.com/watch?v=U5BwfqBpiWU&feature=youtu.be&t=1324 æåŸã« 2æã«ãªããæ°OS Android 12æ
å ±ãåºãŠããã®ã§ããããŸã§ä»¥äžã«ã¢ã³ããé«ããæ
å ±ã®ãã£ããã¢ãããããŠãããããšæã£ãŠãããŸãã æšå¹Žåæ§ Android 11 Meetup ãªã©ãéããŠã®æè¡æ
å ±ã®å
±æãããããããªãããšæããŸãã æšå¹Žã®Android 11ã®æŽæ°ã«ã€ããŠã¯ ãã¡ã ã«ãŸãšãŸã£ãŠãããŸãããèå³ã®ããããã¯ã©ããã æ ªåŒäŒç€Ÿã¹ã¿ã¡ã³ã§ã¯äžç·ã«åããšã³ãžãã¢ãåéããŠããŸãã ãèå³ã®ããæ¹ã¯ãã² ãšã³ãžãã¢æ¡çšãµã€ã ãã芧ãã ããã Android ããããã¯ãGoogle ãäœæããã³æäŸããŠããäœåããè€è£œãŸãã¯å€æŽãããã®ã§ããã Creative Commons 3.0 Attribution ã©ã€ã»ã³ã¹ã«èšèŒãããæ¡ä»¶ã«åŸã£ãŠäœ¿çšããŠããŸãã
ã¯ããã« ã¯ãããŸããŠãæ ªåŒäŒç€Ÿã¹ã¿ã¡ã³ã§ãšã³ãžãã¢ãããŠãããŸã æ°žäº ã§ãã ä»åã®èšäºã§ã¯Reactã§ã¡ã¢åã«ããããã©ãŒãã³ã¹ãæèããå®è£
æ¹æ³ã«ã€ããŠæžããããšæããŸãã ãªãããã©ãŒãã³ã¹ãæèããå®è£
ã倧åãªã®ã§ããããã ãªããªãããŠãŒã¶ãŒã®ããæäœã«å¯Ÿããã¬ã¹ãã³ã¹ã®é床ãé«ããããšã¯ãUXã®æèã«ãããŠéåžžã«éèŠãªèŠçŽ ã ããã§ããäŸãã°ã100msæªæºã®ã¬ã¹ãã³ã¹ã«é¢ããŠã¯ãŠãŒã¶ãŒã¯ç¬æã«æããããŸããã100ms ~ 300msã§ã¯ãã§ã«é
ããšæããŠããŸããŸããé
ãããšã«ã¹ãã¬ã¹ãæãããŠãŒã¶ãŒã¯ãå¥ã®ãµãŒãã¹ã«ãªãã¬ã€ã¹ããŠããŸããããããŸããã Reactã§ããã©ãŒãã³ã¹ãåºãã«ã¯ããã³ãã«ãµã€ãºãæžãããªã©ãããã€ãæ¹æ³ã¯ãããŸãããåºæ¬çãªæŠç¥ãšããŠã¯äžèŠãªã¬ã³ããªã³ã°ãæããããšã ãšæããŸãã ãã®äžèŠãªã¬ã³ããªã³ã°ãæå¶ããããã«ã¯ãReactãã©ã®ããã«æ©èœããããçè§£ããå¿
èŠããããŸããçè§£ããªããŸãŸæ¹åãè¡ããšãåŽã£ãŠããã©ãŒãã³ã¹ã«æªåœ±é¿ãåºãå¯èœæ§ããããŸãã ãã®ãããããã©ãŒãã³ã¹æ¹åã«ç¹ããã¡ã¢åçã®ã¡ãœããã説æããåã«ããã®Reactãã¬ã³ããªã³ã°ã«ãããŠã©ã®ããã«æ©èœããŠãããã説æããããšæããŸãã ã¯ããã« ä»®æ³DOMã«ããReactã®æŽæ°åŠç Reactã®ã¡ã¢å React.memo useCallback useMemo æåŸã« ä»®æ³DOMã«ããReactã®æŽæ°åŠç Reactã§ã¯DOMã®æŽæ°åŠçããä»®æ³DOMã«ããå·®åæŽæ°åŠçã«ä»»ããããšã§ãããã©ãŒãã³ã¹ãé«ããŠããŸãã å
·äœçã«èšããšãå®éã®DOMãJavascriptãªããžã§ã¯ãã®åœ¢åŒã«å€æããããªãŒããŒã¿ãã¡ã¢ãªäžã«äœæããã³ã³ããŒãã³ãã®ç¶æ
ã«å€æŽããã床ã«ãå®éã®DOMãæŽæ°ããã®ã§ã¯ãªãä»®æ³DOMãæŽæ°ããŸãã æŽæ°ãããä»®æ³DOMãšå€ãä»®æ³DOMãæ¯èŒãå·®åãæ€åºããããšã§ãå®éã®DOMã«ã¬ã³ããªã³ã°ãè¡ããŸãã ããããããšã§å®éã®DOMã§ã¯å¿
èŠæäœéã®ç®æã®ã¿ã¬ã³ããªã³ã°ãè¡ãããšãå¯èœã«ãªããŸãã äŸãã°ä»¥äžã®ãããªã³ãŒãããããšããŸãã const Page = () => { return ( < div > < p > Counter App < /p > < Counter / > < /div > ) } const Counter = () => { const [ count , setCount ] = useState ( 0 ) return ( < div > < span > { count } < /span > < button onClick = { () => setCount ( count + 1 ) } > + < /button > < /div > ) } ä»®æ³DOMãšããŠã¯ãååã¬ã³ããªã³ã°æã«PageãšCounterã³ã³ããŒãã³ãã§èšè¿°ãããJSXãå
ã«ãJavascriptã§æ§ç¯ããä»®æ³DOMããªãŒãçæããŸãããããŠã + ãæŒããšã count ã®stateãæŽæ°ãããŠã¬ã³ããªã³ã°ãèµ°ãã count ã®ç®æã 2 ãšãªã£ãæ°ããä»®æ³DOMããªãŒãçæããŸãããããŠæ°æ§2ã€ã®ä»®æ³DOMããªãŒãæ¯èŒããŠå·®åãæ€åºããå·®åããã£ãç®æã§ãã <span>{count}</span> ã ããå®éã®DOMã«åæ ããŸãã ãã®ããã«ãä»®æ³DOMã®æŠå¿µã«ãã£ãŠå¿
èŠæäœéã®ç®æã®ã¿DOMã倿Žããããšãã§ããŸãã Reactã®ã¡ã¢å ä»®æ³DOMã«ããå·®åæŽæ°ã«ãã£ãŠã倿Žç®æã®ã¿ãã¬ã³ããªã³ã°ããããšãã§ããŸããããããé
äžã®ã³ã³ããŒãã³ããåæç»ããããããäžå¿
èŠãªç®æãŸã§åã¬ã³ããªã³ã°ãããŠããŸããŸãã ããã§ãReactã«ããã¡ã¢åã«ãã£ãŠã³ã³ããŒãã³ãã«å€æŽããªãå Žåã¯ã¬ã³ããªã³ã°ãããªãããã«ããŸãããã React.memo Reactã®é«é颿°ã§ãã React.memo ã¯ã³ã³ããŒãã³ããã¡ã¢åããäžã§ãã䜿ãããææ³ã§ãã äŸãã°ä»¥äžã®ãããªã³ãŒãããããšããŸãã const Parent = () => { const [ parentName , setParentName ] = useState ( '' ) return ( < div > < span > parent is { parentName } < /span > < input type= "text" onChange = { e => setParentName ( e. target .value ) } / > < Child / > < /div > ) } const Child = () => { return ( < div > < span > I am Child < /span > < /div > ) } ãã®æã <input //... /> ã«æåãå
¥åãããš setParentName ãçºç«ã㊠name ãæŽæ°ãããŸããstateãæŽæ°ãããã®ã§Parentã³ã³ããŒãã³ãã¯ã¬ã³ããªã³ã°ãããŸãããChildã³ã³ããŒãã³ãã¯ã©ãã§ããããïŒ è©Šãã« console.log('child') ãä»èŸŒãã§ã¿ãŸãããã const Child = () => { console.log ( 'child' ) return ( < div > < span > I am Child < /span > < /div > ) } åã³ <input //... /> ã«æåãå
¥åããŠã¿ãŸãããããããš... => child ãchildããšè¡šç€ºãããŠããŸããŸãããã€ãŸããæåãå
¥åãã床ã«çºçããParentã³ã³ããŒãã³ãã®ã¬ã³ããªã³ã°ã«ä»éããŠãChildã³ã³ããŒãã³ããæ¯åã¬ã³ããªã³ã°ãããŠããŸã£ãŠããã®ã§ãã æ¬æ¥ã§ããã°ãã®ã¬ã³ããªã³ã°ã¯äžèŠãªã®ã§ãããã©ãŒãã³ã¹ãèæ
®ããã®ã§ããã°é²ãããã¬ã³ããªã³ã°ã§ãã ãã®ã¬ã³ããªã³ã°ãæããããã«ã React.memo ã䜿ããŸãã const Child = React.memo (() => { console.log ( 'child' ) const return ( < div > < span > I am Child < /span > < /div > ) } ) ãã®ã³ãŒãã§ã¯ React.memo ã§ã³ã³ããŒãã³ããã©ããããããšã§ãChildã³ã³ããŒãã³ãã«æž¡ãpropsã«å€æŽããªãå Žåã«ãã¬ã³ããªã³ã°ãã¹ãããããŠããŸããParentã³ã³ããŒãã³ãã«ãã <input //... /> ã§åã³æåãå
¥åããŠã¿ããšãã³ã³ãœãŒã«ã«ã¯äœãåºåãããŠããªãããšã確èªã§ãããšæããŸãã ãã® React.memo ã§propsã®ååŸã®å€ãæ¯èŒããŠã¬ã³ããªã³ã°ããããæ±ºå®ããŠããèš³ã§ããããã®æ¯èŒã¯æµ
ãæ¯èŒã§è¡ãããŸããæè¬ããªããžã§ã¯ãã®ã€ã³ã¹ã¿ã³ã¹ã«ãããåç
§ãç°ãªããã©ãããèŠãŠããŸãã â» React.memo ã¯ç¬¬2åŒæ°ã«äœãæå®ããªããšãããã©ã«ãã§ã¯æµ
ãæ¯èŒã§è¡ãããŸãã第2åŒæ°ã«æ¯èŒé¢æ°ãæž¡ãããšã§ã¬ã³ããªã³ã°ãã«ã¹ã¿ã ã§å¶åŸ¡ããããšãã§ããŸãããåºæ¬çã«ã¯ç䟡æ§ã®ãã§ãã¯ã«ã¯ã³ã¹ããæããã®ã§é¿ãããã§ãã ãã®ããã«ã React.memo ã䜿çšããããšã§ãæ¬æ¥å€æŽãããŠããªãã³ã³ããŒãã³ãã®ã¬ã³ããªã³ã°ãæããããšãã§ããŸãããäžã€èœãšã穎ããããŸãã æ¬¡ã®ã³ãŒããèŠãŠã¿ãŠãã ããã const Parent = () => { const [ parentName , setParentName ] = useState ( '' ) const [ childName , setChildName ] = useState ( '' ) const childNameHandler = ( e: React.ChangeEvent < HTMLInputElement >) => { setChildName ( e. target .value ) } return ( < div > < span > parent is { parentName } < /span > < input type= "text" onChange = { e => setParentName ( e. target .value ) } / > < Child name = { childName } onChange = { childNameHandler } / > < /div > ) } const Child = React.memo (( { name , onChange } ) => { console.log ( 'child' ) return ( < div > < span > child is { name } < /span > < input type= "text" onChange = { onChange } / > < /div > ) } ) 倿Žããç®æãšããŠã¯ãChildã³ã³ããŒãã³ãã«stateã® name ãšé¢æ°ã® childNameHandler propsã§æž¡ããŠããŸãã ãã®ã³ãŒãã§åã³Parentã³ã³ããŒãã³ãã«ãã <input //... /> ã«æåãå
¥åããŠã¿ãŸãããããããš... => child React.memo ã§ã¡ã¢åããŠããã®ã«ãé¢ããããåã³ã¬ã³ããªã³ã°ãããŠããŸããŸããããã®åå ã¯ã childNameHandler 颿°ã«ãããŸãã ã¢ããŒé¢æ°ã¯ã¬ã³ããªã³ã°ã®åºŠã«æ°ãã颿°ãªããžã§ã¯ããçæããŸããããã®é¢æ°ãªããžã§ã¯ãã®åçæã«ãã£ãŠãpropsãšããŠæž¡ããŠãã childNameHandler ã®åç
§ã倿ŽãããŠããŸããChildã³ã³ããŒãã³ããã¬ã³ããªã³ã°ãããŠããŸãã®ã§ããïŒ (() => {}) !== (() => {}) ã§ããããïŒ ãããé²ãæ¹æ³ãšã㊠useCallback ããããŸãã useCallback useCallback ãçšããŠæ¹åããã³ãŒãã¯ä»¥äžã®ããã«ãªããŸãã const Parent = () => { const [ parentName , setParentName ] = useState ( '' ) const [ childName , setChildName ] = useState ( '' ) const childNameHandler = useCallback (( e: React.ChangeEvent < HTMLInputElement >) => { setChildName ( e. target .value ) } , [] ) return ( < div > < span > parent is { parentName } < /span > < input type= "text" onChange = { e => setParentName ( e. target .value ) } / > < Child name = { childName } onChange = { childNameHandler } / > < /div > ) } useCallback ã¯ãã¡ã¢åããã颿°ãªããžã§ã¯ããè¿ãhooks APIã§ãã第2åŒæ°ã«ããŠããé
åã¯äŸåé
åã§ãé
åå
ã®ããããã®å€ã倿Žããããšãæ°ãã颿°ãªããžã§ã¯ããçæããŸãã useCallback ã䜿çšããå Žåã¯ãåºæ¬çã« React.memo ã«ãã£ãŠæé©åãããã³ã³ããŒãã³ãã«propsãšããŠæž¡ãå Žåã«éå®ããã¹ãã§ãã React.memo ã䜿çšããŠããªãã³ã³ããŒãã³ãã« useCallback ã«ãã£ãŠã¡ã¢åãã颿°ãæž¡ãããšããŠãã芪ã³ã³ããŒãã³ããã¬ã³ããªã³ã°ããããšåã³ã³ããŒãã³ãã¯ã¬ã³ããªã³ã°ãããŠããŸãããã§ãã ãŸãã React.memo ã«ãã£ãŠã¡ã¢åãããã³ã³ããŒãã³ãã«æž¡ããªãå Žåã«ã useCallback ã§ã¡ã¢åããã®ã¯é¿ããæ¹ãè¯ããšèšãããŠããŸãããã㯠useCallback ã®å®è¡ã³ã¹ãã¯é¢æ°ãªããžã§ã¯ãã®åçæã®ã³ã¹ããããé«ããšèšãããŠããããã§ãã useMemo useMemo ã¯é¢æ°ã®è¿ãå€ãã¡ã¢åããéã«äœ¿çšããŸãïŒ useCallback ã¯é¢æ°èªäœãã¡ã¢åããŸãïŒ äŸãã°ã以äžã®ãããªé¢æ°ããããšããŸããïŒãããªã³ãŒãã¯çŸå®ã«ã¯ååšããªããšæããŸãããããŸã§ãµã³ãã«ãšããããšã§ïŒ const someCalculate = () => { let number = 0 ; while( number <= 1000 ) { console.log ( number ) number ++ } return count * number } éåžžã«ã·ã³ãã«ãªã³ãŒãã§ããã倿° number ã1000ã«ãªããŸã§1ãã€è¶³ããŠãããæçµçã«å€æ° count ãšä¹ç®ãããšãããã®ã§ãã useMemo ã§ã¯ãã®èšç®çµæãã¡ã¢åããããšãã§ããèšç®èªäœãã¹ãããããããšãã§ããŸãã(以äžã®ã³ãŒã) const memorized = useMemo (() => { let number = 0 ; while( number < 1000 ) { console.log ( number ) number ++ } return count * number } , [ count ] ) useMemo ã®äŸåé
åã«ã¯ count ãå
¥ããŠããŸããcountãå€åãããšåèšç®ããå¿
èŠããããŸããã count ãäžå€ã®å Žåã¯èšç®çµæãã¡ã¢åããŠå©çšããããšãã§ããŸãã æåŸã« Reactã§ã®ã¡ã¢åã«ã€ããŠä»åæžããŸãããæ®éã«Reactã§å®è£
ããŠããŠãç»é¢èªäœã¯åºæ¥ãŠããŸãã®ã§ãããReactã®ã¬ã³ããªã³ã°ãã¡ã¢åã«ã€ããŠç¥ããªããšãå®ã¯ããªãããã©ãŒãã³ã¹ãæªãå®è£
ã«ãªã£ãŠããŸãããšã¯åŸã
ã«ããŠãããšæããŸãã åŒç€Ÿã®ãããã¯ãã§ããTUNAGã§ããããã³ããšã³ãé åã«ãããŠããã©ãŒãã³ã¹ãæé©åããããŠããªãéšåããŸã ãŸã ããã®ã§ãåŸã
ã«æé©åã§ããã°ãšæããŸãã ã¹ã¿ã¡ã³ã§ã¯äžç·ã«åããšã³ãžãã¢ãåéããŠããŸãã èå³ãããæ¹ã¯ããã² æ¡çšãµã€ã ãããé£çµ¡ãã ããïŒ
ããã«ã¡ã¯ãã¹ã¿ã¡ã³ã§TUNAGãFANTSã®ã¢ãã€ã«ã¢ããªéçºãæ
åœããŠãã @temoki ã§ãã å
é±ãTwitter iOSã¢ããªã§äœ¿çšãããŠããããã¹ããšãã£ã¿ã TwitterTextEditor ãšããOSSãšããŠå
¬éãããiOSã¢ããªãšã³ãžãã¢ã®éã§è©±é¡ã«ãªããŸãããã以äžãTwitterå
¬åŒã®ãšã³ãžãã¢ãªã³ã°ããã°ã«ãã玹ä»èšäºã§ãã blog.twitter.com ç§ã¯TUNAG iOS/Androidã¢ããªã®éçºã®äžã§ãã¡ã³ã·ã§ã³ãçµµæåã®ã·ã§ãŒãã³ãŒãå
¥åãåããããã¹ãå
¥åæ©èœã®å®è£
ã«èŠåŽããŠããŠããããšãããããã®OSSã®å
¬éã¯ãšãŠãèå³ãããããããã®ã§ããã®ã§ãæ©é詊ããŠã¿ãããšã«ããŸãããä»åã®ããã°ã§ã¯ãå®éã«ãã® TwitterTextEditor ãå©çšãããšãã芳ç¹ã§æžããããšæããŸãã 以éã®å
容㯠TwitterTextEditor v1.0.0 æç¹ã§ã®å
容ãšãªããŸããTwitterTextEditor ã®æŠèŠã«ã€ããŸããŠã¯ãäžèšã®å
¬åŒããã°ããããæ¥æ¬èªã§ç޹ä»ãããŠãã以äžã®èšäºãã芧ãã ããã TwitterがiOSアプリ向けに新しいオープンソースのテキストエディタAPI「Twitter Text Editor」を発表 - GIGAZINE TwitterTextEditorã®æ©èœ å
¬åŒããã°ã§ã¯ TwitterTextEditor ã®æ©èœãšããŠä»¥äžã®ïŒã€ã«ã€ããŠæããããŠããŸãã®ã§ãïŒã€ïŒã€å®éã®ã³ãŒããªã©ã亀ããªãã玹ä»ããŠãããŸãã Easy delegate-based APIs Robust text-attribute update logic Additional text editing events Safe event handling for text input Support for recent versions of iOS Easy delegate-based APIs TwitterTextEditor 㯠UIKit ãšåããããªããªã²ãŒãããŒã¹ã®APIãæäŸãããŠããŸããäŸãã°ããã¹ãå
¥åã®éå§ã»çµäºã®ã€ãã³ã㯠TextEditorViewEditingDelegate ãšãããããã³ã«ãå®è£
ããããšã§ãã³ãã«ããããšãã§ããŸããããã㯠UITextViewDelegate ã®ãããšã»ãŒåãã«ãªã£ãŠããããšãããããŸãã public protocol TextEditorViewEditingDelegate : AnyObject { func textEditorViewShouldBeginEditing (_ textEditorView : TextEditorView ) -> Bool func textEditorViewDidBeginEditing (_ textEditorView : TextEditorView ) func textEditorViewDidEndEditing (_ textEditorView : TextEditorView ) } ãšããã®ã TwitterTextEditor 㯠UITextView ãå
å
ããŠãããã UITextView ã§æäŸãããŠããæ©èœã¯ã»ãŒç¶²çŸ
ãããŠããã®ã§ãããã®ãããæ¢åã®ãããžã§ã¯ãã§ãã§ã« UITextView ãçµã¿èŸŒãã§ããã¹ãå
¥åãå®è£
ããŠããç®æã容æã«çœ®ãæããããšãã§ãããã§ãã TwitterTextEditor ã¯ã€ãã³ãã®çš®é¡ã«å¿ããŠè€æ°ã®ãããã³ã«ã«åå²ãããŠããŸãã textEditorView.font = UIFont.systemFont(ofSize : 15 ) textEditorView.keyboardType = . default textEditorView.textContentInsets = . init (top : 10 , left : 10 , bottom : 10 , right : 10 ) textEditorView.placeholderText = "ã¡ãã»ãŒãžãå
¥å" // ãã¬ãŒã¹ãã«ããŒå¯Ÿå¿ð textEditorView.editingDelegate = self ãããŠå人çã«å¬ããã®ã¯ããã¬ãŒã¹ãã«ããŒã®è¡šç€ºã«å¯Ÿå¿ããŠããç¹ã§ããåã UIKit ã® UITextField ã¯ãã¬ãŒã¹ãã«ããŒã®è¡šç€ºã«å¯Ÿå¿ããŠããã®ã«ããªãã UITextView ã¯å¯Ÿå¿ããŠããªããŠãæ³£ãæ³£ãå®è£
ãã...ãšããããšããªããªããŸããã Robust text-attribute update logic ããããã TwitterTextEditor ãæ¬é çºæ®ããéšåãšãªããŸããTwitterTextEditor ã¯ããã¹ã屿§ãæŽæ°ããããã®APIãæäŸããŠãããäŸãã°ã·ã³ã¿ãã¯ã¹ãã€ã©ã€ãã®ãããªæ©èœãå®è£
ãããããªã£ãŠããŸãã Twitterã¢ããªã§ãããšã¡ã³ã·ã§ã³ãããã·ã¥ã¿ã°ã®ãã€ã©ã€ã衚瀺ã§ãããäŸãã° Markdown ããã¹ãã®å
¥åã«å¯Ÿããç°¡åãªãã¬ãã¥ãŒæ©èœãªããã«ãå¿çšã§ãããã§ãã詊ãã«äºã€ã®ã¢ã¹ã¿ãªã¹ã¯ã§å²ãã§åŒ·èª¿è¡šç€ºããèšæ³ïŒ **text strong emphasis** ) ã§å®è£
ããŠã¿ãŸãã ããã¹ã屿§ãæŽæ°ã§ããã¿ã€ãã³ã°ã§ TextEditorViewTextAttributesDelegate ãããã³ã«ã®ã¡ãœãããåŒã³åºãããŸãã®ã§ãããã§å±æ§ãæŽæ°ããŠè¿ããŸããæŽæ°çµæã¯ completion ãã³ãã©ãä»ããŠè¿ãããšã«ãªãã®ã§ãããã¯ã°ã©ãŠã³ãã§ããã¹ãã®è§£æãšå±æ§æŽæ°ãè¡ããã®ããã€ã³ãã§ãã extension EditorViewController : TextEditorViewTextAttributesDelegate { func textEditorView (_ textEditorView : TextEditorView , updateAttributedString attributedString : NSAttributedString , completion : @escaping (NSAttributedString?) -> Void ) { // ããã¯ã°ã©ãŠã³ãã§ããã¹ããè§£æããŠå±æ§ãæŽæ°ãã DispatchQueue.global().async { // ããã¹ãã®è§£æ let regex = try ! NSRegularExpression(pattern : "(\\*+)(\\s*\\b)([^\\*]*)(\\b\\s*)(\\*+)" , options : [] ) let stringRange = NSRange(location : 0 , length : attributedString.length ) let matches = regex.matches( in : attributedString.string , options : [] , range : stringRange ) // ããã¹ã屿§ã®æŽæ° let newAttributedString = NSMutableAttributedString(attributedString : attributedString ) newAttributedString.removeAttribute(.font, range : stringRange ) newAttributedString.addAttribute(.font, value : UIFont.systemFont (ofSize : 15 ), range : stringRange ) for match in matches { newAttributedString.addAttribute(.font, value : UIFont.boldSystemFont (ofSize : 15 ), range : match.range ) } // ã¡ã€ã³ã¹ã¬ããã§æŽæ°çµæãè¿ã DispatchQueue.main.async { completion(newAttributedString) } } } } å®è¡çµæã®åç»ã§ãã ããæãã§ããããã ãMarkdown ã¯å€ãã®èšæ³ããããç·šéããããã¹ãã®ãµã€ãºã倧ãããªãå¯èœæ§ãé«ãã§ããå®éã« Markdown ãšãã£ã¿ãå®è£
ããå Žåããã®TwitterTextEditorã®æ©èœããã¹ãŠã解決ãããã®ã§ã¯ãªãããšãçè§£ããŠããå¿
èŠããããŸããéçºè
ã® @niw ãããTwitterã§æ¬¡ã®ãããªããšããã£ããã£ãŠããŸãã Nothing prevents to support it! (or probably Markdown grammar itself is, tho.) However, a partial attribute update logic may be needed, depends on the expected size of editing text. — Yoshimasa Niwa (@niw) 2021幎1æ26æ¥ Additional text editing events Twitterã¯äžçäžã§å©çšãããŠããã¢ããªã§ãã®ã§ãããããèšèªã§ã®å
¥åã«å¯Ÿå¿ããªããã°ãªããŸããããã®ãããTwitterTextEditor ã«ã¯å€èšèªãžã®å¯Ÿå¿ãèæ
®ããããã¹ãå
¥åã€ãã³ãã远å ãããŠããŸãã以äžããã®ã€ãã³ãã§ãã å
¥åäžã®èšèªãåãæ¿ãã£ãæã®ã€ãã³ã ããã¹ãå
¥åã®æ¹åãåãæ¿ãã£ãæã®ã€ãã³ãïŒã¢ã©ãã¢èªãªã©ã® Right-to-left writing ãªèšèªãžã®èæ
®ïŒ ãã㯠TextEditorViewTextInputObserver ãããã³ã«ãšããŠæäŸãããŠããŸãããã®ã€ãã³ããããªã¬ãŒã«ãå
¥åã®ããã®UIã®åãæ¿ããªã©ã«äœ¿ãããããšãæ³å®ãããŠããããã§ãã public protocol TextEditorViewTextInputObserver : AnyObject { func textEditorView (_ textEditorView : TextEditorView , didChangeInputPrimaryLanguage inputPrimaryLanguage : String ?) func textEditorView (_ textEditorView : TextEditorView , didChangeBaseWritingDirection writingDirection : NSWritingDirection ) } Safe event handling for text input äŸãã°ãå
¥åæžã®æåæ°ã衚瀺ããããå
¥åäžã®ããã¹ãå
容ã«å¿ããå
¥åãµãžã§ã¹ããªã©ãè¡ãããã«ã¯ããŠãŒã¶ãŒã®ããã¹ãå
¥åã€ãã³ãã䜿çšããŸãã UITextView ã§ãã®ã€ãã³ãããã³ããªã³ã°ããã«ã¯ã UITextViewDelegate ã®ä»¥äžã®ããªã²ãŒãã¡ãœããã䜿ãããšã«ãªããŸãã func textView (UITextView, shouldChangeTextIn : NSRange , replacementText : String ) -> Bool func textViewDidChange (UITextView) TwitterTextEditor ã§ã¯ããããããå®å
šã«ããã¹ãå
¥åã€ãã³ãããã³ããªã³ã°ããããã® TextEditorViewChangeObserver ãããã³ã«ãæäŸãããŠããŸãã TwitterTextEditor ã®ãœãŒã¹ã³ãŒãã®äžã«ã¯ // UIKit behavior ~ ãšããã³ã¡ã³ãã§ãUIKit ã®åäœã®åé¡ç¹ãšãã®ã¯ãŒã¯ã¢ã©ãŠã³ããšãã£ãæ
å ±ãããããèšè¿°ãããŠããããããããµãŸããäžã§å®å
šãªã€ãã³ããæäŸããŠããããšããããã§ããã public protocol TextEditorViewChangeObserver : AnyObject { func textEditorView (_ textEditorView : TextEditorView , didChangeWithChangeResult changeResult : TextEditorViewChangeResult ) } iOSã¢ããªã§ã®ããã¹ãå
¥åã®é£ããããã®è§£æ±ºæ¹æ³ã«ã€ããŠã¯ãäœè
ã® @niw ãããæšå¹Žã® iOSDC Japan 2020 ã§ãçºè¡šãããŠããŸãã®ã§ããã²ã芧ããã ãããã§ãã www.youtube.com ãã®ãã¬ãŒã³ããŒã·ã§ã³ã®äžã§ã¯ãããã¹ãå
¥åã䌎ãã¢ããªãéçºããå ŽåããœãããŠã§ã¢ããŒããŒãã®è¡šç€ºç¶æ
ã®å€æŽã«ã€ããŠãæ°ã«ããªããå®è£
ããå¿
èŠããããšããç¹ã«ã€ããŠãèšåãããŠãããããã«ã€ããŠã¯åãã @niw ãããå
¬éãããŠãã KeyboardGuide ãšããã©ã€ãã©ãªã§ã¹ããŒãã«è§£æ±ºããããšãã§ããã®ã§ããã¡ãããªã¹ã¹ã¡ã§ãã GitHub - niw/KeyboardGuide: A modern, real iOS keyboard system notifications handler framework that Just Works. Support for recent versions of iOS TwitterTextEditor ã¯ãµããŒãããŒãžã§ã³ãšã㊠iOS 11 以éãšããè¯å¿çãªèšå®ã«ãªã£ãŠããŸãïŒTwitter iOS ã¢ããªã®æå°ããŒãžã§ã³ã iOS 12 ãªã®ã«ïŒïŒã ãããŠããµããŒããããŠããããã±ãŒãžãããŒãžã£ãŒã CocoaPodsãCarthageãSwift Package Manager ãšäžè¬çãªãã®ã¯å
šãŠæã£ãŠããã®ã§å°å
¥ã§å°ããšããããšã¯ãªãããã§ããã ãããã« äžçäžã§å©çšããã Twitter iOS ã¢ããªããã®ããã¹ãå
¥åãæ¯ããOSSã TwitterTextEditor ã«ã€ããŠã玹ä»ããããŸãããããããã§ããã§ããããã ãã®ããã°ãæžãã«ããã£ãŠ TwitterTextEditor ã®ãœãŒã¹ã³ãŒããçºããŠã¿ãŸãããããšãŠãå匷ã«ãªãéšåãå€ãã£ãããäœè
ã®å®è£
ã®èŠåŽãå£éèŠãããããŸããããŸããèªåã TUNAG ã¢ããªã®éçºã§å®è£
ããã³ãŒãã«é¡äŒŒããŠãããšãããããã€ãèŠã€ããŠèŠªè¿æãæ²žããããããã®ã§ãæ¹ããŠäººã®ãœãŒã¹ã³ãŒããèªãã®ã¯éèŠãªããšã ãªãšæããŸããã æåŸã«ãªããŸãããã¹ã¿ã¡ã³ã§ã¯ TUNAG ã FANTS ãããŠæ°ããäºæ¥ã«ããããããã¯ãéçºãäžç·ã«çœåŒããŠããã仲éãåéããŠããŸãããšã³ãžãã¢ã«éããããã¶ã€ããŒããããã¯ããããŒãžã£ãŒè·ãåéäžã§ãã®ã§ãèå³ã®ããæ¹ã¯äžèšã®å¿åãããé£çµ¡ãã ããïŒ ãšã³ãžãã¢æ¡çšãµã€ã ã€ã³ããŠã¹ãã¶ã€ããŒWantedïŒåå€å±ã§æ³šç®ã®ãã³ãã£ãŒã§æŽ»èºããŸããã æ¥æé·ããå€§èŠæš¡ SaaSãããã¯ãã®ãããã¯ããããŒãžã£ãŒåéïŒïŒ
ã¹ã¿ã¡ã³ã§ãšã³ãžãã¢ãããŠãã ç°äž ã§ãã ä»åã¯æ±ºæžãã©ãããã©ãŒã ã§ããStripeã®ãµãã¹ã¯ãªãã·ã§ã³ãæ±ãéã«ééããåé¡ã«ã€ããŠãçºçããäºè±¡ãšãã®åå ãããã³å¯Ÿçæ¹æ³ã«ã€ããŠã玹ä»ããŸãã ãªããæ¬èšäºã§ã¯Stripeã®ãµãã¹ã¯ãªãã·ã§ã³ã«ã€ããŠã®è©³çްã¯èª¬æããããŸããããŸããå¯Ÿçæ¹æ³ã«ã€ããŠã¯Rubyã®ã³ãŒãã§èšèŒããŸããRubyã§Stripeã®ãµãã¹ã¯ãªãã·ã§ã³ãæ±ãå Žåã«ã€ããŠã¯ã以äžã®èšäºã«ãŠç޹ä»ããŠããã®ã§ãããããã°ãåç
§ãã ããã ãRuby on RailsãStripeã®ãµãã¹ã¯ãªãã·ã§ã³ã§è©ŠããããšããŸãšããŠã¿ã ãŸãã以åã«ãåæ§ã®ã¿ã€ãã«ã§èšäºãæçš¿ããŸããããä»åã¯å
容ãè¥å¹²ç°ãªããŸãããã ãååã®èšäºã®ç¥èããããšçè§£ãæ©ããªããšæãã®ã§ããã®æ©äŒã«èªãã§ããã ããã°ãšæããŸãã(ã¿ã€ãã«ã®æ¬åŒ§ã®äžèº«ãç°ãªããŸã) ãStripeããµãã¹ã¯ãªãã·ã§ã³ã®æ¯æãã¿ã€ãã³ã°ãç¹å®æ¥æã«ãããŠãºã¬ãåé¡ã«ã€ããŠ(ææ«ç) åæ æ¬èšäºã§æ±ããµãã¹ã¯ãªãã·ã§ã³ã¯è«æ±æéãææ¬¡ã®ãã®ã§ã ãµãã¹ã¯ãªãã·ã§ã³ã®æ¯æãæ¥ã«ã€ããŠãéåžžãç¿æã«åãæ¥ãååšããªãå Žåã¯èªåçã«ãã®åã®æ¥ãæå®ããŠãããŸã äŸ 5/31 â 6/30 8/31 â 9/30 åè https://stripe.com/docs/billing/subscriptions/billing-cycle çºçããäºè±¡ 以äžã®ç»åã®ããã«ãåãæ¥(1æ¥)ã«ãµãã¹ã¯ãªãã·ã§ã³ãéå§ããŸãããã2åç®ã®æ¯æãã®ã¿ã€ãã³ã°ããºã¬ãŠããŸããšããããšããããŸããã 2åç®ã®æ¯æããå忝æããšåãæ¥(1æ¥)ã«è¡ãããŠããã±ãŒã¹ 2åç®ã®æ¯æããå忝æããšç°ãªãæ¥ã«è¡ãããŠããã±ãŒã¹ ãã®ãããäŸãã°æ¯æãæåæã®Webhookã«ãŠäœãããã®åŠçãããå Žåã«ããã®ãºã¬ã«ãã£ãŠåœ±é¿ãçºçããå¯èœæ§ã倧ãã«èããããŸãã çºçåå å
æ¥ã玹ä»ããèšäºãšåæ§ã billing_cycle_anchor ãšã¿ã€ã ãŸãŒã³ã®é¢ä¿ã«ãããã®ã ãšæãããŸãã 以äžã¯ãéå»èšäºã®åŒçšã§ãã ããã§ã billing_cycle_anchor ã«ã€ããŠèª¬æããŸãã billing_cycle_anchor ãšã¯æ¯æãéå§ã®èµ·ç¹ãšãªãæ¥æã®ããšã§ããããšãã°ãæ¯æ1æ¥ã«æ±ºæžãããå Žåããµãã¹ã¯ãªãã·ã§ã³äœææã« billing_cycle_anchor ã«ç¿æã®1æ¥ãæå®ããããšã§ãæ¯æ1æ¥æããå®çŸããããšãåºæ¥ãŸããç¹ã«æå®ãããªããã°ããµãã¹ã¯ãªãã·ã§ã³äœææå» = billing_cycle_anchor ãšãªããŸãã åè https://stripe.com/docs/billing/subscriptions/billing-cycle çºçåå ã«ã€ããŠã®è©³çްã¯äžèšã®éãã§ãã Stripeã®ã·ã¹ãã ã¯ãUTCåºæºã§åäœãã æ¥æ¬æé(JST)ã§ãµãã¹ã¯ãªãã·ã§ã³ãäœæããå Žåã«ãUTCã®æå»ãã9æéã®å·®ããã ãã®ãããUTCåºæºã§ã¯ææ«ã ããæ¥æ¬æéã ãšç¿æãšå€å®ãããŠããŸãããä»åã®åé¡ãçºçãã ããã ãã ãšããåãããªããããå
·äœäŸãæããŠèª¬æããŸãã å
·äœäŸ ïŒ1ïŒ12/1 åå0æã«ãµãã¹ã¯ãªãã·ã§ã³ãäœæããå Žå ã»æ¥æ¬æéã2020-12-01 00:00:00ãã«billing_cycle_anchorãæå® æ¯æåæ° ããã·ã¥ããŒãäžã®æåïŒJSTïŒ å®éã®æå(UTC) 1åç® 2020-12-01 00:00:00 2020-11-30 16:00:00 2åç® 2020-12-31 00:00:00 2020-12-30 16:00:00 3åç® 2020-01-31 00:00:00 2021-01-30 16:00:00 4åç® 2020-03-01 00:00:00 2021-02-28 16:00:00 ïŒ2ïŒ11/1 åå0æã«ãµãã¹ã¯ãªãã·ã§ã³ãäœæããå Žå ã»æ¥æ¬æéã2020-11-01 00:00:00ãã«billing_cycle_anchorãæå® æ¯æåæ° ããã·ã¥ããŒãäžã®æåïŒJSTïŒ å®éã®æå(UTC) 1åç® 2020-11-01 00:00:00 2020-10-31 16:00:00 2åç® 2020-12-01 00:00:00 2020-11-30 16:00:00 3åç® 2021-01-01 00:00:00 2020-12-31 16:00:00 4åç® 2021-02-01 00:00:00 2020-01-31 16:00:00 (1)ã«é¢ããŠã¯UTCåºæºã®å Žåã«billing_cycle_anchorã2020-11-30 16:00:00ã§èšå®ãããŠããŸããããæ¬¡å以éã®æ¯æããµã€ã¯ã«ã以äžã®éãã«ãªã£ãŠããŸããŸãã 31æ¥ãããæã¯31æ¥ã«æ¯æã 31æ¥ããªãæã¯1æ¥ã«æ¯æã (2)ã«é¢ããŠã¯UTCåºæºã®å Žåã«billing_cycle_anchorã2020-10-31 16:00:00ã§èšå®ãããã®ã§ã次å以éã®æ¯æããµã€ã¯ã«ã¯æ¯æ1æ¥æ¯æããšãªããŸãã äžèšã®ããšãããæ¥æ¬æéã«ãããŠä»¥äžã®æ¥æã«ãµãã¹ã¯ãªãã·ã§ã³ãäœæããããšä»åã®åé¡ãçºçãããšèããããŸãã åæã31æ¥ãŸã§ãªãæã®1æ¥(3æ1æ¥, 5æ1æ¥, 7æ1æ¥, 10æ1æ¥, 12æ1æ¥) åå0æããåå9æã®é å¯Ÿçæ¹æ³ ç¹å®æ¥æã§ãµãã¹ã¯ãªãã·ã§ã³ãäœæããå Žåã trial_end ãçšããŠæ¬¡å以éã®æ¯æãæ¥æããããããšã§å¯Ÿå¿ããŸãã 詳现ã«ã€ããŠã¯ ååã®èšäº ãã確èªãã ããã ãããã« ä»åã¯Stripeã®ãµãã¹ã¯ãªãã·ã§ã³ãæ±ãéã«ééããåé¡ã«ã€ããŠã玹ä»ããŸããã æå·®ããã³æã«ãã£ãŠæ¥æ°ãç°ãªãããšãèæ
®ããªããšæ³å®å€ã®æåãçºçããå¯èœæ§ãããã®ã§ãåãæ±ãéã«ã¯ãã®ç¹ãé ã«å
¥ããŠå®è£
ããŠãããŸãããã æåŸã«ãæ ªåŒäŒç€Ÿã¹ã¿ã¡ã³ã§ã¯äžç·ã«åããšã³ãžãã¢ãåéããŠããŸãããèå³ã®ããæ¹ã¯ãã² ãšã³ãžãã¢æ¡çšãµã€ã ãã芧ãã ããã
ããã«ã¡ã¯ãã¹ã¿ã¡ã³ã§VPoEå
Œãããã¯ãéšã®éšé· ãããŠããå°æã§ãã 1æãååãçµãããã¹ã¿ã¡ã³ã§ã¯æ°ããããŒã ããããžã§ã¯ããç«ã¡äžãããæ¬æ Œçã«2021幎ãã¹ã¿ãŒãããŠããŸãã æšå¹Žæ«ã«ãCTOã®æŸè°·ãæè¡ãäžå¿ã«ã ã¹ã¿ã¡ã³éçºããŒã 2020å¹Žã®æ¯ãè¿ããš2021幎ã®å±æ ããæçš¿ããŸããã®ã§ãç§ã¯çµç¹é¢ãäžå¿ã«2021å¹Žã®æ¹åæ§ãã玹ä»ããããšæããŸãã çŸåšã®ãããã¯ãéšã«ã€ã㊠ãããã¯ãéšã¯ã2021幎1æ18æ¥æç¹ã§ãç·å¢26åãšãªãããšã³ãžãã¢ããã¶ã€ããŒããããã¯ããããŒãžã£ãŒãåšç±ããããã®ã¥ãããã®éšéãšãªã£ãŠããŸãã 2016幎ããªãã£ã¹ã«äžäººã§ rails new ããå§ãããšãããããRails, React, Swift, Kotlin, AWS/GCP ãšå€å²ã«ãããæè¡ãçšããŠããã¶ã€ããŒãšãããã¯ããããŒãžã£ãŒ(PdM)ãå ãã£ãŠãTUNAG ãš FANTS ã®ïŒã€ã®äºæ¥ãåµãéšéã«æé·ããŸããã çµç¹(äŒç€Ÿ)ã§ä»äºãããæå³ã¯äžäººã§ã¯ã§ããªã倧ããªä»äºãããŒã ã§æãéããããã«ãããšèšãããŸãããããŠãã¹ã¿ã¡ã³ã®çµå¶ç念ã¯ããäžäººã§ãå€ãã®äººã«ãæåãå±ãã幞ããåºããããã§ãã ç§ãã¡ãããã¯ãéšã«ãšã£ãŠã倧ããªä»äºãšã¯ãTUNAGãFANTSãªã©ãã¹ã¿ã¡ã³ãæäŸãããããã¯ã(âäºæ¥)ã«ãã£ãŠãããå€ãã®äººã«æåãå±ãã幞ããåºããããšã§ãã ãŸãã«èšèéãããã®ããŒã ã§ãªããã°ã§ããªãããšããããããããšæããã»ã©ãããããã®ããšãå®çŸã§ããããŒã ã«ãªã£ãŠããŸãããéã£ãŠãããçããã«æè¬ã§ãã ãããªãããã¯ãéšã®å
èš³ãšããŠã¯äžèšã«ãªããŸãã ãããã¯ãéšã®å
èš³ ãã®ã°ã©ãã®ãšãããã¹ã¿ã¡ã³ã®ãããã¯ãããŒã ã®ç¹åŸŽã¯äžèšã«ãªããŸãã ãšã³ãžãã¢ããã¶ã€ããŒããããã¯ããããŒãžã£ãŒã§æ§æããããã«ã»ããã®ãããã¯ãããŒã ã 圹å¡/瀟å¡ã¯èš24åã§ããšã³ãžãã¢20åããã¶ã€ããŒ2åããããã¯ããããŒãžã£ãŒ2åã å ããŠãåŠçã€ã³ã¿ãŒã³(ã¢ã«ãã€ã)ã®ãšã³ãžãã¢ã2åã è¥æãšçµéšè
ãæ··ãã£ãŠã峿Šåãšè²æã®äž¡ç«ãéèŠããŠããããŒã ã è¥æã¯ãçµéšãåããããã·ã£ã«ã®é«ã人æãæ¡çšããäºæ¥ãšãšãã«æé·ããŠããã çµéšè
ã¯ããã®çµéšã掻ãããŠå³æŠåãšããŠå°éæ§ããããããããŒã ãåºäžãããŠããã ãã ãããŸã ãŸã æºè¶³ã§ããå°éæ§ãäžã®äžãžã®åœ±é¿åã§ã¯ãããŸãããäŒç»ããã¶ã€ã³ãå®è£
ã«ãããŠããã£ãšè¯ãããŒã ã«ãªããè¯ããããã¯ããäžã«æäŸããå¿
èŠããããŸãã 以äžã§ã¯ããã®ããã«VPoEãšããŠèããŠããããšãã玹ä»ããããšæããŸãã æ©èœãå¢ããã®ã§ãªãUXãäžãã SoE (System of Engagement) ãš SoR (System of Record) ãšããèšèããããŸãããäºæ¥ãšã㊠TUNAG ã¯ãæ©èœãå¢ãã SoR ãã UXãåäžãã SoE ã®æ®µéã«æ¥ãŠãããæ©èœã远å ããããããåæ©èœã®äœ¿ãåæã广ãæå€§åããããšãæèããŠæœçã宿œããŠããŸãã ãã ããBtoB ã® SaaS ã§ãã TUNAG ã¯ã察象ãšããé¡§å®¢ã®æ¥æ
ãèŠæš¡ã倿§ã§ãHR Teché åã¯æ³åŸçã§æ±ºãŸã£ã圢ãç¡ãããã解決ãã¹ã課é¡ãèŠæãå€å²ã«æž¡ããŸãã ãŸããTUNAG ã¯ã300瀟以äžã®ã客ããŸã«å°å
¥ããã ãã10人çšåºŠãã1äžäººä»¥äžã®èŠæš¡ã®çµç¹ã§å©çšãããŠããŸããå
šäœçã«ãèŠä»¶å®çŸ©ãé£ãããæ©èœãå€ãè€éã§ã仿§ããã¶ã€ã³ãå®è£
ãè€éã«ãªããã¡ã§ããããã¯ããããžã¡ã³ããé£ãããããã¯ãã§ãã ãããªäžãä»å¹Žãããããã¯ããããŒãžã£ãŒãå¢ããŠäºäººãšãªãããããžã§ã¯ãã®éå¶ã«å ããŠãã«ã¹ããŒãµã¯ã»ã¹ãã»ãŒã«ã¹ãšã®é£æºãæ°å€åæãæ·±ãè°è«ã«æéãå²ãããšãã§ããããã«ãªã£ãŠããŸããããã¶ã€ããŒã®å¢å¡ãé²ããŠããããããžã§ã¯ãã®æ©ã段éãããã¶ã€ããŒãå·»ã蟌ãã§ã仮説æ€èšŒãUI/UXã®åäžã«åãçµãã§ããŸãã ãŸã ãŸã åäžäœå°ãããããŒããããŸãããæ¬¡ã®ãããªåãçµã¿ã«ããããããã¯ãã®äœã蟌ã¿ãæ·±ããªã£ãŠããŠããŸãã ã«ã¹ããŒãµã¯ã»ã¹ãšã»ãŒã«ã¹ãšã®é£æºã«ãã課é¡ã顧客ããŒãºã®ææ¡ ããŒã¿ãçšããå®éçãªåæã«åºã¥ãæææ±ºå® ãã¶ã€ããŒãšãããã¯ããããŒãžã£ãŒã®é£æºã«ããäŒç»ãšãããã¿ã€ãã«ããæ€èšŒ ãšã³ãžãã¢ã瀟å¡ãå·»ã蟌ãã ã¬ãã¥ãŒããããžã§ã¯ãã®ç¯ç®ã§è€æ°åéå¬ äœ¿ãåæã®è¯ãUIãšéçºå¹çãäž¡ç«ããããã®ãã¶ã€ã³ã·ã¹ãã ã®æ§ç¯ æè¡ç課é¡ãšäºæ¥æšé²ã®ãã©ã³ã¹ 2016ã«TUNAGãåµãå§ããŠãã4幎åçµéããŸãããéäžäºæ¥ã®æ¹é転æ(ãããã)ãããŠããŸãããçžæ¬¡ãæ¡åŒµã«ãã£ãŠãã·ã¹ãã ã¯è€éãšãªããæè¡çè² åµãèç©ããŠããŸãã ãããŸã§ããã€ãã®ãããžã§ã¯ãã§è² åµã®è§£æ¶ãè¡ã£ãŠããŸããããŸã ãŸã ããããã®è² åµãæ®ã£ãŠãããé害ãäžå
·åã®çºçããéçºé床ã®äœäžãªã©åŒå®³ãèŠãå§ããŠããŸããåæã«ã·ã¹ãã å
šäœã®ã¹ã±ãŒã©ããªãã£ãã»ãã¥ãªãã£ãåäžãããããªåãçµã¿ãè°è«ãããŠãããè¿ããããžã§ã¯ããç«ã¡äžããäºå®ã§ãã ãã ãã¹ã¿ã¡ã³ã®ãããªå°ããªããŒã ã§ã¯ãéçºãªãœãŒã¹ã«ãéãããããŸãããæè¡çãªäŸåé¢ä¿ãåãšã³ãžãã¢ã®åŸæãªæè¡ãç°ãªããåæã«å®æœå¯èœãªãããžã§ã¯ãã¯éãããŠããŸãã ãã®ããã宿çã«ããŒããããäŒè°ãéå¬ãããã®å
å幎ãã1幎å
ãããã®é·æçãªèŠç¹ã§ã®è°è«ãè¡ããæ©èœã®æ¹åãªã©ã®äºæ¥ãçºå±ãããæœçãšãæè¡çè² åµã®è§£æ¶ãã¢ãŒããã¯ãã£ãŒå€æŽãªã©ã®æè¡çãªæœçã®åªå
é äœã圹å¡ãéãŸã£ãŠæææ±ºå®ããŠããŸãã æè¿ã®äŸã ãšãTUNAGã®ã¡ã€ã³ç»é¢ã§ããã¿ã€ã ã©ã€ã³(React)ããä»å¹Žã®å€ã«å€§ããæ©èœã远å (倿Ž)ããåã«å·æ°ãããããžã§ã¯ããé²ããããšã«ãªããæšå¹Žæ«ããçæããŠããŸãã ãã®ããã«ãæè¡ç課é¡ãšäºæ¥æšé²ã®ãã©ã³ã¹ãåããªããããããã¯ãéšå
šäœãéå¶ããŠããå¿
èŠããããŸãã ãããã¯ãéšã®è¡åæéã§ãã Star Code ã«ããããã«ãæ§ã
ãªãåé¡ãèŠæ¥µãããäºæ¥ã®æé·ã®ããã«ããŠãŒã¶ãŒç®ç·ã§èãããªããäºæ¥ãé²ãããé害ãäžå
·åãªã©ãçºçãããã倱æã«åãåãããæè¡çè² åµã®è§£æ¶ãã¢ãŒããã¯ãã£ãŒå€æŽãè¡ãããããªãããŒã éå¶ãããŠããŸãã å°ããªããŒã ãšæš©éç§»è² çµç¹é¢ã§ãçºå±ãç¶ããŠããŸãã2021幎ã«å
¥ãããã¶ã€ããŒã®å¢å¡ã«äŒŽããã¶ã€ã³ããŒã ãã§ãããããã¯ããããŒãžã£ãŒãå¢ããŠãããŒã ãšããŠãããžã§ã¯ãéå¶ãè¡ãããã«ãªããŸããããšã³ãžãã¢ã¯20åãšãªã6ã€ã®ããŒã ã«æå±ããŠããŸãã å
šäœãšããŠ8ããŒã ãéšé·ã®äžã«ãã©ããã«é
眮ããããæé®åçµç¹ãã«ãªã£ãŠãããéšé·ã®çŽäžã«ãã¹ãŠã®ããŒã ãé
眮ããããšã§ãè¿
éãªææçéãšæææ±ºå®ãè¡ãããã«ããŠããŸãã ããŒã ç·šæãšããŠã¯ãå°éçãªå°ããªããŒã ã®é£æºã«ãããå¹çãšææã®æå€§åãæèããŠããŸãããŸããå°ããªããŒã ã«ããããšã§ããããŒãžã£ãŒããã¬ã€ã€ãŒãšããŠã掻èºïŒæé·ã§ããããã«ããŠããŸãã ãã©ãããªçµç¹ã«ããããšã§ãææçéã¯ããããåé¢ãéšé·(å°æ)ãå€ãã®ããŒã ã管èœããããšã«ãªããããžã¡ã³ããçãã«ãªãæžå¿µããããŸãããæè¡é¢ã CTOã®æŸè°·ã«ç§»è²ã ããããžã§ã¯ãéå¶ããããã¯ããããŒãžã£ãŒãšåããŒã ã®ãããŒãžã£ãŒã«å§ããããšã§ãå°æã¯çµç¹(æ¡çšãšäººäº)ãšäºæ¥ã®æææ±ºå®ã«å°å¿µããããã«ããŠããŸãã ä»åŸã¯ããããªãçµç¹æ¡å€§ã«åããŠååéã§ã®æš©éå§è²ãé²ããå°æã¯å
šäœæé©ã«ãã©ãŒã«ã¹ããŠããäºå®ã§ãã å
šå¡ãæé·ãè²¢ç®ããçµç¹ãž äž»ã«ãçµç¹ãšäºæ¥ã«ã€ããŠã課é¡ãšæããŠããããšãæžããŠã¿ãŸãããååéã§èª²é¡ãããããã§ãããéã«èšãã°äŒžã³ããã«æº¢ããŠãããšãèããŠããŸãã åè¿°ããããã«ã¹ã¿ã¡ã³ã®ãããã¯ãéšã¯ãè¥ããŠçµéšã®æµ
ãã¡ã³ããŒãå€ãå²ã«ãäºæ¥ãšã·ã¹ãã ãè€éãªå€§èŠæš¡ãããã¯ããäœã£ãŠããŸãã ãšã³ãžãã¢ã¯ãå€§èŠæš¡SaaSãããã¯ãã®éçºãå°äººæ°ã®ããŒã ã§äž»åã¡ã³ããŒãšããŠæ
åœããããšãã§ããŸãããé£æåºŠã®é«ãè² è·å¯Ÿçãå€§èŠæš¡ãªãã¡ã¯ã¿ãªã³ã°ãšãã£ã貎éãªçµéšãåŸãããŸãã ãã¶ã€ããŒã¯ãã€ã³ããŠã¹ãã¶ã€ããŒãšããŠã®PCãšã¢ãã€ã«ã§ã®UIãã¶ã€ã³ã¯ãã¡ãããçŽåªäœãããã¢ãŒã·ã§ã³ãµã€ãããã¶ã€ã³ã·ã¹ãã ã®æ§ç¯ãªã©æ§ã
ãªãã¶ã€ã³ãšå
±ã«ããããžã§ã¯ãåæããã®åå ã«ããäžæµå·¥çšã«åå ããããšãã§ããŸãã ãããã¯ããããŒãžã£ãŒã¯ãHR Tech BtoB SaaS ãšããé£ããåéã®ãšã³ã²ãŒãžã¡ã³ãçµå¶ãšããåäŸã®ç¡ããããã¯ãã«å¯ŸããŠããããã¯ããããžã¡ã³ãã®ãã¹ãŠãæãååããããšãã§ããŸãã ãããã®åå°éåéãšãšãã«ãçµç¹é¢ã§ã¯20代ã®ãããŒãžã£ãŒãããããèªçããå°æãšäžç·ã«ãªã£ãŠçµç¹(æ¡çšãè²æãã¢ãµã€ã³ãè©äŸ¡)ãšäºæ¥ã®ãããžã¡ã³ããçµéšããŠããŸãã ãã®ããã«ãäºæ¥ãæè¡ãçµç¹ã䌞ã³ãããããããããããŸã çµç¹ãå°ããããšããã£ãŠãéåžžã«è£éãšçµéšå€ã倧ããªç°å¢ãšãªã£ãŠããŸããè¯ãããŒã ã§è¯ããããã¯ããäœã£ãŠããããã£ãšçããã«ãšã£ãŠäººçã®ä»£è¡šäœãšãªããããã¯ããäœã£ãŠããããšæã£ãŠããŸãã 責任ã倧ããåã倧å€ãªãšããããããšæããŸãããåŒãç¶ãå
šå¡ã§åµæå·¥å€«ããã²ãããã«è¯ããããã¯ããäœã£ãŠãããŸãããïŒ æ°ãã仲éãåéäžã§ã ã¹ã¿ã¡ã³ã§ã¯ãåŒãç¶ãããšã³ãžãã¢ããã¶ã€ããŒããããã¯ããããŒãžã£ãŒãæ¡çšããŠããŸãããããŸã§ããå°å¹Žãã³ã¬ã®æ°ãã£ã©ã¯ã¿ãŒã®ããã«ãæ°ãã仲éããã³ããæããããŒã ã«æ°ããåããããããŠãããŸããã ä»å¹Žãããããã®ä»²éãå ãã£ãŠãæŽã«åŒ·ãããŒã ã«ãªãäºå®ã§ãããããªç°å¢ã«é
åãæããŠãã ãã£ãæ¹ã¯ããã²äžèšããå¿åããŠããã ããªãã§ããããã æ ªåŒäŒç€Ÿã¹ã¿ã¡ã³ ãšã³ãžãã¢æ¡çšãµã€ã ã€ã³ããŠã¹ãã¶ã€ããŒWantedïŒåå€å±ã§æ³šç®ã®ãã³ãã£ãŒã§æŽ»èºããŸããã æ¥æé·ããå€§èŠæš¡ SaaSãããã¯ãã®ãããã¯ããããŒãžã£ãŒåéïŒïŒ ãåŸ
ã¡ããŠãããŸãïŒïŒïŒ
ã¯ããã« ã¯ãããŸããŠãæ ªåŒäŒç€Ÿã¹ã¿ã¡ã³ã§ãšã³ãžãã¢ãããŠãããŸããæ°žäº( @0906koki )ã§ãã 以åã®èšäº ã§ã¯ãçãã¬ãé±5ã§ããŠãããšæžããŠããŸããããä»ã¯é±2ã«æžãããŠäœãã¡ã³ããã³ã¹ããŠããŸãã ä»åã®èšäºã§ã¯RailsãšWebpackããããŠReactã䜿ã£ãŠãwebpack_dev_serverã«ããHot Module ReplacementïŒä»¥äž HMRïŒãå®è£
ããæ¹æ³ã«ã€ããŠæžããããšæããŸãã 軜ãwebpack_dev_serverãšHMRã®èª¬æããããšã webpack_dev_server ãšã¯Webpackãå©çšããéçºç°å¢åãWebãµãŒããŒã§ãWebpack管çå
ã®éçã¢ã»ãããé
ä¿¡ããããšãã§ããŸãããŸãã HMR ãšã¯Webpackã®æäŸããä»çµã¿ã§ããã©ãŠã¶ã®ãªããŒããããã«Javascriptã®å€æŽå
容ãç»é¢ã«åæ ããããŒã«ã§ãã åŒç€Ÿã®ãããã¯ãã§ãã TUNAG ã§ã¯ãµãŒããŒãµã€ããRailsãããã³ããšã³ããReactãšTypeScriptã§å®è£
ããŠãããããã³ããšã³ãã®ãã«ããã¡ã€ã«ããRailsã®sprocketsã§ã³ã³ãã€ã«ããŠerbã§èªã¿èŸŒãŸããŠããŸããã ãããã¯ãã®æé·ã«æ¯äŸããŠWebpackã®bundleãµã€ãºãè¥å€§åããŠãããããã«èµ·å ããŠsprocketsã®ã¢ã»ããã³ã³ãã€ã«ã«æããæéãå¢å ããããã³ããšã³ãéçºç°å¢åã«ãããŠã¹ããŒãæãæã£ãŠéçºããããšãé£ãããªã£ãŠããŸããã ãã®ãŸãŸã§ã¯ããããžã§ã¯ãã®é²è¡ã«å€§ããªæªåœ±é¿ãåãŒãããšãç®ã«èŠããŠããã®ã§ãåé¡ãè§£æ¶ããããã«ã sprocketsã«ããç¡é§ãªã³ã³ãã€ã«ããªãããwebpack_dev_serverã«ããã³ã³ãã€ã«ã®ã¿ã«ãã HMRãå°å
¥ãããªããŒããããšã倿Žå
容ãåæ ãããããã«ãã ãã®ïŒã€ã軞ãšããŠãããã³ããšã³ãéçºç°å¢æ¹åãããžã§ã¯ããã¹ã¿ãŒãããŸããã â» ãã®æ¹åãããžã§ã¯ãã®å
ãwebpack_dev_serverãšRailsã®é£æºéšåã«é¢ããŠã¯ãã¹ã¿ãã£ã¹ãããã® ãããã³ããšã³ãåç䞻矩è
ãç®è«ãã è±webpackerã ãéåžžã«åèã«ãªããŸããã å®è£
ã®æé webpack_dev_serverãå°å
¥ããŠãHMRãé©çšããæé ã¯ä»¥äžã®éãã§ãã webpack_dev_serverã®ã€ã³ã¹ããŒã« webpack_dev_serverãšmanifestPluginã®èšå® webpack_dev_serverã®ãã«ããã¡ã€ã«ãèªã¿èŸŒããã«ããŒã¡ãœããã®å®è£
Railsã®ãããã·èšå® react-hot-loaderã®å°å
¥ãšå®è£
â» TUNAGã§ã¯Railsã®Webpackerã䜿ããçŽç²ãªWebpackãå
ã
䜿çšããŠãããããWebpackã§å®è£
ããåæã§è©±ãé²ããŸãã webpack_dev_serverã®ã€ã³ã¹ããŒã« webpack_dev_serverã«å¿
èŠãªpackageã远å ããŸãã $ yarn add -D webpack_dev_server webpack-manifest-plugin â» webpack-manifest-pluginã¯ãçæãããã«ããã¡ã€ã«ãã¹ã®ç®¡çãã¡ã€ã«ãšããŠäœ¿çšããŸãã webpack_dev_serverãšmanifestPluginã®èšå® èšå®ã¯ä»¥äžã®ããã«ããŠããŸããïŒloaderçã®èšå®ã¯çç¥ããŠããã®ã§ãé©å®è¿œå ããŠãã ããïŒ const path = require( 'path' ); const WebpackManifestPlugin = require( 'webpack-manifest-plugin' ) const outputPath = path.resolve( '../../public/packs' ) module.exports = (env, argv) => { return ( { entry: { bundle: [ 'webpack-dev-server/client?http://localhost:8080' , './src/index.tsx' ] } , output: { path: outputPath, publicPath: 'http://localhost:8080/packs' , filename: '[name].js' , } , plugins: [ new WebpackManifestPlugin( { fileName: 'manifest.json' , publicPath: '/packs/' } ) ] , devServer: { contentBase: 'http://localhost:8080/packs' , port: 8080, hot: true , headers: { 'Access-Control-Allow-Origin' : '*' , } } , } ); } ; ããã§ã¯ããã«ããã¡ã€ã«ã®åºåå
ãpublicãã£ã¬ã¯ããªé
äžã®packsãã£ã¬ã¯ããªã«æå®ããŠããŸãããããŠwebpack_dev_serverã®contentBaseã« /packs ãæå®ããããšã§ã http://localhost:8080/packs ã§åºåå
ããããã«ããã¡ã€ã«ãååŸããããšãã§ããŸãã ãŸããWebpackã®ãã©ã°ã€ã³ã§ãã ManifestPlugin ã䜿çšããŠããã¡ã€ã«åãšå®éã«é
眮ããããã¡ã€ã«ãã¹ãèšè¿°ããããããã§ã¹ããã¡ã€ã«ãçæããŸãã devServerãšmanifestPluginã®åããããã£ã®èª¬æã¯ä»¥äžã®éãã§ãã devServer contentBase: éçãã¡ã€ã«ãé
眮ãããã¹ã®æå® port: ããŒãçªå·ã®æå®ïŒrails serverã3000ã䜿çšããã®ã§ã8080ã«ïŒ hot: HMRã®å©çš headers: webpack_dev_serverããã®ã¬ã¹ãã³ã¹ã«ä»»æã®ããããŒæ
å ±ãå«ãã manifestPlugin filename: çæããããããã§ã¹ããã¡ã€ã«åã®æå® publicPath: valueã«prefixãä»äžãã ããã§webpack_dev_serverããã¢ã»ãããé
ä¿¡ããèšå®ãå®äºããã®ã§ãæ©éwebpack_dev_serverãç«ã¡äžããŠã¿ãããšæããŸãã ç«ã¡äžãæ¹ã¯ã以äžã®ã³ãã³ããå®è¡ããã ãã§ããïŒpackage.jsonã®scriptsã«èšå®ããŠããããšããªã¹ã¹ã¡ããŸãïŒ $ webpack-dev-server --progress --color ããã§ã http://localhost:8080/packs/â¯â¯.js ã«ã¢ã¯ã»ã¹ãããšãåºåå
ããããã«ããã¡ã€ã«ãååŸããããšãã§ããŸãã ã¡ãªã¿ã«ã http://localhost:8080/packs/manifest.json ã§ã以äžã®ãããªãããã§ã¹ããã¡ã€ã«ãååŸã§ãããšæããŸãã { "bundle.js" : "/packs/bundle.js" , } webpack_dev_serverã®ãã«ããã¡ã€ã«ãèªã¿èŸŒããã«ããŒã¡ãœããã®å®è£
次ã«è¡ãããããšã¯ãäžèšã§é
ä¿¡ãããã¢ã»ãããRailsåŽã§èªã¿èŸŒããã«ããŒã¡ãœããã®å®è£
ã§ãã ã³ãŒãã¯ä»¥äžã®ããã«ãªããŸããïŒjsãã¡ã€ã«ã®ã¿ãèªã¿èŸŒãèšå®ã«ãªã£ãŠããŸãããcssãã¡ã€ã«ãèªã¿èŸŒã¿ããå Žåã¯ãå°çšã®ã¡ãœããã远å ããŠãã ããïŒ module WebpackBundleHelper class BundleNotFound < StandardError ; end def javascript_bundle_tag (entry, **options) return javascript_include_tag entry unless Rails .env.development? path = asset_bundle_path( "#{ entry } .js " ) options = { src : path, defer : true }.merge(options) options.delete( :defer ) if options[ :async ] javascript_include_tag '' , **options end private def asset_host Rails .application.config.asset_host || '' end def dev_server_host " http://localhost:8080 " end def dev_manifest # webpack-dev-serverããçŽæ¥ååŸãã OpenURI .open_uri( "#{ dev_server_host } /manifest.json " ).read end def manifest @manifest ||= JSON .parse(dev_manifest) end def valid_entry? (entry) return true if manifest.key?(entry) raise BundleNotFound , " Could not find bundle with name #{ entry }" end def asset_bundle_path (entry, **options) valid_entry?(entry) asset_path(asset_host + manifest.fetch(entry), **options) end end javascript_bundle_tagã§ã¯ãwebpack_dev_serverããé
ä¿¡ãããŠããmanifest.jsonãååŸããmanifest.jsonã®äžã§åŒæ°ã«åèŽãããã¡ã€ã«ãã¹ãååŸããŸãã äŸãã°ãjavascript_bundle_tagã®åŒæ°ã« bundle ãæå®ãããšãmanifest.jsonã§ bundle ã«åèŽããkeyãèŠã€ããŠããã®valueïŒ /packs/bundle.js ïŒãååŸããŸãããããŠã localhost:3000/packs/bundle.js ãžãªã¯ãšã¹ããéãæµãã§ãã ãããã localhost:3000 ã§ã¯ãªã localhost:8080 ã§webpack_dev_serverãç«ã¡äžããŠããã®ã§ãåœç¶ã®ããšãªããããã®æ®µéã§ã¯ã¢ã»ãããååŸã§ããŸããã ãªã®ã§ããããã·ãããŠRailsåŽãwebpack_dev_serverããã¢ã»ãããååŸã§ããããã«èšå®ããŠãããŸãã Railsã®ãããã·èšå® ãããã·ã®åŠçã¯ãrack-proxyãšããGemãRailsã«è¿œå ããŠå®è£
ããŸããã require ' rack/proxy ' class DevServerProxy < Rack :: Proxy def perform_request (env) if env[ ' PATH_INFO ' ].start_with?( ' /packs/ ' ) env[ ' HTTP_HOST ' ] = dev_server_host env[ ' HTTP_X_FORWARDED_HOST ' ] = dev_server_host env[ ' HTTP_X_FORWARDED_SERVER ' ] = dev_server_host super else @app .call(env) end end private def dev_server_host " localhost:8080 " end end ããã§è¡ã£ãŠããããšã¯åçŽã« localhost:3000/packs/ ã§æ¥ããªã¯ãšã¹ãã localhost:8080/packs/ ãžãããã·ããŠããã ããšãªã£ãŠããŸãã éçºç°å¢äžã®ã¿ã§ãããã·ãè¡ãããã®ã§ãdevelopmentã®configãã¡ã€ã«ã«ä»¥äžã®èšå®ã远å ããŸãã config.middleware.use DevServerProxy , ssl_verify_none : true ããã§RailsåŽããããã³ããšã³ãã®ã¢ã»ãããååŸããããšãã§ããããã«ãªã£ãã®ã§ã http://localhost:3000/packs/manifest.json ã«ã¢ã¯ã»ã¹ãããšãwebpack_dev_serverããé
ä¿¡ãããŠãããããã§ã¹ããã¡ã€ã«ãååŸããããšãã§ããã¯ãã§ãã react-hot-loaderã®å°å
¥ãšå®è£
ãããŸã§ã§ãRailsåŽãwebpack_dev_serverããé
ä¿¡ãããã¢ã»ãããååŸã§ããããã«ãªã£ãã®ã§ãä»ãŸã§éããããã³ããšã³ãã®éçºãé²ããããšãã§ããããã«ãªã£ããšæããŸãã ããããã¯ãReactã§HMRãè¡ãæ¹æ³ã«ã€ããŠè§£èª¬ããŸãã ãŸããHMRãè¡ãããã« react-hot-loader ãšããpackgaeã远å ããŸãã $ yarn add react-hot-loader ãããŠã .babelrc ã«ã以äžã®èšå®ã远èšããŸãã { "plugins" : [ "react-hot-loader/babel" ] } 次ã«ãReactã³ã³ããŒãã³ãã®å®è£
ã«ç§»ããŸãã react-hot-loader ã«ããhot颿°ã«ãReactãããžã§ã¯ãã®ãããã³ã³ããŒãã³ããåŒæ°ãšããŠæž¡ããŸãã import React from 'react' ; import { hot } from 'react-hot-loader' import { Todo } from './todo' const App = () => { return ( <> < Todo / > < / > ) } export default hot ( App ) HMRã®ç¢ºèª äžèšã®Reactã³ã³ããŒãã³ãã管çããŠããWebpackããåºåå
ããããã«ããã¡ã€ã«ãbundle.jsãšãããšãå
çšå®çŸ©ããRailsã®ãã«ããŒã¡ãœããã®åŒæ°ã«bundleãæå®ããŸãã <%= javascript_bundle_tag( ' bundle ' ) %> ããã§webpack_dev_serverãç«ã¡äžããŠãChromeã®ã³ã³ãœãŒã«ã«ä»¥äžã®å
容ãåºãŠããã°ãHMRãæå¹ã«ãªã£ãŠããŸãã 詊ãã«ãå
çšæå®ãããããã³ã³ããŒãã³ãé
äžã®ã³ã³ããŒãã³ããããã£ãŠã¿ãŠãã ãããHMRã«ãã£ãŠå³æã«å€æŽå
容ãåæ ãããã¯ãã§ãïŒ ãŸãšã webpack_dev_serverãšReactã«ãããHMRã®å°å
¥ã«ã€ããŠè§£èª¬ããŸããã Railsã®Assets Pipelineã®ä»çµã¿ãç¡æ°ã«ããWebpackã®èšå®ãªã©ãæè¡çã«çè§£ããã¹ãç¯å²ã¯åºããé£ããéšåã¯ãããŸããããä»åã®ãããžã§ã¯ããéããŠããã³ããšã³ãã®ã³ãŒããè§Šããšã³ãžãã¢ã®çç£æ§æ¹åã«è²¢ç®ã§ããã®ã¯è¯ãã£ãã§ãã åŒç€ŸCTOã®èšäº ã«ããããã«ãäºæ¥ã®æé·ã«äŒŽããšã³ãžãã¢ã®äººæ°ãå¢ããŠãããªãã§ãã¡ã³ããŒå
šäœã«é¢ããéçºç°å¢ã®åé¡ã¯ããããžã§ã¯ããé²ããŠããäžã§éåžžã«å€§ããªåé¡ã§ãã ãã§ã«é¡åšåããŠããåé¡ãä»åŸèµ·ããããªèª²é¡ã«å¯ŸããŠããšã³ãžãã¢ããã®éœåºŠåé¡ãæèµ·ãã解決ã«åããŠè¡åããããšã¯ãšãŠã倧åãªã®ã§ããããããããããæèãæã¡ç¶ããããšæããŸãã ã¹ã¿ã¡ã³ã§ã¯äžç·ã«åããšã³ãžãã¢ãåéããŠããŸãã èå³ãããæ¹ã¯ããã² æ¡çšãµã€ã ãããé£çµ¡ãã ããïŒ
ã¹ã¿ã¡ã³ã®æŸè°·( @uuushiro )ã§ãã2020幎3ææ«ã«ã¹ã¿ã¡ã³ã®CTOã«å°±ä»»ããçŽ9ã¶æã»ã©ãçµã¡ãŸãããè²ã
ãšå€åã®å€§ããã£ãã¹ã¿ã¡ã³éçºããŒã ã®2020幎ããç§ã®ç®ç·ã§æ¯ãè¿ããŸãããããŠæåŸ
ã蟌ããŠæ¥å¹Žã®å±æãå
±æããããšæããŸãïŒ ã©ããª2020幎ã ã£ãã äºæ¥ã«ã€ã㊠TUNAG ãŸãã嵿¥äºæ¥ã§ãã TUNAG ã¯ãªãªãŒã¹ããŠä»å¹Žã§4幎ç®ã§ãããTUNAG ã¯ã2017幎~2019幎ãŸã§ã¯ãããšã³ã²ãŒãžã¡ã³ãçµå¶ãã©ãããã©ãŒã ããšããŠå¿
èŠãªäžé£ã®æ©èœãæããŠããŸããããããã¯ãã®æ©èœãã«ããŒã§ããç¯å²ãå¢ããããšã«æ³šåããŠããããšãããããã®äžã€ã²ãšã€ã®æ©èœã«é¢ããŠã¯ãäŸ¡å€æäŸãã§ããæå°éã®ãã®ã§ããã 2020幎ã¯ããããŸã§æããŠããäž»èŠãªæ©èœã®äŸ¡å€ã»äœéšãåŒãäžãããããªæ¹åããæ°æ©èœã®è¿œå ã«ãããŠããªãªãŒã¹æç¹ã®ãããã¯ãã®äœã蟌ã¿ã¬ãã«ãäžããããšãã§ããããã«ãªã£ãŠããããšã§ãéçºçµç¹ãšããŠæäŸã§ããæ©èœäŸ¡å€ã倧ãããªã£ãŠãããšæããŠããŸã(ãã¡ããæ¹åäœå°ã¯æ²¢å±±ã§ã)ãç¹ã«ãããã³ããšã³ããšã³ãžãã¢ã»ãã€ãã£ãã¢ããªãšã³ãžãã¢ã¯ãã¹ãã«ã¢ãããšçµç¹åã«ãã TUNAG ã®ãŠãŒã¶ãŒäœéšãåäžãããããšã«éåžžã«å€§ããªè²¢ç®ãããŠãããŸããã ãŸããTUNAG ã®ã¡ã€ã³æ©èœã§ãããèªç€Ÿã«åããã瀟å
å¶åºŠãéçšã§ããæ©èœã ãã§ãªãããã£ããæ©èœãã¯ãŒã¯ãããŒæ©èœãšãã£ãéåžžæ¥åãè¡ãäžã§å¿
é ã®ããŒã«ãå€ãã®ãŠãŒã¶ãŒæ§ã«äœ¿ã£ãŠããã ãããã«ãªã£ã幎ã§ããã£ãã®ã§ãTUNAG ãžã®ã¢ã¯ã»ã¹æ°ãè² è·ã®ç¹æ§ãå€åããŠããŸãããéçºããŒã ãšããŠããŠãŒã¶ãŒæ§ã®æ¥åãæ¢ããŠããŸãããšããªãããã«ãäžå
·åãç¡ãããã¹ãã¬ã¹ã®ãªãå¿çé床ããªã©ãåœããåå質ãã远æ±ããæèã倧ããé«ãŸã£ãŠãããŸããããããŠããšã³ã¿ãŒãã©ã€ãºäŒæ¥æ§ã®å°å
¥ã«ãããŠããããŸã§çµéšããããšã®ãªãèŠæš¡ã®ãŠãŒã¶ãŒæ°ã®å©çšã·ãŒã³ãæ³å®ããè² è·å¯Ÿçãåã³ã»ãã¥ãªãã£å¯Ÿå¿ã宿œããä»åŸ TUNAG ã®å°å
¥ãæ€èšããŠããã ããäŒæ¥æ§ã®å¹
ã倧ããåºãããŸããããããã®ã·ã¹ãã ã®ä¿¡é Œæ§åäžã®åãçµã¿ã«ã¯ãã€ã³ãã©ããŒã ããããã¯ãéçºå
šäœããªãŒãããŠãããŸããã äžæ¹ã§ããããã¯ãã®äœã蟌ã¿ã¬ãã«ã®åäžãšæ¯äŸããŠãæ©èœã®è€é床ãäžãã£ãŠããŸããããªãªãŒã¹åœåã¯æ³åãããŠããªãã£ããããªãããã¯ãã®é²åãäœåºŠãçºçããã®ã§ããã®å€åã«ãªããšãåãããŠããåã®è² åµãç¡èŠã§ããªããªã£ãŠããŠããŸãããã®çµæãã¢ããªã±ãŒã·ã§ã³ã³ãŒããè€éã«ãªãããããçµæãšããŠäžå
·åããµãŒããŒè² è·ã«ã€ãªããããšãäºæž¬ãã¥ãããšããããšãå€ã
ãããŸããããã¡ãã«ã€ããŠã¯ãæ¥å¹Žæéã確ä¿ãããªãã¡ã¯ã¿ãªã³ã°åã³ãèªåãã¹ãã®æ¡å
ãé²ããŠããäºå®ã§ãã ãŸããTUNAGäºæ¥ã«ãã㊠TERAS ãšããçµç¹èšºæããŒã«ã®æäŸãéå§ããTUNAG ãšå¥ã®ã·ã¹ãã ãšããŠ0ããæ§ç¯ããŸãããTUNAGæ¬äœãšã¯ã¢ãŒããã¯ãã£ãç°ãªããSPA(React)ãšAPIãµãŒã(Rails)ã§äœããããµãŒããŒãã³ã³ãããå©çšãããããããã€ã Blue Green Deployment ãå©çšããããªã©ãã¹ã¿ã¡ã³ã®è¿ãå°æ¥ã®æè¡ã¹ã¿ãã¯ã®æ€èšŒãå
ŒããŠæ§ç¯ããŸãã( TERASã®ã¢ãŒããã¯ã㣠)ãããã§åŸãããç¥èŠã®äžéšãæ¥å¹ŽTUNAGæ¬äœã«é©çšããããšã§ãã·ã¹ãã ã®å®å®æ§ã»éçºã»éçšå¹çåäžãªã©ãç²åŸããŠãããããšèããŠããŸãã FANTS ãããŠä»å¹Žã¯æ°èŠäºæ¥ FANTS ãã¹ã¿ãŒãããŸãããå¿
èŠãªæ©èœã TUNAG ãšè¿ãã®ã§ããœãŒã¹ã³ãŒãã®è»¢çšãã§ããç®æã¯å€ãã£ãã®ã§ãããã©ã€ãé
ä¿¡æ©èœãèª²éæ©èœããµãã³ç®¡çæ©èœãé客æ©èœãªã©ãªã³ã©ã€ã³ãã¡ã³ã³ãã¥ããã£ãµãŒãã¹åºæã®æ©èœéçºãå€ãè¡ããŸãããç¹ã«èª²éæ©èœã«é¢ããŠã¯ãã·ã¹ãã ããéãæ±ãåããŠã®äºäŸã ã£ãããšããã(ã¯ã¬ã«æ
å ±ã¯ä¿æããŠããŸãã)ãä»ãŸã§ã«ãªãç·åŒµæã®äžã§éçºã«ãªããŸãããäºé決æžã誀課éããããŠæ±ºæžãã©ãããã©ãŒã åŽãšFANTSåŽã§ããŒã¿ã®äžæŽåãçºçããªããããªä»çµã¿ããã£ãããšæéãæããŠ(å·ãæ±ããããªãã)æ§ç¯ããç²æããã£ããšæã£ãŠããŸãã責任é倧ãªä»äºã ã£ããšæããŸãããFANTSããŒã ã責任æã£ãŠãããã£ãŠããããããã§ãä»ã¯ FANTS ã®äºæ¥ç念éæã«åããå€ãã®æ©èœãã¹ããŒãã£ã«ãªãªãŒã¹åºæ¥ãŠããŸãã ãã®ä»åãçµã¿ã«ã€ã㊠2020幎ã®ããããã¯ãããŒãããã以å€ã®åãçµã¿ã«ã€ããŠãç¹ã«å°è±¡ã«æ®ã£ãŠãã4ã€ã玹ä»ããŸãã ã¢ã©ãŒãç®¡çæ¹å ã¢ããªã±ãŒã·ã§ã³ã®ã¢ã©ãŒãéç¥ã®æŽçãããŸãããæŽçããåã¯ãäžæ¥ãããã®éç¥æ°ãå€ããããéç¥ã«å¯ŸããéäžåãåããéèŠãªã¢ã©ãŒããèŠéãããããªã£ãŠããŸããããã®çµæãäžå
·åã»é害察å¿ã®ååã®é
ããæŒããçºçããŠããŸãå¯èœæ§ãé«ããªã£ãŠããŸããããã®åé¡ãç§ãã¡ã¯ããªãªã«ãå°å¹Žã¢ã©ãŒãããšåŒã³ãåé¡è§£æ±ºã®ããã«ãã·ã¹ãã æèãã®ãã¬ãŒã ã¯ãŒã¯ã掻çšããŸãã( ã·ã¹ãã æèã§ã¢ã©ãŒãéçšã«é¢ããåé¡ãèãã )ãããã«ãããã¢ã©ãŒãã®è²¬ä»»ç¯å²åã³ã¢ã¯ã·ã§ã³ãæç¢ºåããæ°ããã¡ã³ããŒãè¿·ããã«ç£èŠãããããšãã§ããããã«ãªã£ããšæããŸãããããŠãå幎çµã£ãä»ãæ°ãããšã©ãŒã«å¯ŸããŠåå¿ãæ©ããªã£ããšå®æããŠããŸãããã æè¿ã¯ãããŸã«ãã®ãå°å¹Žããéã³ã«ããŠããæ°ãããªãã§ããªãã®ã§ããŸãåé¡ã«ãªãåã«ç¶ç¶çã«èŠçŽããŠãããããšæããŸãã éçºç°å¢æ¹å TUNAG ã®éçºç°å¢ã«ãããŠãRailsã®ã¢ã»ããã³ã³ãã€ã«ãé
ãåé¡ããã£ãã®ã§ãããJavascriptãªã©ã®Assetã®é
ä¿¡ã®ä»çµã¿ããRailsãšWebpackã§åé¢ãããããšã§ãsprocketsã®ç¡é§ãªã³ã³ãã€ã«ãæé€ããåŸ
ã¡æéã倧ããæžããããšãã§ããŸããããŸãããã³ããšã³ãéçºã«ãããŠãWebpackãæäŸããHot Module Replacement (HMR)ã«ã€ããŠãé©çšããããšãã§ããããã«ãªããä»åŸéçºè
äœéšãåäžããŠããããã§ããæ¥å¹Žä»¥éãããã³ããšã³ãéçºã¯ãŸããŸãå éããŠããã®ã§ãã®æ¹åã¯éåžžã«ãããããã§ãã äžæ¹ã§èª²é¡ã«æããã®ã¯ããã£ãšåãç°å¢ã§éçºããŠãããšç·©ããã«é
ããªã£ãŠããéçºç°å¢ã«å¯ŸããŠéæã«ãªã£ãŠããŸããšããããšããããŠãRailsãšWebpackãäŸåãåã£ãŠããä»çµã¿ã ãšãäž¡æ¹ã®æè¡ãçè§£ããŠããªããšåé¡æèµ·ãã«ãããšããé£ãããæããŸãããããããéçºç°å¢ãé
ãããšããäºè±¡ã«å¯ŸããŠã¯ã誰ã§ãå€å°ã¹ãã¬ã¹ãæããã¯ãã§ããããã«æ
£ããã®ã§ã¯ãªãããã°ã©ããŒã®äžå€§çŸåŸ³ã®äžã€ããçæ°ããªãã€ã³ããæã¡ãç®ã®åã®éçºç°å¢ã®æ æ
¢ãã«æããæããåé¡ãæèµ·ãã解決ã«å°ãããšã¯éåžžã«éèŠã§ãããããã£ããšã³ãžãã¢ãã©ãã ãçµç¹ã«ãããïŒãšããææšã¯äžé·æçã«ãããã¯ãéšãšããŠã®ã¢ãŠããããéã倧ããå·Šå³ããŸãã倧ããªããšãæãéããäžã§ãæ§ãç ãããšãã©ãã ã倧äºãªã®ããéçºç°å¢ã1%ã§ãè¯ãããããšããä»åŸäººæ°ãå¢ããŠããéçºçµç¹ã«ãããŠã©ãã ã倧äºãªã®ãããšããããšãããŒã ã«ã«ãã£ãŒãšããŠæµžéãããŠãããæ¥å¹Žã¯ãšã³ãžãã¢å
šå¡ããçæ°ãã«ãªã£ãŠãããã°ãšæããŸãã APIããã¥ã¡ã³ããŒã·ã§ã³æšæºå APIããã¥ã¡ã³ããŒã·ã§ã³æšæºåãããã以åã¯ãAPIããã¥ã¡ã³ãã¯ç€Ÿå
wikiã«èç©ãããŠããŸããããæ©èœãå¢ããŠããããšã«ãã£ãŠããã¥ã¡ã³ãã®æ°ãå¢ããŠç®¡çãé£ãããªã£ããã ãã©ãŒããããæç¢ºã§ãªãã®ã§æžã人ã«ãã£ãŠã°ãã€ãããããšããåé¡ããããŸãããããã§APIãæäŸããåŽã»äœ¿ãåŽã®äž¡æ¹ã®ç«å Žã®ãšã³ãžãã¢ãååããŠãããŒã«ã®éžå®ãéçšæ¹æ³ã®ç¢ºç«åã³æµžéãæšé²ããŠãããŸãããæ¢åè³ç£ã§ããRSpecãšãããã¹ããã¬ãŒã ã¯ãŒã¯ããã®ãŸãŸæŽ»ããããšã§å®è£
è
ã«ã»ãŒè² æ
ã®ãªã圢ã§å°å
¥ã§ããSwagger UIããã¹ãã£ã³ã°ããããšã§ç°¡åã«ããã¥ã¡ã³ãã«ã¢ã¯ã»ã¹ã§ãããã«ããŠãããŸããããããŠãéçšããäžã§åºãŠãã課é¡ãé©å®è§£æ±ºããŠãããŸããã RSpec ãã API ããã¥ã¡ã³ããçæãããrspec-openapiãã詊ããŠã¿ã JSON:APIã®RequestSpecã«ãjsonapi-rspecãå°å
¥ãã - stmn tech blog ãã®ãããžã§ã¯ãã¯ãæè¡é åãããŒã ãæšªæããè¯ãäŸã ã£ããšæããŸããããã¥ã¡ã³ãã®ãºã¬ããã¡ãã¡æåã§ä¿®æ£ããã®ãããã©ããããšãããã°ã©ããŒã®äžå€§çŸåŸ³ã®äžã€ãæ æ°ããªãã€ã³ãã§èª²é¡ã«åãåã£ãŠããããããã ãšæããŸãããã®ãããªãæè¡é åãããŒã é åã®éãåãããšã³ãžãã¢ãè¶å¢ãããšã³ãžãã¢ãšãã£ãååšã¯äºæ¥ãæšé²ããäžã§éåžžã«éèŠã«ãªã£ãŠããã®ã§ãä»åŸãåãããããã©ããŒããŠãããããšæããŸãã 倱æããåŠã¶åãçµã¿ ã¹ã¿ã¡ã³ã®ãããã¯ãéšã«ã¯ã倱æã«åãåãããšãã ããªã¥ãŒ ãå®ããããŠããŸãã2020幎ãäžå
·åãé害ãªã©å€±æãããŠããŸããããä»å¹Žãæ¯ãè¿ããšçµç¹å
šäœã§å€±æã«åãåãå§¿å¢ã®ã¬ãã«ãäžæ®µäžãã£ããªãšæããŠããŸãããã 倱æãåçããã ãã§ãªããåã
人ã®åå 远æ±ã»åçºé²æ¢ã»æªç¶é²æ¢ã®è³ªãé«ãŸããåã倱æãããªãããæ¹åã§ããããã«ãªã£ãŠããŠãããšæããŠããŸããé害æ¯ãè¿ãäŒã§ã®è°è«ã掻çºã«ãªã£ãŠããŠãæ¬é³ã§ãªãŒãã³ã«åå ã远æ±ããçµç¹å
šäœã倱æããåŠã¶ã«ã«ãã£ãŒã浞éããŠããŠãããªãšæããŠããŸãã 2021幎ã«ããããš ç§å人ãšããŠãçµç¹å
šäœãšããŠ2021幎ãå®è¡ãããããšã¯2ç¹ã§ãã æè¡æŠç¥ãæãå®è¡ãã å
šäœæé©ã»åºæºæ±ºãã«æ³šåããŠãã æè¡æŠç¥ãæãå®è¡ãã 2020å¹Žãæ¯ãè¿ããšãäºæ¥ã®èŠæ±ã«å¿ããªããå€ãã®éçºã§ãããã¯ãã®æé·ãæ¯ããé²åãããŠããããšãã§ããŸããã äžæ¹ã§ç§èªèº«ãéçºçµç¹ã«ããããæè¡æŠç¥ãã«ã€ããŠèšèªåã»çºä¿¡ãè¶³ããªãã£ããªãšããåçããããŸãããæè¡æŠç¥ããšãããã®ã¯ãäºæ¥äžã®èŠæã«120%å¿ãã€ã€ããããã¯ãã®åè³ªãæ¹åã¹ããŒããäœã³ã¹ãå®çŸãæ¡çšåãè²æå...ãªã©äºæ¥æŠç¥ãå éããã匷ã¿ãšããŠãéçºçµç¹ã»ã¢ãŒããã¯ãã£ã»ã«ã«ãã£ãŒãã©ã®æé軞ã§éæãããã®ãããã®ããã«éããããªãœãŒã¹ãã©ãé
åãããããã®ãããšããããšã瀺ãããã®ã ãšèããŠããŸãããããã«åãçµãåãã匱ãã£ããšæããŠããŸãããããã¹ããªã¹ããã¯åžžã«ç®ã®åã«ãããŸããããã¯æŠç¥ã§ã¯ãªãã§ããäºæ¥ãçœåŒããã¹ã¿ã¡ã³ãªãã§ã¯ã®ãæè¡æŠç¥ãã®æãçãããã¯ãã§ãä»åŸã¯ããå
·äœçã«èããèšèªåããçºä¿¡ããŠãããŸããããã§å¿
èŠã«ãªã£ãŠããããšã¯ãç®ã«èŠãã課é¡ã ãã§ã¯ãªãããŸã ç®ã«èŠããªãããéèŠãªèª²é¡ãçºèŠãã¢ãããŒãããããšã§ããäœãããã£ãããšã®ã³ã¹ããšãªã¿ãŒã³ã¯èŠããŸããããèŠããŠããªããããã£ãŠããªããããšã«ããæ©äŒæå€±ã¯ãã以äžã«éãæããã¹ããšæã£ãŠããŸããèŠéããŠãããã£ã³ã¹ãç¡ãããã«ä»äžåºŠã·ã¹ãã ã»çµç¹ã»æªæ¥ã®äºæ¥ã®å§¿ãèããŠãåŒãç¶ããããã¯ãéšã®ããžã§ã³ã§ããããããã¯ãã§äºæ¥ãçœåŒãããã®å®çŸã远æ±ããŠãããŸãã å
šäœæé©ã»åºæºæ±ºãã«æ³šåããŠãã 2020幎ã¯ãããã¯ãšã³ãé åã«é¢ããŠã¯ç§ãäžå¿ãšãªã£ãŠæè¡çãªæææ±ºå®ãããŠããŸãããããã®ä»ããã³ããšã³ãããã€ãã£ãã¢ããªé åã«é¢ããŠã¯ãæè¡éžå®ããã®å®è¡ã¿ã€ãã³ã°ã¯åæè¡é åã®ããŒã ããšã«æææ±ºå®ããä»»ãããŠããŸããã2021幎ãåãããä¿¡é ŒããŠãé¡ãããŠããããäžæ¹ã§ãæææ±ºå®ã®ãã©ããŒãå
šäœæé©ãšãªãããã«ãã©ã³ã¹ããšãããšã¯CTOãšããŠã®éèŠãªè²¬ä»»ã§ããä»åŸã人ã»ããŒã ã»äºæ¥ã»æè¡é åãå¢ããäžã§ãæè¡çæææ±ºå®ã®åºæºã»äŸ¡å€èгãæããããšã¯éèŠã«ãªã£ãŠããŸãã æ£çŽãTUNAG ã¯èªåã§ãå
šäœã®æè¡ãææ¡ããããªãèŠæš¡ã«æé·ããŠããã®ã§ãããäŸãã°ããããã¯ãéçºãäžæçã«æ¢ããŠã§ãæè³ãã¹ãæè¡çãªæææ±ºå®ã®å€æãè¿«ãããæã«ãåãããŸããããã話ã«ãªããŸããããçè§£ããŠæè³ãå¿
èŠãšå€æã§ããã°ãäºæ¥è²¬ä»»è
ã«èª¬æããŠçŽåŸããŠããããããã«åãããã責任ãCTOã«ã¯ãããŸããå®éãç§ãå
šãŠã®é åãçè§£ã倿ããŠããããšã¯é£ããã§ãããåé¡æèµ·ãè°è«ã®ãã¡ã·ãªããŒããããªãããåæææ±ºå®ããªãŒãã³ã«æ®ãããšã³ãžãã¢ããŒã å
šäœã§ãã¹ããªæææ±ºå®ã«å°ããã©ããŒã¯ã§ããã¯ãã§ããèããŠã¿ãã°åœããåãªã®ã§ãããèªç€Ÿã®ã·ã¹ãã ãååã«çè§£ããŠããªãããšã«ãã£ãŠèµ·ããæ©äŒæå€±ã¯ãææ°æè¡ã®ãã¬ã³ããä»ç€Ÿã®äºäŸç¥ããªã以äžã«å€§ãããšæããŠããŸãããªã®ã§2021幎ã¯å
šäœæé©ã®ãªãŒããã§ããããã«ãèªåã®æè¡é åãå¢ããæ¹åã§ã€ã³ããããããŸãã¯ã·ã¹ãã ã®çè§£ãæ·±ããŠãããããšæããŸãã ãŸããäºæ¥ãè€æ°å±éãçµç¹åãé²ãäžã§ãåããããªèª²é¡ãæææ±ºå®ãå¢ããŠããã¯ãã§ããçµç¹å
ã§ã®è»èŒªã®åçºæãé²ããçµç¹åããŠããããããã®åŒ·ã¿ãçãããŠããããã«ã暪å±éããããšãæ³å®ããèšèšãåºç€ã®æŽåãåã³ãã¬ããžã®æ°Žå¹³å±éãå¯èœãªæ
å ±å
±æã»å±éã®ä»çµã¿ãèããŠããŸãã ãããŠã瀟å
ã®ãšã³ãžãã¢å
šäœãžãããã®ã¡ãã»ãŒãžã宿çã«çºä¿¡ã§ããããã«ãæäžãããã§CTOéä¿¡çãªãã®ãå§ããŠã¿ãããšæããŸãã æ¯ãè¿ã£ãŠã¿ããšã2020幎ã¯çµç¹ãæè¡ã®å€åãæ²¢å±±ãããŸããããŸã æžãè¶³ããªãã§ãããããã§çµããã«ããŸãã幎å§ã«è¯ãã¹ã¿ãŒãããã·ã¥ãåããããã«ã幎æ«ã¯æ¥å¹Žã®ã€ã¡ãŒãžãèšããŸããªãããã£ãããªãã¬ãã·ã¥ãããŸãïŒ çããïŒå¹Žéãç²ãããŸã§ããïŒ æåŸã« æ ªåŒäŒç€Ÿã¹ã¿ã¡ã³ã¯ã2020幎12æ15æ¥ããã¡ãŸããŠæ±äº¬èšŒåžååŒæãã¶ãŒãºãžæ°èŠäžå ŽããããŸããããããŸã§æ¯ããŠãã ãã£ãæ¹ã
ãžã®æè¬ã®æ°æã¡ãšããŸããããããªã¹ã¿ãŒãããæ¬¡ã®é«ãå±±ãç®æããŠããäžå±€ãããã¯ãéçºã«å±ãã§ãããããšããæãã§ãã æ¥å¹Žã¯ãæ¢åã·ã¹ãã ã®ã¢ãŒããã¯ãã£ãäºæ¥æé·ã®æ¹åã«åãããŠå€§ããå€ããŠããã¢ãŒããã¯ãããå€§èŠæš¡ãªã·ã¹ãã ã®éçšããœãããŠã§ã¢éçºããªãŒããããšã³ãžãã¢ãªã©ãå¹
åºã仲éãèŠã€ããŠãããããšæã£ãŠããŸããB2Bã® TUNAG ã ãã§ãªãããªã³ã©ã€ã³ãã¡ã³ãµãã³äºæ¥ FANTS ãå±éããŠãããä»åŸãå€è§çã«äºæ¥ãå±éããŠãããããšæã£ãŠããã®ã§ãTUNAG ã FANTS ã«èå³ãæã£ãŠãããæ¹ããããã§ãªãæ¹ãäžç·ã«äœã£ãŠãããšã³ãžãã¢ãåéããŠããŸãïŒèå³ãæã£ãŠãããæ¹ã¯ã Wantedly ã§å¿åããã ããã°ãšæããŸãïŒæè¡ã»äŒç€Ÿã»äºæ¥ã«ã€ããŠãã£ãšè©³ããèããŠã¿ããæ¹ã¯ãæŸè°·( @uuushiro )ãŸã§æ°è»œã«DMããã ããã°åãã§è¿äºããŸãïŒãšããããã§ãããŸã§èªãã§ããã ãããããšãããããŸããã
ç®æ¬¡ ã¯ããã« ãžã§ããªãã¯åãšã¯ æ±çšæ§ã®é«ãã³ã³ããŒãã³ããäœæ ãããã« ã¯ããã« ããã«ã¡ã¯ãã¹ã¿ã¡ã³ã§ãšã³ãžãã¢ãããŠããæå¶ã§ããæ®æ®µã¯ãReact+TypeScriptã§ããã³ããšã³ãã¡ã€ã³ã§éçºãããŠããŸããéçºã®äžã§Reactã³ã³ããŒãã³ã(以äžã³ã³ããŒãã³ã)ãå
±éçã«äœ¿ãããããšãå€ã
ããã®ã§ããããã®ææ³ã®äžã€ãšããŠãžã§ããªãã¯åãæå¹ã ã£ãã®ã§ãä»å玹ä»ããããšæããŸãã ãžã§ããªãã¯åãšã¯ ãžã§ããªãã¯åã¯äžèšã§è¡šããšããåãæœè±¡åãããã®ãã§ãã å®çŸ©ã ãã§ã¯åããã«ããã®ã§ãçè§£ãæ©ããããã«äŸãæããŸãã 以äžã®ããã«textãšindexãããããstringåãnumberåã§åãåã£ãŠãè¿ã颿°ããã£ããšããŸãã const showText = ( text: string ) : string => { return text } const showIndex = ( index: number ) : number => { return index } ãã®äŒŒããããªåŠçãå
±éåããéã«ããžã§ããªãã¯åã圹ç«ã¡ãŸãã 以äžã®ããã«å€æŽããããšã§ã颿°ãåŒã³åºãéã«åãæå®ããã°åŠçããŸãšããããšãã§ããŸãã ãåã®ã¿ç°ãªããã³ãŒããæœè±¡åããããšã§ãæ±çšæ§ãé«ãããããšãåºæ¥ãŸããã const genericFunction < T > = ( arg: T ) : T => { return arg } genericFunction < string >( "hoge" ) // showText()ãšåã genericFunction < number >( 10 ) // showIndex()ãšåã ãã®èããå¿çšããReactã§æ±çšæ§ã®é«ãã³ã³ããŒãã³ããäœæããŸãã æ±çšæ§ã®é«ãã³ã³ããŒãã³ããäœæ äŸãšããŠä»¥äžã³ãŒããæããŸãã DropDownListã³ã³ããŒãã³ãã¯ãã¢ããªã±ãŒã·ã§ã³å
ã§æ±çšçã«äœ¿ããã®ã ãšæ³å®ããŠãã ããã 圹å²ãšããŠã¯ã芪ã³ã³ããŒãã³ãããåãåã£ãusersãmapã§åããŠåã³ã³ããŒãã³ã(DropDownItemã³ã³ããŒãã³ã)ã«æž¡ãããšã§ãã 芪ã³ã³ããŒãã³ãã§ã¯DropDownã§éžæããåäžã®useråãStateãšããŠç®¡çããŠããŸãã (ã¹ã¿ã€ã«ãDropDownItemã³ã³ããŒãã³ãã®äžèº«ã¯å²æããŠããŸã) ãžã§ããªãã¯å䜿çšå //types export type UserType = { key: number ; name: string ; } ; // 芪ã³ã³ããŒãã³ã import React , { useState , useCallback } from 'react' ; import DropDownList from 'components/common/DropDownList' ; import UserType from 'types/user' ; interface Props { users: UserType [] ; } const User = ( props: Props ) => { const { users } = props ; // DropDownã§éžæããåäžã®ãŠãŒã¶ãŒã®ååãStateã§ç®¡ç const [ userName , setUserName ] = useState (); const handleSetUserName = useCallback (( name: string ) => { setUserName ( name ) } , [] ); return ( < div > < span > ãŠãŒã¶ãŒäžèЧ < span > < DropDownList users = { users } setUserName = { handleSetUserName } / > < div > ); } ; export default User ; // DropDownListã³ã³ããŒãã³ã import React from 'react' ; import DropDownItem from 'components/commmon/DropDownItem' ; import UserType from 'types/user' interface Props { users: UserType [] ; setUserName: ( name: string ) => void ; //芪ã³ã³ããŒãã³ãã§ç®¡çããStateãã»ããããAction } const DropDownList = ( props: Props ) => { const { users , setUserName } = props ; return ( < div > { users.map ( user => { return ( < DropdownItem key = { user.key } value = { user.name } setValue = { setUserName } / > ); } ) } < div > ); } ; export default DropDownList ; ãã®ç¶æ
ã§ãåé¡ãªãã³ãŒãã¯åäœãããŠãŒã¶ãŒã®ååãDropDownListãšããŠè¡šç€ºã§ããŸãã ãããããŠãŒã¶ãŒã®åå以å€(äŸãã°Numberåã®ãªã¹ã)ã衚瀺ãããå Žåã¯ã©ãã§ããããã DropDownListã³ã³ããŒãã³ãã®interfaceã å
·äœç ããã(users,setUserNameããèš±å¯ããŠããªã)ã®ã§ãåå©çšããããšãã§ããŸããã ã¢ããªã±ãŒã·ã§ã³å
ã§åãèŠãç®ãå®çŸããéã«ãã³ã³ããŒãã³ãã䜿ãåããªãã®ã¯å¿äœãªãã§ãã 解決çãšããŠã以äžã®ããã«ãžã§ããªãã¯åã䜿çšããŸãã ãžã§ããªãã¯å䜿çšåŸ // 芪ã³ã³ããŒãã³ãâ import React , { useState , useCallback } from 'react' ; import DropDownList from 'components/common/DropDownList' ; import UserType from 'types/user' ; interface Props { users: UserType [] ; } const User = ( props: Props ) => { const { users } = props ; // DropDownã§éžæããåäžã®ãŠãŒã¶ãŒã®ååãStateã§ç®¡ç const [ userName , setUserName ] = useState (); const handleSetUserName = useCallback (( name: string ) => { setUserName ( name ) } , [] ); return ( < div > < span > ãŠãŒã¶ãŒäžèЧ < span > // DropDownListã«å¯ŸããŠstringåãæå®ããŠåŒã³åºã < DropDownList < string > users = { users } setListItem = { handleSetUserName } / > < div > ); } ; export default User ; // 芪ã³ã³ããŒãã³ãâ¡ import React , { useState , useCallback } from 'react' ; import DropDownList from 'components/common/DropDownList' ; import PriceType from 'types/price' ; interface Props { price: PriceType [] ; } const Price = ( props: Props ) => { const { price } = props ; // DropDownã§éžæããåäžã®äŸ¡æ ŒãStateã§ç®¡ç const [ price , setPrice ] = useState (); const handleSetPrice = useCallback (( price: number ) => { setPrice ( price ) } , [] ); return ( < div > < span > äŸ¡æ ŒäžèЧ < span > // DropDownListã«å¯ŸããŠnumberåãæå®ããŠåŒã³åºã < DropDownList < number > listItems = { price } setListItem = { handleSetPrice } / > < div > ); } ; export default Price ; //types export type ListItemType < T > = { key: number ; value: T ; //keyãæ±çšçãªvalueãšããååã«ãvalueã®åã¯ãžã§ããªãã¯ã« } ; // DropDownListã³ã³ããŒãã³ã import React from 'react' ; import DropDownItem from 'components/commmon/DropDownItem' ; import ListItemType from 'types/common' //æ±çšçãªåã«å€æŽ //芪ã³ã³ããŒãã³ãããæž¡ããåãTã« interface Props < T > { listItems: ListItemType < T > [] ; setListItem: ( value: T ) => void ; //芪ã³ã³ããŒãã³ãã§ç®¡çããStateãã»ããããAction } //芪ã³ã³ããŒãã³ãããæž¡ããåãTã« const DropDownList = < T ,>( props: Props < T >) => { const { listItems , setListItem } = props ; return ( < div > { listItems.map ( listItem => { return ( < DropdownItem < T > key = { listItem.key } value = { listItem.value } setValue = { setListItem } / > ); } ) } < div > ); } ; export default DropDownList ; äžèšã®ããã«DropDownListã³ã³ããŒãã³ãã® interfaceãæœè±¡ç ã«ããŠãããããšã§ãè€æ°ã®(åãéã)芪ã³ã³ããŒãã³ãããåŒã³åºãäºãå¯èœã«ãªããŸããã DropDownListã³ã³ããŒãã³ãå
ã§æ±ãpropsãæ±çšæ§ã®é«ãååã«ããããšã§ãã¢ããªã±ãŒã·ã§ã³å
šäœã§å
±éå©çšãããããªããšæããŸãã ãããã« ä»åã¯ãžã§ããªãã¯åãçšããŠãæ±çšæ§ã®é«ãReactã³ã³ããŒãã³ããäœæããæ¹æ³ã玹ä»ããŸããã æ¯éãã³ã³ããŒãã³ããå
±éåããéã®éžæè¢ã®äžã€ãšããŠèæ
®ããŠã¿ãŠãã ããã ã¹ã¿ã¡ã³ã§ã¯äžç·ã«ãããã¯ãéçºãé²ããŠããã仲éãåéããŠããŸãïŒ èå³ãæã£ãŠããã ããæ¹ã¯ãæ¯éäžèšã®åéããŒãžã埡芧ãã ããã Webã¢ããªã±ãŒã·ã§ã³ãšã³ãžãã¢åéããŒãž
ç®æ¬¡ ã¯ããã« jsonapi-rspecã®install æ¢åã®RequestSpecã«ããèŠããããã¹ãã±ãŒã¹ã®äŸ jsonapi-rspecã§çœ®ãæããŠã¿ã ãããã« ã¯ããã« ããã«ã¡ã¯ãæ ªåŒäŒç€Ÿã¹ã¿ã¡ã³ã§ãšã³ãžãã¢ãããŠãã ã¯ã«ãŸã ã§ãã 4æãããµãŒããŒãµã€ããšã³ãžãã¢ãšããŠãåŒç€Ÿãããã¯ã TUNAG ã®éçºãè¡ã£ãŠãããŸãã TUNAGã§ã¯ããŠãŒã¶ããªãã£ã®åäžãç®çã«ãæ¢åæ©èœã®ReactåãNativeåãé²ããããŠããŸãã ãã®éã«ã jsonapi_serializer ãšããGemã䜿çšããŠAPIå®è£
ãè¡ã£ãŠããŸããresponseã¯JSON:API圢åŒã§ååŸããããšãåºæ¥ãŸãã ãŸããåŒç€Ÿã§ã¯ APIããã¥ã¡ã³ãå ãé²ããŠãããRequestSpecã«ããçµåãã¹ããå¿
ã远å ããAPIã€ã³ã¿ãŒãã§ãŒã¹ã«å¯ŸããŠããã¥ã¡ã³ããäœæã远å ããããã«ããŠããŸãã TUNAGã®æ¢åã®RequestSpecã«ã¯äžèšã®ãããªåé¡ç¹ããããŸãã responseã®statusãIDå€ã®ã¿ã®ãã¹ãã±ãŒã¹ãå€ããAPIããã¥ã¡ã³ãã«èšèŒãããŠããå屿§å€ã«é¢ãããã¹ãã±ãŒã¹ãå°ãªã responseã®ãã¹ããæ·±ããªãå Žåã«ã response['data'][0]['a']['b'] ã®ããã«å¯Ÿè±¡ã®ãã¹ãããŒã¿ãååŸããå¿
èŠãããããããã¹ããäœæãã人以å€ãèŠãå Žåã«ãçŽæçã«åããã«ãããã¹ãã±ãŒã¹ã«ãªã£ãŠããŸã ä»åŸãAPIãå®è£
ããæ©äŒãå¢å ãããAPIããã¥ã¡ã³ãã®å屿§å€ã«é¢ããŠãæ£ãããæ
ä¿ããçºã«ããã现ããããããŠçŽæçã«RequestSpecãæžããããšããããŒãºããããŸããã ãã®ããããããã®åé¡ç¹ãè§£æ¶ããããã«ãä»å㯠jsonapi-rspec ãšããGemã詊ããŠã¿ãŸããã ãã®äœ¿çšæãææ³ã«ã€ããŠãŸãšããŠã¿ãããšæããŸãã jsonapi-rspecã®install å
¬åŒã®README éãã§ãããäžèšã®æé ã§installãèšå®ãããŸãã Gemfileã«è¿œèšããŸã gem ' jsonapi-rspec ' ãããžã§ã¯ãã«installããŸã bundle install spec/spec_helpers.rbã«èšå®ã远èšããŸã ãã¹ãã±ãŒã¹ã®äžã§keyãstringåãsymbolåã®ã©ã¡ãã䜿çšãããå Žå㯠config.jsonapi_indifferent_hash = true ãšèšå®ããŸãã # spec/spec_helpers.rb require ' jsonapi/rspec ' RSpec .configure do | config | config.include JSONAPI :: RSpec # Support for documents with mixed string/symbol keys. Disabled by default. config.jsonapi_indifferent_hash = true end æ¢åã®RequestSpecã«ããèŠããããã¹ãã±ãŒã¹ã®äŸ äžèšã®ãããªTODOã¢ããªã±ãŒã·ã§ã³ãäŸãšããŠããã¹ãã±ãŒã¹ãäœæããŸãã /api/v1/tasksã«ã¢ã¯ã»ã¹ããéã«ãTODOãªã¹ãäžèЧãååŸããããšãåºæ¥ã TODOãªã¹ãã®äžã«ã¯ããå®äºããšãæªå®äºãã®ã¿ã¹ã¯ãããã/api/v1/tasksã®ãšã³ããã€ã³ãã«ãã©ã¡ãŒã¿ãä»äžããããšã§ãçµã蟌ã¿ãè¡ãããšãå¯èœ require ' rails_helper ' RSpec .describe ' Api::V1::Tasks ' , type : :request do describe ' GET /api/v1/tasks ' do # å®äºããŠããTODOã¿ã¹ã¯ããŒã¿ãäœæ let!( :complete_todo_task ) # 詳现ã¯å²æ # æªå®äºã®TODOã¿ã¹ã¯ããŒã¿ãäœæ let!( :incomplete_todo_task ) # 詳现ã¯å²æ # responseãããååŸããããŒã¿IDãé
åãžæ ŒçŽ let( :json ) { JSON .parse(response.body, symbolize_names : true ) let( :response_todo_tasks ) { json[ :data ].map { | task | task[ :id ].to_i } } context ' æ£åžžç³» ' do context ' ãã©ã¡ãŒã¿ãŒãååšããªãå Žå ' do it ' TODOãªã¹ããååŸãã ' do get ' api/v1/tasks ' expect(response_todo_tasks).to eq [complete_todo_task.id, incomplete_todo_task.id] end end context ' ãã©ã¡ãŒã¿ãŒãååšããå Žå ' do context ' å®äºã®ãã©ã¡ãŒã¿ãŒãä»äžããå Žå ' do it ' å®äºããŠããTODOããŒã¿ã®ã¿ååŸãã ' do get ' api/v1/tasks ' , params : { status : ' complete ' } expect(response_todo_tasks).to eq [complete_todo_task.id] end end context ' æªå®äºã®ãã©ã¡ãŒã¿ãŒãä»äžããå Žå ' do it ' æªå®äºã®TODOããŒã¿ã®ã¿ååŸãã ' do get ' api/v1/âââ ' , params : { status : ' incomplete ' } expect(response_todo_tasks).to eq [incomplete_todo_task.id] end end end end end end TUNAGã®æ¢åã®RequestSpecã§ã¯ãã®ããã«ãã¬ã¹ãã³ã¹ããååŸããããŒã¿ã®IDã«ããINãOUTå€ããã¹ããããã¹ãã±ãŒã¹ãå€ãååšããŸãã ä»åã®APIã®responseäŸã¯äžèšã®ãããªæ§é ãšãªããŸãããIDå€ä»¥å€ã®å屿§å€ããã¹ããããå Žåã«ã察象ã®ããŒã¿ãååŸãããŸã§ã倧å€ã§ããããŸãAPIã®ã€ã³ã¿ãŒãã§ãŒã¹ã倿Žãããéã®ããã¹ãã®ä¿®æ£ç¹ãå€ããªã£ãŠããŸããŸãã { :data => [{ :id => " âââ " , :type => " tasks " , :attributes => { :title => " 宿é¡ãçµããããïŒ " :status => " å®äº " , } }, { :id => " âââ " , :type => " tasks " , :attributes => { :title => " è²·ãç©ã«è¡ãïŒ " :status => " æªå®äº " , } } ], :meta => { :total_todo_num => 2 } } jsonapi-rspecã§çœ®ãæããŠã¿ã å
çšã®ãã¹ãã±ãŒã¹ã jsonapi-rspec ã䜿çšããŠçœ®ãæãããã®ãäžèšã«ãªããŸãã require ' rails_helper ' RSpec .describe ' Api::V1::Tasks ' , type : :request do describe ' GET /api/v1/tasks ' do # ããŒã¿ãäœæããç®æã¯å²æ # 屿§æ¯ã®ãã¹ããããããå€æŽ let( :json ) { JSON .parse(response.body, symbolize_names : true ) let( :response_todo_tasks ) { json[ :data ] } context ' æ£åžžç³» ' do context ' ãã©ã¡ãŒã¿ãŒãååšããªãå Žå ' do it ' TODOãªã¹ããååŸãã ' do get ' api/v1/tasks ' expect(response_todo_tasks[ 0 ]).to have_id(complete_todo_task.id) expect(response_todo_tasks[ 1 ]).to have_id(incomplete_todo_task.id) end # æ°èŠã«metaã®ãã¹ãã±ãŒã¹ã远å it ' metaããŒã¿ãååŸããããšãåºæ¥ã ' do get ' api/v1/tasks ' expect(json).to have_meta( total_todo_num : 2 ) end end context ' ãã©ã¡ãŒã¿ãŒãååšããå Žå ' do context ' å®äºã®ãã©ã¡ãŒã¿ãŒãä»äžããå Ž ' do it ' å®äºããŠããTODOããŒã¿ã®ã¿ååŸãã ' do get ' api/v1/tasks ' , params : { status : ' complete ' } expect(response_todo_tasks[ 0 ]).to have_type( ' tasks ' ) expect(response_todo_tasks[ 0 ]).to have_id(complete_todo_task.id) expect(response_todo_tasks[ 0 ]).to have_attribute( :title ).with_value( ' 宿é¡ãçµããããïŒ ' ) expect(response_data[ 0 ]).to have_attribute( :status ).with_value( ' å®äº ' ) end end context ' æªå®äºã®ãã©ã¡ãŒã¿ãŒãä»äžããå Žå ' do it ' æªå®äºã®TODOããŒã¿ã®ã¿ååŸãã ' do get ' api/v1/tasks ' , params : { status : ' incomplete ' } expect(response_todo_tasks[ 0 ]).to have_type( ' tasks ' ) expect(response_todo_tasks[ 0 ]).to have_id(incomplete_todo_task.id) expect(response_todo_tasks[ 0 ]).to have_attribute( :title ).with_value( ' è²·ãç©ã«è¡ãïŒ ' ) expect(response_todo_tasks[ 0 ]).to have_attribute( :status ).with_value( ' æªå®äº ' ) end end end end end end ãããã£ãšããŠäžèšã䜿çšããŠããŸãã have_type have_id JSON:APIã§ãªãœãŒã¹ã®å€å¥ã«äœ¿çšããã type ãš id ããã¹ãããmatcher have_attribute(key).with_value(value) attributesé
äžã«keyãå«ãŸããããšãã®å€ããã¹ãããmatcher have_meta metaããŒã¿ã«é¢ããŠkeyãšå€ããã¹ãããmatcher ãã®ä»ã«ããªãœãŒã¹éã®é¢é£ããã¹ãããå¿
èŠãããå Žåã« have_relationship().with_data() ãªã©ã®matcherãçšæãããŠããŸãã APIã®ã€ã³ã¿ãŒãã§ãŒã¹ã«æ²¿ã£ã圢ã§ãã¹ãã±ãŒã¹ãæžãããšãåºæ¥ããããããçŽæçã«ãã¹ããæžãããšãåºæ¥ãããã«ãªããŸããã ãŸãããã¹ãäœæè
以å€ãèŠãŠããã¹ãã®æå³ãæç¢ºã§ãããã€ã³ã¿ãŒãã§ãŒã¹ã®å€æŽã«äŒŽããã¹ãã®ä¿®æ£ã容æã«ãªããšæããŸãã ãããã« APIããã¥ã¡ã³ãã¯æ¢åæ©èœãReactåãNativeåããã«ããããå€ãã®ããŒã ãåç
§ãããããAPIã®ã€ã³ã¿ãŒãã§ãŒã¹ã®æ£ç¢ºæ§ãæ
ä¿ããããšãéèŠã§ããããªãã¹ã詳现ã«ãã¹ããæžãå¿
èŠããããšèããŠããŸãã JSON:APIã®RequestSpecãããæžãããããåãããããããããã«æçšãªGemã ãšæããŸãã®ã§ãæ¯é詊ããŠã¿ãŠãã ããïŒ ã¹ã¿ã¡ã³ã§ã¯äžç·ã«ãããã¯ãéçºãé²ããŠããã仲éãåéããŠããŸãïŒ èå³ãæã£ãŠããã ããæ¹ã¯ãæ¯éäžèšã®åéããŒãžã埡芧ãã ããã Webã¢ããªã±ãŒã·ã§ã³ãšã³ãžãã¢åéããŒãž
ç®æ¬¡ ã¯ããã« ã¢ããããŒãã®æµã Google Cloud Storage ã®æºå å®è£
ãããã« ã¯ããã« ããã«ã¡ã¯ãã¹ã¿ã¡ã³ã®ããã¢ãã§ãã ã¹ã¿ã¡ã³ã§ã¯ TUNAG ã FANTS ãšãããµãŒãã¹ãæäŸããŠãããç»åã®ä¿åå
ãšã㊠Amazon Web Services ã®S3ïŒSimple Storage ServiceïŒãæ¡çšããŠããŸãã Google Cloud StorageïŒä»¥äžãGCSïŒã®å Žåãã©ãããæµãã§ç»åãä¿åãããç¥ããããšæããèªåã®åŠç¿ãšã㊠GCS ãçšãã眲åä»ãURLã«ããç»åã®ã¢ããããŒããå®è£
ããã®ã§ç޹ä»ãããŠããã ããŸãã ã¢ããããŒãã®æµã ä»åã¯ã¯ã©ã€ã¢ã³ãããçŽæ¥GCSãžç»åãã¢ããããŒãããŸãã éä¿¡ã®æµãã¯ä»¥äžã«ãªããŸãã Google Cloud Storage ã®æºå ãµãŒãã¹ã¢ã«ãŠã³ã æåã«ãGCSã®ãã±ããã«ã¢ã¯ã»ã¹ããããã®ãµãŒãã¹ã¢ã«ãŠã³ããäœæããŸãã Google Cloud Platformã«ã¢ã¯ã»ã¹ãããµã€ãããŒãããIAMãšç®¡ç > ãµãŒãã¹ã¢ã«ãŠã³ãããéžæããŠãã ããã ããµãŒãã¹ã¢ã«ãŠã³ãã®äœæããã¯ãªãã¯ããŸãã ãµãŒãã¹ã¢ã«ãŠã³ãåãå
¥åãããµãŒãã¹ã¢ã«ãŠã³ãã®æš©éãšããŠãCloud Storage > Storageãªããžã§ã¯ã管çè
ããéžæããŸãã ã¢ããªã±ãŒã·ã§ã³ã§äœæãããµãŒãã¹ã¢ã«ãŠã³ããå©çšããããããŒã远å ããŸãããµãŒãã¹ã¢ã«ãŠã³ãã®äžèЧã§å¯Ÿè±¡ã¢ã«ãŠã³ãã®ãç·šéããã¯ãªãã¯ããŠãã ããã ãµãŒãã¹ã¢ã«ãŠã³ãã®è©³çްãããéµã远å ããã¯ãªãã¯ããJSON圢åŒã§éµãäœæããŠãã ãããããã§äœæããéµããµãŒããŒãµã€ãã®å®è£
æã«å©çšããŸãã ãã±ãã ç¶ããŠãã±ããã®äœæãããŸãã ãµã€ãããŒãããStorage > ãã©ãŠã¶ããéžæããŠãã ããã ãã±ããåã®å
¥åãããŒã¿ã®ä¿åå Žæãã¹ãã¬ãŒãžã¯ã©ã¹çãéžæãããã±ãããäœæããŸãã 以äžã§ Google Cloud Storage ã®æºåã¯å®äºã§ãã å®è£
ãµãŒããŒãµã€ã 眲åä»ãURLãçºè¡ããããã®ã¢ãžã¥ãŒã«ãäœæããŸãã å
çšäœæãããµãŒãã¹ã¢ã«ãŠã³ããçšããŠã¯ã¬ãã³ã·ã£ã«ãçæãããããçšããŠãã±ããã«å¯Ÿãã眲åä»ãURLãçºè¡ããŸãã content_typeãæå®ããªããšã¯ã©ã€ã¢ã³ãããã®ã¢ããããŒããäžæããããªãããã眲åä»ãURLãçºè¡ããæç¹ã§content_typeãæå®ããŠãããŸãã require ' google/cloud/storage ' module Utils :: Gcp :: Storage GCP_SA_CREDENTIALS = { private_key : ' ãµãŒãã¹ã¢ã«ãŠã³ãã®private_key ' , client_email : ' ãµãŒãã¹ã¢ã«ãŠã³ãã®client_email ' } GCS_PROJECT_ID = ' GCPã®ãããžã§ã¯ãID ' GCS_BUCKET_NAME = ' GCPã®ãã±ããå ' class << self def pre_signed_url (path, content_type, expires) @storage = Google :: Cloud :: Storage .new( project_id : GCP_PROJECT_ID , credentials : GC_SA_CREDENTIALS ) expires = expires.to_i @storage .signed_url( GCS_BUCKET_NAME , path, method : ' PUT ' , content_type : content_type, expires : expires) end end end Resourceã§ããã€ã³ã¹ã¿ã³ã¹ããã¢ãžã¥ãŒã«ã® pre_signed_url ã¡ãœãããåŒã³åºããã¬ã¹ãã³ã¹ãšããŠè¿åŽããŸãã class Resource < ApplicationRecord def pre_signed_url (filenameã GCSäžã®ãã¡ã€ã«å ã, content_type) Utils :: Gcp :: Storage .pre_signed_url( " resouces/ #{ id } /images/ " + filename, content_type, 5 .minutes.from_now) end end ã¯ã©ã€ã¢ã³ããµã€ã æåã®ã·ãŒã±ã³ã¹å³éãã以äžã®é çªã§ãªã¯ãšã¹ããéããŸããïŒãšã©ãŒãã³ããªã³ã°ã¯çç¥ããŠããŸããïŒ çœ²åä»ãURLã®ååŸ GCSãžã®ç»åã¢ããããŒã ã¢ããããŒããããç»åã®æ
å ±ãDBãžä¿å å®è£
ãšããŠã¯ä»¥äžã®ããã«ãªããŸãã const uploadImage = async ( file , resourceId ) => { // 眲åä»ãURLã®ååŸ const res = await fetch ( "眲åä»ãURLååŸãšã³ããã€ã³ã" + `?content_type= ${ file . type } ` ) const resJson = await res . json () ; // 眲åä»ãURLãçšã㊠Google Cloud Storage ãžã¢ããããŒã await fetch ( resJson . preSignedUrl , { method : "PUT" , headers : { "Content-Type" : file . type } , body : file }) // ã¢ããããŒããããç»åã®æ
å ±ãDBãžä¿å fetch ( "ç»åã®æ
å ±ãDBãžä¿åãããšã³ããã€ã³ã" , { method : "POST" , headers : { "Content-Type" : "application/x-www-form-urlencoded; charset=utf-8" } , body : `uniq_filename= ${ resJson . filename } &filename= ${ file . name } &content_type= ${ file . type } &byte_size= ${ file . size } ` } ) } ãããã« GCS ãçšãã眲åä»ãURLã«ããç»åã®ã¢ããããŒãã«ã€ããŠç޹ä»ãããŠããã ããŸãããæ³å®ããŠããããç°¡åã«ç»åã®ã¢ããããŒããå®çŸã§ããã®ã§è¯ãã£ãã§ããä»åã¯ã¢ããããŒãã®æµããæžããŸããããæ©äŒãããã°ç»åé
ä¿¡ã«ã€ããŠãèšäºã«ã§ããããšæããŸãã ã¹ã¿ã¡ã³ã§ã¯äžç·ã«åããšã³ãžãã¢ãåéããŠããŸãã èå³ãããæ¹ã¯ããã² æ¡çšãµã€ã ãããé£çµ¡ãã ããïŒ
ã¯ããã« æ¬èšäºã§ã¯ RSpec ã® request spec ãã OpenAPI 仿§ã®ããã¥ã¡ã³ããåºåãã Gemãrspec-openapi ã玹ä»ããŸãã ããã¥ã¡ã³ããŒã·ã§ã³ããŒã«å°å
¥ã«ããã£ãŠã®è² æ
ãå°ãªãããããå®è£
ãšããã¥ã¡ã³ããä¹é¢ããªãããã«ãããããšããå Žåã«åèã«ãªããããããŸããã èæ¯ ãããŸã§åŒç€Ÿã§ã¯ã API ããã¥ã¡ã³ãã¯ç€Ÿå
wiki ã«èç©ãããŠããŸããã æåã¯ããã§ãåé¡ã«ãªããªãã£ãã®ã§ãããæ©èœãå¢ããŠããããšã«ãã£ãŠããã¥ã¡ã³ãã®æ°ãå¢ããŠç®¡çãé£ãããªã£ããã ãã©ãŒããããæç¢ºã§ãªãã®ã§æžã人ã«ãã£ãŠã°ãã€ãããããšããåé¡ãã¡ãã»ãåºãŠããããã«ãªããŸãã API ããã¥ã¡ã³ãæšæºåãšããã° OpenAPI ãæãã€ããã®ã®ãèšè¿°ã®ããã« DSL ãçè§£ããå¿
èŠããããšã远å ã§äœãåŠç¿ãå¿
èŠãšãªããšãå
šå¡ã«æµžéãããã®ã¯ããŒãã«ãé«ããã§ãã ãã¡ãã OpenAPI 仿§ã«åãããšã®äŸ¡å€ãããŒã ãšããŠåæã§ããŠããã話ã¯å¥ã ãšæããŸããä»åã¯ãããŸã§ãŸã£ãã䜿ã£ãŠããªãç¶æ³ããå°å
¥ããããšããåæãªã®ã§å°ãã§ãç°¡åã«å°å
¥ã§ããã»ããæãŸããã§ãã rspec-openapi ã¯ã¢ãŠããããã OpenAPI ãã©ãŒããããã€æ¢åã® request spec ããã®ãŸãŸå©çšã§ãããšããããšã§ãäžèšã®æ¡ä»¶ã«é©ããŠããã®ã§ã¯ãªãããšæã詊ããŠã¿ãŸããã äœ¿ãæ¹ Gemfile ã«ä»¥äžã®ããã«è¿œèšã㊠Gem ãã€ã³ã¹ããŒã«ããŸãã gem ' rpsec-openapi ' , group : :test OPENAPI=1 ãšç°å¢å€æ°ãã»ããã㊠request spec ãå®è¡ãããšãdoc é
äžã« openapi.yaml ãšãããã¡ã€ã«ãçæãããŸãã $ OPENAPI = 1 rspec path/to/request_spec_file Rails ã§ãªããŠã䜿ããŸãããå
éšã§ Rails ãã©ããã®å€å®ã§åŠçãåå²ããŠããç®æãããã€ãããã®ã§ã现ããéšåãªã©éãããããããããŸããã äŸãèŠãŠãŸãããã 以äžã®ãããªã³ã³ãããŒã©ãŒãšãã¹ãã±ãŒã¹ãçšæããŸããã class Api :: PostsController < ApplicationController def index posts = [ { title : ' foo ' } ] render json : { posts : posts } end end require ' rails_helper ' RSpec .describe ' Api::Posts ' , type : :request do describe ' GET /api/posts ' do it ' get posts ' do get api_posts_path, params : { title : ' f ' } expect(response).to have_http_status( :ok ) end end end ãã¹ããå®è¡ãããš OPENAPI = 1 rspec spec/requests/api/posts_spec.rb doc/openapi.yaml ã«ä»¥äžã®ãããªå
容ãçæãããŸãã --- openapi : 3.0.3 info : title : rspec-openapi-sample paths : "/api/posts" : get : summary : index tags : - Api::Post parameters : - name : title in : query schema : type : string example : f responses : '200' : description : get posts content : application/json : schema : type : object properties : posts : type : array items : type : object properties : title : type : string example : posts : - title : foo ãã®ãã¡ã€ã«ã Swagger Editor ãªã©ã«èªã¿èŸŒãŸãããšãåé¡ãªãçæã§ããŠããã®ããããããšæããŸããïŒversion ã ãæåã§è¿œèšããŸããïŒ å®è¡çµæããçæãããšãã仿§äžãå®è¡çµæã«å«ãŸããªãæ
å ±ã¯ååŸã§ããªãã®ã§ããã®ç¹ã«ã€ããŠã¯æçŽããå¿
èŠã§ãã äŸãã°å¿
é ãã©ã¡ãŒã¿ãã¬ã¹ãã³ã¹ã®ãã£ãŒã«ãã nullable ãªã®ãã©ãããªã©ã®å³å¯ãªåæ
å ±ã¯ããã¹ãã±ãŒã¹ã ãã ãšå€å¥ãã€ããŸããã åºåãã¡ã€ã«ã«ã¯è¿œèšã¯ãããŠãäžæžãã¯ãããªãã®ã§ãæã§çŽããç®æãä¿æããªããããã¥ã¡ã³ããæ¡å
ããŠããããšãã§ããŸãã ãŸãšã RSpec ããããã¥ã¡ã³ããçæãã rspec-openapi ã玹ä»ããŸããã æ¢åè³ç£ïŒrequest specïŒããã®ãŸãŸæŽ»ããããšã§å®è£
è
ã«ã»ãŒè² æ
ã®ãªã圢ã§å°å
¥ã§ãããšããç¹ã¯ãé¡äŒŒã®ã©ã€ãã©ãªãšæ¯ã¹ãŠãåªããŠãããšããã ãªãšæããŸãã è¯ããã°è©ŠããŠã¿ãŠãã ããã åè rspec-openapi OpenAPI Specification
ããã«ã¡ã¯ãããã³ããšã³ããšã³ãžãã¢ã® æž¡é ã§ãã æ®æ®µã¯ReactãšTypeScriptãæžããŠããŸãã ä»åã®å
容ã¯ã¿ã€ãã«ã«ãèšèŒãããŠããŸãããNext.jsã䜿ã£ãç»åã®æé©åã§ãã ç»åã®æé©åã§ããã¹ãããšã¯å€ã
ãããŸãã äŸãã°ãç»åã®ãµã€ãºã»éã調æŽãããã©ãŒããããé
å»¶èªã¿èŸŒã¿ãªã©ãããŸãã Next.js 10ã§çºè¡šããã next/image ã䜿ãã°èª°ã§ãç°¡åã«ç»åã®æé©åãè¡ããããã«ãªããŸããã ãã®èšäºã§ã¯ä»¥äžã®ãããªæ¹ã察象è
ãšãªããŸãã - ç»åã®æé©åïŒããããšãªãã - èªåã§ãã£ãŠããããªã詊ããŠã¿ãã ãã ããNext.jsã®äœ¿ãæ¹ãªã©ã¯ä»åã¯èšèŒããŠããªãã®ã§ããäºæ¿ãã ããã ç®æ¬¡ ç»åæé©åãããšãªã«ãããã®ïŒ å®éã«next/image䜿ã£ãŠã¿ã ãŸãšã ç»åæé©åãããšãªã«ãããã®ïŒ 以äžã®ãããªã¡ãªããããããŸãã - ç»åãæé©åããããšã«ããããŒãžã®èªã¿èŸŒã¿éåºŠãæ¹åã§ãã - SEOã®æ¹å ç»åãæé©åããããšã«ããããŒãžã®èªã¿èŸŒã¿éåºŠãæ¹åã§ãã ç»åãå€çšããããŒãžã§ã¯æé©åããŠããããããŠããªããã§å€§ããèªã¿èŸŒã¿é床ã«å·®ãåºãŠããŸãã äŸãã°ãECãµã€ãã§ãã£ãããã©ã³ãã£ã³ã°ããŒãžã«çœ®ããŠèªã¿èŸŒã¿é床ãé
ããšãŠãŒã¶ãŒãé¢è±ããŠå£²äžã«ãããªã圱é¿åºãŠããŸãã 以äžã®ç»åã¯GoogleãããŒãžè¡šç€ºé床ããŠãŒã¶ãŒã«ã©ã®ããã圱é¿ãããã調æ»ããå
容ã§ãã åŒçšå
ïŒ Find Out How You Stack Up to New Industry Benchmarks for Mobile Page Speed 1ç§ãã3ç§ã§32ïŒ
1ç§ãã5ç§ã§90% 1ç§ãã6ç§ã§106% 1ç§ãã10ç§ã§123% çŽåž°ç ãå¢å ããŠããŸããŸãã SEOã®æ¹å SEOã®æ¹åïŒãšæãããæ¹ããããšæããŸãã ã©ãããããšããšãããšãGoogleããWebããŒãžã®è¡šç€ºé床ãé
ããšæ€çŽ¢ã®ã©ã³ãã³ã°ã«åœ±é¿ãåºãããšèšã£ãŠããŸãã 詳现㯠ãã¡ã ãšããããšãããç»åã®æé©åããããŠããªã衚瀺é床ãé
ããªãæ€çŽ¢ã©ã³ãã³ã°ãäœäžãããããããŠãŒã¶ãŒã«èŠã«æ¥ãŠããããªãå¯èœæ§ãã§ãŠããŸãã äžèšã®ä»ã«ãæé©åããããšã«ãã£ãŠã®ã¡ãªããã¯å€ã
ãããŸãã ãã ããã¡ããæé©åããã«ã¯å·¥æ°ããããããã«å€§å€ã§ãã ããã§ãNext.jsã䜿ãã°ç»åã®æé©åãèªåã§è¡ã£ãŠããããšããããšã§ãã å®éã«next/image䜿ã£ãŠã¿ã nextã®ãµã³ãã«ã¢ããªã±ãŒã·ã§ã³ãäœæãèµ·åãããŸãã npx create-next-app image-pra cd image-pra yarn dev ã¢ããªã±ãŒã·ã§ã³ãèµ·åããã public é
äžã«ä»åã詊ãã§äœ¿çšããç»åãé
眮ããã®ãšã page/index.js ã以äžã®ããã«æžãæããŸãã import Image from 'next/image' function Home() { return ( <> <h1>Image optimisation</h1> <Image src= "/sample.jpg" // publicã«é
眮ããç»å alt= "sample picture" width= { 500 } height= { 300 } /> </> ) } export default Home ããã ãã§æé©åãããç»åã衚瀺ãããŸãã åºæ¬çã«äœ¿ãæ¹ã¯æ¢åã® <img> ãšåãã§ãã ãã ã height ãš width ãèšå®ããªããšãšã©ãŒãåºãŸãã ããã§ã¯ãã¢ã¹ãã¯ãæ¯ã«ãã£ãæ°å€ããããŠããããã°ãããšã¯Imageã³ã³ããŒãã³ããã¬ã¹ãã³ã·ãã«ç»åãµã€ãºã調æŽããŠãããŸãã å®éã«Imageã³ã³ããŒãã³ãã¯ä»¥äžã®ããã«å€æãããŠããŸãã 倿ããã <img> ã§src屿§ã® /_next/image ãšãããšã³ããã€ã³ããæ°ã«ãªã£ãã®ã§èª¬æããŠãããŸãã ä»åsrcã§æå®ãããŠãã /_next/image ã¯Next.js 10ãããäºãçšæãããŠãããšã³ããã€ã³ãã§ãã _next/image ã®ãªã¯ãšã¹ããåãããš next-server ã¯imageOptimizerãå®è¡ããŠããŸãã https://github.com/vercel/next.js/blob/canary/packages/next/next-server/server/next-server.ts æç² { match: route( '/_next/image' ), type: 'route' , name: '_next/image catchall' , fn: (req, res, _params, parsedUrl) => imageOptimizer(server, req, res, parsedUrl), } , image-optimizer.ts ãã®åŒã³åºãããŠãã image-optimizer.ts ã§æ§ã
ãªæé©ååŠçãè¡ããŠããŸãã äŸãã°ããã©ãŠã¶ãWebPã«å¯Ÿå¿ããŠããå Žåã«ã¯WebPã«å€æãããªã©ã®å¯Ÿå¿ããããŠããŸãã ãã®ããã«ãã³ãŒãã®äžãèªããšå®éã«ã©ã®ããã«æé©åããŠããããããã£ãŠé¢çœãã®ã§æ¯éãæéããæ¹ã¯èªãã§ã¿ãŠãã ããã 話ãããããããŠããŸããŸãããã Vercel ã«ãããã€ããã°ç¹ã«èšå®ããå¿
èŠãªã䜿ããŸãããšãŠã楜ã§ãããã å€éšãµãŒãã¹ã§æé©åããå Žå imgixãCloudinaryã®å€éšã®ãµãŒãã¹ã§ç»åã®æé©åãè¡ãå Žå㯠next.config.js ã§èšå®ããŸãã äŸãã°imgix䜿ãå Žåã¯ä»¥äžã®ããã«ãªããŸãã module.exports = { images: { loader: 'imgix' , path: 'https://example.com/myaccount/' , } , } 詳ããç¥ãããæ¹ã¯ image-optimization#loader ã埡芧ãã ããã <img> ãšImageã³ã³ããŒãã³ãã®æ¯èŒ äžã® sample.jpg ã <img> ã§è¡šç€ºããŠããç»åã§ãäžã® image?url=~~ ã®ã»ãã Image ã³ã³ããŒãã³ãã§è¡šç€ºããç»åã§ãã ç»åã®èªã¿èŸŒã¿æã®è©³çްãèŠãŠã¿ããšãèªã¿èŸŒã¿é床ãšãµã€ãºã倧å¹
ã«æ¹åãããŠããŸãã ããã©ã«ãã§ãããŸã§æ¹åã§ãããçŽ æŽãããã§ãã äŸãã°ãããç»åã ãå質ãäžããŠããããªãšãããšãã«ã¯ã quality ã«æ°å€ãæž¡ããŠãããã ãã§èª¿æŽãã§ããŸãã <Image src= "/sample.jpg" alt= "sample picture" width= { 500 } height= { 300 } quality= { 50 } // ããã§èª¿æŽãã(ããã©ã«ãã¯75) /> ããããããšã§ãããSizeãæã蟌ããŸãã ãã®ä»propsã«ã€ããŠã¯ next/image#usage ã埡芧ãã ããã ç»åæé©åã®å
šäœèšå® ç»åæé©åã®å
šäœã§ã®èšå®ã¯ next.config.js ã§è¡ããŸãã module.exports = { images: { // ããã«èšèŒ } , } ãã¡ãã詳现㯠image-optimization#configuration ã埡芧ãã ãã ãŸãšã Next.jsã®Imageã³ã³ããŒãã³ãã䜿ãã ãã§ç»åãç°¡åã«æé©åããããšãã§ããŸãã ä»å玹ä»ããããªãã£ããã§ãããåæè¡šç€ºã§è¡šç€ºãããç»åãç»é¢ã®å€ã«ããå Žåã¯ãviewportãèšç®ããŠé
å»¶èªã¿èŸŒã¿ãŸã§ããŠãããŸããæè¿ã®Next.jsã¯æé·ããšãŠã€ããªãéãã質ãé«ãã®ã§ä»åŸã楜ãã¿ã§ãã æ ªåŒäŒç€Ÿã¹ã¿ã¡ã³ã§ã¯äžç·ã«åããšã³ãžãã¢ãåéããŠããŸãããèå³ã®ããæ¹ã¯ãã² ãšã³ãžãã¢æ¡çšãµã€ã ãã芧ãã ããã
ç®æ¬¡ ã¯ãã㫠䜿çšããé¢é£ä»ã preloadãeager_loadãincludesã®æå includesã¯ã©ã®ãããªå Žåã«preloadãšeager_loadã®æåãšãªãã®ã preloadãeager_loadã®äœ¿ãåã ãããã« ã¯ããã« ããã«ã¡ã¯ãæ ªåŒäŒç€Ÿã¹ã¿ã¡ã³ã§ãšã³ãžãã¢ãããŠãã ã¯ã«ãŸã ã§ãïŒ 4æãããµãŒããŒãµã€ããšã³ãžãã¢ãšããŠãåŒç€Ÿãããã¯ã TUNAG ã®éçºãè¡ã£ãŠãããŸãã å
æ¥ãåŒç€ŸCTOã® æŸè°· ãšãã¢ãããè¡ããŸããã ããã©ãŒãã³ã¹æ¹åã®ã¿ã¹ã¯ãè¡ããŸããããã¿ã¹ã¯ãéããŠN + 1åé¡ã«è€æ°åçŽé¢ããŸããã Active Recordã«ãããŠãN + 1åé¡ãè§£æ¶ããæ¹æ³ãšããŠãé¢é£ããŒãã«ã®ããŒã¿ãäºåã«èªã¿èŸŒãã§ããããã£ã·ã¥ããŠãããšããæ¹æ³ãåããšæããŸãããRailsã§ã¯ãã®æ¹æ³ãšããŠpreloadãeager_loadãincludesã¡ãœãããçšæãããŠããŸãã ããããã®ã¡ãœããã®æåã®éãã«ã€ããŠãéœåºŠèª¿ã¹çè§£ããããã«ããŠããŸãããããã¢ãããéããŠçè§£ãæµ
ããšæããçºãä»åã¯preloadãeager_loadãincludesã®æåã®éãã䜿ãæã«ã€ããŠãŸãšããŠãããŸãã æ€èšŒç°å¢ Ruby version 2.5.1 Rails version 6.0.3.4 䜿çšããé¢é£ä»ã äžèšã®ã¢ãã«éã®é¢é£ä»ããåæãšããŠåã¡ãœããã®æåã®éãã説æããŠãããŸãã class Company < ApplicationRecord has_many :users has_many :departments end class User < ApplicationRecord belongs_to :companies has_many :departments , through : :deparment_user_maps end class Department < ApplicationRecord belongs_to :company has_many :users , through : deparment_user_maps end # ãŠãŒã¶ãŒãéšçœ²ã«æå±ããŠããããæ±ãäžéããŒãã« class DepartmenUserMap < ApplicationRecord has_many :users has_many :deparments end åã¡ãœããã®æå preload æå®ããé¢é£ããŒãã«æ¯ã«å¥ã¯ãšãªãäœæãé¢é£ããŒãã«ã®ããŒã¿é
åãååŸãããã£ãã·ã¥ããŸãã åŒæ°ã«å€å¯Ÿå€ã®é¢é£å
ãæž¡ããå Žåã¯ãäžéããŒãã«ãä»ããŠååŸããã£ãã·ã¥ããŸãã preloadããé¢é£å
ã§çµã蟌ã¿ãè¡ã£ãå Žåã¯ãäŸå€ãæããŸãã Company .preload( :users , :departments ) â SELECT ` companies ` .* FROM ` companies ` SELECT ` users ` .* FROM ` users ` WHERE ` users ` . ` company_id ` IN â»â»â» SELECT ` departments ` .* FROM ` departments ` WHERE ` departments ` . ` company_id ` IN â»â»â» Department .preload( :users ) â SELECT ` departments ` .* FROM ` departments ` SELECT ` department_user_maps ` .* FROM ` department_user_maps ` WHERE ` department_user_maps ` . ` department_id ` IN â»â»â» SELECT ` users ` .* FROM ` users ` WHERE ` users ` . ` id ` IN â»â»â» # äŸå€ãæãã Company .preload( :users ).where( users : { id : 1 }) â Mysql2 :: Error : Unknown column ' users.id ' in ' where clause ' : SELECT ` companies ` .* FROM ` companies ` WHERE ` users ` . ` id ` = 1 eager_load LEFT_OUTER_JOINã§æå®ããããŒã¿ãçµåããŠé¢é£ããŒãã«ã®ããŒã¿é
åãååŸãããã£ãã·ã¥ããŸãã åŒæ°ãšããŠæž¡ããé¢é£å
ã®èŠçŽ ã§çµã蟌ã¿ãè¡ãããšãåºæ¥ãŸãã Company .eager_load( :users ).where( users : { id : 1 }) â SELECT ` companies ` . ` id ` AS t0_r0, ` companies ` . ` name ` AS t0_r1, ` users ` . ` id ` AS t1_r0, ` users ` . ` name ` AS t1_r1, FROM ` companies ` LEFT OUTER JOIN ` users ` ON ` users ` . ` company_id ` = ` companies ` . ` id ` WHERE ` users ` . ` id ` = 1 includes åŸè¿°ããŸãããããã©ã«ãã§ã¯preloadãšåãæåãé¢é£å
ã®ããŒãã«ã®èŠçŽ ã§çµã蟌ã¿ãè¡ã£ãå Žåãªã©ã¯eager_loadãšåãæåãããŸãã Company .includes( :users ) â SELECT ` companies ` .* FROM ` companies ` SELECT ` users ` .* FROM ` users ` WHERE ` users ` . ` company_id ` IN â»â»â» Company .includes( :users ).where( users : { id : 1 }) â SELECT ` companies ` . ` id ` AS t0_r0, ` companies ` . ` name ` AS t0_r1, ` users ` . ` id ` AS t1_r0, ` users ` . ` name ` AS t1_r1, FROM ` companies ` LEFT OUTER JOIN ` users ` ON ` users ` . ` company_id ` = ` companies ` . ` id ` WHERE ` users ` . ` id ` = 1 includesã¯ã©ã®ãããªå Žåã«preloadãšeager_loadã®æåãšãªãã®ã ActiveRecordã«ã¯äžèšã®ããã«åã¡ãœãããå®çŸ©ãããŠããŸã # activerecord/lib/active_record/relation/query_methods.rb:150 def includes (*args) check_if_method_has_arguments!( :includes , args) spawn.includes!(*args) end def includes! (*args) self .includes_values |= args self end # activerecord/lib/active_record/relation/query_methods.rb: 166 def eager_load (*args) check_if_method_has_arguments!( :eager_load , args) spawn.eager_load!(*args) end def eager_load! (*args) self .eager_load_values |= args self end # activerecord/lib/active_record/relation/query_methods.rb:180 def preload (*args) check_if_method_has_arguments!( :preload , args) spawn.preload!(*args) end def preload! (*args) self .preload_values |= args self end ãã®æç¹ã§ã¯ã¯ãšãªãçºè¡ãããããããincludes_valuesãeager_load_valuesãpreload_valuesã«å€ãæ ŒçŽããŠããã ãã§ãã ãã®åŸãexec_queriesã¡ãœããå
ã§eager_loading?ã¡ãœããã«ããå€å®ãè¡ããpreloadãšeager_loadã䜿ãåããŠããŸãã # activerecord/lib/active_record/relation.rb:667 def exec_queries (&block) @records = if eager_loading? find_with_associations do | relation , join_dependency | if ActiveRecord :: NullRelation === relation [] else rows = connection.select_all(relation.arel, " SQL " , relation.bound_attributes) join_dependency.instantiate(rows, &block) end .freeze end else klass.find_by_sql(arel, bound_attributes, &block).freeze end preload = preload_values preload += includes_values unless eager_loading? preloader = nil preload.each do | associations | preloader ||= build_preloader preloader.preload @records , associations end @records .each(& :readonly! ) if readonly_value @loaded = true @records end # activerecord/lib/active_record/relation.rb:597 def eager_loading? @should_eager_load ||= eager_load_values.any? || includes_values.any? && (joined_includes_values.any? || references_eager_loaded_tables?) end eager_loading?ã¡ãœããã¯äžèšã®å Žåã«trueãšãªããŸãã eager_load_valuesãååšããŠãã(eager_loadã¡ãœããã䜿çšããŠãã) includes_valuesãååšããŠãã(includesã¡ãœããã䜿çšããŠãã) ã〠å¥ããŒãã«ãjoinsããŠãã ã é¢é£å
ã®ããŒãã«ã§çµã蟌ã¿ãè¡ã£ãŠãã includesã¡ãœããã®å Žåã¯2ã€ç®ã®æ¡ä»¶ã«åœãŠã¯ãŸãå Žåãeager_loading?ãtrueãšãªããŸãã 詳现ã¯å²æããŸãããeager_loading?ãtrueã®å Žåã¯find_with_associationsã¡ãœããå
ã§çµååŠçããããŠãããŸãã ãŸãšãããšincludes㯠ããã©ã«ãã§ã¯preloadãšåæ§ã®æå ä»ããŒãã«ãçµååŠçããŠããããé¢é£å
ã®ããŒãã«ã§çµã蟌ã¿ãè¡ã£ãŠããå Žåã¯eager_loadãšåãæåã«ãªã ã¡ãœããã®å®è£
ã®éããè€æ°ã®ã¢ãœã·ãšãŒã·ã§ã³ãåŒæ°ã§æž¡ãããšããŠããã©ã¡ããçæ¹ã®ã¿preloadãããçæ¹ã¯eager_loadãè¡ããšããæåã«ã¯ãªããŸãããå¿
ãã©ã¡ãã®ã¢ãœã·ãšãŒã·ã§ã³ãpreloadãããããeager_loadããããšããæåã«ãªããŸãã preloadãeager_loadã®äœ¿ãåã äžè¿°ã®å
容ãèžãŸãããšãincludesã¯ã¯ãšãªãå¶åŸ¡ãã«ãããããåºæ¬çã«åªå
ããŠpreloadãeager_loadã䜿çšããæ¹ãè¯ããšèããããŸãã ãã®äžã§preloadãeager_loadã®äœ¿ãæãèããŠã¿ãŸãã preload has_manyã®é¢é£ãæã€ããŒã¿ã®äºåèªã¿èŸŒã¿ãè¡ãå Žå è€æ°ã®é¢é£å
ã®äºåèªã¿èŸŒã¿ãè¡ãå Žå eager_loadã§ã¯åžžã«çµååŠçãè¡ããããããŒã¿éã倧ãããšèããããæ¡ä»¶äžã§ã¯ãéãã¯ãšãªãå®è¡ããããšã«ãªã£ãŠããŸããã¯ãšãªãåå²ããŠäºåèªã¿èŸŒã¿ãè¡ã£ãæ¹ãã¬ã¹ãã³ã¹ãæ©ããªããšèããããŸãã â»äž»ããŒãã«ã®ã¬ã³ãŒãæ°ãå€ãå Žåã¯ãINå¥ã倧ãããªã£ãŠããŸããããDBåŽã§ã®èšå®å€ã確èªããå¿
èŠãããããã§ãã eager_load é¢é£å
ã®èŠçŽ ã§çµã蟌ã¿ãè¡ãããå Žå has_oneãbelongs_toé¢é£ãªã©1ã¯ãšãªã§ããŒã¿ãååŸããæ¹ãå¹çãè¯ããšèããããå Žå é¢é£å
ãäžèšã®ããã«â察1ã§é¢é£ä»ããããŠããå Žåãå€éšçµåããŠãååŸããã¬ã³ãŒãæ°ã«å€ããã¯ç¡ãã1ã¯ãšãªã§ããŒã¿ãååŸåºæ¥ãããpreloadããå¹çãè¯ããšèããããŸãã æåŸã« preloadãeager_loadãincludesã®æåã䜿ãã©ããã«ã€ããŠãŸãšããŠã¿ãŸããã ããã©ãŒãã³ã¹ã®åé¡ã¯ã¬ã³ãŒãæ°ãå¢å ããã«ã€ããŠé¡åšåããŠãããããæªç¶ã«é²æ¢ããçºã«ããæ¥é ããããããã©ãŒãã³ã¹ãæèããã³ãŒããæžãããšãåºæ¥ãããã«æèããŠãããããšæããŸãã ã¹ã¿ã¡ã³ã§ã¯äžç·ã«ãããã¯ãéçºãé²ããŠããã仲éãåéããŠããŸãïŒ èå³ãæã£ãŠããã ããæ¹ã¯ãæ¯éäžèšã®åéããŒãžã埡芧ãã ããã Webã¢ããªã±ãŒã·ã§ã³ãšã³ãžãã¢åéããŒãž
ã¿ãªããããã«ã¡ã¯ïŒ æ ªåŒäŒç€Ÿã¹ã¿ã¡ã³ã§äž»ã«TUNAGã®ã¢ãã€ã«ã¢ããªãéçºããŠãã ã«ãŒã ã§ãã ã¹ã¿ã¡ã³ã«æ£åŒã«å
¥ç€ŸããŠ11æã§çŽå幎ãçµã¡ãŸããã ã¹ã¿ã¡ã³ã§ã¯èªå·±ç éœãšããŠã®èªæžãæšå¥šãããŠããã瀟å
ã§ãäºãã«æ¬ããªã¹ã¹ã¡ãåããå¿
èªBookããšããå¶åºŠãã圹å¡ããçŽæ¥ ç®æ¬ããŠããããã圹å¡ç®æ¬ããšããå¶åºŠããããŸãã ãã®èšäºã§ã¯ããããªã¹ã¿ã¡ã³ã§å幎ãéãããŠããæ°åãšã³ãžãã¢ããå
¥ç€ŸåŸå幎ã§ã©ããªããžãã¹æžãèªãã§ããã®ãã玹ä»ããããšæããŸãã ãã®èšäºã§ã¯ããžãã¹æžã®ç޹ä»ã®ãããæè¡æžã¯äžåç»å ŽããŸããããšã³ãžãã¢åãã®èªã¿ç©ãä»åã¯çããŸããã æèç³» ã©ã€ããã€ããŠããŸããâåé¡çºèŠã®äººéåŠ ã©ã€ããã€ããŠãŸããâåé¡çºèŠã®äººéåŠ äœè
: ããã«ãã»Cã»ãŽãŒã¹ , G.M.ã¯ã€ã³ããŒã° çºå£²æ¥: 1987/10/25 ã¡ãã£ã¢: åè¡æ¬ ã¿ã€ãã«ã«ãããããã«æ¬è³ªçãªåé¡ã®çºèŠãäž»é¡ã«ãããæ¬ã§ããåé¡ãé 匵ã£ãŠè§£ããŠãããããã®åé¡ãæ¬è³ªçã§ãªã誀ã£ãŠããã°ãæå³ããããŸãããæ¬æžã瀺ããåé¡ãèŠæ¥µããã㯠ãããã¯ãããŒã ã®VALUE(䟡å€èгãè¡åæé) ã«ãå«ãŸããŠãããã¹ã¿ã¡ã³ ãããã¯ãããŒã ã®è¡ãšãªã骚ãšãªã£ãŠããŸãã ã€ã·ã¥ãŒããã¯ãããââç¥ççç£ã®ãã·ã³ãã«ãªæ¬è³ªã ã€ã·ã¥ãŒããã¯ããã â ç¥ççç£ã®ãã·ã³ãã«ãªæ¬è³ªã äœè
: å®å®
å人 çºå£²æ¥: 2014/09/01 ã¡ãã£ã¢: Kindleç ç¥ççç£ã®æ¬è³ªãæã瀺ããŠãããæ¬ããã®æ¬ãèªãã§ãããä»ãŸã§èªåããªããšéå¹çã«ä»äºãããŠããã®ãããšæãç¥ããŸããããã®æ¬ã®ã¯ããã«ããããæ©ãããšãèãããã®éããã¯ãšãŠãå°è±¡ã«æ®ã£ãŠããŠãèªåããæ©ãã§ããããšèªèŠãããã³ã«æ¬æžãæãåºããŠãèãããããšåãæ¿ããããããã«ãªããŸããããŸããåé¡è§£æ±ºã®5ã¹ããããã¯åžžã«ç¢ºèªã§ãããããã¡ã¢ããŠåäžã«çœ®ããŠããŸãã ãšãã»ã³ã·ã£ã«æè æå°ã®æéã§ææãæå€§ã«ãã ãšãã»ã³ã·ã£ã«æè æå°ã®æéã§ææãæå€§ã«ãã äœè
: ã°ã¬ãã°ã»ããã¥ãŒã³ çºå£²æ¥: 2014/12/12 ã¡ãã£ã¢: Kindleç èªåã«ãšã£ãŠæ¬åœã«å¿
èŠãªä»äºã ããããããšããæ¬ãå
¥ç€ŸãããŠãšããããšãããããä»äºããããããšãå¬ãããŠãªãã§ãåŒãåããŠããŸããã¡ãªèªåã«ã¯åºãããŸããããåããããšããåããªãããšãã®ç·åŒãã®ç« ã¯ãšãŠãå°è±¡ã«æ®ã£ãŠããŸãã SINGLE TASK SINGLE TASK äžç¹éäžè¡ââãã·ã³ã°ã«ã¿ã¹ã¯ã®ååãã§ãã¹ãŠã®ææãæå€§ã«ãªã äœè
: ããã©ã»ã¶ã㯠çºå£²æ¥: 2017/09/01 ã¡ãã£ã¢: Kindleç ãã«ãã¿ã¹ã¯ã¯ãããŠäžã€ã®ããšã«éäžããããšããæ¬ãä»å¹Žã¯ãªã¢ãŒãã§æ¥åãè¡ãæéãé·ããå®¶ã ãšãªããªãéäžåãç¶ããªããšæãèªã¿ãŸãããæ¬æžã§ã¯ãã ã·ã³ã°ã«ã¿ã¹ã¯ããããïŒãšèšãã ãã§ã¯ãªãããã®ããã®ç°å¢ã¥ãã(åšå²ã®äººãžã®é
æ
®ãç¿æ
£å)ããã£ãã説æãããŠããŠãå®è·µçã§ãšãŠãè¯ãã£ãã§ãã æèäžæ¯ã«ãªã æèäžæ¯ã«ãªãïŒ (å¹»å¬èæ°æž) äœè
: éœè€å çºå£²æ¥: 2020/07/29 ã¡ãã£ã¢: Kindleç æèããç¿æ
£ã®ã¡ãªããããã®æ¹æ³ã«ã€ããŠæžãããŠããŸããåŸè¿°ãã ä»äºãã§ãããšã¯ã©ãããããšã ãèªãã ãšãã«ãã»ã³ã¹ã身ã«ã€ããã«ã¯æèãç¶ãããããªãããããªããããšæããã®æ¬ãæã«ããŸããããç¬ããšã¯ãªãšã€ãã£ããã£ãã«ã€ããŠæžãããç« ãå人çã«ã¯èè
ã®æè€åããããããŠãšãŠã奜ãã§ããã ã³ãã¥ãã±ãŒã·ã§ã³ 人ãåãã 人ãåãã æåº«ç äœè
: ã»ã«ãŒãã®ãŒ çºå£²æ¥: 2016/01/26 ã¡ãã£ã¢: Kindleç åæ»ãªå¯Ÿäººé¢ä¿ã«ã€ããŠæžãããèšãããšç¥ããåèãåãã¯ãªãŒãã£ãªããã¯ãšããŠè³Œå
¥ããŠããŸããããäœç³»çã«èªã¿çŽããããšæãæåº«çã賌å
¥ãçŽããŸãããæžããŠããããšäžã€äžã€ã¯åœããåã®ããšãå€ãã§ãããæ±çšæ§ããšãŠãé«ããåãã°åãã»ã©å³ã®åºãã¹ã«ã¡ã®ãããªæ¬ã§ãããæäžã§ãã©ãã©ããã£ãŠèªã¿è¿ãããã§ãã éè«ã®äžæµãäºæµãäžæµ éè«ã®äžæµãäºæµãäžæµ (ã¢ã¹ã«ããžãã¹) äœè
: æ¡ç çš çºå£²æ¥: 2020/03/05 ã¡ãã£ã¢: åè¡æ¬ïŒãœããã«ããŒïŒ äžæµãäºæµãäžæµã®éè«ã段éçã«æžãããŠããæ¬ãèªåã¯ãšã³ãžãã¢ã§ã¯ãããã®ã®ã瀟å
ã§ã®ã¡ãã£ãšããéè«ãã亀æµãçãŸããããšããããŸãããªã¢ãŒãã ãããšèšã£ãŠãéè«ããèãã«ã§ããªããšæãèªã¿å§ããŸãããèªåã®éè«ã®ãã¿ãŒã³ãçµæ§ãäºæµãã®ãã®ãå€ããèªãã§ããŠé©ããšçºèŠããããŸãããèªäºããåŸã¯éè«ãžã®ãæããããæ¥œãã¿ãã«å€ãããŸããã Team Geek Team Geek âGoogleã®ã®ãŒã¯ãã¡ã¯ããã«ããŠããŒã ãäœãã®ã äœè
: Brian W. Fitzpatrick , Ben Collins-Sussman çºå£²æ¥: 2013/07/20 ã¡ãã£ã¢: åè¡æ¬ïŒãœããã«ããŒïŒ ãšã³ãžãã¢éå£ã«ãããããŒã ã®äœãæ¹ã»ããæ¹ãæžããæ¬ãèªåã®äžã§ã¢ã€ã£ãŠãããå¿ççå®å
šããšèšãã¯ãŒããè¬èã»å°æ¬ã»ä¿¡é Œã®äžæ¬æ±ã§æ¯ããããŠãããã ïŒãšåããçŽåŸããæ¬ãä»ã¯æ°äººãšããããšã§ãè¬èã»å°æ¬ã»ä¿¡é Œããä¿ãŠãŠãããã©ãããããåŸèŒ©ãå
¥ã£ãŠãããšãã«ããã®æ±ã¯å€§äºã«ããããšæããŸãã åãæ¹ å°ããªããŒã ã倧ããªä»äº å°ããªããŒã ã倧ããªä»äºãåãæ¹ã®æ°ããã¹ã¿ã³ããŒã (ãã€ã«ã¯æåº«NF) äœè
: ãžã§ã€ãœã³ ããªãŒã , ãã€ãŽã£ãã ãã€ããã€ã€ãŒ ãã³ãœã³ çºå£²æ¥: 2016/12/15 ã¡ãã£ã¢: Kindleç Ruby on Railsã®éçºè
ã§ããDHHãªã©ãèè
ãšããŠåå ããŠããæ¬ããã³ãã£ãŒãªã©å°ããªããŒã ã«ãããä»äºã®æ¹æ³ãæèæ³ã«ã€ããŠæžãããæ¬ã§ãå
¥ç€ŸããçŽåã«èªãã§å£«æ°ãé«ããŠããŸããããšã³ãžãã¢çéã§æå㪠Getting Real ãããäžè¬åããæ¬ã§ãããæ¥æ¬èªã®æåº«æ¬ãšããŠèªããã®ã¯ãã®æ¬ã®ã¿ãªã®ã§ãªã¹ã¹ã¡ã§ãã æ©ãæ£ããæ±ºããæè¡ æ©ãæ£ããæ±ºããæè¡ äœè
: åºå£ æ²»æ çºå£²æ¥: 2018/02/26 ã¡ãã£ã¢: Audibleç ã©ã€ããããçåœåµæ¥è
ã®åºå£ãããèè
ã®æ¬ã決æåã®ãªãèªåããªããšãããªãããšæã£ãŠè³Œå
¥ããŸãããæ¬æžã§ã¯æ±ºæã¯ãæ°åãããã¡ã¯ãããããžãã¯ãã§æ±ºãŸããšãããŸããèªåã®äžã§ãµããµããšæµ®ããŠãããæ±ºæåããšããææ§ãªèšèãããæ°åãããã¡ã¯ãããããžãã¯ãã®3ã€ã«èœãšã蟌ãŸããããšã§ããä»ã®ç¶æ³ã§ã¯ããã¡ã¯ãããè¶³ããŠããªãã®ã§ã¯ïŒããªã©ãšãããå
·äœçã«æèããããšãã§ããããã«ãªããŸããã ãä»äºãã§ããããšã¯ã©ãããããšã ãä»äºãã§ããããšã¯ã©ãããããšãïŒ äœè
: æ¥ æšå¥ , å±±å£åš çºå£²æ¥: 2019/12/16 ã¡ãã£ã¢: Kindleç ãä»äºãã§ããããšã¯ã¹ãã«ã§ã¯ãªããã»ã³ã¹ã®åé¡ã§ãããšããæ¬ãæ¬ãèªãããšã§ã¹ãã«ã¯æã«å
¥ããããããªããã©ãã»ã³ã¹ãšãªããšèªåã®äžã§æèããŠçæããããããªãã®ããªãšæããããŸãããã»ã³ã¹ã磚ãããã«å
·äœãšæœè±¡ãå埩çã«æèããã ã£ãããããããæèãè¶³ããŠãªãããããªãããªã©ãããããèãããã£ããã«ãªããŸããã äžçªã«ãªã人 äžçªã«ãªã人 äœè
: ã€ããâ çºå£²æ¥: 2013/11/01 ã¡ãã£ã¢: Kindleç ä»å¹Žã«ãªã£ãŠãããŒãããžã§ã¯ãã«ã©ãããããã®ã§ãããããåµå§è
ã®ã€ããâãå·çããããã®æ¬ãèªã¿ãŸãããã·ã£ä¹±Qã®ããŒã«ã«ããããŠã¢ãŒãã³ã°åšãã®ãããã¥ãŒãµãŒãšããŠæŽ»èºããã€ããâã®ä»äºå²åŠãè©°ãŸã£ãŠããŸããæžãããŠããããšèªäœã¯ç®æ°ããããšã¯ãªãã§ãããããããã·ã£ä¹±Qãã¢ãŒåšããããã¥ãŒã¹æä»£ã®åºæ¥äºã«äžæãã¯ãŸã£ãŠããŠèª¬åŸåããããŸãã 岩ç°ãã-岩ç°è¡ã¯ãããªããšã話ããŠããã 岩ç°ãã: 岩ç°è¡ã¯ãããªããšã話ããŠããã (ã»ãŒæ¥ããã¯ã¹) äœè
: ã»ãŒæ¥åã€ãã€æ°è çºå£²æ¥: 2019/08/05 ã¡ãã£ã¢: Kindleç 任倩å ã®å
瀟é·ã§ããã倩æããã°ã©ããŒã§ããã£ã岩ç°ããã®èããŠããããšããã€ã³ã¿ãã¥ãŒããŸãšãŸã£ãŠããæ¬ããã®æ¬ãèªããŸã§å²©ç°ããã¯ãDSãšãWiiã®çºè¡šåç»ã«åºãŠã人ããããã®èªèã ã£ããã®ã®ããã®æ¬ãã岩ç°ããã®èª å®ããæ»²ã¿åºãŠããŠãããããèªåããããªãšã³ãžãã¢ã«ãªãããããšæãããŸããã ããžãã¹ THE MODEL THE MODELïŒMarkeZine BOOKSïŒ ããŒã±ãã£ã³ã°ã»ã€ã³ãµã€ãã»ãŒã«ã¹ã»å¶æ¥ã»ã«ã¹ã¿ããŒãµã¯ã»ã¹ã®å
±æ¥ããã»ã¹ äœè
: çŠç° 康é çºå£²æ¥: 2019/01/30 ã¡ãã£ã¢: Kindleç ããŒã±ãã£ã³ã°ãã€ã³ãµã€ãã»ãŒã«ã¹ãå¶æ¥ãã«ã¹ã¿ããŒãµã¯ã»ã¹ããæ§æãããæ°ããå¶æ¥ã®ããæ¹ããšã³ã·ã¹ãã ã«ã€ããŠæžãããæ¬ããŸãã«ã¹ã¿ã¡ã³ã®TUNAGã®äºæ¥äœå¶ãæ¬æžãåèã«æ§æãããŠããã®ã§ãTUNAGã®ããžãã¹ã¢ãã«ããã£ãšç¥ãããã«èªã¿ãŸããã ã°ã¬ã€ããã«ãããã«ããŒã±ãã£ã³ã°ãåŠã¶ ã°ã¬ã€ããã«ã»ãããã«ããŒã±ãã£ã³ã°ãåŠã¶ (æ¥çµããžãã¹äººæåº«) äœè
: ãã©ã€ã¢ã³ã»ããªã¬ã³ , ãã€ãŽã£ããã»ããŒã¢ãã³ã»ã¹ã³ãã çºå£²æ¥: 2020/04/02 ã¡ãã£ã¢: æåº« ã°ã¬ã€ããã«ããããšããç±³åœã®ãã³ãããããã«ããŠãã¡ã³ãšã®é¢ä¿ãç¯ããå®å®çãªåå
¥ãåŸãŠããããããŒã±ãã£ã³ã°ã®èŠç¹ã§ã¿ãæ¬ã瀟å
ã§ãããã FANTSäºæ¥ ãå§ãŸãéã«ãäž»å¬è
ãšãã¡ã³ãšã®é¢ä¿ã®äºäŸããã£ãšç¥ããããšæãèªãã æ¬ã§ãã ãã¡ã³ãã ã»ã¬ããªã¥ãŒã·ã§ã³ ãã¡ã³ãã ã»ã¬ããªã¥ãŒã·ã§ã³ãSNSæä»£ã®æ°ããªç±ç (æ©å·æžæ¿) äœè
: ãŸãŒã€ ãã©ãŒã=ãã©ã㌠, ã¢ãŒãã³ M ã°ã¬ã€ã¶ãŒ çºå£²æ¥: 2017/12/15 ã¡ãã£ã¢: Kindleç æå人ãã¢ãŒãã£ã¹ãèªèº«ã®æŽ»åã§ã¯ãªãããã®åšçžã®ãã¡ã³ã®æŽ»åãè¿å¹Žã«ãªã£ãŠå€åããŠããŠããããšã«ã€ããŠæžãããæ¬ããããFANTSäºæ¥ãå§ãŸããšãã«ããã¡ã³ã®æŽ»åãæããäœããµãã³å
ã§ã®æœçã«ã©ã圱é¿ããŠããã®ããæ°ã«ãªãèªãã æ¬ã§ãã ãã³ãã£ã¯ã·ã§ã³ çéçµå¶-æ°çã€ããŒã®500æ¥ çéçµå¶ äœè
: è¯è°·æ çºå£²æ¥: 2013/11/07 ã¡ãã£ã¢: Kindleç 2012幎ã«å®®ååŠãããã€ããŒã®ä»£è¡šåç· åœ¹ã«ãªã£ãŠããã®500æ¥ããŸãšããæ¬ãå
¥ç€ŸãããŠã®åã¯ç€Ÿé·ã£ãŠäžäœäœãããŠãããã ããïŒäºæ¥ãåãã®ã¯çŸå Žã®äººéãåããŠãããããªããããªããïŒãšæã£ãŠããŸãããããããèªãã§ã瀟é·å«ãçµå¶é£ã®æè
ã§äŒç€Ÿã¯ãããã§ãå€åãããŠãããšããããšãåŠã³ãŸããããããŠã€ããŒãšãã倧ããªçµç¹ã®æ¹é©ãçéã§è¡ã£ãå®®åããã®çµå¶è
ãšããŠã®åã¿ãæããŸããã 21æ³ã®åŠçãã200äžäººãåŒã³èŸŒããã©ãŸã€ãããäœãäžãã! 人ãè¡ãåãã!å·»ã蟌ã¿å 21æ³ã®åŠçãã200äžäººãåŒã³èŸŒããã©ãŸã€ãããäœãäžããïŒã人ãè¡ãåããïŒå·»ã蟌ã¿å äœè
: æ°Žé åäž çºå£²æ¥: 2020/04/01 ã¡ãã£ã¢: Kindleç åå€å±ã§20幎éå¬ãããŠãã ãããã³ã©çãäžç¥ã (éç§°: ã©ãŸã€ã)ã®åéå¬ãããŠæ¡å€§ã«ããããå·»ã蟌ã¿åãã«ã€ããŠæžãããæ¬ã瀟å
ã§å匷äŒãªã©ãéå¬ããã«ããã£ãŠãå·»ã蟌ã¿åãå¿
èŠã ãªãšæãèªã¿ãŸãããèªåã¯æç¥ã«äœãã§ããªããäžåºŠãã©ç¥ããçµéšããããšããªããã§ãããåœæã®å€§åŠçãçºèµ·äººãšãªã£ãŠäž»å¬ãããŠããããšã«é©ããŸãããçžæã«çè§£ããŠãããããã«ããªãããã®ããã®æ³ããäŒãããªã©ãã¹ããŒãªãŒã ãã§ãªããã¢ã¯ã·ã§ã³ã«æ³šæããŠèªããšèªåã«ã掻ãããããªãšãããããã€ããããŸãã å¿ã®æã¡æ¹ EQ 2.0 (ãå¿ã®ç¥èœææ°ããé«ãã66ã®ãã¯ããã¯) EQ 2.0 (ãå¿ã®ç¥èœææ°ããé«ãã66ã®ãã¯ããã¯) äœè
: ãã©ãŽã£ã¹ã»ãã©ããããªãŒ , ãžãŒã³ã»ã°ãªãŒãã¹ çºå£²æ¥: 2019/02/25 ã¡ãã£ã¢: åè¡æ¬ïŒãœããã«ããŒïŒ EQ(Emotional Intelligence Quotient)ã¯å¿ã®ç¥èœææ°ãšãåŒã°ããèªåã®ç²Ÿç¥ç¶æ
ãããããä¿ã£ããã仲éãšååã§äœæ¥ãããéã«å¿
èŠãšãããŠããŸãããã®EQã4ã€ã«åé¡ããããããããé«ããããã®æ¹æ³ãæžãããŠããŸããæ¬æžã«ã€ããŠããã³ãŒãã§EQã®ãã¹ãããããããšãã§ããããããèªåã«è¶³ããªãããšãæœåºããŠæããŠãããã®ã§ãèªåãã©ãã«æ³šåããŠããã°ããã®ããåãããšãŠãè¯ãã£ãã§ãã ããã©ãŒãã³ã¹ã»ãããžã¡ã³ã-åé¡è§£æ±ºã®ããã®è¡ååæ- ããã©ãŒãã³ã¹ã»ãããžã¡ã³ãâåé¡è§£æ±ºã®ããã®è¡ååæåŠ äœè
: å³¶å® ç çºå£²æ¥: 2000/03/01 ã¡ãã£ã¢: åè¡æ¬ è¡ååæåŠãèªåãã¡ã®è¡åã«å¿çšããŠæ¹åããŠããããšããæ¬ãæ¬æžã¯å
šãŠãèªåæ»æããããããããå§ãŸã£ãŠããŸãããèªåã®ããã ããšæã£ãŠããŸããšæ¬¡ã«ã¯äœãæ¹åããããæ¬åœã®åé¡ã解決ã§ããŸãããããã§ãã£ãããšèªåã®è¡åãåæããæ¹åããããã«è¡åããããŠããŠããŸãšããããŠããŸããèªåã ãšæè¡ã®å匷ãç¶ããªããšãã«ãµãšãèªåã¯ãªããŠæ æ°ãªãã ããšæã£ãŠããŸããšããããã®ã§ãããæ¬æžãæãåºããŠãã©ããããè¯ãã£ãã®ããªããšåæçã«èããããããã«ãªããŸããã æåŸã« ãããŸã§å幎éã«èªãã§ããæ¬ãæ¯ãè¿ã£ãŠã¿ãŠãããã®æ¬ãããªããšæžããŠããªãããªã©å¿ããããŠããããšãããããšãŠãããæ©äŒã«ãªããŸããã ã¹ã¿ã¡ã³ã¯è¡åæéã« Take Ownership ããããèªå·±ç éœãæšå¥šããæåããããŸããåé ã«ãè¿°ã¹ãŸããããã¹ã¿ã¡ã³ç€Ÿå
ã§ã¯å€ãã®äººãèªæžãéããŠèªå·±ç éœãè¡ã£ãŠããŸãã ããã¯ãšã³ãžãã¢ã§ãåãã§æè¡æžã ãã§ãªãããã¡ç€Ÿå¡ãšããŠåæ»ã«ä»äºãé²ããããã®èªæžãæ¥ã
è¡ã£ãŠããŸãã ã¹ã¿ã¡ã³ã§ã¯ãããªèªå·±ç éœãããŠèªåã«ç£šãããããŠãããšã³ãžãã¢ã®æ¹ãåéããŠããŸãã
ããã«ã¡ã¯ãã¹ã¿ã¡ã³ã§éçºè
ãããŠãã æŽ¥ç° ã§ããIntelliJ IDEAç³»ã®IDEã§ãªã¢ãŒãå
±åéçºãšããã¢ã»ããã°ã©ãã³ã°è¡ãããã®ããŒã«ã Code With Meã9ææ«ã«EAPãªãªãŒã¹ ããããããååãšè©ŠçšããŠã¿ãŸããã Ruby on Railsã¢ããªã±ãŒã·ã§ã³éçºã®ãã¢ã»ããã°ã©ãã³ã°ããé£ã®åžã§è¡ã£ãã®ã§ããããªã¢ãŒãã»ã¯ãŒã¯ã«ãéåžžã«äŸ¿å©ãªããŒã«ã ãšæã£ãã®ã§ãäœ¿çšæã玹ä»ããŸãã Code With Meãšã¯ ã Code With Me EAP ãªãªãŒã¹ ãã«ãããšã Code With Me 㯠IntelliJ IDEA ãšä»ã® IntelliJ ããŒã¹ã® IDE ã§ããŒãžã§ã³ 2020.2.x ãã䜿çšã§ããæ°æ©èœã§ãã ããŒã«ã«ã§å®è¡äžã®ãããžã§ã¯ãã忣ããŒã ãšå
±æã§ããããã«ããŸãã ããŒã ããã°ããã³ãŒãã«ã¢ã¯ã»ã¹ãããªã¢ã«ã¿ã€ã ã«åé¡ã®èª¿æ»ãã¬ãã¥ãŒãã³ãŒãã£ã³ã°äœæ¥ãå
±åã§è¡ããããã«ãªããŸãã ãŸããJetBrains IDE 補åã§äœ¿çšã§ããã³ãŒãã®èªåè£å®ãé«åºŠãªããã²ãŒã·ã§ã³ããªãã¡ã¯ã¿ãªã³ã°ãåçš®ãããã°æ©èœãããã³çµã¿èŸŒã¿ã¿ãŒããã«ã®ã¡ãªãããæå€§éã«æŽ»ãããªããããããã¹ãŠã®äœæ¥ã宿œã§ããŸãã ãšã®ããšã§ãã察å¿ããŠããã®ã¯ã以äžã®IDEã§ãä»åã¯ãã¹ãã«RubyMineã䜿çšããŸããã IDEA Community ããã³ Ultimate / WebStorm / PyCharm Community ããã³ Professional / PhpStorm / GoLand / RubyMine / CLion / AppCode 倧éæã«ãããšãããã¹ãåŽã®IDEããå°çšã¯ã©ã€ã¢ã³ãã䜿ã£ãŠãªã¢ãŒãããæäœã§ãããæ©èœã§ãããã¡ã€ã«ã¯å
šãŠãã¹ãåŽã«ãããã²ã¹ãã¯ãã¹ãã«ãããã¡ã€ã«ãç·šéããããšã«ãªããŸããåžžã«ç»é¢ãåæãããããã§ã¯ãªãããããã¹ããšã²ã¹ã(è€æ°å¯)ã¯å¥ã
ã®ãã¡ã€ã«ãç·šéåºæ¥ãŸãã ãã¹ã(RubyMine)ã®ç»é¢ ã²ã¹ã(IntelliJ Client)ã®ç»é¢ ãäºããä»ã©ã®ãã¡ã€ã«ã§äœæ¥ããŠãããã¯ãâã®ç»é¢ã®ããã«ããã¡ã€ã«ã®ã¿ãã«è¡šç€ºãããåããã¡ã€ã«ã衚瀺ããŠããå Žåã¯ãããããã®ã«ãŒãœã«ã衚瀺ãããŸãã ç»é¢å·Šã®Project Paneã«ã¯ãã¹ãŠã®ãã¡ã€ã«ã衚瀺ãããŠããŸããã FAQ about Code With Me ã«ãããšããã¡ã€ã«ãã³ããŒããŠåæããŠããããã§ã¯ãªãããŸãã éä¿¡ã¯ãã¹ãã»ã²ã¹ãéã®end-to-endã§æå·åããŠãããã§ãã å°å
¥ã»ã»ãã·ã§ã³éå§/åå å°å
¥ã¯ Code With Me EAP ãªãªãŒã¹ ã§èª¬æãããŠãããšããã§ãéåžžã«ç°¡åã§ããã ãã¹ããšãªãåŽã®IDEã§Code With Meãã©ã°ã€ã³ãå°å
¥ãããEnable Access and Copy Invitation Linkããããšã»ãã·ã§ã³ã®URLãçºè¡ããã ã²ã¹ãã¯IntelliJ Clientãã€ã³ã¹ããŒã«ããçºè¡ãããURLã§ã»ãã·ã§ã³ã«åå ãã ãšããæé ã«ãªããŸããä»åã¯åæ¹RubyMineãã€ã³ã¹ããŒã«ãããç¶æ
ã§ã¯ãããã®ã§ãããã²ã¹ããšããŠåå ããåŽã¯ãå¿
ãIntelliJ Clientã䜿çšããããšã«ãªããŸãã IntelliJ Clientã¯ä»ã®IntelliJ ããŒã¹ã® IDEãšäŒŒãç»é¢æ§æã§ããããããŸã§å¥éã«ã€ã³ã¹ããŒã«ãããã¢ããªã±ãŒã·ã§ã³ã§ãããããæ®æ®µäœ¿ã£ãŠããIDEãšåãããã«äœ¿ãããã«ãäºåèšå®ãè¡ã£ãã»ãã䟿å©ã§ããã èªåã®å Žåã(ã©ãããä»çµã¿ã§ãããªã£ããããããªãã§ãã)ããŒãã€ã³ãã¯RubyMineã®ãã®ãåŒãç¶ãããŠãŸããããIdeaVimçã®ãã©ã°ã€ã³ã¯æ¹ããŠã€ã³ã¹ããŒã«ããå¿
èŠããããŸããã èªåã®äœã£ãã»ãã·ã§ã³ã«èªåã§åå ããããšãã§ãããããã¯ãããŠå©çšããåã«ããŒã«ã«ã§è©ŠããŠèšå®ã調æŽãããšã¹ã ãŒãºã ãšæããŸãã Code With Meã®è¯ãç¹ ãã¢ã»ããã°ã©ãã³ã°æã«ç°å¢ã®éããåžåã§ãã ãã¢ã»ããã°ã©ãã³ã°äžãã¡ãã£ãšããŒããŒããåããŠå
¥åããããšãããããªéã«ãããŒããŒãã®ã¬ã€ã¢ãŠãã®éããããŒã¢ãµã€ã³ã®éãetcã§å°æããã±ãŒã¹ããããšæããŸããããããå®å
šã«é²ããŸãã ä»åã¯ãååãMacãèªåã¯UbuntuãšOSããç°ãªãç°å¢ã§ããããããããèªåã®èŠªããã ç°å¢ã§äœæ¥ã§ããŸããã ã²ã¹ããããã¹ãåŽã®Run Configurationãã¿ãŒããã«ã䜿ãã ãã¡ã€ã«ã®ç·šéã ãã§ãªãããã¹ãã®Run Configurationãå©çšãããã¹ãã®å®è¡ããã¿ãŒããã«çµç±ã§ãã°ã®tailãªãããå¯èœã§ãã ä»åã¯åããªãã£ã¹ã§äœæ¥ããŠãããã²ã¹ãã®ãã·ã³ããããã¹ãã®ããŒã«ã«IPãåç
§ããŠWebããŒãžãšããŠè¡šç€ºããããšãå¯èœã ã£ãããRailsã¢ããªã±ãŒã·ã§ã³ã®éçºã«æ®æ®µå¿
èŠãªäœæ¥ã¯ã ãããç¶²çŸ
ã§ãããã§ããã 詊ããŠããŸãããããããã°ã»ãã·ã§ã³ã䜿çšã§ããããã§ãã Jump To, Syncã¢ãŒããäŸ¿å© ããŒã«ããŒã«è¡šç€ºãããŠããä»ã®ãŠãŒã¶ãŒãã¯ãªãã¯ããããCode With Meã®ãã¿ã³ããä»ã®ãŠãŒã¶ãŒãæå®ããããšã§ãFull SyncãFollowã¢ãŒãã«ç§»è¡ã§ããŸãããããã®ã¢ãŒãã®å Žåã¯ãéããŠããã¡ã€ã«ãå Žæãªã©ã®ããšãã£ã¿ã®ç¶æ
ãåæãããŸããJump Toã§ããã°ããã®ãŠãŒã¶ãŒãçŸåšéããŠãããã¡ã€ã«ã«é£ã¶ããšãåºæ¥ãã®ã§ãäžæŠå¥ããŠäœæ¥ã調æ»ããŠããå Žåã§ãç°¡åã«åæµã§ããŸãã äžäŸ¿ã ã£ãç¹ æ€çŽ¢ãé
ã ã²ã¹ãåŽããã®ããã¡ã€ã«åãå
¥åããŠã®ãã¡ã€ã«ãªãŒãã³ããã¯ãŒãã«ããæ€çŽ¢ã®ã¬ã¹ãã³ã¹ããããªãé
ãæããŸããSyncã¢ãŒãã§ãªãå Žåã¯ããã¹ãåŽã§éãããã¡ã€ã«ãåæã«éãããããã§ããªãããããã¡ã€ã«ãæ¢ãã®ã«è¥å¹²æéåããŸããVCS(Git)ã¿ããç¡ããmodifiedãã¡ã€ã«ã«ç°¡åã«ã¢ã¯ã»ã¹ããããšãåºæ¥ãªãããã«æãããããã²ã¹ãåŽã¯ç·šéãããã¡ã€ã«ã¯éãã£ã±ã«ããŠäœæ¥ããã»ããå¿«é©ããç¥ããŸããã å
¥åãæ¶ããŠããŸã ã²ã¹ãã®ãã¡ã€ã«ç·šéãåæ ãããªãããšããã±ãŒã¹ãæã
ãããŸãããç¹ã«ãã»ãã·ã§ã³éå§çŽåŸã«å€ãã£ãå°è±¡ã§ããããã¯çµæ§å°ã£ãã®ã§æ©æã«ä¿®æ£ããããšãããããã§ãã ã²ã¹ããè²ã
ã§ãããã ããã¯äžäŸ¿ãšãããã仿¹ããªãã®ã§ããããããžã§ã¯ãå
šäœãå
±æãããã®ã§ãscratchãã¡ã€ã«ã«ã®ãããŠããã¡ã¢çãå
šãŠå
±æãããŠããŸããŸãã ç¹ã«ãã¿ãŒããã«ã¯ããã¹ãåŽã®ãŠãŒã¶ãŒã§äœã§ãåºæ¥ãŠããŸããããæ³šæãå¿
èŠãªã±ãŒã¹ãããããã§ããã¿ãŒããã«ã®å
±æã¯ãã»ãã·ã§ã³ãžã®åå ãšã¯å¥ã«ãåå¥ã«èš±å¯ãåŽäžã§ãã以äžã®ãããªãã€ã¢ãã°ãåºãŸãã ãŸãšã Code With Meããåãå Žæã§ã®ãã¢ã»ããã°ã©ãã³ã°ã§äœ¿çšããŸããããã¡ã€ã«ã®ç¶æ
ã¯å
±æããªãããå®å
šã«å¥ã®ã¯ã©ã€ã¢ã³ãã§äœæ¥ã§ãããããå¥ã
ã®ç°å¢ã§äœæ¥ã§ããã®ã䟿å©ã§ããããªã¢ãŒãã»ã¯ãŒã¯ã®éã¯ãç»é¢ã®å
±æã ãã§ã¯é£ãããå
±åã§ã®äœæ¥ãè¡ããããã䟿å©ãªã®ã§ã¯ãªãããšæãã®ã§ããªã¢ãŒãã§ã®å
±æã詊ããŠã¿ãããšæããŸãã
ããã«ã¡ã¯ãã¹ã¿ã¡ã³ã§ãšã³ãžãã¢ãªã³ã°ãããŒãžã£ãŒãããŠãã @temoki ã§ãã ååã ãããžã§ã¯ããããžã¡ã³ãå
¥é以å ãšããèšäºã§ãããžã§ã¯ããããžã¡ã³ããšã¯äœãªã®ãïŒã«ã€ããŠæ¬¡ã®ããã«ãŸãšããŸããã ãããžã§ã¯ããšã¯ ç¬èªã®ç®æšãéæããããã«ã決ãŸã£ãæéã®äžã§ãéå£ã§æŽ»åããããš ã§ãã ãããžã§ã¯ããšããã®ã¯ãšãŠãå°é£ã§ããããšãå€ããšæããŸãããããã ãªããšã察åŠããŠ ç®æšãéæããããšã«å°ãã®ããããžã§ã¯ããããžã¡ã³ããªã®ã§ãã ä»åã¯ããããžã§ã¯ãããªããšãããããã®æ¹æ³ã«ã€ããŠãç¹ã«éèŠãªãã€ã³ãã«ã€ããŠãäŒãããããšæããŸãã ãªããšãããé å ååãäŒããã PMBOK ã§ã¯ããããžã§ã¯ãã§ãªããšããã察象ã10åã®ç¥èé åïŒãšãªã¢ïŒãšããŠå®çŸ©ããŠããŸãã ãããŠãããã¯ä»¥äžã«åæãããšããããããžã§ã¯ãã® ãŽãŒã« ã«é¢ãããšãªã¢ãš ããã»ã¹ ã«é¢ãããšãªã¢ã®äºã€ã«åé¡ãããŸãã ãŽãŒã«ã«é¢ããïŒã€ã®ãšãªã¢ Quality / åè³ªïŒææç©ã®åè³ªïŒ Cost / åäŸ¡ïŒææè²»ã人件費ããªã©ãªã©ïŒ Time(Delivery) / çŽæãã¹ã±ãžã¥ãŒã« ããã»ã¹ã«é¢ããïŒã€ã®ãšãªã¢ Scope / ã¹ã³ãŒãïŒãªã«ãããã®ãïŒ Human Resource / èŠå¡ïŒã©ã®ã¡ã³ããŒã§ããã®ãïŒ Communication / ã³ãã¥ãã±ãŒã·ã§ã³ïŒå®äŸäŒã座åžãããŒã«ïŒ Risk / ãªã¹ã¯ïŒç®æšã®éæãé»å®³ããããã®ãšããã®äºé²ïŒ Procurement / 調éïŒå¿
èŠãªããã»ã¢ãã»ã«ããå€éšãã調éïŒ Stakeholders / ã¹ããŒã¯ãã«ããŒïŒãããžã§ã¯ãã«é¢ãããã¹ãŠã®äººïŒ Integration / çµ±åïŒâã®ãšãªã¢ãã¹ãŠãçµ±åããŠã¿ãªããšãïŒ ãããããããŸããããããžã§ã¯ããæåã«å°ãããã«ïŒãããžã§ã¯ãã®å€§å°ã«é¢ãããïŒãããããèããŠããå¿
èŠãããããšã°ããã§ãã ä»åã¯ãã®äžã§ãç§ãæãéèŠã ãšèããããããžã§ã¯ãã®ãŽãŒã«ã«é¢ããïŒã€ã®ãšãªã¢ã«çµã£ãŠèããŠãããããšæããŸãã ãããžã§ã¯ãã®ãŽãŒã« ãããžã§ã¯ãã®ãŽãŒã«ãèããã«ããã£ãŠããŸãã¯ä»äºã§ã®æ¥åžžçãªã·ãŒã³ãäŸã«æããŠã¿ãããšæããŸãã ä»äºäžã§ã®ãšããã·ãŒã³ ããæ¥ã®ããš... ðââïžããã®æžé¡ãã¹ã¿ã¡ã³ã®ðšâðŒããã«éã£ãŠãããŠïŒã ðââïžãããããŸããïŒã åŸæ¥... ðââïžãããªãã ãé¡ãããæžé¡ã®ä»¶ã§ðšâðŒããã«æããã¡ãã£ããïŒã ðââïžããïŒãããã¡ãããšãã®æ¥ã®å€æ¹ã«ã¯éããŸãããïŒã ðââïžãã¡ãããšäžå¯§ãªéä»ç¶ãæ·»ããŸããããã ðââïžããããšãããéã£ãæã®ã¬ã¿ãŒããã¯ã®é åæžã§ããçµè²»ç²Ÿç®ãé¡ãããŸããã ð€Šââïžããªããš...ã ããŠãðââïžããã¯ã¡ãããšå¯Ÿå¿ããããã«èŠããŸããäœããããªãã£ããã§ããããïŒ åé¡ã¯èªèã®ãã ã©ãããðââïžãšðââïžãšã®éã§æ¬¡ã®ãããªèªèã®ããããã£ãããšãåé¡ã®ããã§ãã ðââïžã®å¯Ÿå¿ ðââïžã®æåŸ
éããã® æžé¡ã®åæ¬ æžé¡ã®ã³ã㌠éãææ®µ ã¬ã¿ãŒãã㯠FAX åããšãæ¥ ïŒæ¥åŸ åœæ¥ è²»çš Â¥520 Â¥0 ãã®äžã§ðšâðŒãæãããŠããŸã£ãçç±ã¯ããã®æžé¡ã å¿
èŠãªæ¥ã«åãåããªãã£ã ããšã§ãã ãããžã§ã¯ãã®ãŽãŒã«ã«é¢ãããšãªã¢ãšã㊠Quality ã» Cost ã» Time(Delivery) ã®ïŒã€ãããããšãå
çšãäŒãããŸããã ããã¯äž»ã«è£œé æ¥ã«ãããŠæããéèŠãšãããŠãããšãªã¢ã§ããããã QCD ãšåŒã°ãããã®ã§ãã ãã® QCD ã®èгç¹ã§ãµãããã£ãŠã¿ããšãðââïžã¯ Quality ãæåªå
ãã察å¿ã§ãã£ããšèšããŸãã ããæžé¡ããšãŠãéèŠãªãã®ã§ã確å®ã«åæ¬ãðšâðŒã«å±ããªããã°ãªããªãç¶æ³ã ã£ããšããããðââïžã®å¯Ÿå¿ã¯100ç¹ã§ãã ããããå®éã«ã¯ðšâðŒãæãåªå
ããŠããã®ã¯ Delivery ã§ãããðââïžã®å¯Ÿå¿ã§ã¯ãããæºããããªãã£ãããã«ãðââïžã¯ðšâðŒã«æãããããšã«ãªã£ãŠããŸããŸããã ãŽãŒã«ã®ããåãã ä»åã®åé¡ããªãèµ·ããããäžèšã§èšããšããŽãŒã«ã®ããåãããè¶³ããªãã£ããšããããšã§ãã äŸé Œè
ã§ããðââïžãã仿¥äžã«æ¬²ãããããããFAXã§éã£ãŠïŒããšäžèšæ·»ããŠããã°åé¡ã¯èµ·ããªãã£ãã§ãããã ãããŠäŸé Œãåããðââïžãããããã€ãŸã§ã«å±ãã°ããã§ããïŒããšäžæç¹ã確èªããŠããããšã§ãé²ãããšæããŸãã ããã§ãäŒããããã®ã¯ãäŸé ŒããåŽããããåŽã®ã©ã¡ãããäžæ¹çã«æªããšããããšã¯ããŸããªããšããããšã§ãã ãœãããŠã§ã¢éçºãããžã§ã¯ãã«ãããè£å€ å°ãéã話ã«ãªããŸããããœãããŠã§ã¢éçºãããžã§ã¯ãã«ãããŠçºæ³šå
ãšçºæ³šå
ã®éã§è£å€ãè¡ãããããšããããŸãã 蚎èšã«è³ãäž»ãªåå ã¯ããããžã§ã¯ãã®é
å»¶ã宿ãããã®ã®å質ãè²»çšã®ãµããã¿ãªã©ãQCD ãšãããŽãŒã«ã®ãºã¬ãåå ã§ãã è£å€ã«ãããè«ç¹ã¯ãçºæ³šå
ãšçºæ³šå
ã®ã©ã¡ãã«åé¡ããã£ããããšãªããŸãã ãœãããŠã§ã¢éçºã® çºæ³šå
ã¯ãœãããŠã§ã¢éçºã®ãããšã¿ãªãããããããœãããŠã§ã¢éçºã®ãããžã§ã¯ããããžã¡ã³ã矩åãå
šãããŠãããã©ããããã§ãã¯ãããŸãã ãããŠ çºæ³šå
ã¯çºæ³šãããœãããŠã§ã¢ã§è§£æ±ºãããŠãŒã¶ãŒæ¥åã«é¢ãããããšã¿ãªããããããçºæ³šå
ãžã®å¿
èŠãªæ
å ±æäŸãèŠä»¶å®çŸ©ãžã®åå ãªã©ããœãããŠã§ã¢éçºãžã®åå矩åãæãããŠãããã©ãããåãããŸãã ã€ãŸãããããžã§ã¯ãã«é¢ãã人ãã¹ãŠãååããªããšãããžã§ã¯ãã®æåã¯é£ãããšããããšã§ããã ãããžã§ã¯ãã®ãŽãŒã«èšå® ç§ã¯ ãããžã§ã¯ãã®æåã¯ãŽãŒã«èšå®ãæãéèŠã§ãã ãšèããŠããŸãã ãããžã§ã¯ãéå§æã«èšå®ãããŽãŒã«ã誀ã£ãŠãããšããã®åŸã®ããã»ã¹ããããããŸããã£ãŠãééã£ããŽãŒã«ã«åãã£ãŠããŸãããã§ãã ãããžã§ã¯ããå§ãŸãæã誰ãããŸãã¯çæ³çãªãŽãŒã«ãæ³åããŸãã Quality : é«ã Cost : å®ã Delivery : æ©ã ãããçæ³çãªQCDã§ãããããããã®ãããªãŽãŒã«ããœãããŠã§ã¢éçºã®äžã§æãç«ã€ããšã¯ãŸããããŸããïŒæšããå®ããæ©ãã®æãç«ã€ç䞌ã¯å倧ã§ãïŒã ãªããªããäºç®ã決ãŸã£ãŠããããªãªãŒã¹æ¥ãããã¬ã¹ãªãªãŒã¹ããŠããŸã£ãŠããããªã©ãããžã§ã¯ãã«ã¯å¿
ã QCD ã®ã©ããã«å¶çŽãããããã§ãã ãããžã§ã¯ãããšã«ã©ã®ãããªå¶çŽãããããæœåºãããã®äžã§æè¯ãã©ã³ã¹ã® QCD ã§ãŽãŒã«èšå®ããããšãéèŠã§ãã ãœãããŠã§ã¢éçºãããžã§ã¯ãã§ã®ãŽãŒã«èšå® ãœãããŠã§ã¢éçºãããžã§ã¯ãã«ããã QCD ãå
·äœçã«ãããšæ¬¡ã®ããã«ãªããŸãã Quality / ãœãããŠã§ã¢ã®å質ïŒïŒãã°ãå°ãªããã ãã§ã¯ãªãã®ã§ãŸãå¥ã®æ©äŒã«ïŒ Cost / ã€ã³ãã©è²»çšã人件費ïŒïŒå·¥æ°ïŒ Delivery / çŽæããªãªãŒã¹æ¥ ãœãããŠã§ã¢ã®ãšã³ãžãã¢ã§ããã°ããããã®ã©ãããåªå
ãããšãå¥ã®ãã®ãç ç²ã«ãªããšããã®ã¯æèŠãšããŠããããšæããŸãã ã§ãã®ã§ãããžã§ã¯ãã®å¶çŽã«å¿ããŠæãåªå
ãã¹ããã®ãèšå®ããŸããããäŸãã°ãããªæãã§ããã å»ççŸå Žã§å©çšãããæè¬ç®¡çã·ã¹ãã ã®éçº ð Quality éçšäžã®ã·ã¹ãã ã§çºçãã圱é¿åºŠã®å€§ããé害ã®å¯Ÿå¿ ð Delivery ã³ããã§åçã®æžã£ãŠããŸã£ã芳å
æœèšã®PRãŠã§ããµã€ãã®æ¹ä¿® ð Cost ãã¡ãããããªã«ããããããç¶æ³ã¯ãªãã®ã§ãäŸé Œè
ãšãã£ããããåãããŠãŽãŒã«ãèšå®ããã¹ããŒã¯ãã«ããŒéã§åæããšã£ãŠãããããžã§ã¯ããéå§ããŸãããïŒããã¯ã¹ããŒã¯ãã«ããŒãããžã¡ã³ããšãããšãªã¢ã®è©±ã«é¢é£ããŸããïŒã ãŸãšã ãããžã§ã¯ããããžã¡ã³ãã«ãããŠæãéèŠãªã®ã¯ QCD ãšãããŽãŒã«èšå®ã«ãããŸãã ãããŠãããžã§ã¯ãåºæã®å¶çŽã®äžã§ããã®ãããžã§ã¯ãã®ç¬èªã®ç®æšãéæããããã®æè¯ãã©ã³ã¹ã® QCD ãèšå®ããããšãããããžã§ã¯ãæåãžã®å¿
èŠæ¡ä»¶ã§ãããšããã®ãä»åã®èšäºã®ãŸãšãã§ãã ä»åã®å
容ãå®è·µããã®ã¯ãããžã§ã¯ããããŒãžã£ãŒã ãã§ã¯ãããŸããã äŸã§ãããæ¥åžžçãªä»äºã®ã·ãŒã³ã®ããã«ãå°ããªã¿ã¹ã¯ã§ãã£ãŠããŽãŒã«èšå®ã¯ãšãŠãéèŠã§ãã 倧ããªãããžã§ã¯ãã§ãããã¯å°ããªã¿ã¹ã¯ã®éåã§ãã ãããžã§ã¯ãã«é¢ããã¡ã³ããŒå
šå¡ããããããã®ã¿ã¹ã¯ãæè¯ã®ãŽãŒã«ãšãªãããã«æèããŠè¡åã§ãããã©ãããããããžã§ã¯ãã®é²æã«å€§ããªåœ±é¿ãäžããããšã«ãªããŸãã ãããã宿œããäºå®ã®ã¿ã¹ã¯ã«ã€ããŠæ¹ããŠãŽãŒã«ã®ããåãããããŠããçæããŠã¿ãŠãã ããã ããããããžã§ã¯ããããžã¡ã³ãã®æã广çãªå
¥éãšãªãã¯ãã§ãã æåŸã«ãªããŸãããã¹ã¿ã¡ã³ã§ã¯èªç€Ÿãããã¯ãã®éçºãããžã§ã¯ããäžç·ã«ãªããšãããŠããã仲éãåéããŠããŸããèå³ãæã£ãŠãããæ¹ã¯ããã²äžèšã®æ¡çšãµã€ããã芧ãã ããã ã¹ã¿ã¡ã³ ãšã³ãžãã¢æ¡çšãµã€ã ãã¶ã€ããŒåéããŒãž ãµãŒããŒãµã€ããšã³ãžãã¢åéããŒãž ããã³ããšã³ããšã³ãžãã¢åéããŒãž ã€ã³ãã©ãšã³ãžãã¢åéããŒãž ã¢ãã€ã«ã¢ããªãšã³ãžãã¢åéããŒãž