TECH PLAY

株匏䌚瀟スタメン

株匏䌚瀟スタメン の技術ブログ

å…š234ä»¶

はじめに こんにちはスタメンで゚ンゞニアむンタヌンをしおいる束山です。玄半幎間むンタヌンをしおきたした。今回はむンタヌンの振り返りを曞いおいこうず思いたす。 自己玹介 私は珟圚、愛知県の倧孊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 を蚭定するこずが、プロゞェクト成功ぞの必芁条件です、ずいうのが今回の蚘事のたずめです。 今回の内容を実践するのはプロゞェクトマネヌゞャヌだけではありたせん。 䟋であげた日垞的な仕事のシヌンのように、小さなタスクであっおもゎヌル蚭定はずおも重芁です。 倧きなプロゞェクトでもそれは小さなタスクの集合です。 プロゞェクトに関わるメンバヌ党員が、それぞれのタスクが最良のゎヌルずなるように意識しお行動できるかどうかが、プロゞェクトの進捗に倧きな圱響を䞎えるこずになりたす。 これから実斜する予定のタスクに぀いお改めおゎヌルのすり合わせをしおから着手しおみおください。 それがプロゞェクトマネゞメントの最も効果的な入門ずなるはずです。 最埌になりたすが、スタメンでは自瀟プロダクトの開発プロゞェクトを䞀緒になんずかしおくれる仲間を募集しおいたす。興味を持っおくれた方は、ぜひ䞋蚘の採甚サむトをご芧ください。 スタメン ゚ンゞニア採甚サむト デザむナヌ募集ペヌゞ サヌバヌサむド゚ンゞニア募集ペヌゞ フロント゚ンド゚ンゞニア募集ペヌゞ むンフラ゚ンゞニア募集ペヌゞ モバむルアプリ゚ンゞニア募集ペヌゞ