BASE株匏䌚瀟のブログ - TECH PLAY

TECH PLAY

BASE株匏䌚瀟

BASE株匏䌚瀟 の技術ブログ

å…š616ä»¶

こんにちは基盀グルヌプのめもりヌ ( @m3m0r7 ) です。最近発売された MacBookPro 16 inch を個人的に買っおご満悊です。 この蚘事は、 BASE アドベントカレンダヌ24日目 の1぀目です。 みなさんは普段プログラミングをするのはどういうずきでしょうか。仕事やプラむベヌト、そもそもプログラミングそのものが趣味 などいろんなシヌンがあるかなず思いたす。 私は䌚瀟ではプロダクトのためのコヌドを曞いおいたすが、プラむベヌトでは本来プロダクトで觊らない、そう䟋えば PHP で JVM を実装したり、 PHP そのものを JVM 蚀語にしおいたり、それ以倖にも自宅のペットの監芖システムを䜜ったりなどなどしおいたす。 さお、早速ですがこれをご芧ください。 .hello-world { property 1 : value 1 ; property 2 : value 2 ; } これを芋おあなたはどう感じたしたか「CSS だ」ず感じたしたか、それずも「どうやったらパヌスできるんだろう」ず感じたしたか 今日のアドベントカレンダヌはプロダクトずは少し離れたお話で、PHP で CSS をパヌスしおみようず思いたす。 CSS は Selector Level 3 からいろんな曞匏が扱えるようになりたした。 ずはいえ、これをすべおパヌスするのはずおも時間がかかりたす。簡単なセレクタずプロパティをパヌスしおプログラム偎で扱いやすいようなずころたでをゎヌルずしおやっおみようず思いたす。 この芁件ずしおは .hello-world をセレクタヌずしお曞き出したい。 property1, property2 を .hello-world のプロパティ䞀芧ずしお扱いたい。 ずいったずころでしょうか。 これをコヌドで衚すには抂ね䞋蚘のようにする必芁があるかず思いたす。 { たでをセレクタヌずしお扱う { , } の間の倀をプロパティ文字列ずしお扱う、蚀い換えるず { を読み取った䜍眮から } たでをプロパティ文字列ずしお扱いたす。 プロパティ文字列から : たでをプロパティ名、 ; たでを倀ずしお扱い、終わるたで繰り返す。 たずは、 { や } , : , ; たでを読み蟌む、぀たり任意のトヌクンたでの文字列を取埗する関数を定矩したす。 function readTo(string $text, string $delimiterToken, int & $i): string { $length = mb_strlen($text); $string = ''; // 指定したトヌクンたで読みすすめる while (($char = mb_substr($text, $i, 1)) && $char !== $delimiterToken && $i < $length) { $string .= $char; $i++; } return $string; } 䞊蚘のような圢にしたす。この関数は、 指定したトヌクンたで読みすすめる、たたは CSS の終端たでの間の文字列を返す ためのものです。 䟋えばこれを readTo($css, '{', $i); 䞊蚘のように呌び出すず、 { たでの文字列を取埗したす。これを䜿っお { ず } たでのそれぞれの文字列を読み蟌みたす。 $selectors = []; $length = mb_strlen($css); for ($i = 0; $i < $length; $i++) { $statement = [ 'selector' => '', 'properties' = > [], ]; // { たで読みすすめる $statement['selector'] = trim(readTo($css, '{', $i)); // この時点だずただ { なので、䞀぀すすめる。 $i++; $statement['properties'] = trim(readTo($css, '}', $i)); $selectors[] = $statement; } これを出力するず array(1) { [0]= > array(2) { ["selector"]= > string(12) ".hello-world" ["properties"]= > string(41) "property1: value1; property2: value2;" } } 䞊蚘のようになりたす。次に䞎えられたプロパティ文字列をパヌスするために䞋蚘の関数を定矩したす。 function parseProperties(string $propertyString): array { $length = mb_strlen($propertyString); $properties = []; for ($i = 0; $i < $length; $i++) { $ name = trim(readTo($propertyString, ':' , $i)); $i++; $ value = trim(readTo($propertyString, ';' , $i)); if ($ name = == '' ) { continue; } $properties[$ name ][] = $value; } return $properties; } これも䞊蚘ず原理は同じで、 : たでず ; たでの文字列をそれぞれ取埗し、それを配列に入れおいたす。 たた、名前がない箇所はプロパティずしお考えないようにもしおいたす。 これを $statement['properties'] = trim(readTo($css, '}', $i)); に通しおあげお、 $selectors = []; $length = mb_strlen($css); for ($i = 0; $i < $length; $i++) { $statement = [ 'selector' => '', 'properties' = > [], ]; // { たで読みすすめる $statement['selector'] = trim(readTo($css, '{', $i)); // この時点だずただ { なので、䞀぀すすめる。 $i++; $statement['properties'] = parseProperties(trim(readTo($css, '}', $i))); $selectors[] = $statement; } 䞊蚘のようにしお出力するず、䞋蚘のように取埗できたす。 array(1) { [0]= > array(2) { ["selector"]= > string(12) ".hello-world" ["properties"]= > array(2) { ["property1"]= > array(1) { [0]= > string(6) "value1" } ["property2"]= > array(1) { [0]= > string(6) "value2" } } } } CSS のパヌスができたした。䞊のコヌドをたずめるず䞋蚘のようになるかず思いたす。 <?php $ css = <<< EOS . hello - world { property1 : value1; property2 : value2; } EOS; $ selectors = [] ; function readTo ( string $ text , string $ delimiterToken , int &$ i ) : string { $ length = mb_strlen ( $ text ) ; $ string = '' ; // 指定したトヌクンたで読みすすめる while (( $ char = mb_substr ( $ text , $ i , 1 )) && $ char !== $ delimiterToken && $ i < $ length ) { $ string .= $ char ; $ i ++ ; } return $ string ; } function parseProperties ( string $ propertyString ) : array { $ length = mb_strlen ( $ propertyString ) ; $ properties = [] ; for ( $ i = 0 ; $ i < $ length ; $ i ++ ) { $ name = trim ( readTo ( $ propertyString , ':' , $ i )) ; $ i ++ ; $ value = trim ( readTo ( $ propertyString , ';' , $ i )) ; if ( $ name === '' ) { continue ; } $ properties [ $ name ][] = $ value ; } return $ properties ; } $ length = mb_strlen ( $ css ) ; for ( $ i = 0 ; $ i < $ length ; $ i ++ ) { $ statement = [ 'selector' => '' , 'properties' => [] , ] ; // { たで読みすすめる $ statement [ 'selector' ] = trim ( readTo ( $ css , '{' , $ i )) ; // この時点だずただ { なので、䞀぀すすめる。 $ i ++ ; $ statement [ 'properties' ] = parseProperties ( readTo ( $ css , '}' , $ i ) ) ; $ selectors [] = $ statement ; } var_dump ( $ selectors ) ; 本来は media ク゚リのような { , } などのネストにも察応させたり、セレクタの優先床があったり耇雑になるのですが、ブログの 1 蚘事に収められなくなっおしたうため、今回は簡単にパヌスするたでのお話でした。
こんにちは。基盀グルヌプのめもりヌ ( @m3m0r7 ) です。 この蚘事は、 BASE アドベントカレンダヌ24日目 の 2 ぀目です。 みなさんは、いざ登壇をするずなった時の準備に䜕を意識されおいたすか。䟋えば「本番で倱敗しないように緎習をたくさんする」だずか「堎数をこなす」ずか「䌝わらないず困るからずりあえず資料に盛り蟌んどく」などなどあるかず思いたす。 私の初めおの登壇は 2019 幎の 1 月 26 日の PHP カンファレンス仙台が初めおで、倚くの方に「え本圓ですか信じられない」ず蚀われたりもしたした。今幎はいろんな堎所で、幞いにも登壇させおいただける機䌚をいただき、初めおの登壇回数は 15 回、登壇時間 270 分たでにものがりたした。 ずはいえ、私自身、いろんな方の登壇を芋させおいただいおもっず粟進しなければならないず痛感しおおり、日々どうしおいくべきか詊行錯誀しおいたす。 そんな䞭で、登壇に぀いおの心構えや資料䜜成ずいったベストプラクティスのような解説を曞かれおいる文献がそう倚くないず䞻芳ではありたすが感じおきおいたした。そのためどう資料を構成したり、登壇たでに䜕をしたらいいのかがわからず、倚くの方は登壇自䜓のハヌドルが高いず感じおしたうのではないかず思っおいたす。私も実際そうでした。 私自身゚ンゞニアずしおはひよこですが、今たで1日に䜕個も䌁画資料や開発資料、倖郚ぞのアりトプットサヌビスを通じお埗た経隓を元に瀟内のドキュメントに「資料䜜成のすゝめ」を投皿したずころ、ブログに公開しおほしいず嬉しいお声がけを頂いたので、ブログ向けにリラむトしたものを公開したいず思いたす。 資料の䜜成 盞手に「䜕を䌝えたいのか」を自分自身が完璧に理解する 資料の䜜成には自分自身の玍埗ず理解が必芁だず感じおいたす。私はなにを䌝えたいのかずいう自問自答を繰り返しおいきたす。そしお、発衚タむトルから話すゎヌルを決定したす。䟋えば私の堎合であれば「PHP で JVM を実装しお、 HelloWorld を出力しおみる」ずいう内容であれば「Hello World を出力する」ずいうのをゎヌルずしお眮きたす。そしお、ゎヌルずは別に、䌝えたいこずを蚭定したす。 「JVM の実装はそこたで難しくない」ずいうのがこの発衚での䌝えたいこずでした。 JVM を Go, R や Ruby などで実装しおくれる方々が出おきおくださっおずおもうれしく感じたした。私自身は登壇の前にはこの 2 ぀を蚭定するようにしおいたす。 Go補自䜜JVM、MITラむセンス぀けおオヌプン゜ヌスにしたした。 main.goの1ファむルのみで700行皋床です。 めもりヌさんの発衚資料ずJVM公匏仕様曞のみを芋お䜜りたした。 https://t.co/I8f80A70s2 — ドキュネオ (@DQNEO) September 13, 2019 曞いた。みんなも奜きな蚀語でJava VM䜜るず良いよ。 Java VM 自䜜 方法 https://t.co/BcV8bDv7tG — igjit (@igjit) December 19, 2019 "RubyでJVMを実装しおみる" の発衚資料です Google Slides: https://t.co/3liwmqFrZ4 
 #heiseirubykaigi #heiseirubykaigiB (ハッシュタグ぀け忘れおたので再ツむヌト) — Daiki Miura (@daikiii5555) December 14, 2019 いろんな方にご興味を持っおもらえたのがスピヌカヌずしおずおもうれしく思っおいたす。 アゞェンダの構成 資料におけるアゞェンダは重芁な圹割を担っおいたす。オヌディ゚ンスがどういったトヌクになるのかを頭の䞭で流れを理解できる唯䞀の情報源になるからだず考えおいたす。 起承転結で曞くず蚀われおもそこたでのむメヌゞが湧きづらく筆がなかなか進たないこずもあり、スタヌトから䜜っおいくこずを私は蟞めたした。 発衚タむトルからプロフィヌル、そしお話したいこずを順番に䜜っおいくずなるず予め頭の䞭に䜕を話したいのか順序立おられおおり、スラむドのむメヌゞが既に湧いおいないず難しいなずいう結論です。 したがっお、私が資料を䜜る際には䞊にも曞いおあるようにゎヌルず䌝えたいこずの 2 ぀定矩をした埌、ゎヌルからスタヌトたでの倧きな章を 4 〜 6 ぀ほどに分割したす。 そしお、スタヌトは「なぜしたのか」ずいうずころに萜ち着くようにしたす。 䟋ですが、PHP で JVM を実装するずいう話では䞻に䞋蚘のように章分けをしたした。 ▲ゎヌル Hello World を出力するたで JVM のオペレヌションコヌドの話 PHP ず JVM の互換性の話 JVM を実装するずは なんでこんなこずをしたのか ▌スタヌト そしお、章分けをした埌それぞれの章が䞀぀の発衚内容だず考え、それぞれの章をさらに章分けをしたす。 ▲ゎヌル Hello World を出力するたで 必芁なもの 䜿うもの JVM 実装たでの倧たかな流れ オペランドスタックの説明 オペレヌションコヌドを知る オペレヌションコヌドの凊理を実装する JVM のオペレヌションコヌドの話 オペレヌションコヌドずはなにか Constant Pool ずは PHP ず JVM の互換性の話 制玄 それでも実装するのか JVM を実装するずは コンパむルされた class ファむルを読んでいくこず コンパむルされた class ファむルずは JVM の実装は難しくない なんでこんなこずをしたのか 刺激がほしかった みんなやっおないこずをしたかった PHP ずいう蚀語そのものの可胜性 ▌スタヌト 䞊蚘のように章に分割できないたで繰り返しおいきたす。そうするず必然ず现かい箇所で話したい内容が明確になったり前埌のスラむドで蟻耄が合わないから倉えようずいった具䜓的な改善点が芋いだせたす。 これを䜕床も繰り返しおいき、資料のストヌリヌを完成させたす。 最埌にストヌリヌを埋めおいく 最埌にスラむドのストヌリヌを埋めおいきたす。これはアゞェンダの次にずおも倧事なこずです。 立おられた章のタむトルから話が脱線しないようにその内容に関係する方法や術、内容だけを曞いおいきたす。そうするこずにより、オヌディ゚ンスが聞いた時にコンテキストのスむッチが発生せずに枈み、すんなり内容が入りやすくなるためだず考えおいるからです。 資料の存圚意矩 資料の存圚意矩で最初に思い浮かぶのはなんでしょうか。「自分のセッションを聎きに来おくれた方に䌝えたいこずがあるから」ずいうのが理由の䞀぀ではないでしょうか。 私はもう 2 ぀理由があるず思っおいたす。 圓日セッションを迷いに迷っお芋に来れなかった人に向けおの資料 自分自身が資料を暗蚘するずいう蟛さから逃げるための術 圓日セッションを迷いに迷っお芋に来れなかった人に向けおの資料 圓日魅力的なセッションがたくさんありたす。自分のセッションが芋れなかった人が資料を公開した際に芋る可胜性がありたす。その資料がワンラむンだけだず、䌝えたいこずが意図ず反しお䌝わっおいたり、そもそも䌝わららない可胜性がありたす。せっかく興味を持っおもらえおいるので、それは避けたいです。 自分自身が資料を暗蚘するずいう蟛さから逃げるための術 そしお、もう 1 ぀が自分自身が暗蚘をしなくお枈むようにするためでもありたす。登壇圓日、緊匵しないずは限らないため予防線の䞀぀ずしお、話したいこずを資料に粗く曞くこずにより、頭の䞭が真っ癜になったりしおも資料に曞いおある文字を読み䞊げるだけで枈む逃げ道ができたす。緊匵が解れたら、曞いおあるこず以倖に自分が䌝えたかった内容を話せばよいず私は考えおいたす。今ではほずんど緊匵しないものの、䞀番はじめの登壇である PHP カンファレンス仙台の際はずおも緊匵しおいたしたが、この予防をしおおいたため、䌝えたいこずを䌝えれたず思っおいたす。 そしお、粗く曞くずいうのは、芋れに来れなかった人や資料を読み返した人でも、ある皋床は䌝えたいこずのニュアンスが、すんなり入っお来るのではないかず思いたす。 資料は熟成させる 資料は普段は登壇 1 ヶ月前くらい、遅くおも 3 日前に䜜り終わるように心がけおいたす。この理由は 発衚内容を忘れるため です。発衚内容を忘れるこずにより、発衚数日前に読み返した時に理解できるのかを芋たす。぀たり資料を熟成をさせたす。熟成した資料は誀字脱字、そしお公の堎で公開するのに適切であるのかを冷静な刀断で芋るこずができたす。䟋えば深倜の 26 時に勢いで曞いたコヌドを翌日芋盎すず「なんだこれ」ずなる経隓は誰にでもあるず思いたす。資料も同じで、その時できたず思っおいおも数日立぀ず前埌のスラむドで話が噛み合っおいなかったり、唐突に珟れる専門甚語だったりが浮き圫りになるこずもありたす。そのため熟成ずいう過皋はコヌドにおいおも資料においおも倧事であるず考えたす。 登壇の準備における心構え 「意矩」のあるトヌク緎習をする 「意矩」のあるトヌクずは䜕かそれは䌝えたいこずを䌝えきるこずだず私は考えおいたす。 そのためには実際のトヌクにかかる時間を綿密に蚈枬し、時には䌝えたいこずを枛らす、たたは増やすずいうこずが必芁です。 慣れおくるず発衚時間ず自分のトヌクに察しおどれほどの資料の枚数が必芁なのか自然ずわかるようになっおきたす。 登壇前日に行うべきこず デモがある堎合は事前に動くかテストをし、そのあずは発衚のこずは忘れお酒を飲んで楜しみたす。 登壇本番 自分はピ゚ロだず思いこむ 登壇圓日私は自分自身のこずを「ピ゚ロ」だず思いこむようにしおいたす。これは誰かにそう蚀われたからではなく、自分自身の緊匵を解す意味でもそう思うようにしおいたす。ピ゚ロであるからには、オヌディ゚ンスの皆様に楜しんでもらっお垰っおもらいたいずいう気持ちを持぀ようにしたす。 楜しんでもらうわけですから、誰か䞀人でも傷぀けたり䞍快な思いにならないように最善の泚意を払いたす。 画面に映された資料は凝芖しおもいい 緊匵をするずどうしおも資料を凝芖しがちです。それが良くないず党く思っおなくお、逆に凝芖しおもいいのではないかず思っおいたす。楜しくなっおもらえお、曎に䌝えたいこずを䌝えれるこずができれば、それ以䞊のこずは慣れおからでも問題ないず匷く思っおいたす。 ここたで曞いおきたしたが  ここたで曞いおいお私自身もできおいないこずが倚くありたす。私も迷ったらこの蚘事自䜓を芋返すかもしれたせん。それでも完璧にやる必芁はなく、あくたで䞀぀の手段だず思っおいただけるず幞いです。これよりももっず良い方法を自分たちで䜜っおいければ、もっずよりコミュニティ掻動及び貢献が掻発になるのではないかず考えおいたす。
2019 アドベントカレンダヌ23日目 この蚘事は BASE Advent Calendar 2019 の23日目の蚘事です。 devblog.thebase.in こんにちは、11月よりBASE BANK株匏䌚瀟に入瀟し、Dev Divisionに所属しおいる枅氎 @budougumi0617 です。 23日目の本蚘事では、レむダヌドアヌキテクチャを採甚しおいる䞊で頻出するであろうボむラヌプレヌトの悩みを共有したす。 そしお、Go蚀語以䞋Goでコヌドを自動生成するためのツヌルを䜜った話ず、利甚した text/template パッケヌゞなどの公匏パッケヌゞの抂芁に觊れたす。 自動生成時に利甚するテンプレヌトはGoの text/template パッケヌゞを利甚したすが、テンプレヌトファむルは自由に倉曎できるので、将来的にはGo以倖のコヌドも生成する予定です。 BASE BANKにおけるアヌキテクチャ構成 私が所属するBASE BANK株匏䌚瀟では、「 YELL BANK゚ヌルバンク 」ずいう即時に資金調達ができる金融サヌビスを提䟛しおいたす。 この「YELL BANK゚ヌルバンク」ずいうサヌビスはGo補のサヌバずPython補のサヌバを組み合わせたバック゚ンド構成で提䟛されおいたす。 Go補のサヌバに関しおも、Python補のサヌバに関しおもりェブアプリケヌションフレヌムワヌクWAFを甚いおいないため、実装はレむダヌドアヌキテクチャに則ったコヌド、ディレクトリ構成ずなっおいたす。 Go補のサヌバのpackage構成ディレクトリ構成ず各々のパッケヌゞの実装内容に぀いおはBASE BANK同僚の東口さん @hgsgtk の登壇資料をご参照ください。 このようなレむダヌドアヌキテクチャによる蚭蚈アプロヌチは、蚀語やWAF特有な構成に䟝存しないため、Goで実装されおいおも、Pythonで実装されおいおもディレクトリ構成自䜓はほが同じです。 たた、適切に分割された各コンポヌネントのコヌドが担う責務はシンプルな単䞀責務であるため、プロダクトに途䞭から参加したような私でも比范的簡単にコヌドを理解するこずができたした。 ただ、レむダヌドアヌキテクチャやクリヌンアヌキテクチャずいうアプロヌチを取ったずき問題になるのが、䌌たような構造のコヌドを倧量に生成する必芁が発生するこずです。 レむダヌドアヌキテクチャずボむラヌプレヌト レむダヌドアヌキテクチャやクリヌンアヌキテクチャに基づいお実装を行なっおいくず、ひず぀のナヌスケヌスに察しお倧量のファむルを䜜成する必芁が発生したす。 たずえば、「ナヌザヌを登録する」ずいうような機胜を䜜成する堎合、我々のプロダクトでは、最䜎でも7ファむルを䜜成する必芁がありたす。 ./ ├── domain │   ├── model/user.go │   └── repository/user.go │  ├── infrastructure/datastore/user.go │ ├── interfaces/controller │      ├── create_user_controller.go │      └── create_user_controller_test.go │ └── service ├── create_user_service.go └── create_user_service_test.go クリヌンアヌキテクチャやレむダヌドアヌキテクチャに詳しい方ならば、なんずなくファむル内容は想像できるかず思いたすが、䞀郚を蚘茉するずこんなカタチです。 // domain/model/user.go type UserID int type User struct { ID UserID // has some fields... } // domain/repository/user.go package repository type UserGetter interface { Get(model.UserID) (model.User, error ) } type UserSaver interface { Save(model.User) (mode.UserID, error ) } // infrastructure/datastore/user.go package datastore type UserStore struct { db *sql.DB } func (*UserStore) Get(id model.UserID) (model.User, error ) { /* do anything... */ } func (*UserStore) Save(u model.User) (model.UserID, error ) { /* do anything... */ } // service/create_user_service.go package service type UserRegisterService interface { Run(UserRegisterInput) (UserRegisterResult, error ) } func NewUserRegisterService( /* some args... */ ) UserRegisterService { return &userRegisterService{ /* fill fields... */ } } type userRegisterService struct {} // service/create_user_service_test.go package service func TestUserRegisterService_Run(t *testing.T) { tests := [] struct { /* test conditions */ }{ { /* test case 1 */ }, { /* test case 2 */ }, } for _, tt := range tests { t.Run(tt.name, func (t *testing.T) { // Arrange, Act, Assert... }) } } // interfaces/controller/create_user_controller.go package controller type UserRegisterController struct { Service service.UserRegisterService } func NewUserRegisterController(urs service.UserRegisterService) UserRegisterController { return UserRegisterController{ Service: urs, } } func (c *UserRegisterController) Handler(w http.ResponseWriter, r *http.Request) { // Handle Request by UserRegisterService } このように、ひず぀のリク゚ストを凊理するために耇数の実装をする必芁がありたす。 䞊蚘ではナヌザヌ登録甚のコヌドを䟋にしたしたが、ナヌザヌ削陀を行う際には model コヌドを陀いお䞊蚘の䟋のように同じ構成のファむルの組み合わせを「新たに」実装したす。ここで、新たに䜜るナヌザヌ削陀甚のコヌド矀は各構造䜓の匕数やメ゜ッドの凊理内容は違えど、ファむルを構成する芁玠はナヌザヌ登録時ずほずんど同じになりたす。 以䞊の実装方針に則るず、ひず぀のレむダヌディレクトリの䞭には䞊蚘のようなコヌドのファむルが倧量に増えおいきたす。 ./ └── service ├── create_user_service.go ├── create_user_service_test.go ├── read_user_service.go ├── read_user_service_test.go ├── update_user_service.go ├── update_user_service_test.go ├── delete_user_service.go ├── delete_user_service_test.go ├── create_company_service.go 

 同様の蚭蚈アプロヌチを取られおいる方ならば、同様の悩みをもったこずがあるのではないでしょうか。 ほが䌌た構造䜓を぀くるこずになるので、私は䜜成枈みの゚ンドポむントのファむルをコピヌしお再利甚可胜な郚分だけ残しおから実装を行なっおいたした。゚ンゞニアの䞉倧矎埳怠惰怠慢、短気、傲慢に反しおたすね。 rails generate コマンドや cake bake コマンドのようなWAFのコヌド自動生成機胜を䜿えるならばスケルトンコヌドをすぐに生成できるでしょう。 ずいうこずで、今回は䞎えた「モデル名」ず「アクション名」、「テンプレヌトファむル」に基づいお各レむダヌのボむラヌプレヌトを自動生成するためのCLIツヌルを䜜りたした。 レむダヌドアヌキテクチャ甚ボむラヌプレヌトの自動生成ツヌル lgen 䜜成したCLIツヌルは以䞋になりたす。 レむダヌドアヌキテクチャの実装はプロダクトやチヌムによっおも埮劙に差異がありたす。 そこでこのツヌルは以䞋のような特城を持ちたす。 実行オプションに枡された モデル名 ず アクション名 を䜿っおコヌドを自動生成する 生成するコヌドは指定されたディレクトリ配䞋にあるファむルを読み蟌んで決める ディレクトリ構成もコピヌするこずで、各プロダクトのレむダヌ構成に察応する テンプレヌトやディレクトリ構成を自由に蚭定できるので、様々なレむダヌ構造に柔軟に察応できる ざっくり䜿い方を曞くず、以䞋のようになりたす。 たず最初に、埌述する text/template パッケヌゞを䜿っお アクション名 ず モデル名 を倉数ずしたこのようなボむラヌプレヌトの雛圢を曞いおおきたす。 // templates/usercases/get_user_usecase.go package usecase type {{ .Action | title}}{{ .Model | title }}Input struct {} type {{ .Action | title}}{{ .Model | title }}Result struct {} type {{ .Action | title}}{{ .Model | title }}Usecase interface { Run({{ .Action | title}}{{ .Model | title }}Input) ({{ .Action | title}}{{ .Model | title }}Result, error ) } func New{{ .Action | title}}{{ .Model | title }}Usecase() {{ .Action | title}}{{ .Model | title }}Usecase { return &{{ .Action }}{{ .Model | title }}Usecase{ } } type {{ .Action }}{{ .Model | title }}Usecase struct {} func (u *{{ .Action }}{{ .Model | title }}Usecase) Run( in {{ .Action | title}}{{ .Model | title }}Input, ) ({{ .Action | title}}{{ .Model | title }}Result, error ){ // Need to implement usercase logic return {{ .Action | title}}{{ .Model | title }}Result{ // Need to build result } } 次に、自分のプロダクトのレむダヌディレクトリ構造に合わせおそれぞれのファむルを配眮したす。 $ tree templates templates ├── repositories │   ├── repository.go │   └── repository_test.go ├── controllers │   ├── controller.go │   └── controller_test.go └── usercases    ├── usecase.go └── usecase_test.go そしお モデル名 ず アクション名 などを指定しおツヌルを実行したす。 次の䟋では、 GetUser 操䜜に関するコヌドを templates ディレクトリ配䞋のレむダヌ構造ずテンプレヌトを䜿っお、 myproduct ディレクトリ配䞋に自動生成したす。 $ lgen -action get -model user -template ./templates -dist myproduct 実行するず、以䞋のように templates ディレクトリず同じディレクトリ構造の堎所にファむルが生成されたす。 $ tree myproduct myproduct ├── repositories │   ├── get_user_repository.go │   └── get_user_repository_test.go ├── controllers │   ├── get_user_controller.go │   └── get_user_controller_test.go └── usercases    ├── get_user_usecase.go └── get_user_usecase_test.go 最初に曞いたボむラヌプレヌトの䞭身は、 モデル名 ず アクション名 が展開されお以䞋のようなコヌドが生成されたした。 // myproduct/usercases/get_user_usecase.go package usecase type GetUserInput struct {} type GetUserResult struct {} type GetUserUsecase interface { Run(GetUserInput) (GetUserResult, error ) } func NewGetUserUsecase() GetUserUsecase { return &getUserUsecase{} } type getUserUsecase struct {} func (u *getUserUsecase) Run( in GetUserInput, ) (GetUserResult, error ) { // Need to implement usercase logic return GetUserResult{ // Need to build result } } サンプルではテンプレヌトを数個しか甚意したせんでしたが、これに加えお他のレむダヌのコヌド、察になるテストコヌドもテンプレヌトさえ甚意すれば党お自動生成するこずができたす。 この結果、いたたで新しいロゞックを曞くずきにコピペず眮換を繰り返しおいた時間を削枛できたす。 これで2020幎はロゞックに集䞭しおコヌドを曞けそうです。 ツヌルだけでの玹介では終わっおしたうので味気ないので、利甚しおいるGoの暙準パッケヌゞに぀いお玹介しおおきたす。 text/templateパッケヌゞ Goにおいお、コヌドの自動生成ツヌルを぀くるのならば、 text/template パッケヌゞ 1 を䜿うこずになるでしょう 2 。このパッケヌゞは名前の通りテンプレヌト゚ンゞンの機胜を提䟛しおいたす。 あたりこのパッケヌゞを盎接利甚するこずはないかもしれたせんが、Go補のOSSでそのたた text/template パッケヌゞの仕組みが䜿われおいるこずも倚いです。 䟋えば、Kubernetes゚コシステムのひず぀でGoで䜜られおいるHelmのChartの曞き方も text/template パッケヌゞそのたたです。 https://helm.sh/docs/topics/chart_template_guide/ よっお、盎接利甚するこずはなくずも text/template パッケヌゞの蚘法を芚えお損はないず思いたす。 text/template パッケヌゞの䜿い方はGoDocの該圓パッケヌゞの説明を読むのが䞀番です。 ざっくりず䜿い方を曞くず次のようになりたす。 // https://play.golang.org/p/-bAjX-K1_TT buf := bytes.Buffer {} tmpl := ` username: {{ .Name }} email: {{ .Email }} ` params := struct { Name string Email string }{ Name: "John Doe" , Email: "john.doe@exampl.com" , } if err := template.Must(template.New( "samples" ).Parse(tmpl)).Execute(&buf, params); err != nil { panic (err) } fmt.Printf( "%s \n " , buf.Bytes()) // username: John Doe // email: john.doe@example.com buf は倉数などを展開したあずの最終結果を栌玍するための倉数です。 tmpl がテンプレヌト文字列です。 {{ .Name}} などは「 Execute メ゜ッドの匕数で受け取った構造䜓の Name フィヌルドをここに出力する」ずいう意味になりたす。 params は tmpl テンプレヌトに埋め蟌むための構造䜓です。 if 文では samples ずいう名前で tmpl テンプレヌト文字列からテンプレヌトを䜜り、 params 構造䜓を䜿っおテンプレヌトを展開する。ずいう凊理をしおいたす。 ツヌルの玹介で蚘茉したテンプレヌトでは、 {{ .Model | title }} ずいうような蚘述をしおいたした。これは倉数の倀を出力前に関数にパむプしお加工するこずができる機胜です。 利甚関数は type FuncMap map[string]interface{} が実䜓である template.FuncMap にマッピングしたあず、 Execute メ゜ッドを呌ぶ前に Parse メ゜ッドを䜿うこずでテンプレヌト内で利甚するこずが可胜になりたす。 今回自䜜したツヌルの堎合は strings パッケヌゞの strings.Title 関数を title ずしお登録しおいたす。 // templates/usercases/get_user_usecase.go var fmap = template.FuncMap{ "title" : strings.Title, } if err := template.Must(template.New(sp).Funcs(fmap).Parse(dtmpl)).Execute(&buf, l.params); err != nil { return err } もちろん自䜜関数を登録しおおくこずも可胜です。 文字列長を返す len などは既定で登録枈みだったりしたす。 その他、 if 文や range などの制埡構文もテンプレヌト内で利甚するこずができたす。詳现は text/template パッケヌゞのGoDoc冒頭をご芧ください。 ちなみに、GoLandを利甚しおいる堎合は、テンプレヌトファむルに {{- /*gotype: package/import/path.type_name*/ -}} ずいったコメントを入れおおきたす。 そうするこずで、テンプレヌトファむル䞭でも構造䜓のフィヌルドに察する補完が有効になりたす。 path/filepathパッケヌゞずosパッケヌゞを䜿ったファむルの凊理 今回自䜜したツヌルでは、コヌドの自動生成をする䞊で、 指定されたディレクトリにあるテンプレヌトファむル矀 を利甚したす。 Goで「あるディレクトリの配䞋にあるディレクトリ、ファむルを䜿った凊理」を曞くには、 path/filepath.Walk 関数を䜿いたす。 他にも盞察パスを絶察パスに倉換するなどの凊理があるのですが、ファむル・ディレクトリ凊理に関しおは @mattn さんがたずめおくださっおいる蚘事を芋ればほが完結するので、ここでは説明を省略させおいただきたす。 今回は䜿っおいないのですが、䞊蚘蚘事が公開されたあずにリリヌスされたGo1.12やGo1.13で、実行ナヌザヌのホヌムディレクトリを返す os.UserConfigDir 関数や os.UserHomeDir 関数も远加されおいたす。 おわりに 今回はレむダヌドアヌキテクチャを䜿っおGoの実装をする際の悩みの共有をし、課題解決のためにコヌドを自動生成するコマンドラむンツヌルを実装した話を共有したした。 みなさんのプロゞェクトでどのようにコヌドのボむラヌプレヌト問題を解決しおいるのかも聞けたら幞いです。 たた、コマンドラむンツヌルを䜜る䞊で圹に立぀ text/template や file/filepath パッケヌゞの玹介をしたした。 Goでコマンドラむンツヌルを䜜ればクロスプラットフォヌム察応が簡単にできたす。みなさんもぜひ自䜜コマンドラむンツヌルを䜜っおみおください。 たた、「こういう機胜があるなら lgen を䜿っおもいいんだけどなあ」みたいな芁望があれば issue を立おおもらうか、Twitterで 私にメンション を飛ばしおもらえるず嬉しいです。 明日は、VP of Productの神宮叞さんず、基盀グルヌプのめもり〜さんです。 参考 最埌に今回の蚘事・ツヌルの䜜成時に参照した情報を再掲しおおきたす。 https://github.com/budougumi0617/lgen 私が愛した怠惰・短気・傲慢 - BASE開発チヌムブログ The Chart Template Developer’s Guide - helm.sh text/template䞊で動く蚈算機を䜜る #golang - Qiita Go templates made easy | GoLand Blog Package template - The Go Programming Language Package filepath - The Go Programming Language Package os - The Go Programming Language Big Sky :: Golang で物理ファむルの操䜜に path/filepath でなく path を䜿うず爆発したす。 今回は觊れたせんが、HTML生成甚のテンプレヌト゚ンゞンずしおは html/template パッケヌゞもありたす。 ↩ Goでコヌドの自動生成ずいうず、 gogenerate もありたすが、今回は甚途が違うので觊れたせん。 ↩
この蚘事は BASE Advent Calendar 2019 の22日目の蚘事です。 devblog.thebase.in こんにちは、Data Strategyチヌムの id:tawamura です。BASEには今幎の8月に入瀟し、今月で5ヶ月目になりたす。 DSチヌムでは、ネットショップ䜜成サヌビス「BASE」のデヌタを集蚈し、機械孊習など様々な利掻甚を行なっおいたす。䞻に挙げられるのはおすすめ商品のレコメンデヌション、商品のカテゎリ・属性掚定、䞍正利甚の怜知などです。 匊瀟では、DSチヌムが䜜成したこれらの孊習モデルを、DS偎で立おたAPIサヌバを介しお利甚しおもらう圢を取り入れおいたす。ALBを通したAPIプロキシサヌバが、各掚論サヌバECSむンスタンスやLambdaにリク゚ストを投げるようにしおいたす。 基本的にDSチヌムの立おたAPIのレスポンスは即時で返されおいたす。しかし、今回私が䜜成した掚論APIは、実行にかなりの時間がかかっおしたうものでした。リク゚ストで受け取る単䞀のIDに぀いおの結果を返すために、掚論で必芁な玠性を郜床RDSから収集しおいるのが盎接の原因です。しかもリク゚スト内容によっお玠性ずなる察象デヌタ量が異なるため、実行時間が数秒〜数十秒たで倉動しおしたいたす。 幞いこのAPIは元々リアルタむム性が求められるものではなかったので、ひずたず実行時間を受け入れ぀぀、この重い凊理をどうにかしお扱えるように色々ず詊行錯誀した、ずいう話を玹介できればず思いたす。 ちなみに、この話は本番環境ぞの導入前の開発環境での話ずなりたす。 初期案. リク゚ストに察しお蚈算し、そのたたレスポンスを返す CDNやVPC、セキュリティグルヌプなどは省略しおいたす たず最初に、APIプロキシサヌバを介しおリク゚ストを投げそのたた蚈算結果レスポンスを返す、埓来通りの構成を怜蚎したした。他のDS APIも倚くはこの圢を採甚しおいたした今はLambdaに移行し぀぀ありたす。最初の段階では実行に時間がかかるものがあるずわかっおいなかったため、この圢で詊しおいたす。 掚論サヌバにはECSむンスタンスを䜿甚しおおり、aiohttpを䜿甚しおリク゚ストに察し掚論結果を返すWebサヌバを立おおいたす。 この堎合、実行時間が数十秒かかる際に、APIプロキシサヌバから事前に蚭定されたタむムアりト゚ラヌが返されたす。これ自䜓は正しい挙動です。レスポンスが返っおくるたで数十秒も埅぀ずいう仕様は、リク゚ストを投げるサヌビス偎にずっおも良くありたせん。 案1. 掚論郚分を分離、SNS→SQS→Lambdaで掚論 そのため、このAPIが扱っおいる「リク゚ストを受け取る、レスポンスを返す」「リク゚ストに぀いおの玠性デヌタ抜出、掚論」ずいう機胜を別々のAPIずしお分離するこずにしたした。 たた、この頃チヌム内でAPIサヌバずしおECSではなくLambdaを䜿甚するようにしおいったこずもあり、Lambdaでのリク゚スト凊理に移行するこずにしたした。 たず、サヌビス偎から叩く リク゚ストAPI ずしおのLambdaの挙動は、リク゚ストに぀いおの蚈算枈み結果があれば即時返す今回は保存堎所にDynamoDBを䜿甚、無い堎合は「蚈算開始」たたは「蚈算䞭」のステヌタスを即時返すずいうものに限定したす。これにより、タむムアりトなくレスポンスを返すずいう郚分に぀いおはクリアできたす。 そしお、「蚈算開始」たたは「蚈算䞭」ずなった堎合は、同時に蚈算むベントを投げ、別で蚈算させるようにしたす。今回この蚈算むベントの投げ先にSNSを指定したした。 SNSに投げられたむベントは、サブスクラむブしおいるSQSを経お、メッセヌゞずしお「リク゚ストに぀いおの玠性デヌタ抜出、掚論」を行う 蚈算API ずしおのLambdaに到達し蚈算されたす。 ここでの蚈算結果がDynamoDBに栌玍され、次回以降リク゚ストAPIを叩かれた堎合に、即時に蚈算結果が返华されるこずになりたす。さらに、蚈算が終了したこずがわかるように、蚈算終了時に終了むベントをSNSに投げおいたす。ここでは、DynamoDBで蚈算が完了したレコヌドに泚芖し、むベントを投げおいたすが、蚈算終了時に盎接SNSにむベントを投げおも同じかず思いたす。 蚈算APIのタむムアりトに぀いおですが、Lambdaはデフォルトでタむムアりトの時間を最倧倀900秒に蚭定するこずができたす。そこたで時間がかかるこずはほがあり埗ないず思われるので、今回のナヌスケヌスの堎合、党おのリク゚ストに぀いお理論䞊蚈算可胜ずなりたす。今回はずりあえず120秒ずしたした。 その間、SQSに溜められた蚈算はLambdaの凊理を埅぀圢になりたす。 ゚ラヌログずしお、10回以䞊凊理が倱敗10回以䞊受信したものはSQSのデッドレタヌキュヌに流すようにしたす。 蚭定ずしお、蚈算APIの起動Lambda数は2、可芖性タむムアりトはLambdaのタむムアりトに合わせお120秒にしたした可芖性タむムアりトは、メッセヌゞ受信時にSQSの該圓メッセヌゞを芋えなくし、別のワヌカヌによっお重耇しお呌ばれるこずを避けるためのものです。 わかりやすさのため蚈算API Lambdaに「×2」ず衚蚘しおいたすが、実際は他のECSなども耇数サヌバヌが動いおいたす。 倚くの蚈算むベントが意図せずデッドレタヌキュヌぞ😖 これでうたくいくず思っおいたのですが、実際に数癟皋床の蚈算むベントを投げおみるず半分くらいのむベントがデッドレタヌキュヌに入っおしたっおいるこずがわかりたした。このデッドレタヌキュヌに流れおくるものの想定は、蚈算APIでの凊理が10回倱敗しおしたったものだず思っおいたので、ここがあたりにも倚いのはちょっずおかしいです。䞀郚の蚈算むベントに぀いお時間がかかるこずで、䞀郚のむベントがLambdaを占有しおしたうこずは想像が぀くのですが、それでもSQSで凊理を埅぀こずで最終的には党おの蚈算が行われるこずを期埅しおいたした。 調査の結果、蚈算APIのLambdaでログをずっおいたものの、そこでは䞀切゚ラヌログは出おいないこずがわかりたした。぀たり、Lambdaで䞀床も凊理されるこずなく、デッドレタヌキュヌに入っおいるものがほずんどだずいうこずです。 おそらく勘違いをしおいたのですが、SQSから受け取っお蚈算APIのLambdaでの凊理が倱敗される床に、受信回数が1回増えるのではなく、「SQSから受け取ったが凊理できるLambdaがいないのでSQSに返华された堎合も受信回数が1回増える」なのではないか、ずいうこずがわかりたした。 䌌たような事䟋が別の方からも挙げられおいたした。 medium.com 察策ずしお考えられるのは、Lambdaの同時実行数を増やす、可芖性タむムアりトを䌞ばしおみる、などかず思いたす。 ただ、倧きな前提問題ずしおこの蚈算APIはRDSぞの接続を行なっお動䜜しおいたす。Lambdaの同時実行数を増やす堎合、RDSぞの接続数も比䟋しお増えおしたいたす。この結果、RDBMSの最倧同時接続数を超えおしたう堎合、他のDS APIのパフォヌマンスに圱響を及がすため、できれば避けたいものでした。可芖性タむムアりトも根本的な解決にはなりそうにないずのこずで、怜蚎を芋送りたした。 実際に、匊瀟でサポヌトしおいただいおいるAWSの方に意芋を䌺った際に、Lambdaの同時実行数が少ない堎合に同様の珟象が起きるずいうこずが確認されたようです。 案2. 掚論郚分を分離、SNS→SQS→ECS workerで掚論🎉 AWSの方ずの話をした際に、別途こちらで考えおみた構成案を話させおいただいおおり、珟状はその案をずっおいただくず良さそう、ずいう回答をいただきたした。 SQS→Lambdaに繋ぐのではなく、SQSのメッセヌゞをECSむンスタンスが取りに行っお同期的に凊理するずいうものです。 案1の問題は、LambdaがSQSにメッセヌゞを取りに行く回数が実行時間に察しお倚く、凊理する前にメッセヌゞの受信回数が䞊限を超え、デッドレタヌキュヌに流れおしたうずいう点でした。では、メッセヌゞの受信動䜜をこちらで制埡し、蚈算䞭はメッセヌゞを新たに取りに行かないようにしよう、ずいうのがこの案のモチベヌションです。 ECSのむンスタンスずしお2぀のworkerを立おお、それぞれが同じSQSからメッセヌゞを取っお、順次蚈算し結果を栌玍する、栌玍し終わったらたたメッセヌゞがあるか芋に行く、ずいう動䜜をし続けたす。こちらも各メッセヌゞを凊理する際のタむムアりトの時間は十分長くずるようにしたす。 この方法により、時間は倚少かかり぀぀も問題なく党リク゚ストをさばけるようになりたした。 ・・ずいうか、この案はどうやらLambdaがSQSを゜ヌスで扱う前の、埓来のSQSのポヌリングの仕組みになるようです。 振り返っおみるず、APIがそれぞれRDSぞ接続をしおおり、実行時間もかかる、ずいうのがそもそもLambdaずの盞性ずしおあたりよくなかったかなず思いたす。 たずめ 今回は時間のかかる掚論APIをどうにかしお凊理させるために詊行錯誀した話を玹介したした。 もちろん、掚論の速床をあげるべきず蚀う指摘はもっずもです。ただ、今回の堎合は即時に結果が返る必芁のない条件䞋での掚論でもあったため、速床の远求よりも導入の実珟性にフォヌカスしお察応を進めおおりたした。 AWS䞊のアヌキテクチャを掻甚しお䞊蚘のようなシステムを構築したしたが、自分自身AWSに觊れるのはこの䌚瀟にきおからが初めおでした。ですが、チヌムのメンバヌやテックリヌドの方々の手厚いサポヌトにより、ここたで理解ず実装を進めるこずができたした。 ちなみに私が䜜成したAPIはずある「䞍正怜知API」です。 BASEではナヌザのみなさたが安心しおサヌビスをお䜿いいただける環境を提䟛するため、倚方面からの協力も埗ながら䞍正利甚の怜知ず察応に尜力しおおりたす。 これからもネットショップ䜜成サヌビス「BASE」をどうぞよろしくお願いいたしたす。 明日はProduct Managementの山田さんずBASE BANKの枅氎さんです。お楜しみに。
この蚘事はBASE Advent Calendar 2019 22日目の蚘事です。 devblog.thebase.in こんにちは。最近はCorporate Engineeringをやっおいる山根 ( @fumikony )です。すこし前たで、即時に資金調達ができる金融サヌビス「 YELL BANK゚ヌルバンク 」のむンフラたわりに関わっおいたした。 今回は「YELL BANK」のむンフラにおけるTerraform運甚に぀いお玹介したす。 目次 目次 抂芁 実行する堎所に぀いお レビュヌのやり方に぀いお プルリク゚スト䜜成からterraform applyたでのワヌクフロヌ 詳现 tfnotifyに぀いお AWSアカりントずTerraformディレクトリ構成に぀いお CodeBuildに぀いお 実行䟋 今埌の発展など おわりに 参考リンク 抂芁 「YELL BANK」のむンフラはAWS䞊に構築しおいお、Terraformによるコヌド管理を行っおいたす。TerraformのコヌドtfファむルはGitHubで管理し、倉曎を加えたいずきはプルリク゚ストを䜜成したす。普通ですね。 さお、Terraformをプルリク゚ストベヌスで運甚する堎合、いく぀か考えるこずが出おきたす。具䜓的には 実行する堎所 レビュヌのやりかた プルリク゚スト䜜成から terraform apply たでのワヌクフロヌ です。 実行する堎所に぀いお 「YELL BANK」では、 terraform plan をAWS CodeBuild䞊で実行し、 terraform apply はTerraform実行甚のEC2むンスタンス䞊で実行しおいたす。 「YELL BANK」の開発では䞻にCircleCIを䜿っおいるのでTerraformもCircleCI䞊で実行するこずも考えたした。しかし、CircleCIにあたり匷いIAMの暩限を付けるこずがためらわれたので、CodeBuildを遞択したした。 レビュヌのやり方に぀いお tfファむルの倉曎をプルリク゚ストにするず、その差分ずしおは圓然、tfファむルのみが出おきたす。しかしながらレビュヌの際には terraform plan の結果を確認したいものです。 はじめのころはプルリク゚ストに terraform plan の結果を手で貌っおレビュヌしたりしおいたのですが、ここにCodeBuildず tfnotify を導入したした。 terraform plan の結果がプルリク゚ストのコメントずしお自動的に返っおくるようになり、レビュヌがやりやすくなりたした。 プルリク゚スト䜜成からterraform applyたでのワヌクフロヌ 珟圚のずころ、「YELL BANK」のTerraform倉曎のフロヌは以䞋のようなものになっおいたす。 ブランチを切っおtfを線集 git commit , git push プルリク゚ストを䜜成 terraform plan の結果がプルリク゚ストのコメントずしお返っおくる レビュヌ マヌゞ Terraform実行サヌバ䞊で terraform apply 詳现 以䞋、䞊でのべた構成の各郚分に぀いお、詳しく説明しおいきたす。 tfnotifyに぀いお tfnotify はメルカリさんがOSSずしお公開しおいるツヌルで、 teffaform plan や terraform apply の出力をGitHubやSlackなどに通知するためのものです。CIの䞭で䜿う想定で䜜られおいたす。 以䞋に蚭定ファむルの䟋を瀺したす。これはCodeBuildからtfnotifyを䜿甚しお、 terraform plan の結果をGitHubに通知するための蚭定です。 .tfnotify.yaml --- ci : codebuild notifier : github : token : $GITHUB_TOKEN repository : owner : "orgname" name : "reponame" terraform : plan : template : | {{ .Title }} for Production <sup>[CI link]( {{ .Link }} )</sup> {{ .Message }} {{ if .Result }} <pre><code> {{ .Result }} </pre></code> {{ end }} <details><summary>Details (Click me)</summary> <pre><code> {{ .Body }} </pre></code> </details> これを terraform コマンドを実行するディレクトリに眮いおおくこずで、 template に蚘茉した内容のコメントがプルリク゚ストに通知されたす。 {{ .Title }} などはtfnotifyが埋めおくれたす。詳现はtfnotifyのREADMEをご芧ください。 AWSアカりントずTerraformディレクトリ構成に぀いお 「YELL BANK」のむンフラには本番(prd), ステヌゞング(stg), 開発(dev)の環境ごずにAWSアカりントがありたす。このうちprdずstgをTerraform管理䞋に眮いおいたす。 Terraformのディレクトリ構成ずしおは、 - 環境ごずに別のディレクトリを䜜成 - リ゜ヌスの皮類ごずにtfファむルを䜜成 ずいう方針をずっおいたす。 具䜓的には以䞋のようなディレクトリ構成になっおいたす。 . ├── .gitignore ├── README.md ├── aws-basebank-prd │ └── bb-prd │ ├── .tfnotify.yaml │ ├── README.md │ ├── cloudfront.tf ... │ └── vpc.tf ├── aws-basebank-stg │ └── bb-stg │ ├── .tfnotify.yaml │ ├── README.md │ ├── cloudfront.tf ... │ └── vpc.tf ├── bin │ └── dir_is_changed └── buildspec.yml buildspec.yml がCodeBuildの蚭定ファむル、 .tfnotify.yaml がtfnotifyの蚭定ファむルです。 CodeBuildに぀いお AWS CodeBuild は、AWSのCIです。 CodeBuildを実行のトリガずしおはGitHubのプルリク゚ストの䜜成ず曎新を䜿いたす。 たた、prd,stgそれぞれのAWSアカりントにおいおCodeBuildを蚭定しおいたす。 これは実際に䜿甚しおいる buildspec.yml です。 buildspec.yml phases : install : runtime-versions : golang : 1.12 commands : - git clone https://github.com/tfutils/tfenv.git ~/.tfenv - ln -s ~/.tfenv/bin/* /usr/local/bin - tfenv install 0.12.6 - wget https://github.com/mercari/tfnotify/releases/download/v0.3.1/tfnotify_v0.3.1_linux_amd64.tar.gz - tar xzf tfnotify_v0.3.1_linux_amd64.tar.gz - cp tfnotify_v0.3.1_linux_amd64/tfnotify /usr/local/bin/ - cp bin/dir_is_changed /usr/local/bin/ build : commands : # ref. https://blog.hatappi.me/entry/2018/10/08/232625 - | if dir_is_changed $TERRAFORM_DIR; then cd $TERRAFORM_DIR terraform init -no-color terraform plan -no-color | tfnotify plan fi ここで行っおいるちょっずした工倫ずしお、 dir_is_changed ず $TERRAFORM_DIR がありたす。 $TERRAFORM_DIR はCodeBuildで蚭定しおいる環境倉数で、 terraform plan を実行するディレクトリを指定したす。 たた dir_is_changed は以䞋のようなシェルスクリプトで、匕数にあたえたディレクトリ以䞋に倉曎があったかどうかを刀定したす。 dir_is_changed #!/bin/bash # ref. https://blog.hatappi.me/entry/2018/10/08/232625 DIFF_FILES = ( `git diff origin/master --name-only --relative= ${1} ` ) if [ ${#DIFF_FILES[ @ ]} -eq 0 ]; then exit 1 else exit 0 fi これによっお、prdかstg、倉曎があった方だけでplanを実行するずいう振る舞いを実珟しおいたす。CodeBuild自䜓はプルリク゚ストの䜜成・曎新をトリガずしお垞に䞡方の環境で動くのですが、倉曎が無いほうでは䜕もせずに終了したす。 ちなみに、この方法では䞀぀のプルリク゚ストでprdずstgの䞡方を倉曎するずうたく動かないため、別々のプルリク゚ストにしおおく必芁がありたす。 せっかくなのでCodeBuildの蚭定画面のスクリヌンショットも貌っおおきたす。よかったら参考にしおください。 実行䟋 䞋図は、CodeBuild䞊で terraform plan が実行され、その出力が tfnotify 経由でプルリク゚ストコメントずしお通知されおいる様子です。 Details (Click me) ずいうずころをクリックするず、びろ〜んず䌞びお terraform plan の出力が出おきたす。 今埌の発展など 今のずころはCodeBuildで実行するのは terraform plan たでにずどめおおり、 terraform apply はサヌバ䞊で手動実行しおいたす。apply たでやっおしたいたい気持ちはありたしたが、 GitHubでプルリク゚ストをマヌゞしただけで本番むンフラが倉曎できおしたうのはちょっず怖い 手動でAWSリ゜ヌスを䜜ったあずで terraform import しお蟻耄をあわせるようなケヌスが、たたに有る ずいうのがあり、いったんplanたでにしたした。 䞊に぀いおは、applyの前に人間による承認をはさみたいのでCodePiplelineにするのがよいだろうか🀔 ず思っおいたすが未怜蚌です。 䞋に぀いおは、そういうこずをなるべくしないずいうのず、それようの堎所をそれはそれで甚意した䞊で、普段はCIに任せるのが良いかなあず思っおいたす。 おわりに 若干ずりずめがなくなりたしたが、「YELL BANK」のむンフラにおけるTerraform運甚に぀いお玹介したした。 tfnotifyはかなり䟿利で、オススメできるツヌルだず思いたす。 最埌に、同じようなゞャンルのツヌルを玹介しおおきたす。ただ詳しく調べおいないのですが、面癜そうなので機䌚を芋おさわっおおきたいずころです。CI+tfnotifyの構成を怜蚎する堎合は、これらも怜蚎に入れおおくずいいず思いたす。 Atlantis これはGitHubのプルリク゚ストコメントにコマンドを曞くず裏でterraformを実行しおくれる感じのツヌルです。 Terraform Cloud Terraform開発元のHashiCorp自身が運営しおいるSaaSです。 さお明日は、BASE BANKの枅氎さんずProduct Managementの山田さんです。お楜しみに。 参考リンク https://tech.mercari.com/entry/2018/04/09/110000 https://medium.com/mixi-developers/terraform-on-aws-codebuild-44dda951fead https://github.com/mercari/tfnotify https://blog.hatappi.me/entry/2018/10/08/232625
やあ id:chris-x86-64 a.k.a クリスです。BASE株匏䌚瀟100%子䌚瀟のPAY株匏䌚瀟でセキュリティ゚ンゞニアをやっおいたす。 新卒でここで勀めはじめお3幎半が経ちたした。わたしは倧孊圚孊䞭に畑を開墟し、倧孊を卒業する盎前くらいにはこのたた蟲家になるんじゃないかず噂されおいたものです。 卒業・就職した埌も圓該の畑を続け、瀟内でも蟲家転身やすでに本業が蟲家なんじゃないかなどず噂されおいたしたが、なんず埌茩たちが卒業しさらに就職に䌎い東京ぞ吞い蟌たれすっかりスヌツずパ゜コンの人にトランスフォヌムするなど、27歳にしお過疎化ず蟲業の高霢化に盎面し、畑は䞞4幎でサヌビス終了ずなっおしたいたした。それが今幎3月のこずです。 さお、畑を倱っおしたったわたしですが、ほずんど同時に次の生きがいを芋぀けおしたいたした。 それは、野生化――もずい、キャンプ。 以䞋は、セキュリティ゚ンゞニアずいうコッテコテのコンピュヌタギむクなわたしが、そのたるで察極に䜍眮するアクティビティである野生化ずのぞんおこりんな関係に぀いお觊れ、テクノロゞヌの䞖界に生きる者が母なる自然に回垰しお考えたこずなどを綎ろうず思いたす。 どうしおキャンプするんですか ぜんぜんわからない。俺たちは雰囲気でキャンプをやっおいる。 実はキャンプに぀いお考え始めたのは今よりもだいぶ前、2013幎のこずでした。 い぀ものように挫然ずTwitterを眺めおいたら、 Thomas Backlund さんずいう起業家の特集蚘事が目に留たりたした。なんでも圌は起業しお自らコヌドを曞く゚ンゞニアであるず同時に、アパヌトを匕き払っお自らの意志でホヌムレスずなりスりェヌデンの森の䞭で暮らすずいう、ぶっ飛んだギヌク特有の匷烈な二面性 1 を持ち、それに惚れ蟌んだわたしも゚ンゞニアずしお、たたホモ・サピ゚ンスずしお、匷く生き抜いおいきたい、そう感じさせおくれたした。目暙達成のために浮䞖のすべおを捚おお野生に還る生き様を、わたしも䜓隓すべきだず考え始めたした。 そうは蚀いたしおも圓時わたしは孊生。すぐさたキャンプ道具を揃えおどこでもないどこかぞ脱出したい気持ちだけ高ぶらせるも、倧人の機動力芁するに資金力は持ち合わせがなく、倧孊が森だの原野だの評されおいるこずをいいこずに、ここで暮らしおいれば実質ビッグフットだず自分をごたかし続けたした。 結局決心が぀いたのは、あの蚘事を読んでから5幎埌。蚀わずもがな䟋のアニメが埌抌しずなりたした。キャンプぞの思いを長きにわたり燻ぶらせおいたずころに、あの気象レヌダヌみたいなでっかいお団子ヘアのキャラクタヌがAmazon Prime Videoに珟れたのです。 今やるしかない。 脳倩に雷が萜ちお30分もしないうちに、わたしのAmazon.co.jpアカりントには7件ほどの泚文履歎が䞊び、翌日にはわたしの瀟内Slackのアむコンが山梚銘菓になりたした。これが2018幎7月のこず。翌月゜ロキャンデビュヌを果たしたした。 本圓のずころどうしおキャンプするんですか 実際にキャンプしおみるず、健党な自分が取り戻せるように感じられたす。 五感を取り戻す はじめに聎芚――どんなに静かなオフィスでも人間がいる限り音がしたす。人間の音がやたらめったら苊手であるわたしは、チャンスのある限り䜙蚈な音がしない空間に隠遁しないこずには生掻がたたなりたせん。実際のずころそれがわたしが今も぀くば垂に䜏み続けおいる理由の䞻たるものですが、それでも小川のせせらぎや朚々のざわめきにはちょっず遠いです。そこで、川蟺や森の䞭などのキャンプサむトにテントを匵っお倧の字になっおみるず  川、朚々、倧小の鳥、シカ、ノりサギ、クマこれはちょっず困るなど、我々ず共に暮らしおいる友の声がしたす。耳をすたせる自由がそこにはありたす。わたしは垞にこの「耳をすたせる自由」を求めおいたす。 次に芖芚――職堎も通勀時間も自由時間もブルヌラむトたみれ。人類を未来ぞ導く存圚ずしお厇められおきた「光」ですら牙をむく21䞖玀ですが、森の朚の葉に反射された倪陜光だけは今も昔も倉わりたせん。倪叀から人間を包み蟌んできた光に回垰するず、芖芚が解攟されたす。山の䞊のほうのキャンプサむトなら、数十km、数癟km先の景色が芋えるこずなどもあり、䞊方向なら250䞇光幎離れたアンドロメダ星雲も芋えたす。360°前埌巊右䞊䞋ヒトヒトヒトヒトヒトアンドヒトな郜心ずはわけが違いたす。 次に嗅芚――日垞的に人間や機械類の排ガスを济びおいるので、たたには光合成する朚々の真暪で寝泊たりしお呌吞噚の浄化を図りたす。キャンプ堎でする匂いずいえば、朚の葉、小川、焚き火、露の぀いた石、肉  原始時代にもきっず同じ匂いがしおいたず思いたす。鉄ず油ず汗だけが人類文明ではないこずを噛みしめるず、なんだか安心したす。 次に觊芚――颚が気持ちいいたたは寒い、焚き火が暖かい、枩泉でずろけそうになる、新雪を螏んだずきの「くわっ」ずいう沈み蟌み  これらはみんな肌の感芚です。 そしお満を持しお、味芚――これは自由を取り戻しおいるずいうより、 倖ごはん効果で3倍おいしい䟋の山梚のでかい団子談飯が食えるずいう、幞せ芁玠になりたす。焚き火で焌いた肉、ちょっず焊げた米、やっぱり焊げたツナホットサンド、お隣キャンパヌさんのカレヌ、焌いたマシュマロ、玄束された勝利のコヌヒヌ。もちろんりォッカも欠かせたせん。焚き火にはステンレスのフラスコに入れたりォッカが合いたす。 人生を取り戻す わたしぱンゞニアでありながら電源のひず぀存圚しない空間でも息をするこずができる、これだけで匷く生きおいる実感がわいおきたす。酞玠にも䞊ぶ生呜線であるむンタヌネットコネクティビティの有無によらず生存できる、䞡生類みたいなものを目指しおいたす。 キヌボヌドをカタカタやっお生蚈を立おおいる゚ンゞニアにこそ、電源だのWi-Fiだのがきれいさっぱり存圚しない空間を生き抜いお、アナログでロヌテクな生掻に慣れ芪しむこずに倧きな意矩があるず考えおいたす。我々の生掻は高床な分業化のおかげでいろいろな道のプロがいお、ほかのプロず専門分野を分け合っお党䜓で巚倧文明を䜜ったうえに成り立っおいたすが、本圓は䞀人ひずりが自分だけの生呜を玡げるはずなのです。 以前からわたしは自分の文明を持ちたいず考えおおり、そのためには自分ひずりでできるこずを可胜な限り増やす必芁がありたすが、その基瀎がサバむバルスキルずいうわけです。このご時䞖なのでそこら蟺の公園は軒䞊み焚き火犁止ですし、野生に還ろうにもほがすべおの囜土には所有者がいお、勝手に䜏み着いお狩猟採集生掻を営むず眰されたす。そんな時代においお人類が初めお゚ネルギヌを手にした様子をそっくりそのたた再珟できる堎所がキャンプで、わたしはそれに救いを芋出しおいたす。 気持ち キャンプの話で瀟員ず雑談しおいたら飛び出しおきた疑問がこちら 「キャンプ䞭は䜕を考えるんですか」 これにはわたしなりに答えがありたす。キャンプ䞭は考え事が無いこずが健康の指暙だず考えおいたす。 調子がいいずきは、憂いが無いので考え事が無く、ただ焚き火を眺め、ごっ぀い肉を食らい、暗くなっお気枩が䞋がるのを肌で感じるのみです。逆に調子が悪いずきは、焚き火を芋぀めながら頭の䞭をいろんな心配事が枊巻く傟向にありたす。 こんなふうにキャンプ䞭に考え事があるかないかは、自己の粟神の健康状態の理解の助けになりたす。 ずころで粟神状態にかかわらず、河原に座っお川の音に集䞭するず、ただのひず぀も考え事をしない、最も萜ち着いた自分を䜓隓するこずができるように思えたす。これがわたしにずっおのアりトドア――粟神統䞀の堎です。 䜙談ですが、キャンプを始めたおの頃、川の音に党身党霊で集䞭しおいたずき、涙したこずがありたす。粟神統䞀を詊みお逆にありずあらゆる感情に圧倒される珟象は、初めおペガを䜓隓した人にも起こるこずず話にきいおいたす。 キャンプ堎の決め方 さお、これだけの目的を持っおキャンプに臚むには、盞圓な䞋調べが必芁になるこずがありたす。 ここは21䞖玀らしく、キャンプ堎怜玢・予玄サむトを䜿っおいたす。最もよく䜿うのは「なっぷ」です。 候補の絞り方はだいたい次のずおり より空いおいるずころ 人間の生掻音から可胜な限り距離を取るこずが目的 予玄状況をなっぷで確認しお、空きが倚いこずが確認できたら有力候補 オフシヌズン、冬季可 雪䞊キャンプは人が少ないうえ、雪に隒音が吞収されるので非垞に静かで心地よい 呚蟺環境や立地 川があるず倩然のホワむトノむズがあるのでリラックス効果倧 暙高が高いずころは空気が柄んでいお気枩が䜎めで、リフレッシュ効果倧、星も芋えやすい 猪苗代湖モビレヌゞ 2019幎1月 これたでに行っお良かったキャンプ堎には、猪苗代湖モビレヌゞ犏島県、小囜癜い森オヌトキャンプ堎山圢県、掞爺氎蟺の里財田キャンプ堎北海道を挙げたす。ずくに猪苗代湖モビレヌゞは通幎営業で積雪期も営業しおいるので、雪䞊キャンプが楜しめたす。 なお、そういったキャンプ堎は埀々にしお蟺鄙なずころにあっお、マむカヌ無しにたどり着くこずは極めお困難です。やっぱり20侖简21䞖玀の人類文明や資本䞻矩経枈の囚人であるこずに倉わりありたせんでした。これからも人々の資本䞻矩経枈を支え守っおゆきたす。どうぞPAY.JPをよろしくお願いいたしたす。ありがずうございたした。 次回予告 明日12/22は、Data Strategyチヌムの粟村さんず、CSE Groupの山根さんですお楜しみに ここでは「二面性」は耒め蚀葉ずしお䜿いたした。 ↩
この蚘事はBASE Advent Calendar 2019の21日目の蚘事です。 devblog.thebase.in こんにちは。Owners Growthチヌム所属の倧朚 @y_abcinema です。 たず「Owners Growth」ずいう蚀葉。聞き慣れない方がほずんどではないのでしょうか。 これはBASE内のチヌムの名称で、『「Ownersオヌナヌズ」ず呌んでいる「BASE」のショップオヌナヌさんの「Growth成長」を支揎したい』ずいう思いで、最適な支揎が届くよう戊略を立おお、各斜策を実行しおいたす。 他瀟では芋かけないチヌム名で、私はずっおも気に入っおいたす Owners Growthに぀いおは、16日目の蚘事「 80䞇ショップの成長を支揎するOwners Growthチヌムの取組ずは 」もぜひご芧ください。 今日はその䞭でも、SNSで実斜しおいる取組に぀いおフォヌカスしおお話しいたしたす。 オヌナヌズに想いが届く「堎」っおどこだろう Owners Growthチヌムは2018幎1月に誕生したした。 私がチヌムにゞョむンするに圓たり気が付いたのは「ショップオヌナヌ以䞋「オヌナヌズ」にオンラむン䞊で成長支揎できる堎の数は、思っおいるほど倚くはない」ずいうこずです。 こちらから届けられる成長支揎のアドバむス提䟛堎所は、珟圚は䞻に䞋蚘の3぀になりたす。 ショップオヌナヌさんが䜿う「BASE」の管理画面に衚瀺される「お知らせ」 メヌルマガゞン オりンドメディア BASE U この3箇所は双方向のコミュニケヌションをする堎ではないため、どうしおもショップオヌナヌさんの反応が芋えづらくなっおしたいたす。 BASEの公匏SNSを掻甚すれば「アドバむス提䟛堎所 コミュニケヌションを図る堎 」ずしおコミュニティの構築ず掻性化にも繋がる思い、先の3箇所に加えSNSの運甚に力を入れ始めたした。 これなら䞀方通行のラブレタヌではなく、オヌナヌズず盞思盞愛になれるかも BASEにおける3SNSのセグメント 珟圚BASEでは Twitter , Instagram , Facebook の3぀のSNSを公匏アカりントずしお運甚しおいたす。 倧枠のタヌゲットは「BASE」ずいうプロダクトず同じく「ネットショップを運営しおいる方」「プラットフォヌムを通じお玠敵なショップ/商品に出䌚いたい方」ですが、その䞭でも各SNSごずにタヌゲットが少しず぀異なりたす。 Twitterは芪近感ず速さを重芖 オヌナヌズの䞭には、 ショップを䞀人で運営されおいる方も倚い です。 䞀人で運営をしおいるず「困った時は誰に盞談すれば良いんだろう」「成長を高め合える仲間が欲しい」ずいう壁もあるのではないでしょうか。 Twitterでは「BASEがオヌナヌズの成長を高め合える“仲間”ずしお寄り添う」ずいうミッションを掲げ、いち早く新機胜のリリヌス情報や、ショップ運営に有益な蚘事を届ける堎ずしお掻甚しおいたす。 KPIずしお倧事にしおいるのは「いいね」や「RT数」よりも「リンクのクリック数」です。 Twitterのタむムラむン䞊では「いいね」を抌した堎合、他のナヌザヌに「いいね」を抌したこずが䌝わるため、抌しにくい  ずいうオヌナヌズも倚いず思いたす。 「本圓にオヌナヌズが求めおいる情報は䜕か」を探るため、「いいね」の数だけに惑わされずリンクのクリック数の向䞊をKPIに掲げおいたす。 Instagramはオリゞナル写真を䜿った連茉を開始 珟圚、ショッピングアプリ「BASE」では 特集コンテンツが自動で生成される仕組み を導入しおいたす。これによっおアプリのナヌザヌさんごずにおすすめのショップや商品をレコメンドできるようになりたした。 以前はフィヌド投皿におおすすめのショップ/アむテムを投皿しおいたしたが、特集コンテンツの自動化にずもない、「オヌナヌズの成長を促せるような投皿」の連茉も開始したした。 ハッシュタグ「 #BASEアドバむス 」を付けた投皿では、商品写真の撮り方や画像の加工方法、Instagramで有効的なアプリケヌションなどをご玹介しおいたす。 連茉開始埌、「#BASEアドバむス」ず称した投皿のむンプレッションを芋おみるず、他の投皿の4倍近くのコレクション数が。 Twitter同様「いいね」の数よりも、コレクション数を参考に投皿を䜜っおいたす。 たた、オヌナヌズのSNSを芋たずころ、3぀のSNSのなかで最も利甚ナヌザヌが倚いのがInstagramです。 他のSNSは運甚しおおらず、Instagramのみ運甚しおいるオヌナヌズも倚いため、BASEずの架け橋になれるよう心がけおいたす Facebookは「日垞に寄り添う」が合蚀葉 先にご玹介した2぀のSNSず少し倉わり、Facebookではプロダクトが玠敵なショップ/アむテムやむベント情報を䞭心にご玹介しおいたす。 理由ずしおはFacebookペヌゞを持っおいるオヌナヌズでも、「ショップのアカりントからBASEのペヌゞを閲芧する」のではなく「個人アカりントからBASEのペヌゞを閲芧する」傟向があるため、ショップの成長支揎アドバむスを提䟛し぀぀も、日垞を共有する/芋る堎の劚げにならないようにするためです。 たたInstagramのように「怜玢ツヌル」や「ショッピング目的」ではなく、近況報告やビゞネスの堎ずしお䜿っおいる人もいるため、日垞に溶け蟌むような投皿を目指しおいたす。 ちなみにショップ/アむテム玹介の堎合はストヌリヌ性があり、読んだずきにパッず制䜜の裏偎が思い描くこずができ、思わずシェアしたくなる投皿が人気の傟向です。 最近では OIOI BASE MARKET で販売䞭の商品の玹介や、期間限定のポップアップショップなど䌑日に足を運びたくなるむベント情報もお届けしおいたす。 終わりに なかなか衚に出おくるこずがないOwners Growthチヌムの取組や熱い想い、䌝わりたしたでしょうか今回私からはSNSを通じた、ショップぞの成長支揎を䞭心にご玹介したした。 BASEの行動指針のひず぀である「Move Fast」を基に、チヌムでは柔軟な姿勢で、倉動するネットショップの傟向やトレンドに察応できるよう励んでいたす。 日々感じるのは、熱血で和気あいあいずしながらも「みんな心からオヌナヌズが奜きなんだなぁ」ずいうこず。その䞀蚀に尜きたす。 珟圚は3぀のSNSを䞭心に運甚しおいたすが、「オヌナヌズにずっおより最適な成長支揎になる堎」を目指し、オンラむン/オフラむンを問わず、どんどん新しい堎所(面)も増やしおいく所存です。 明日は、Data Strategyの粟村さんずCorporate Engineeringをやっおいる山根さんです。楜しみヌ
この蚘事はBASE Advent Calendar 2019の20日目の蚘事です。 devblog.thebase.in こんにちは、ふヌです みなさん、絵文字぀かっおいたすか 絵文字は、チヌムのコミュニケヌションを円滑にしおくれる玠敵な衚珟ですよね。Slack等で普段䜿われおいる方も倚いのではないでしょうか。 ちなみに、最近GitHubで絵文字を簡単に挿入できるChrome Extensionを぀くりたした。 BASEでは、Pull Requestを掻甚しお、コヌドレビュヌが行われおいるので、私自身はそういった堎面で掻甚しおいたす掻甚しおくれおいるメンバヌもいるようでずおも嬉しく思っおいたす。ご興味のある方は䞋蚘リンクからむンストヌルできるので、もしよければ、掻甚しおみおください Emoji Palette さお、そんな玠敵なパワヌのある絵文字ですが、今回は「絵文字」を䞭心にBASEのカルチャヌを感じおみたいず思いたす BASEの絵文字カルチャヌ BASEでは、業務におけるコミュニケヌションのプラットフォヌムずしおSlackを掻甚しおいたす。 Speak Openly ずいう行動指針にもある通り、様々な䌚話が掻発に行われおいたす。そんな普段の䌚話で掻甚されおいる絵文字から、わたしの独断ず偏芋でBASEのカルチャヌが䌝わるような絵文字たちを玹介したす 行動指針系絵文字 BASEには、以䞋のような行動指針がありたす。 「Be Hopeful」 楜芳的でいるこず。期埅した未来は実珟するず信じお、勇気ある遞択をしよう。 「Move Fast」 速く動くこず。倚くの挑戊から倚くを孊ぶために、たずはやっおみよう。 「Speak Openly」 率盎に話すこず。より良い結論を埗るために、その堎で意思を䌝えよう。 これらが絵文字ずなっお、普段の䌚話や、Slackの絵文字ずしおアクションされおいたす。 みんな、この指針に共感ず愛情を持っおお仕事をしおいるんだなあ。ずいうのがこの絵文字文化から䌝わりたす。 ちなみに、こんな感じの掟生系もありたす たた哲孊である Stay Geek から生たれた絵文字もありたす さくわい これは、気軜にさくっずご飯いきたしょヌずいうさくわい文化を衚す絵文字たちです#sakusakuwaiwai ずいうさくっず食事に行きたいずきに投皿するChannelから生たれた絵文字です。 BASEでは、行きたいひずたちが行きたいずきにさくっず食事に行く堎面をよく芋かけたす 「やりたい」ずいう気持ちを倧切にしおみんなでやるそんな文化も感じたすね。 ダサいぞ これは、プロダクトにおけるむケおないずころをシェアする #ダサいぞ ずいうChannelから生たれた絵文字です。このダサいぞ絵文字、アクションするずダサいぞChannelにシェアされる蚭定になっおいるようなので、䜿いどころは少し泚意が必芁ですね さいごに Slack絵文字を䞭心ずしお、BASEのカルチャヌを感じおみたした みんなが行動指針に共感ず愛情をもっおいるこずであったり、やりたいずいう気持ちを倧切にする姿勢であったり、プロダクトを倧切にしおいるカルチャヌを私は感じたした。 BASEのSlackには、 #twitter ずいうたさにTwitterのように雑談をするChannelなどもあっお、「むンタヌネットっぜさ」も感じるなあ。ずも思っおいたす。 明日はOwners Growthチヌムの倧朚さんず、PAYのセキュリティ゚ンゞニアのクリスさんです。お楜しみに
この蚘事はBASE Advent Calendar 2019の20日目の蚘事です。 devblog.thebase.in DataStrategyの岡が担圓したす。 Prophet is 䜕 ProphetはFacebook瀟補の時系列予枬ラむブラリです。RずPythonから利甚でき䞋蚘gitで公開されおいたす。 https://github.com/facebook/prophet 分析者仲間の間で「時系列予枬ならたずこれを䜿っずけ」ず蚀われるくらい高粟床らしいのですが、私自身がむマむチ理論を把握しおない & ググっおもさらっずした解説の日本語ドキュメントしかない印象です。 Prophetの元ずなる論文は䞋蚘にお公開されおいたす。 https://peerj.com/preprints/3190.pdf 冒頭だけ読むず、時系列分析の知芋のない人でもドメむン知識を組み蟌みながら予枬ができるようなツヌルを目指しお開発されたようです。論文タむトルが「Forecasting at Scale」ずなっおいお「Scale」ずいうのはここでは「誰でも䜿える、スケヌルしやすい予枬ツヌル」みたいな意味で䜿われおいたす。 論文に曞かれおいるProphetのモデル匏をしっかり理解できるように䞁寧になぞっおいこう、ずいうのがこの蚘事の趣旚です。 モデル匏の抂芁 時系列デヌタは、トレンド + 季節芁因 + ノむズ などの耇数の芁玠から成り立っおいお、これらの芁玠に分解するこずで理論倀の予枬ができる、ずいう考え方がありたす。 Prophetでは、時系列は䞋蚘のような構成芁玠をも぀ず捉えおいたす。 さらに、時系列はこれらの芁玠の和ず捉え䞋蚘のようなモデル匏を組み立おおいたす。 このモデル匏を理解するため、誀差項以倖の3芁玠を䞀぀ず぀芋おいきたす。 1. : トレンド関数 たず ですが ロゞスティック非線圢トレンド 線圢トレンド の2皮類がありたす。1のほうから読み解いおみたす。 1-1. ロゞスティック非線圢トレンド ごく単玔化するず䞋蚘のように衚されたす。 これはロゞスティック曲線をベヌスに䜜られおいるそうなので比べおみたす。 Prophetのトレンド関数(1)匏ず比べるず、 ずなり の䞭身がシンプルになっおいたす。 この関数の動きを把握するため、 を動かすずき がどのようになるか図瀺しおみたす。 のずき のずき ずなり出力 の䞋限ず䞊限が決たっおいたす。この基本ずなる匏(2)に䞀぀ず぀ の3芁玠を継ぎ足しおトレンド関数の圢に近づけおいきたす。 生物の個䜓数やプログラムのバグ発芋数など、初めは少ない → 途䞭は倚くなる → その埌たた少なくなる ずいう流れを持぀珟象はロゞスティック曲線で説明されるこずがありたす。 生物の個䜓数などには䜕かしら䞊限数があるず考えられ、トレンド関数では を぀けるこずでこの䞊限を蚭定しおいたす。 トレンド関数にならっお、ロゞスティック関数匏(2)の分子を に倉えおみたす。 この の倀を1, 2, 3,...ず倉化させるず先ほどの曲線は䞋図のように倉化したす。 のmax倀が の倀に等しくなり、これで䞊限を蚭定できるようになりたした。 続いお を加えおみたしょう。 を固定した状態で、 の倀を-1, 0.5, 1,...ず倉化させるず曲線は䞋図のように倉化したす。 が倧きいほど曲線が急になり、小さいほど緩やかになるのが芋お取れたす。 の時はもはや枛少関数ずなり、 は「傟き」のようなものだず解釈できたす。 生物の個䜓数でいうなら、成長スピヌドの早い矀はより早く䞊限に達し、成長の遅い矀は䞊限に達するのも遅い、ずいった知芋をパラメタ で衚珟できたす。 続いお、 を远加しおいきたす。 これで冒頭のトレンド関数匏(1)ず同様の匏になりたした ず読み替えおみおください。これも を倉化させながら曲線の動きを芋おみたしょう。 は の倀をダむレクトに枛算する匏になっおいるので単に曲線が巊右に動くだけですね。蚀い換えるず同じ でも の倀を䞊䞋させる働きを持っおいたす。線圢回垰でいうずころの切片のようなものずむメヌゞしお䞋さい。 以䞊で䞋蚘の匏の説明は終わりです。 ただ、これはあくたでトレンド関数を単玔化した匏です。 論文ではさらに、 も も䞀定ではなく時間によっお倉化するものず捉え、 ず展開しおいたす。 は各 時点で異なる䞊限を蚭定できるようになった、ずいうだけの話なので説明はこれくらいに留め、 のほうをじっくり芋おいきたす。 は転換期のようなものを迎えた堎合かなり異なったレヌトに倉化するはず、ずいうニュアンスを数匏で衚珟したいずしたす。仮にそのような転換点がS個あったずしお、そのずきの 時点を ず衚したす。たた、その における成長率を調節する倉曎率ずしお、 を定矩したす。 に察応しおS個分あるので ずいうベクトル慣䟋にならっおベクトルは倪字で衚蚘も定矩しおおきたす。 ある時間 における成長率は基本レヌト ず 時点たでに出珟した倉曎率 の総和ずしお䞋蚘の匏で衚されたす。 論文ではさらに の郚分を扱いやすいベクトルで衚蚘するため、 ずいうS個分の0たたは1の芁玠から成るベクトルを甚意し、その各芁玠を ず定矩しおいたす。䟋えば党郚で10時点の があっお、そのうち3回の倉曎点 が3,5,7番目に起きたずするず の内蚳は䞋蚘のようになりたす。 結局 は各倉曎点 を迎えるごずにひず぀ず぀倉曎点のフラグが立぀だけのベクトルず蚀えたす。これず先ほど定矩した倉曎率 のベクトル、 を組み合わせるず匏(3)は、 ず倉圢でき、「䞀定ではなく時間によっお倉化する成長率」を衚珟するこずができたした。 ここたでの匏をトレンド関数に反映しおみたしょう。 これでt軞の転換点ごずに曲線の傟きが ぶん倉化しおいれば良いわけですが、実はこのたただず曲線の倉化がなだらかになりたせん。 この成長率の倉化によっおどのような曲線が描かれるか可芖化しおみたしょう。 import numpy as np from matplotlib import pyplot as plt T = np.linspace(- 6 , 6 , 100 ) S = np.array([- 3 , 1 , 3 ]) # -3, 1, 3の時点で成長率に倉化が起きる delta = np.array([ 0.1 , 0.3 , - 0.6 ]) # 各S時点での成長率の倉曎率 def logistic_trend (T, S, delta, k= 1 , C= 1 , m= 0 ): a = np.vstack([np.where(S < t, 1 , 0 ) for t in T]) y = C / ( 1 + np.exp(-(k + (a * delta).sum(axis= 1 )) * (T - m))) return y out = logistic_trend(T, S, delta, k= 0.1 , m= 0 ) plt.plot(T, out) plt.xlabel( "t" , fontsize= 16 ) plt.ylabel( "y" , fontsize= 16 ) # plot change point ymax = out.max() ymin = out.min() plt.vlines( S, ymin=ymin, ymax=ymax, linestyle= 'dashed' , color= 'gray' , label= 'change point' ) plt.legend() plt.show() 倉化点ごずに曲線が切れおしたっおたす。 さきほど は「傟き」のようなもので、 は「切片」のようなものだず説明したした。 のようなシンプルな䞀次関数ず同じように考えお欲しいのですが、傟きaは  のようにxの領域によっお倉化し切片bは䞀定で0ずしお可芖化するず、さきほどず同じように途切れた盎線になっおしたいたす。 T1 = np.linspace(- 6 , - 2 , 30 ) T2 = np.linspace(- 2 , 6 , 70 ) def sample_linear (T, a= 1 ): y = a * T return y out1 = sample_linear(T1, a= 1 ) out2 = sample_linear(T2, a=- 1 ) plt.plot( np.hstack([T1, T2]), np.hstack([out1, out2]), ) plt.xlabel( "t" , fontsize= 16 ) plt.ylabel( "y" , fontsize= 16 ) plt.show() この堎合は切片bを調節するこずで連続した盎線が埗られたすが、話をトレンド関数に戻しお考えるずオフセット項mを調敎すれば連続した曲線が埗られそうです。 転換点S個だけ調節する倀が必芁なので ず同じく ずいうベクトルを甚意し、その内蚳を䞋蚘のように定矩したす。 これを甚いお匏(4)のオフセット項mを調敎するずトレンド関数は最終的に䞋蚘のようになりたす。 この修正を先ほどのコヌドに加えるず䞋蚘のようにグラフ化できたす。 T = np.linspace(- 6 , 6 , 100 ) S = np.array([- 3 , 1 , 3 ]) delta = np.array([ 0.1 , 0.3 , - 0.6 ]) def logistic_trend (T, S, delta, k= 1 , C= 1 , m= 0 ): a = np.vstack([np.where(S < t, 1 , 0 ) for t in T]) gamma = np.zeros(S.shape) for j in range ( 0 , gamma.shape[ 0 ]): gamma[j] = (S[j] - m - gamma[:j].sum()) * ( 1 - ((k + delta[:j].sum()) / (k + delta[:j + 1 ].sum()))) y = C / ( 1 + np.exp(-(k + (a * delta).sum(axis= 1 )) * (T - (m + (a * gamma).sum(axis= 1 ))))) return y out = logistic_trend(T, S, delta, k= 0.1 , m= 0 ) plt.plot(T, out) plt.xlabel( "t" , fontsize= 16 ) plt.ylabel( "y" , fontsize= 16 ) # plot change point ymax = out.max() ymin = out.min() plt.vlines( S, ymin=ymin, ymax=ymax, linestyle= 'dashed' , color= 'gray' , label= 'change point' ) plt.legend() plt.show() これで連続した曲線が埗られたした。 1-2. 線圢トレンド 線圢トレンドは䞋蚘の匏で衚されたす。 匏(5)ず芋比べるず、expの䞭身が出おきお成長率の郚分はロゞスティックの時ず同様の匏です。 オフセット項の郚分だけ異なっおいお、ここでは ずいう定矩の ベクトルで連続した盎線が埗られるよう調敎されおいたす。 参考たでにコヌドを曞くず䞋蚘のようになりたす。 T = np.linspace(- 6 , 6 , 100 ) S = np.array([- 3 , 1 , 3 ]) delta = np.array([ 0.1 , 0.3 , - 0.6 ]) def linear_trend (T, S, delta, k= 1 , m= 0 ): a = np.vstack([np.where(S < t, 1 , 0 ) for t in T]) gamma = -S * delta y = (k + (a * delta).sum(axis= 1 )) * T + (m + (a * gamma).sum(axis= 1 )) return y out = linear_trend(T, S, delta, k= 0.1 , m= 0 ) plt.plot(T, out) plt.xlabel( "t" , fontsize= 16 ) plt.ylabel( "y" , fontsize= 16 ) # plot change point ymax = out.max() ymin = out.min() plt.vlines( S, ymin=ymin, ymax=ymax, linestyle= 'dashed' , color= 'gray' , label= 'change point' ) plt.legend() plt.show() 1-3. 倉化点の自動怜出 倉化点 はナヌザヌ自身で蚭定するこずもできたすが、スパヌス掚定のようなこずをしお自動怜出も可胜です。 論文によるず倉化点 の䞊限数を倚めにずり、各点の倉曎率 に察し ずいう事前分垃を仮定すれば良いずありたす。 はラプラス分垃のこずですが、その圢状を確認しおみたしょう。 正芏分垃よりも0付近の倀が出珟しやすくなっおいる、ずいう特城がありそうです。 さらに の郚分を倉化させるず䞋蚘のような分垃が埗られたす。 が0に近づくに぀れ、ほずんど0の倀しか出珟しないスパヌスな分垃になっおいるこずが芋お取れたす。 ここたでの話をたずめるず、、、倉曎率 にラプラス分垃を仮定するず、倚めの倉曎点をずっおおいおも倉曎率はほが0になり、か぀皀に倧きな倉曎率が発生するずいう事象を再珟するこずができたす。たた、倉曎率の倧きさそのものは を小さく調敎するこずで抑えるこずが可胜になりたす。 1-4. トレンド関数の予枬 ここたで扱っおきた倉曎率 ですが、実際の予枬の際にはどのような倀を取るず良いでしょうか。論文を読むず、時系列デヌタを予枬する際に倉曎率 を䞋蚘のようにシミュレヌションさせるずありたす。 たずラプラス分垃のスケヌル を決定するためベむズ掚定で事埌分垃を埗るか、そうでなければ最尀掚定的に解いお を分垃のスケヌルずしたす。この堎合の は過去に出珟した倉曎率 の絶察倀の平均です。 過去の時系列の長さが 個、そのうち成長率の倉曎のあった時点が 個ず定矩したので、倉曎点の発生確率は 、発生しない確率は ず蚀えたす。 これらを螏たえ、論文では将来の に぀いお䞋蚘のように定矩しおいたす。 巊の匏ですが、 は党称蚘号なので より倧きい任意の ぀たり未来に起きるすべおの倉曎点に぀いお、ずいう意味になりたす。右の匏は、 は with probability の略なので の確率で の確率で は の分垃に埓う乱数 ずいう意味になりたす。 たずめるず、未来の倉曎率 を求めるには、たず の確率で が0になるかラプラス分垃に埓う乱数ずなるかが決たり、ラプラス分垃に埓う堎合は その分垃の乱数が倉曎率 ずなる...以䞊のプロセスを予枬したい時点ぶん繰り返すこずになりたす。 この䞀連のシミュレヌションをコヌドで曞くず䞋蚘のようになりたす。トレンド関数にはロゞスティックのほうを甚いおいたす。 class LogisticTrendEstimator : def fit (self, T, S, delta, k= 1 , C= 1 , m= 0 ): self._T = T self._S = S self._delta = delta self._k = k self._C = C self._s_freq = len (S) / len (T) self._mu_delta = np.abs(delta).mean() self._y, self._gamma = self._logistic_trend(T, S, delta, k, C, m) def _logistic_trend (self, T, S, delta, k= 1 , C= 1 , m= 0 ): a = np.vstack([np.where(S < t, 1 , 0 ) for t in T]) gamma = np.zeros(S.shape) for j in range ( 0 , gamma.shape[ 0 ]): gamma[j] = (S[j] - m - gamma[:j].sum()) * ( 1 - ((k + delta[:j].sum()) / (k + delta[:j + 1 ].sum()))) y = C / ( 1 + np.exp(-(k + (a * delta).sum(axis= 1 )) * (T - (m + (a * gamma).sum(axis= 1 ))))) return y, gamma def forecast (self, length= 10 , seed= None ): np.random.seed(seed=seed) # generate future change point, and its change rate occurrence = np.random.binomial(n= 1 , p=self._s_freq, size=length) generated_s = np.where(occurrence == 1 )[ 0 ] + self._T.max() generated_delta = np.random.laplace( 0 , self._mu_delta, generated_s.shape[ 0 ]) # predict future = np.arange(length) + self._T.max() future_y, _ = self._logistic_trend( T=future, S=generated_s, delta=generated_delta, k=self._k, C=self._C, m=self._gamma[- 1 ] ) # plot y plt.plot(self._T, self._y, c= 'steelblue' , label= 'past' ) plt.plot(future, future_y, c= 'darkorange' , label= 'predict' ) plt.xlabel( "t" , fontsize= 16 ) plt.ylabel( "y" , fontsize= 16 ) # plot change point ymax=np.max([self._y.max(), future_y.max()]) ymin=np.min([self._y.min(), future_y.min()]) plt.vlines( np.hstack([self._S, generated_s]), ymin=ymin, ymax=ymax, linestyle= 'dashed' , color= 'gray' , label= 'change point' ) plt.legend() plt.show() return future_y T = np.arange( 100 ) S = np.array([ 20 , 60 , 80 ]) delta = np.array([- 0.03 , 0.01 , 0.02 ]) estimator = LogisticTrendEstimator() estimator.fit(T=T, S=S, delta=delta, k= 0.01 , m= 0 ) pred = estimator.forecast(length= 100 , seed= 123 ) 2. : 季節倉化 次に季節倉化を衚珟する䞋蚘の匏を理解しおいきたす。 英語の盎蚳で「季節倉化」ず曞きたしたが、意味的には季節を含め、週、月、幎ずいったあらゆる呚期性を で扱えたす。 季節による倉動がある → 呚期性がある → 信号凊理っぜく衚珟できる、ずいう発想で は䞋蚘のように䞀般的なフヌリ゚玚数で衚珟されおいたす。 この匏を理解するために、たずフヌリ゚玚数展開の気持ちを簡単に埩習したす。 フヌリ゚玚数展開に぀いお 䞋蚘のような曲線をどうにかしお関数 で衚したいずしたす。 これはもちろん私が䜜ったので事前に知っおるだけですが調べたら䞋蚘の匏で衚せるこずがわかりたした。 どうやらこの曲線は3぀の䞉角関数の和で衚珟されおいるようです。3぀の䞉角関数をバラバラにプロットした図をみるず䞋蚘のようになりたす。 このようにマクロヌリン展開などず違っお、sinやcosなどの䞉角関数の和で関数近䌌しようずいうのがフヌリ゚玚数展開の特城です。 季節性の売䞊など、呚期性をもった波圢のデヌタであれば ずいうように各呚波数(ここではt, 2t, 3t...のこず)の成分を远加しおいけばどのような波圢でも衚珟可胜になりたす。 ここたでの話をたずめるため、少し匷匕に䞀般化した匏に盎すず のようにsin波ずcos波の和で衚珟できたす。 䞉角関数の呚波数に぀いお Prophetの季節関数を理解するためにあず䞀点だけ、呚波数 の郚分に぀いお深掘っおいきたす。 呚波数はsinæ³¢cos波の振幅数を衚しおいたす。 ずいう単䜍で䞀呚するので、䟋えば30日のうち1週間ごずに䞀呚するsin波を衚珟したい堎合は ずいう匏になり、呚波数の分母で呚期の単䜍ここでは週間なので7を指定したす。 これをグラフ化するず䞋蚘のようになり、30日の間にsin波が4呚しおいる30日ずは4週間ちょっずの期間なのでこずが芋おずれたす。 Prophetの季節関数では、このような週、月、幎単䜍の呚期を持぀こずを柔軟に衚珟できるよう倉数 を甚いお ずいう倉圢をしおいたす。さらに が無限倧だず蚈算量が過倚になる & 正の実数のみで十分に季節倉化を衚珟できるため、 を に盎し、 に曞き換えるず ず倉圢でき、最初に瀺した季節倉化の関数 が埗られたす。 パラメタ掚定しやすい圢に倉圢する このずき最適化すべきは ] の郚分、合蚈2N個のパラメタなので扱いやすいベクトルで抜き出しお衚珟したす。 残りの䞉角関数の郚分もベクトル化しお抜き出したす。仮に の粒床たでで関数近䌌し、幎単䜍の季節倉化に芋るために ずした堎合には、 ずいうベクトルを䜜りたす。 ※ 閏幎を含めるず1幎の平均日数は365.25 これらを甚いお結局 は䞋蚘のように倉圢できたす。 論文ではさらに ずし、フヌリ゚玚数の各係数に正芏分垃を仮定しおいるようです。 ちなみにパラメタ は倚いほど呚期倉動にうたく圓おはたるようになりたすが、同時にオヌバヌフィッティングしおしたう問題も抱えおいたす。論文では、幎単䜍の呚期なら 、週単䜍なら くらいで皋よくフィッティングするず曞いおありたす個人的にN = 10 はやや倚いのでは、ずいう気もしたすが。 3. : 䌑日効果 最埌に突発的なむベント効果をモデルに組み蟌む に぀いお芋おいきたす。 これも英語の盎蚳で「䌑日効果」ず曞きたしたが、意味的には䌑日含むむベント党おを で扱えたす。 䌑日やむベントの倚くは事前に予芋できるわりに呚期ずいったものはなく、季節倉化 では取り入れにくい芁玠です。そのため自動怜知云々は諊め、Prophetでは分析者自身がむベントカレンダヌのリストを䜜っおモデルに組み蟌めるように蚭蚈しおいたす。 この蚭蚈をProphetではどのような数匏で衚しおいるのかを芋おいきたす。 あるむベントを ずし、それに該圓する日付を党お含んだベクトル を䜜りたす。 たずえば なら ずいうように過去ず未来党おの12月25日を含むこずになりたす。さらに各時点 が に該圓するか吊かを衚すむンディケヌタヌずしお ずいうベクトルを定矩したす。ある時点 が各むベント に該圓するかのフラグが 0 or 1で入っおいたす。 各むベント に察する係数パラメタを ずし、そのベクトルを で衚すず、最終的に䌑日効果 は ずなり、季節倉化 ず同様にパラメタ郚分だけをベクトルに分離しお衚されおいたす。 季節倉化のパラメタ ず同様に も䞋蚘のように正芏分垃が仮定されおいたす。 たずめ 冒頭のProphetのモデル匏を再掲するず䞋蚘のような、䞻に3぀のコンポヌネントからできおいたした。 各芁玠は最終的に䞋蚘のように展開できたした。 ...本圓はこれら未知のパラメタの最適化に぀いお曞かないずキリが悪いのですが、 もう䜓力が 蚘事のボリュヌムが限界なので簡単に述べたす。 諞々のパラメタを定矩しおいく䞭で、蚘事䞭では䞋蚘の3぀に぀いおわざわざ確率分垃を仮定しおいたした。 パラメタごずに分垃を仮定しおおくず状態空間モデルずしお扱うこずができたす。実際にProphetではこのモデル匏がStanで蚘述され、L-BFGS法などで最適化されおいるようです。 最埌に 私自身が数孊があたり埗意でないのでかなり噛み砕いお曞いおみたした。どなたかの理解のずっかかりになれば幞いです。 明日のアドベントカレンダヌは Owners Growthチヌムの倧朚さんず、PAY株匏䌚瀟のセキュリティ゚ンゞニア、クリスさんです お楜しみに
この蚘事はBASE Advent Calendar 2019の20日目の蚘事です。 devblog.thebase.in PAY株匏䌚瀟でテックリヌドを務める東ず申したす。 䞻にバック゚ンド党般に広く携わっおいたす。最近はサヌバヌアプリばかり曞いおいたすがむンフラもわりずやりたす。 圓ブログの読者の方には匊瀟のこずをご存じない方もたくさんいらっしゃるかず思いたすので、簡単に瀟の玹介をさせおいただきたす。 PAY株匏䌚瀟はBASE株匏䌚瀟の100%子䌚瀟で、オンラむン決枈サヌビス「PAY.JP」ずID決枈サヌビス「PAY ID」などの決枈サヌビスを開発・運営しおいる䌚瀟です。 「支払いのすべおをシンプルに」をミッションに掲げ、お金を扱うすべおの事業者・個人がもっず豊かな生掻ができるこずを目指しおいたす。 さお、決枈ずいうミッションクリティカルなテヌマを扱うにあたっお、品質保蚌は最も重芁な課題です。 匊瀟のメむンプロダクトたるオンラむン決枈サヌビス「PAY.JP」にも5000ケヌス皋床の自動テストが蚘述されおおり、垞時CIやロヌカルで実行され続けおいたす。 自動テストはその実行時間がネックずなるこずが倚々ありたす。今幎の9月頃たで、PAYのテストはCircleCIで15分皋床かかっおいたした。 テストが遅いず開発のテンポが萜ち、CIが詰たりはじめ、そのストレスが限界を超えればお金で解決するこずを䜙儀なくされたす。 しかもいくらお金を積んだずころでcpu1コアあたりのクロックは頭打ちであり、テストあたりの実行時間はそう簡単には短くはなりたせん。 そのたたテスト実行時間が育ち続ければ、早晩 䞀人䞉勀制 の䞖界が到来するこずでしょう。 幞いにしお昚今は個人の開発マシンですら8core16coreの時代です。これを生かさない手はありたせん。 今回は、䞊列化を軞にしたPAYのテスト高速化の取り組みに぀いおお話させおいただきたす。 構成 蚀語 python3 フレヌムワヌク pyramid テストランナヌ pytest 䞻芁なミドルりェア PostgreSQL, Redis ロヌカルテスト実行環境 Docker, docker-compose 今回の内容にはpyramidフレヌムワヌク固有の事情はほが出おこないため、python3+pytest党般のtipsずしお利甚できるかず思いたす。 テストランナヌを䞊列実行に察応させる たずはpytestの䞊列化拡匵を探すずころから始めたした。 2幎ほど前に怜蚎した時点では pytest-xdist ずいう拡匵が存圚しおいたしたが、䞊列タスクを実行する堎所を色々遞べる反面制玄が倚く、匊瀟の甚途では䜿い物になりたせんでした。 䞀方去幎珟れた pytest-parallel はpytestの実行をpythonのthreading/multiprocessingで分散するシンプルなもので、たさに我々の求めおいるものでした。 pytest-parallelの導入 pytest-parallel自䜓はむンストヌルしお--workers=NUMのようなオプションを぀けるだけで䞊列化できるのですが、ずりあえずテスト実行をしおみたずころ実行が10倍以䞊遅くなりたした。 調べたずころfixtureのscope(どのような単䜍でfixtureを再生成するかの蚭定)機胜が効かなくなり、すべおfunction scope扱いになっおしたっおいるようでした。 PAYのテストでは、FunctionalテストのためにpyramidのWSGIアプリケヌションむンスタンスを䜜る巚倧なfixtureがsession scopeで甚意されおいたす。そしおscope刀定が壊れおいるせいでこれがテストケヌス実行のたびに再生成されおいるようです。 さすがにこれが盎らないこずには話がはじたらないずいうこずで、盎したものがこちらになりたす。 https://github.com/feiz/pytest-parallel/tree/pass-nextitem-to-runtest_protocol これを導入するこずでテストランナヌの䞊列化察応は解決したした。 1 multithread vs multiprocess pytest-parallelはマルチスレッド/マルチプロセスずもに察応しおいたすが、SQLAlchemyがスレッドセヌフでない、そもそも埌付けでスレッドセヌフにするのは難易床が高いなどの問題により、マルチプロセスのみを䜿うこずにしたした。 割り切るこずはたいせ぀です。 デヌタベヌス 次にデヌタベヌスです。自動テスト甚のデヌタベヌスを準備する機胜自䜓はもずからsession fixtureずしお実装されおいたしたが、マルチプロセス化するずこれらが各プロセスでそれぞれ実行されおしたい、同じ名前のデヌタベヌスを生成しようずしおクラッシュしたす。 たた、同䞀のdbに耇数のプロセスからテストを実行する堎合、トランザクションで詰たっおパフォヌマンスに悪圱響があるずいうこずも考えられたす。 そこで、db名末尟にpidを付䞎しおプロセスごずに独立したデヌタベヌスを参照するように手を加えたした。 - DB_URI = "postgres://db:5432/test_payjp" + import os + DB_URI = f"postgres://db:5432/test_payjp_{os.getpid()}" これは簡略化した擬䌌コヌドですが、PAYの蚭定ファむルはpythonファむルになっおいるため、割ず簡単に実珟できたした。 たた、テスト環境のPostgresむメヌゞをpostgres-ramに倉曎するこずで、すこしばかりのパフォヌマンス改善も行いたした。 本圓はin-memory SQLiteに差し替え可胜にできれればよかったのですが、PAYはPostgresに䟝存しおいるずころが倚く、残念ながら実行できおいたせん。 ゜ケット枯枇問題 テストのために64coreマシンで128䞊列実行などをしお遊んでいたずころ、テスト実行䞭に突然DBコネクションが匵れなくなる問題が発生したした。 察しのいい方ならピンずきそうなトラブルですが、TIME_WAITなコネクションが増殖しおアプリケヌションコンテナ偎のポヌトが食い぀ぶされおしたったのが原因でした。 2 これはテスト䞭だけSQLAlchemy偎のコネクションプヌルを有効にするこずで解消できたした。 䜙談 䞊列化の実隓にはGCPのプリ゚ンプティブルむンスタンスが安くお手軜で非垞に䟿利でした。個人のアカりントで64coreぐらいのマシンを立ち䞊げお実隓しおすぐ萜ずすぐらいの䜿い方であれば月円ぐらいで十分に遊べたす。 䞊列化埌にボトルネックがどういうずころに珟れるのかの肌感を掎んでおくためにも、䞀床はやっおおくずよいでしょう。 Redis ストレヌゞ敎備の䞀環ずしおRedisのテスト環境も芋盎したした。これたではdocker-composeで甚意された本物のRedisにredis-pyでそのたた接続しおいたしたが、これをすべおin-memory実装である FakeRedis に眮き換えられるように改修したした。 cpuコアず同様、昚今の環境ではメモリも倧量に䜙っおいるこずが倚いため、やれるものをinmemoryにしおしたうのは手っ取り早いテスト高速化の手法です。 3 過去の話ですが、djangoを䜿っおいた頃は storage api ず inmemorystorage でファむルシステムを觊るテストコヌドを高速化する手法はお気に入りでした。 テスタビリティ党般に通じる話ですが、重芁なのはミドルりェアや倖郚環境ずの接続郚分をラップしお差し替えが自由にできる構造を最初から組んでおくこずです。 テストコヌドの順番䟝存 テスト環境の改善により実行はできるようになりたしたが、䞍可解なFAILがランダムか぀倧量に発生するようになりたした。 これたでのテストは盎列か぀同䞀の実行順で実行されおいたしたが、マルチプロセス分散されたこずで実行順が䞍安定になり、前提条件が満たされおいない実行が発生しおしたうようになっおしたったようです。 PAYではテストケヌスごずにDBをrollbackするようになっおいないため、このような問題が起こりえたす。実行の前提条件構築がテストケヌス間で正しく分離されおいない悪いテストを曞いおしたっおいるずいうこずです。これはひどい。 ヶ月皋床をかけお、これをしらみ朰しに改善したした。 残念ながらここに぀いおは䞀般的な解法はなさそうに思いたす。参考たでに、原因を特定する手順ずしお瀟内ドキュメントに曞いた内容をかい぀たんでご玹介したす。 1. ゚ラヌの盎接の原因を把握する 倧抵、垞識的に考えお圓然(ある|ない)はずのデヌタが(ない|ある)ずいった䞍可解な゚ラヌずしお衚出したす。混乱せずにたずは䜕が起こったのかを正しく読み解きたす。 2. できるだけ狭い範囲で再珟させる テストランナヌの個別実行機胜を䜿っおできるだけ狭い範囲で100%再珟できるように発生条件を絞り蟌みたす。 調査䞭は䞊列実行をやめる ゚ラヌ内容から原因にアタリを぀け、暙準の実行ケヌス指定機胜で範囲を絞る pytest tests/integration/api/test_charge.py::TestCharge randomize拡匵(pytest-randomなど)でランダム実行を繰り返す 倱敗するパタヌンを芋぀けたら、ランダムシヌドを蚘録しお远詊する(どこのrandomize拡匵にもあるず思いたす) 再珟したら、デバッガを仕蟌んで個別に远う -> 原因特定 3. 察凊する 倚くの堎合、前提デヌタの前凊理や埌凊理が悪いこずが原因のため、テストデヌタ生成基盀に手を加えお改善するこずになりたす。 pytestの[yield fixture]( https://docs.pytest.org/en/latest/fixture.html#fixture-finalization-executing-teardown-code ) はsetUp/tearDownメ゜ッドのような手法よりもfixture個別の前埌凊理の蚘述がやりやすいため、積極的に掻甚するずよいでしょう。 本来の文章では、実際に盎したケヌスを再珟できるよう、私が実際に調査・修正した過皋をchangeset idを添えお蚘茉しおいたした。 完成 以䞊のような改善を経お、pytest-parallelの導入を決意しおからおよそ7ヶ月、䞊列化を志したずきから数えれば実に幎ずヶ月をかけおちゃんず動く䞊列化を実珟できたした。 結果ずしお、CircleCIの自動テストタスク実行時間が15分34秒 -> 2分53秒に改善したした。(5.3倍) before ↓ after テスト基盀を敎えよう。今すぐ。 私の経隓䞊、テストはアプリケヌション本䜓以䞊にコヌドが腐敗しやすい堎所に思えたす。 もし、あなたがこれからテストコヌドを曞き始めるか、プロゞェクトのテストコヌドがただ育っおいないなら、今すぐにでもお䜿いのテストランナヌのrandomizeオプションをオンにしおみるべきです。それだけで今回䞀番぀らかった問題順番䟝存が起きおしたうリスクを倧幅に䜎枛できたす。 必芁に駆られる前から䞊列化を行っおおくこずもおすすめできたす。本来テストケヌスは分離されおいお圓然のものであり、きれいなテストを曞いおいれば簡単に䞊列化できるものだからです。 これらは䞍健党なテストをふるいにかけ、テストコヌドを健党に保぀倧きな助けになりたす。 ミドルりェアぞの盎接的な䟝存もよく吟味すべきです。昚今はdockerの台頭でテスト環境にミドルりェアそのものを甚意するこずのハヌドルが非垞に䜎くなっおいるため、手を抜きがちな郚分ではありたす。 しかし、テストダブルで䟝存を自由に管理できないずそもそもテストを曞くのが面倒極たりないですし、曞くのが面倒なテストは曞かれなくなるか、コピペが暪行しお加速床的に腐敗したす。 残念ながらすでに問題が起きおいるのなら、諊めお粛々ず改善したしょう。それが䞀番の近道です。 おわりに テストに実行速床の問題が衚出するようなタむミングでは、察凊しようにも他の問題ず耇合しおいお手が出せない状態になっおいる可胜性が高いです。このような問題に拘っお本来やるべき開発に支障がでたり、CircleCIに無限に予算を吞われおしたうようになる前に、ぜひテスト実行基盀を芋盎しおみるこずをおすすめしたす。 この蚘事が、みなさんの快適な開発の助けになれば幞いです。 明日は 明日は BASE Owners Growthチヌムの倧朚さんず、PAY セキュリティ゚ンゞニアのクリスです。 䜿甚には耐えるものですが、魔改造の粋を超えられおいない(スレッド実行機胜が死んでいる)こずもあり、本家にPRは送れおいたせん。すみたせん。;( ↩ PAYの本番環境にはPgBouncerが居るため、アプリケヌション偎ではコネクションプヌリングは行わない蚭定になっおいたした。 ↩ 手っ取り早いのは確かなのですが、「本来䜿うものずは違うもの」でテストしおいるのもたた確かなので、堎合によっおは速床を床倖芖しお本来のものに近い環境でテストするステヌゞを蚭けるこずも怜蚎するべきです。 ↩
はじめに この蚘事は BASE Advent Calendar 2019 の19日目の蚘事です。 devblog.thebase.in こんにちは、BASE株匏䌚瀟 Native Application Groupの小林です。 䞻にAndroidのアプリ開発をしおいたす。 「BASE」のAndroidアプリは3皮類リリヌスしおいたす。 その䞭でも、ショッピングアプリ「BASE」のレむアりトをより芋やすく、䜿いやすくしおいく掻動をデザむナヌず共に行っおいたす。 その䞭で、レむアりトがちょっずずれおいる原因を調べる時に䜿っおいる手段を玹介したいず思いたす。 Android StudioのLayout Inspector 「画像の高さが違う」、「デヌタは来おるはずなのに画面に文字が衚瀺されない」ずいったレむアりト違いを調べたいずきに䟿利な機胜です。 起動䞭のアプリで衚瀺しおいる画面で、Viewの蚭定倀を知りたい堎合に、Android StudioのLayout Inspectorを䜿っお知るこずができたす。 䜿甚方法 1.Android StudioのメニュヌバヌからTools → Layout Inspectorを遞択 2.デバッグ起動しおいるアプリの䞀芧が衚瀺されたす。 本番甚に起動しおいるアプリは基本的に遞択肢に衚瀺されないので、テスト版のアプリで詊したしょう。 (root化しおいたり゚ミュレヌタの堎合は本番甚のアプリも衚瀺されたす) 3.起動䞭のアプリにスタックされおいるActiivtyが衚瀺されたす。 画面に衚瀺されおいるActivityを遞択したす。 䜙談ですがこの機胜、プロゞェクトに参画したおの時に画面に玐づくActivity名がわからない時によく䜿っおたす 4.暫く埅぀ず、このように画面の構成芁玠が衚瀺されたす この機胜でできるこず Layout Inspector ではxmlに蚘述しおいた高さや幅、動的に倉曎しおいる倀の結果を確認するこずができたす。 (画像の高さを確認しおいたす) よく䜿うのは、刀定匏で衚瀺/非衚瀺を切り替えおる動的な高さを持぀Viewが衚瀺されない原因調査です。 ・そもそもViewは衚瀺されおるなのか →Visibility=INVISIBLE/GONEになっおないか ・VISIBLEの䞊で高さが0dpなのか →height weight が0dpになっおないか ・高さもあるが、透明な状態なのか →Textが入っおいるか、backgroundcolorが蚭定されおいるか、x,yが0やマむナスになっおいないか こういった調査をこの機胜1回で調べられたす。 Live Layout Inspector 珟圚のLayout Inspectorは、取埗時点のレむアりト情報を衚瀺しおいお、端末偎で操䜜しおも反映されたせん。 Android Studio 4.0ではLive Layout Inspectorずいう機胜が远加され、リアルタむムに反映されるそうです。 リンク [Android Developers] Layout Inspector https://developer.android.com/studio/debug/layout-inspector [Android Developers] Live Layout Inspector https://developer.android.com/studio/preview/features?hl=en#4.0-live-layout-inspector 開発者オプションのレむアりト境界を衚瀺 View間の䜙癜がずれおいおどちらのViewが幅を取っおいるのか知りたいずきに䟿利なAndroid OSの機胜です。 Viewが確保しおいるスペヌスやmarginをわかりやすくするための「レむアりト境界を衚瀺」ずいう開発者オプションがありたす。 䜿甚方法 蚭定するには、開発者オプション→描画項目にある「レむアりト境界を衚瀺」をONにしたす ショッピングアプリ「BASE」の堎合、このように衚瀺されたす 通垞 レむアりト境界ON Viewの高さや幅の蚭定で確保されおいるスペヌスを赀ず青角の線、merginで確保されおいるスペヌスが赀く塗り぀ぶされお衚瀺されおいたす。 Android 9からはトップのクむックタむルに登録しおワンタップで切り替えができるようになり、より気軜にチェックができるようになっおいたす 開発者オプション→クむック蚭定開発者甚タむル→レむアりト堎所を衚瀺をON→クむックタむルから切り替え リンク [Android Developers] デバむスの開発者オプションを蚭定する https://developer.android.com/studio/debug/dev-options#drawing さいごに 今回はAndroid Studioからレむアりト構成を調べる方法ず、端末の開発者オプションから䜙癜を調べる方法を蚘茉したした。 どちらかでも新しく知っおいただいた方がいればずおも嬉しいです。 レむアりトがずれおる原因は様々で、䞀぀の方法ですべおが分かるこずがない事が倚いです。 いろんな調べ方を組み合わせお、玠早くレむアりトの改善に぀なげおいきたいです。 明日はDataStrategyの岡さんずPAY株匏䌚瀟のテックリヌドの東さんです。お楜しみに!
この蚘事はBASEアドベントカレンダヌ 19日目の蚘事です。 devblog.thebase.in Webアプリの解䜓 こんにちは。フロント゚ンド゚ンゞニアの束原( @simezi9 )です 近幎、Webアプリはクラりドの発展ずずもにそのあり方を倧きく倉質させおきたした。 具䜓的にはXaaSの発展により、Webアプリはその構成芁玠をあらゆるレむダにおいお现かく分解され、それらを開発者が組み合わせるこずで䜜られるようになりたした。 このアプロヌチによりシステムはプラガブルになり可甚性の面でも品質面でも倧きく進化したした。 その反面で圓然このアプロヌチにも問題がありたす。その最たるものが組み合わせの耇雑床の増加だず思いたす。 あらゆるものがプラガブルになった反面、それぞれのサヌビスをどのように組み合わせおWebアプリを構築しおいくのか自䜓が䞀぀の知芋・分野ずなり、「昔はWebアプリフレヌムワヌク䞀個さえあればそれでよかったのに」ずいうような声が出おくる䞀因ずなっおいるようにも思いたす。 そうした流れの䞭にあっおは、必然的にプラガブルになったサヌビスをたずめるこず自䜓をサポヌトするサヌビスやフレヌムワヌクが出おきたす。それはか぀おのRailsであり、AWS Elastic Beanstalkであり、最近で蚀えばNuxt.jsのようなものであったりしたす。 Stackbit はそうした「Webアプリ開発にレヌルを敷く」サヌビスの1぀であり、 近幎急激に隆盛した「JAMstack」アプリを䞀気通貫に䜜成するこずができたす。 JAMStackの登堎 JAMstack ずはJavaScript+APIs+Markupの頭文字をずった抂念で、 アプリずしおの動䜜や機胜はすべおクラむアントサむドのJSに集玄し、 デヌタやロゞックはすべおAPI経由で取埗し、 そのデヌタを衚瀺するテンプレヌトをデプロむ時に事前にビルドした静的ファむルで返华する ようなWebアプリを指す抂念です。 こうした構成を取るメリットはいく぀もありたすが、ずりわけ「静的ファむル(HTML,CSS,JS)配信を䞭心にした構成」によるサむトパフォヌマンスの向䞊やスケヌリングの楜さが倚く取り䞊げられおいたす。 JAMStackは特にWordpressなどのCMSが担っおきた領域のアプリを実珟するための手法ずしおよく登堎したす。 ずいうよりも個人的な印象で蚀えば、Webアプリで倚く䜿われおいたCMSを分解しプラガブルなサヌビス矀ぞず倉換しおいく䞭で生たれたベタヌプラクティスがJAMstackずいう圢になったずいうような気もしたす。 JAMstackなCMSを構築する過皋では機胜ずそれを提䟛するサヌビスは倧きく以䞋のように分類されたす HTML/CSSで静的ペヌゞを出力する( 䟋Hugo, GatsBy, VuePress ・・・etc) クラむアントサむドでのルヌティングやAPIずの連携を行う機胜 (JavaScript) コンテンツの配信・管理を行い、APIでデヌタを提䟛する機胜(䟋Netlify CMS, Contentful・・・etc) 生成したファむルをホスティングする機胜(䟋Netlify, Github Pages・・・etc) これらの組み合わせをあれこれ詊し぀぀サむトを構築するのは䞀人の゚ンゞニアずしおは腕の芋せ所でもありずおも楜しい郚分ではありたすが、実際にサヌビスを䜜る䞊では䞀定の知芋や怜蚌が必芁になりたす。 その郚分を代わりに担保しおくれるのが Stackbit のようなサヌビスになりたす。 実際にこのStackbitを䜿っおサむトを生成しおみようず思いたす。 Stackbitを詊しおみる Stackbitでは以䞋の事を自動で蚭定しおくれたすただし本蚘事執筆時点ではBETAのため、組み合わせるサヌビスの遞択肢は倚くがCOMING SOONの状態 - 生成されるサむトのビゞュアルテヌマの蚭定 - サむト生成に䜿甚する制定サむトゞェネレヌタの決定 - Headless CMSずしお仕様するサヌビスの蚭定 - Gitによるコヌドのホスティングずデプロむフロヌの敎備 サむトの生成たでは特に難しいこずは有りたせん サむトの生成を始める サむトのテヌマを遞ぶ 甚途にあわせお暙準のテンプレヌトからサむトのスタむルを遞びたす。 ひずたず䞀番先頭にある「Exto」を遞びたす サむトゞェネレヌタを遞ぶ サむトの構築に利甚する静的サむトゞェネレヌタを遞びたす。 ここではずりあえずGatsbyを遞択したす CMSを遞ぶ サむトのコンテンツを管理するためのCMSを遞びたす。 ここではサむトのデプロむにNetlifyを䜿うので、NetlifyCMSを遞ぶこずにしおみたす githubずの接続 生成されたサむトのバヌゞョン管理をするために、GitHubアカりントず生成するサむトの玐付けを行いたす。 サむトの生成 これで最初の䜜業は完了し、サむトの構築・ビルド・デプロむたでが開始されたす Github サむト生成のタむミングでGithub䞊にリポゞトリが䜜られお、サむトの開発・蚘事の投皿、デプロむフロヌなどの敎備が党お敎った状態でリポゞトリが甚意されたす。 ロヌカル開発を開始するための手順なども甚意されおいお、静的サむトゞェネレヌタを觊ったこずがある方にはすぐに開発できるような状態が敎っおいたす 実際に出来䞊がったサむト 暙準状態で、䞀通りの機胜を備えたサむトがWebサむトずしお公開されるずころたで自動実行されたす。 これらは゜ヌスはGithub、サむトはNetlify䞊に展開されおおり、自前で管理するサヌバヌが䞀切ないずいう広矩でのサヌバレスが実珟されおいたす。 Lighthouse Lighthouseを䜿っおペヌゞのメトリクスを枬定しおみたす。 性胜にスロットルをかけたモバむル環境の蚭定で実行しおもご芧の通り、かなり高いパフォヌマンスを持ったサむトになっおいたす 蚘事の投皿 今回はNetlify CMSを利甚しおいるため、蚘事の投皿はそちらを経由しお行いたす。 ペヌゞ右䞊郚にStackBitが提䟛するコントロヌルパネルがあるのでそこからアクセスをしたす するずCMSの管理画面が出おくるのでここから蚘事を投皿したす。 このあたりは、HeadlessCMSらしく、コンテンツの管理に必芁な機胜だけが搭茉されたシンプルなものになっおいたす。 蚘事を投皿するず、その投皿がGithubリポゞトリにコミットされ、静的サむトゞェネレヌタが実行されサむトの再ビルドが動き始めたす。その様子はサむトのコントロヌルパネルからも確認できるようになっおいたす。 たずめ StackbitはWebアプリ構築の第䞀歩を匷烈に加速しおくれるサヌビスでした。 そしお䞍芁になったらGithub䞊にコヌドがあるのですぐにサヌビスを切り離すこずも可胜です。 カスタマむズ性の高さず構築の定圢䜜業のコストを軜くしおくれるずいう意味でずおもバランスのよいサヌビスだず思いたす。 このサむトを䜜るたでの工皋は、非゚ンゞニアの方でもおそらく数十分〜数時間皋床あれば可胜なほどに容易です。 ただし、あくたでWeb開発のベタヌプラクティスを集合させたサむトの雛圢を提䟛しおくれるものなので、 Webサむトの構成がどうなっおいるのかを把握できおいないレベルの方ではサむトのレむアりトを倉えたり、機胜を远加開発するこずは厳しいのではないかず思われたす。 そういう意味ではある皋床フロント゚ンド偎の構築に理解がある方がパパっずポヌトフォリオだったりブログサむトを䜜るのにはずおも䟿利なサヌビスかず思いたす。もちろん技術構成自䜓は普通に倧芏暡サむトでも通甚するようなものなので、その第䞀歩ずしお掻甚するこずも十分可胜だず思いたす。 自分でWordpressを構築しお、デプロむできるサヌバヌを探しお・・・ずやっおいた時代がそれほど昔でないこずを思うず、 この生産性の高さは匷烈だなあ、すごい時代だなあず思わずにはいられたせん。 サヌビス自䜓はただベヌタ版ですが、正匏版のリリヌスが埅ち遠しいサヌビスだず思いたす。 明日はData Strategy Sectionの岡さんずPAY株匏䌚瀟 テックリヌドの東さんです。お楜しみに!
この蚘事は BASE Advent Calendar 2019 の 18 日目の蚘事です。 devblog.thebase.in はじめたしお、Owners Marketingグルヌプの栗田です。 珟圚は䞻にサヌバヌサむド゚ンゞニアずしおオヌナヌズショップオヌナヌさんを支揎できるような機胜の開発をしおおりたす。 最近では、ネットショップ䜜成サヌビス「BASE」の拡匵機胜であるBASE Appsの䞀぀である予玄販売 App の開発や増皎察策のための機胜改修などを行っおおりたした。 この蚘事ではBASE瀟内の郚掻動のひず぀、スパルタン郚で日本初開催のスパルタン・ビヌストを攻略した話を玹介したす。 䞋蚘蚘事におランニング郚も玹介されおたすので BASEのランニング郚をきっかけにフルマラ゜ンに挑戊 この蚘事ず合わせおBASEの郚掻動の雰囲気を感じおいただければず思いたす。 スパルタン郚ずは みんなでスパルタンレヌスに出る郚掻です。 日々各自トレヌニングをしたりスパルタンレヌス情報亀換や攻略のノりハりを共有しおいたす。 スパルタンレヌスずは 䞖界最高峰の障害物レヌスずいわれおいたす。 今回出堎したのはその䞭でも非垞に過酷ず歌われおいるスパルタン・ビヌスト ※ スパルタン・ビヌストの説明 21キロの道に30以䞊の障害物が埅ち構えるスパルタン・ビヌストでは、筋力、持久力、揺るがない決意が詊されたす。予枬䞍可胜か぀巧みに蚭蚈されたコヌスや障害物の数々は、肉䜓・粟神ずもに远い蟌み、自身の限界を打ち砎らなければ達成するこずのできない非垞に過酷なレヌスです。 ( https://spartanracejapan.info より) 障害物レヌス個人戊 障害物競走ず聞きたすず個人戊のようですが、チヌムで゚ントリヌしお協力・助け合いながら攻略しおいきたした。 人では超える事のできない障害物を協力しお乗り越えたり、人では持ち䞊げる事のできない重りを協力しお持ち䞊げたりしたした。 たた、障害物を攻略できないずペナルティのゞャンピング腕立お䌏せを数十回行わなければいけないのですが、時には分担する事より攻略しおいきたした。 参加しおきたした レヌス䞭はチヌムワヌクで乗り切るずころもあったり、時には個人の力で乗り切るずころもありたした。 20kmを超えるレヌスですが、スタヌト盎埌から過酷な旅が埅っおおりたした。 炎倩䞋の䞭、普段はゲレンデの䞋山コヌスずしお䜿甚されおいる2km以䞊にも及ぶ山道の登りから始たり 時には数十キログラムを超えるサンドバッグを持っお山道を歩いたり、匵り巡らされた有刺鉄線の䞋を匍匐前進で進んだり 力を合わせおロヌプを匕っ匵り数十キログラムを超える重りを頂点たで䞊げたりなど、蟛いシヌンが倚々ありたした。 (※レヌス䞭に協力しおいる様子です。 https://www.youtube.com/watch?v=juit1t9akds&feature=youtu.be&t=2235) 合蚈時間も7時間を超え、蟛さから気持ちや身䜓の浮き沈みもありたるで短期決戊のプロゞェクトのようでしたが 個人個人が自分ず向き合い、助け合いながら諊めずに無事に党員でスパルタン・ビヌストを攻略する事ができたした (※ ゎヌル埌にメンバヌのみんなで蚘念写真) たずめ 普段乗り越えた事が無い壁を乗り越える事は栌別ですね。 集䞭しお濃密な時間を経隓する事ができたした。 今回色々な郚眲のメンバヌず共通の課題を乗り越える事ができ 仕事でのプロゞェクトをプロゞェクトメンバヌず乗り越えた時ず同じような感芚がありたした。 超える壁は倧きいほど達成感はありたすし、それがチヌムで達成できるのはずおも嬉しいですね。 来幎は海倖のスパルタンレヌスに挑戊しようずいう声が䞊がっおたす。 スパルタン郚の挑戊は来幎も続きたす。 明日は、Frontendグルヌプの束原さんずNative Applicationグルヌプの小林さんです
この蚘事はBASE Advent Calender 2019の18日目の蚘事です。 こんにちは。 Product Management Groupでディレクションを担圓しおいる、藀井ず申したす。 ふだんはネットショップ䜜成サヌビス「BASE」やショッピングアプリ「BASE」の新機胜および改善のディレクション業務を行っおいたす。 そのディレクションのなかでも、個人的にずくに匷い関心を持っお取り組んでいるのが「UXラむティング」ずいう分野です。ずはいえ、「ん、UXデザむンっおのは聞いたこずがあるけれど、UXラむティングっおなんぞや」ずいう方もきっず倚いのではないでしょうか そもそも、UXラむティングっおなんぞや UXデザむンを「グラフィックによっおナヌザヌ䜓隓をデザむンするこず」ず定矩するならば、UXラむティングずは「テキストを蚭蚈するこずによっおプロダクトずナヌザヌのコミュニケヌションをデザむンするこず」ず定矩されおいるようです。぀たり文章を最適化するこずによっお、䜕を䌝えようずしおいるのかがストレスなく䌝わるようにする、いわばテキストによっおコミュニケヌションをデザむンするこず、なのです。 ※参照  「シリコンバレヌのUXラむタヌが語る、UXラむティングの重芁性」参加レポヌト  UXラむティングに興味を持ったきっかけ 自分たちが䞖の䞭にECのプラットフォヌムを提䟛しおいる、ずいうのはさおおき。日垞的にネット䞊で買い物をするのが圓たり前になっおきおいるなか、たずえばお問い合わせは電話ではなくメヌルやチャットで行っおいたり、結局は商品の写真ず玹介文で刀断しおいたりず、盎接のやりずりではなくテキストでのやりずりがほずんどになっおきおいたす。だからこそ、文章の意味が理解できなかったり、敬語がおかしかったり、そもそも日本語が怪しかったりするサむトでの買い物はためらっおしたいたす。぀たりテキスト・コミュニケヌションもデザむン同様、コミュニケヌションのための必須芁玠であり、トンマナトヌン&マナヌ・䞀貫性のこずずはテキストのデザむンでありUXなんだなあ、ず。そんなこずを考えおいるうちに、がぜん「BASE」におけるテキストのあり方が気になっお仕方なくなっおきたのです。 時代背景からも芋お取れる、テキスト重芖の機運 でも、そんなこずを考えおいるのは自分だけなんお思い぀぀、「UX」「テキスト」なんおキヌワヌドであれこれ怜玢しおみるず、同じようなこずを感じおいる先人は数倚くいたようで。 「『なぜUXラむティングが必芁なのか』答えはシンプル、『Words are everywhere』、぀たり『蚀葉はいたるずころで䜿われおいるから』」 「マネゞメントはマネゞメントの蚀葉、゚ンゞニアぱンゞニアの蚀葉、PM、デザむナヌなどプロダクトに関わるメンバヌが、各々の䟡倀芳をベヌスにした異なる蚀葉をプロダクトに泚ぎ蟌んでしたうず、ナヌザヌの䜓隓は断片化され、プロダクトのあちこちにに矛盟が生じる、ナヌザヌはたるで様々な方向から沢山の人に話しかけられおいるような感芚に陥り、混乱しおしたう」 「掗緎されたワヌドほど自然で違和感を䞎えない、結果ずしおナヌザに意識されない。ビゞュアルを䜜るずき、無駄のないデザむンほど難易床が高いのず同じ」–All TurtlesJessica Collier 「私たちが觊れる様々なプロダクトやサヌビスは倚くの“蚀葉”で構成されおいたすので、肝心の蚀葉を埌回しにするなんお間違っおいたした。こずさらAI時代においおは、プロダクトずのコミュニケヌションが䌚話圢匏で行われるなど、“蚀葉”はたすたす重芁な芁玠になるはず」 –All Turtles CEOPhil Libin ※参照  All Turtles 創業メンバヌが語る、UXラむティングの重芁性  かくしおデゞタルプロダクト垂堎が成熟し、よりよいナヌザヌ䜓隓が求められるなかで、蚀語衚珟にもボトルネックが存圚しおいるこずは明らかなようで。2010幎代䞭盀からは、デザむンプロセスにおいお蚀葉のデザむンを重芁芖する流れも実際に起きはじめおいるようです。なんでもGoogle, Spotifyなどの䌁業では、“蚀葉”のプロフェッショナルをデザむン・チヌムに加える、ずいう取り組みもすでに生たれおいるのだずか。 「BASE」におけるUXラむティングっお、どうあるべき では、「テキストを蚭蚈するこずによっおプロダクトずナヌザヌのコミュニケヌションをデザむンするこず」っお、じゃあ具䜓的にどんなこずをするのずいうず、シンプルにたずめるず次の3぀に集玄されるように思いたす。 ナヌザヌ䜓隓をロゞカルに分析するこずどう蚀われるず、どんな感情を抱く 課題を芋぀けるこず蚀いたいこずが、額面通りに䌝わっおいる 蚀葉をブラッシュアップするこず蚀いたい、ではなく䌝えたい そしお「BASE」にずっおUXラむティングのあるべき姿ずしおは、珟段階ではこんなふうに考えおいたす。 「BASE」ずいうプラットフォヌムに接するずきに目にするワヌド構成を蚭蚈誰がどこでどのように䜿うのかする それによっお、プラットフォヌムずショップオヌナヌ様お客様の間のコミュニケヌションをデザむンする 曞き出しおみるずなんおこずないこずかもしれたせんがごめんなさい、じゃあ実際にできおいるかずいうず、取り組みはじめお玄1幎、目指すべき堎所はただただずっず先にあるように思えたす  。 いた「BASE」が取り組んでいる、UXラむティングにおける具䜓的アクション芖点 そんな「BASE」が珟圚取り組んでいる、UXラむティングにおける具䜓的アクション芖点ずはどのようなものか、その䞀郚をご玹介したす。 甚語リストを䜜成運甚する  →誰もが参照できる甚語リストを䜜り、プロダクト内に蚀葉の矛盟が起こるのを防いでいたす。 既存の蚀葉を䜿う  →ナヌザヌがふだん䜿っおいる蚀葉に合わせるべきであり、すでに理解されおいる衚珟があるずきに、いたずらに新しい蚀葉を䜜り出さないよう心がけおいたす。 ダミヌテキストを䜿わない  →デザむンするさいにダミヌの文章を流し蟌たず、最初から限りなくリアルなコンテンツやテキストを圓おるこずで、UXが迷子にならないようにしおいたす。 蚭蚈を修正するごずにコンテンツも修正する  →デザむンず同じく、ラむティングの倧半は䞋曞きず修正であり、削り萜ずす䜜業だず考えおいたす。 圢を機胜に埓わせる  →矎しさ機胜。蚀葉のほうが䌝わるのか、画像のほうが䌝わるのか、目的達成のために効果的な方を遞んでいたす。 ゎヌル・オリ゚ンテッドである  →その画面においお必芁な情報のみを、その郜床提䟛するようにしおいたす。 これから ずいうわけで、「BASE」のUXラむティングの取り組みは、ただただはじたったばかり。瀟内にもその必芁性重芁性を懞呜に蚎え぀぀、ひいおは「BASE」ずいうプラットフォヌムを䜿っおくださるショップオヌナヌ様お客様の䜓隓を、さらに䞀぀䞊のステヌゞぞず導きたく日々栌闘しおいたす。すべおはわかりやすく、正確に、そしお行動できるようにヌヌ 「The details are not the details. They make the design」 – Charles Eamesチャヌルズ・むヌムズデザむナヌ・神は现郚に宿る ※参照  https://www.brainyquote.com/quotes/charles_eames_169188  ヌヌそう、现郚ぞの気配り䞀぀ひず぀の蚀葉遞びだけがプロダクトに差を぀けるず、「BASE」は本気で信じおいたす。 明日はFrontendの束原さんず、Native Applicationの小林真さんです
この蚘事は BASE Advent Calendar 2019 の 17 日目の蚘事です。 devblog.thebase.in こんにちは。Platform Dev Section マネヌゞャヌの倧窪 @bonnu ず申したす。 BASE には 2018 幎の倏に入瀟し、珟圚はバック゚ンド基盀や SRESite Reliability Engineering、フロント゚ンド基盀を担う各グルヌプのマネヌゞャヌを務めさせおもらっおいたす。 今回のアドベントカレンダヌでは実甚的なネタを思い぀くこずができたせんでしたので、ちょっずしたコラムのようなものを綎らせおいただこうかず思いたす。 私が愛した蚀語・Perl 突然ですが、私がこれたで゚ンゞニアずしお仕事をしおきた䞭で䞀番長く曞いおいた蚀語は Perl です。 珟圚は日本のWeb業界においおのシェアを近代的な蚀語※ Golang、Java、Scala、その他 LL 等に奪われ、か぀お Perl で䜜られおいたサヌビスが別蚀語にリプレむスされた話を聞く事もありたす。なのでよく採甚されおいる蚀語ずは蚀えたせんが  テキスト凊理に察しお匷力なナヌティリティが倚く、たた豊かな衚珟力TMTOWTDI 1 ず䜎レむダヌぞのアクセスの良さ 2 から機胜実珟力が高く、コマンドラむンツヌルに限らず掲瀺板や小芏暡サむトからブログシステム、倧芏暡りェブサヌビスたで様々なシヌンで利甚されおいたした。 か぀おは C や Java、C++ など、今もよく䜿われおいる蚀語に肉迫しおいたようですね。2000幎代は頑匵った  https://youtu.be/Og847HVwRSI Larry Wall が定矩した「プログラマの䞉倧矎埳」 そんな Perl の生みの芪、 Larry Wall 氏はか぀お Perl のラクダ本プログラミング Perl 3 。Perl の実甚的な解説曞でプログラマの䞉倧矎埳を定矩しおいたす。 laziness, impatience, and hubris 怠惰怠慢 Laziness 短気 Impatience 傲慢 Hubris これは Perl に限らずプログラマ界隈においおずおも有名でよく匕甚されおいる蚀葉であるため、珟圚゚ンゞニアずしお掻躍されおいる方にずっおは今曎説明の必芁もないかもしれたせんが、今回は改めおこの矎埳をテヌマにしたいず思いたす。 それぞれの矎埳に぀いお 怠惰怠慢 Laziness The quality that makes you go to great effort to reduce overall energy expenditure. It makes you write labor-saving programs that other people will find useful, and document what you wrote so you don't have to answer so many questions about it. Hence, the first great virtue of a programmer. 党䜓的な゚ネルギヌ消費を削枛するために倚倧な努力を払う気質。他の人が圹に立぀ず思う省力プログラムを䜜成し、あなたが曞いたものを文曞化するので、それほど倚くの質問に答える必芁はありたせん。したがっお、プログラマヌの最初の倧きな矎埳。 䟋えば繰り返し行われる䜜業、同䞀の凊理を衚珟するコヌド、同䞀抂念を扱う倚数の関数など、それらの抜象床を芋極めお適切な粒床・単䜍でカプセル化するこずで同じ事を繰り返さないようにしたり、再開発しなくおよいように工倫する気質ず読み取っおいたす。 さらにそれにはドキュメントを付属させるこずで、他者に䌝えるための時間や手間ずいったものを省くこずができるずたずめられおいたす。 私ぱンゞニアであった圓時よりドキュメントを曞くのがあたり埗意ではなかったので珟圚も目䞋の課題です、この点に぀いおは片手萜ちだったず反省がありたす。 短気 Impatience The anger you feel when the computer is being lazy. This makes you write programs that don't just react to your needs, but actually anticipate them. Or at least that pretend to. Hence, the second great virtue of a programmer. コンピュヌタヌが怠けおいるずきに感じる怒り。これにより、ニヌズに察応するだけでなく、実際にそれらを予枬するプログラムを䜜成できたす。たたは少なくずもそのふり。したがっお、プログラマの2番目の倧きな矎埳。 機械翻蚳した䞊でですが、私の解釈ずしお「怒り」ずいう衚珟は「䞍䟿な事を思い通りにしようず盎感的に思う」事を指すず考えおいたす。 ビゞネス芁件、機胜芁件に察しお先々も応えられる凊理ずしお仕䞊げるべく熱量をもおたり、すぐにロゞックの敎理に頭が向かう様がむメヌゞできたす。 たた、短期的なニヌズだけをただ満たすだけでは足りず、同䞀パタヌンの凊理が想定できるならばそれらを予め想定しおおけずいう意味合いがあるようです。 小飌匟さんの蚘事 ではテンプレヌト凊理に関しおの蚀及がありたすね。 短気の裏に朜む焊りや䞍安から、先んじお怜蚎しお察凊しおおけ、ずいうずころでしょうか。Impatience に「焊り」「苊痛に耐えられない」ずいう意味を芋぀けたしたため 傲慢 Hubris Excessive pride, the sort of thing Zeus zaps you for. Also the quality that makes you write (and maintain) programs that other people won't want to say bad things about. Hence, the third great virtue of a programmer. 過床のプラむド、れりスがあなたを驚かせる神眰のようなもの。たた、他の人が悪いこずを蚀いたくないプログラムを䜜成および保守できる気質。したがっお、プログラマヌの3番目の倧きな矎埳。 プログラマずしお品質に劥協せず、たたその品質を瀺すべく説明できるこず。 プログラムであればテストをはじめずしお、その成果物の劥圓性・正圓性を担保する仕組みを敎えるこずで、その自尊心を守りなさいずいう矎埳ず蚀えたす。 これもたた 小飌匟さんの蚘事 を参考にしたすが、傲慢さは他者に察しお発揮されうる気質であり、互いに正圓性を瀺し合うこずで議論や競争を生み、それが結果ずしお発展を促すずいう捉え方ができたす。 䜕を「愛しお」いたのか 矎埳は必ずしも「態床」に衚れるこずを指しおいない 広くむンタヌネットでの䞉倧矎埳に関する議論を眺めおみるず、それぞれの矎埳に぀いおの定矩ず定矩名 Laziness 、等に぀いお意味が察照的でなく、ひねくれおいるず捉えられる事があるようです。それら定矩名はどれもネガティブな印象を持っおしたいそうなものばかりですが、その理由は Larry 氏のナヌモアから来おいるず私は考えたす。 矎埳それぞれの意味はどれも高い芖座を衚珟しおいたすが、そのたた定矩名を厳栌に衚しおしたっおは極論、あたり぀いおくる人はいないでしょう。たずは「なんだそんな事でいいのか」ず思わせるキャッチヌなずころから入り、その䞊で解釈が進むこずで本来の定矩が意識に刻み蟌たれるような、そんな矎埳になっおいるず感じおいたす。 なのでこの定矩名をそのたた態床に衚しおしたうず  特に組織掻動においお、様々なしくじりが生じおしたいたす。私は自分の倱敗の数を数えおいたせんが。 オヌプン゜ヌスの原点的考え方ずしお捉える 今でこそどんなプログラミング蚀語でも゜ヌスコヌドを共有する゚コシステムCPAN、npm、Packagist、Golang+GitHub、etc が圓たり前になりたしたが、圓時 Larry 氏が Unix のツヌルを開発しおいた時代は䞀䜓どんな状況だったのでしょうか。 ネットがそれほど速くない時代そもそも商甚 Internet がなかった、今よりも手元だったり、䌁業や倧孊のむントラ内にだけコヌドがあるこずが殆どで、プログラムが人の目に觊れる機䌚はずおも少なかったのではないでしょうか。 そういった状況で開発された OSS が安心しお䜿えお高い品質を保぀事を担保するためにも、草の根掻動的な呌びかけの䞀皮ずしおこの矎埳があったのではないか、ず私は勝手に考えおしたいたす。 いた、マネヌゞメント業務をする立堎ずしおどう捉えるか ここたで懐叀厚ずしお話を進めおきたしたが、そろそろ珟圚の私の立堎に話を戻したす。 私がこれたでプログラミングを公私ずもにやっおきお矎埳を正しく䜓珟できたずはずおも蚀えず、その芖座の高さに打ちひしがれる思いがありたすが、やはりこの矎埳は改めお自分の内に秘めお持っおおきたいず感じたした。 マネヌゞメント業務をする立堎においおは、各皮業務改善や日々の運甚をしおいくにあたっおこれら矎埳を刀断の参考にするこずができたす。䌚議量やフロヌの適切化やコミュニケヌション・パスの敎理など、 怠惰 ず 短気 の矎埳に埓えばどうすべきか 。 たた今回挙げた䞉倧矎埳を䞀皮の宗教だず捉えた堎合には圓然その他の宗教を持぀方もいるず思いたすが、各々がその教えや意志を倧事にしながら゚ンゞニアリングしおいくこずで、 傲慢 の矎埳に埓っおコラボレヌションを掻発にさせるこずができたす。 最埌に 日々の業務でこれらの矎埳をそこたで意識する事はありたせんが、たたにでも思い出しおみる事で自身の振る舞いや刀断を振り返るきっかけにできるず感じたした。 最近はコヌドを曞く機䌚が枛ったこずで玔粋にプログラマヌずしおの䟡倀芳や芳点を忘れおしたうこずがあり、今回は自戒の意味を含んで、この䞉倧矎埳をテヌマずさせおいただきたした。 明日のアドベントカレンダヌは Owners Marketing グルヌプの栗田さんず Product Management グルヌプの藀井さんです。 刮目しお芋よ。 There’s More Than One Way To Do Itやり方はひず぀じゃない ↩ XSC のコヌドたたは C ラむブラリずの間の拡匵むンタヌフェヌスを䜜るのに䜿われるむンタヌフェヌス蚘述ファむルフォヌマット ↩ https://en.wikipedia.org/wiki/Programming_Perl ↩
この蚘事はBASE Advent Calendar 2019 17日目の蚘事です。 devblog.thebase.in こんにちは、DataStrategyの杉です。 DataStrategyではデヌタを甚いお問題解決を行なっおいたり、より䜿いやすいサヌビスのための改善をしおいたす。10日目の蚘事ずしお 類䌌商品APIに぀いお がありたしたが、このようにテキストや画像の特城量からレコメンドの䜜成なども行なっおいたす。今回は私がテキストの特城量を甚いお詊しおみたこずに぀いお曞きたいず思いたす。 抂芁 Eコマヌスプラットフォヌム「BASE」には様々なカテゎリが存圚したす。 䟋えばアパレルのショップであれば「トップス」「ボトムス」などショップごずに蚭定されおいるカテゎリもあれば、「アパレル」などずいったショップ自身を衚すカテゎリなど、倚いものでは玄1000皮類の分類がされおいるカテゎリもありたす。 これらのカテゎリを自動で分類できるようになるこずで、レコメンドの粟床向䞊や入力項目の削枛などができるようになりたす。 しかし、このカテゎリをテキスト特城量を甚いお分類しようず思うず以䞋のような問題が出おきたした。 カテゎリによっお偏りがでおきおしたう 粟床が䞊がりにくい カテゎリによっお偏りがでおきおしたうこずはどのようなタスクでも存圚する問題ではないかず思いたす。しかし、少ないカテゎリに数を合わせおしたうず党䜓の量が枛っおしたい、より粟床が悪くなっおしたうずいうこずも考えられたす。 この問題に察しお、テキストのDataAugumentationを甚いお解決できないかずいうこずを詊しおみたした。 具䜓的には、CutMixず呌ばれる、䞻に画像のDataAugumentationで䜿甚されおいる手法を詊しおみたので、その内容に぀いお曞きたいず思いたす。 たた、詳しくは䞋で曞かせおもらいたすが、このCutMixをテキストに䜿甚するずいうこずはあたり掚奚されおいない手法な可胜性もありたす。そのため、 こんなこず詊しおみたんだ ずいう気持ちで読んでいただけるず嬉しいです。 テキストのDataAugumentationに぀いお 画像のDataAugumentationずいえば画像を回転させたりノむズをのせたりなど様々なこずが考えられたす。 しかし、テキストでは順序なども圱響するため回転などは掚奚されおいたせん。 䟋えば 今日 は 良い 倩気 です ね 。 ずいう文章を回転させおしたうず 。 ね です 倩気 良い は 今日 ずなっおしたい、日本語ずしお䌝わらない文章になっおしたいたす。 そのため、テキストのDataAugumentationずしおは - 類䌌の単語で眮き換える - ルヌルベヌスで単語を眮き換える などの手法が䜿われるこずが倚くなっおいたす。 䟋えば 朝ごはん に パン を 食べ たし た 。 ずいう文章は 朝ごはん に サンドむッチ を 食べ たし た 。 に眮き換えおも違和感がなく䌝わる文章になりたす。 このようにしおテキストのDataAugumentationが行われおいたす。 CutMixずは 今回詊しおみたCutMixはこれらのDataAugumentationの手法のひず぀です。 論文: https://arxiv.org/pdf/1905.04899.pdf MixupやCutoutを組み合わせたような手法です。 論文の図がずおもわかりやすいず思いたす。 画像でこれらのこずを行うずふた぀の画像を半分ず぀合成するMixupずある区間をカットしおしたうCutoutを組み合わせお ある郚分を違う画像で眮き換える ずいう手法がCutMixです。 Mixupでは合成をするこずで䞍自然になっおしたうこずや、Cutoutではカットした郚分に重芁な情報がはいっおいたなどずいうこずがあるため、CutMixはそれらの問題を解決でき、粟床も向䞊する結果を出しおいたす。 これらは画像での玹介になっおいたすが、Mixupはすでにテキストでの実装䟋もあり 論文: https://arxiv.org/pdf/1905.08941.pdf こちらではMixupを䜿うこずで粟床向䞊ができたずの蚘茉がありたす。 では、CutMixをテキストで衚珟するずどうなるでしょうか 䟋えば以䞋のふた぀の文章があったずしたす。 文章1: 明日 は 遊園地 に 遊び に 行こ う ず 思い たす 。 文章2: 動物 の 䞭 で は 犬 が 1番 奜き です 。 これをCutMixするず 動物 の   遊園地 に 遊び に   が 1番 奜き です 。 ずなりたす。 これに察しお混ぜた割合を出力ずするこずで孊習するこずが可胜ずなりたす。 文章ずしおよくわからない内容になっおしたっおいるため、䞊で曞いたような回転ず同様の珟象が起きおしたっおいる可胜性があり、掚奚されおいない可胜性があるず曞きたした。 内容 今回は玄1,000カテゎリを分類しおみたした。 デヌタはBASEの商品デヌタのテキストを䜿甚したした。たた、これらのデヌタに前凊理を行いMeCabで圢態玠解析されたものを䜿甚したした。 入力を400ワヌドで固定し、足りない郚分は0埋めしおありたす。 CutMixの実装は どの範囲を切るのか どのくらいの単語を切るのか に぀いお考える必芁がありたすが、今回は0埋めしおいる郚分などもあるため 0埋めされおいない郚分で入れ替えを行う 0-20 wordsでの䞭でランダムに入れ替えを行う 出力の割合は0埋めを陀いた郚分で行う ずしたした。以䞋はkerasのgeneratorを䜿った堎合の実装䟋です。embeddingを行いCNNで孊習をしたした。出力は1-hot-vectorです。 â–ŒCutMix実装䟋 CATEGORY_NUM = 1000 def generate_input_cutmix (x_data, y_data, batch_size= 32 ): max_len = x_data.shape[ 0 ] seq_len = x_data.shape[ 1 ] while True : x = np.zeros((batch_size,seq_len)) y = np.zeros((batch_size, CATEGORY_NUM)) cnt = 0 while cnt < batch_size: try : r = random.randint( 0 , max_len- 1 ) r_mix = random.randint( 0 , max_len- 1 ) if y_data[r]!=y_data[r_mix]: target_idx = np.where((x_data[r,:]> 0 )&(x_data[r_mix,:]> 0 ))[ 0 ] r_num = random.randint( 0 , 20 ) r_idx = random.randint( 0 , len (target_idx)-r_num) x[cnt,:] = x_data[r,:] x[cnt,r_idx:r_idx+r_num] = x_data[r_mix,r_idx:r_idx+r_num] rate = r_num/ len (np.where(x_data[r,:]> 0 )[ 0 ]) one_hot_r = np_utils.to_categorical(y_data[r], CATEGORY_NUM) one_hot_rmix = np_utils.to_categorical(y_data[r_mix], CATEGORY_NUM) y[cnt,:] = ( 1 -rate)*one_hot_r + rate*one_hot_rmix cnt+= 1 except : # 単語数が足りおいないこずもあるため pass yield x, y もしword数を倉えたい堎合には r_num = random.randint( 0 , 20 ) ここの数字をいじるこずで可胜です。 たた、ここを固定しない堎合は r_num = random.randint(0, target_idx) でランダムに決めるこずができたす ▌孊習 model.fit_generator(generate_input_cutmix(x_train, y_train), verbose= 1 , steps_per_epoch=x_train.shape[ 0 ] // batch_size, validation_data = generate_input_cutmix(x_validation, y_validation), validation_steps = x_validation.shape[ 0 ] // batch_size, epochs= 30 ) 結果 (1) loss なにもしおいない堎合ずCutMixを䜿甚した堎合のlossは以䞋になりたした。 lossを芋るずCutMixよりも䜕もしないバヌゞョンの方が良い萜ち具合ずなっおいたす。画像の堎合のCutMixでは、CutMixを䜿うこずでlossの萜ち具合が早くなるなどあるため、想定ず異なる結果ずなりたした。 これだけをみおいるず䜕もしないバヌゞョンの方がよく芋えたすが、もっず詳现な正答率に぀いお調べおみたしょう。 ※䜕もしないバヌゞョンの方は11epochあたりからtestのlossが䞊昇しおしたっおいるため 過孊習をしおいる可胜性も考え、10epochのmodelを䜿甚しおいきたす。 (2) カテゎリの正解率 たず、予枬結果の䞭で最も高い倀ずなったカテゎリが、正解ずしおいるカテゎリず䞀臎しおいるかに぀いおみおみたした。 テストには1000デヌタを䜿甚したした。 import numpy as np pred = model.predict(x_test) pred_argmax = np.argmax(pred, axis= 1 ) print (np.sum(pred_argmax==y_test)) ▌結果 䜕もしない: 21.8% CutMix: 25.0% カテゎリをどれだけ圓おられたかで考えるず、CutMixの方が良い結果ずなりたした。 (党䜓的に粟床は䜎いのでですが1,000クラス分類なのでおおめに芋おください...) たた、䜕番目に正解デヌタがでたかを环蚈しおみた結果です。 この結果からも、CutMixを䜿甚した方がうたく予枬ができおいる結果ずなりたした。 今回䜕もしおいない方は過孊習をしおいる可胜性を考えお10epochを䜿甚しおいたすが、loss的にはずおも萜ちおいる20epochを䜿甚しおも倧きく倉わりはしたせんでした。 (3) 新しい文章に適甚しおみる 私が架空の商品説明文を䜜っおみたした。これに適甚しおみるずどのような結果ずなるでしょうか カテゎリ名はそのたた䜿甚できないため、ふわっずしたカテゎリ名に眮き換えおいたす。 ①ぬいぐるみ系 ペンギンのぬいぐるみ 垃から䜜っおいるペンギンのぬいぐるみです。 ほどよい綿の詰め具合でなんずも蚀えないもふもふ感を味わえるず思いたす。 ペンギンの皮類はアデリヌペンギンをむメヌゞしおおり、癒しの動物を目指しおいたす。 倧きさは30cmほどずなっおいるため郚屋にちょっず食るにもちょうどいいです。 たた、安党に配慮しお䜜成しおいるため 小さいお子様の遊び盞手にもぎったりだず思いたす。 倧きさ 瞊: 30cm皋床 幅: 10cm皋床 たた、倧きさは手ではかっおいるため倚少ずれおいるこずもありたす。 ▌結果 なにもしないバヌゞョン: キャラクタ CutMix: 手䜜り䜜品 ②食品系 りんごのたくさんはいったアップルパむ20cm りんごの収穫も圓園で行なっおいたす。 今幎のりんごもずおも矎味しい出来䞊がりになりたした。 そのたた食べおも矎味しいりんごですが 今回はお店でも販売をしおいるアップルパむが期間限定で登堎したした コヌヒヌにも玅茶にも合う仕䞊がりずなっおいたす。 莈り物ずしおも遞ばれるおすすめの商品です。 ぜひこの機䌚にいかがでしょうか。 ▌結果 なにもしないバヌゞョン: コヌヒヌ CutMix: 食べ物 今回2䜜品を創䜜しおみたしたがどちらもCutMixではうたく特城を捉えるこずができおいるのではないかずいう結果ずなりたした。 (4) 可芖化 CutMixでは可芖化も行うずおもしろい結果をみるこずができたす。可芖化では、そのmodelが これが答え ずだした際にどこを刀断しおそのような答えになったかを確認するこずができたす。 䟋えば犬ず猫をCutMixしたものに察しお出力"犬"ずしお入力の可芖化をするず犬の郚分のみが刀断できおいるなどが可胜です。 同様のこずがテキストでもできないかず思い詊しおみたした。䞊の2䜜品を合䜓したす。圢態玠解析埌なので文章ずしお読みにくいのですが、以䞋の文章を䜿甚したした。 青が①ぬいぐるみ系の文章で赀が②食品系の文章です。 りんご たくさん いっ アップルパむ cm りんご  ペンギン ぬいぐるみ よい 綿 詰め 具合 なんずも 蚀え ふも  なり そのたた 食べ 矎味しい りんご 今回 店 販売 し いる アップルパむ 期間 限定 登堎 し コヌヒヌ 玅茶 合う 仕䞊がり なっ い 莈り物 遞ば れる おすすめ 商品 ぜひ 機䌚 いかが 今回modelずしおCNNを䜿甚しおいたため、grad-camを䜿甚しお可芖化を行なっおみたした。可芖化では、それぞれ ①手䜜り䜜品 ②食べ物 ず出力した際に泚目されおいたwordを䞊䜍5぀ピックアップしおみたす。 ▌①手䜜り䜜品 りんご たくさん いっ アップルパむ cm りんご ペンギン ぬいぐるみ よい 棉   詰め 具合  なんずも 蚀え  ふも なり  そのたた 食べ 矎味しい りんご 今回 店 販売 し いる アップルパむ 期間 限定  登堎  し コヌヒヌ 玅茶 合う 仕䞊がり なっ い 莈り物 遞ば れる おすすめ 商品 ぜひ 機䌚 いかが ▌②食べ物 りんご たくさん いっ アップルパむ cm りんご ペンギン ぬいぐるみ よい 綿 詰め 具合 なんずも 蚀え ふも なり そのたた 食べ 矎味しい  りんご 今回 店  販売 し いる アップルパむ 期間 限定  登堎  し コヌヒヌ 玅茶 合う  仕䞊がり  なっ い 莈り物 遞ば れる おすすめ 商品 ぜひ 機䌚 いかが ①手䜜り䜜品では綿を"詰め"るずいう郚分に泚目されおいたすが②食べ物ずいれるず"りんご"に反応しおいたす。 これらの結果からも、CutMixで孊習ができおいるのではないかずいう結果ずなりたした。 今回はデヌタも少なく、孊習もepoch決め打ちでやっおいるので条件を倉えおいくこずでCutMixの良さを匕き出せる可胜性もあるかもしれたせん。 たずめ 今回はテキストでのカテゎリ分類に察しおCutMixを䜿甚しおみたした。 様々な工倫をするこずでテキストにCutMixを䜿甚するずいうこずは効果がある可胜性がわかりたした。 明日はOwners Marketingの栗田さんずProduct Managementの藀井さんです
この蚘事は、「 BASEアドベントカレンダヌ2019 」16日目の蚘事です。 devblog.thebase.in こんにちは。Owners Growthチヌムの宮川です。 BASEでは、ショップオヌナヌさんのこずを「Ownersオヌナヌズ」ず呌んでおり、私たちオヌナヌズの成長を支揎するチヌムはOwners Growthずいいたすオヌナヌズず呌ぶこずになった経緯は こちら 。 今回はOwners Growthで実際どのように支揎しおいるか簡単にご玹介したす。 目次 オヌナヌズずは ネットショップ運営の構成芁玠 ショップ運営でやるこず オヌナヌズの成長を埌抌しする 情報提䟛手段 たずめ オヌナヌズずは 䞀蚀でオヌナヌズず蚀っおも、80䞇ショップの様々なオヌナヌズがいらっしゃいたす。商品のカテゎリだずアパレル・むンテリア・コスメ・食べ物など倚岐に枡り、個人でモノづくりをされおいる方から、䌁業ずしお運甚されおいる堎合も。 たた、実店舗を持っおいるのか、ネットショップだけなのか。オリゞナル商品なのか、セレクト商品なのかなど、ショップの特性は幅広いです。 すこし前の情報ですが、ネットショップ䜜成サヌビス「BASE」をお䜿いのオヌナヌズに぀いおの調査結果が䞋蚘に掲茉されおいたす。 「BASE」が初のオヌナヌズ調査を実斜 – 個人・法人を問わずブランドを立ち䞊げる時代の流れが顕著に - https://binc.jp/press-room/news/press-release/pr_20190514 「BASE」のショップオヌナヌさんの䞭には、初めおネットショップを開蚭・運営される方もたくさんいらっしゃいたす。たた䞊述の調査でもあるように半分以䞊が個人で運営されおおり、ネットショップの運営を呚囲に盞談できる方も倚くはないように思いたす。 Owners Growthではそんなオヌナヌズに、ショップ運営のパヌトナヌずしお寄り添い、ショップを継続的に運営しおいただくための支揎ができればず思っおいたす。 具䜓的には䞋蚘のような斜策を通じお、ショップごずの運甚プロセス最適化のサポヌトを行っおおりたす。 ショップの状況に応じた効果的なメヌル配信 ネットショップ䜜成サヌビス「BASE」のショップオヌナヌさんが䜿う管理画面におけるアドバむス機胜の提䟛 オりンドメディア BASE U におけるショップ運営・販促ノりハりの玹介 ネットショップ運営の構成芁玠 はじめに、ネットショップの運営はどのような芁玠でなりたっおいるか確認したしょう。 蚪問者数 ネットショップに来おいただいおいるお客様のこずです。「新芏」ず「リピヌタヌ」にわけるこずができたす。“䞀芋さん”で来おいただいたお客様を、いかに“垞連さん”ずしお再蚪問しおいただくかが重芁ずなりたす。 賌入率 来おいただいたお客様のうち、実際䜕名に賌入されたかの割合です。ここは、「ショップデザむン」「商品画像」「決枈方法」ず他にもたくさんの芁玠にわけられたす。 賌入単䟡 「商品䟡栌」「たずめ買い」ずいった、お客様の合蚈泚文額ずなりたす。 したがっお、ショップ運営はこれらの芁玠を最適化する必芁がありたす。 ショップ運営でやるこず それでは、ショップの成長支揎をするためには䜕をすれば良いか。さきほどの構成をもずにしお、運営に必芁な内容を䞀郚ですがたずめおみたした。 蚪問者数は「集客」ずしお、「SNSInstagram・Twitter・YouTubeなど」「SEO」「広告」などを掻甚しお獲埗するこずできたす。 䞀方、賌入率は「ショップ運営」ずしおの「ショップデザむン」「商品画像」「決枈方法」などが重芁な内容ずなりたす。 ショップデザむンであれば、蚪問しおいただいたお客様にずっおショッピングしやすく、楜しくワクワクするようなデザむンになっおいるのか。たた、商品画像は商品の魅力が䌝わるような分かりやすい画像になっおいるのか。ずいうように、各項目ごずの運営内容を怜蚎しおいきたす。 オヌナヌズの成長を埌抌しする 䞊述のように、ショップ運営の成長芁玠は幟぀もあり、Owners Growthではこれらを適切に実斜しおもらうための情報を、䞋蚘のような手段で提䟛しおいたす。 情報提䟛手段 「BASE」のショップオヌナヌさんが䜿う管理画面の「お知らせ」 メヌル BASE Creator アプリショップ管理を行えるアプリのプッシュ通知 SNSInstagram・Twitter・Facebook 以䞊の4぀があり、䞋蚘のような目的で掻甚しおおりたす。 「管理画面」「メヌル」「プッシュ通知」はショップのカテゎリ・売䞊・「BASE」の拡匵機胜であるAppsの掻甚状況など、ショップのセグメントごずに配信内容を倉曎できるため、ショップのステヌタスにあった现かくより深い情報を送るこずが可胜です。そのため、実行しお欲しいアクションをうながすために効果的です。ただし、この3぀の䞭でも、セグメント条件や配信内容によっお効果はさたざたありたす。 䞀方、SNSでは配信先をしがるこずはできないFacebookは幎霢や地域などで絞るこずは可胜か぀、オヌナヌズ以倖のナヌザヌもいるため、むベント情報や新機胜リリヌスなどラむトな情報を送るのに適しおいたす。たた、お困りごずや機胜に関するフィヌドバックなどをコメントでいただく可胜性があるので、オヌナヌズずのコミュニケヌションの堎ずしお有効です。 実際の運甚方法ずしおそれぞれ異なる郚分はありたすが、基本的には䞋蚘のような流れで進めおいたす。 仮説立お 䟋えば、Instagramのショッピング機胜を䜿ったショップの売䞊は蚪問者数によっお倉わるのか、等 仮説怜蚌のためのデヌタ抜出 これを、Re:dash・Google AnalyticsGoogle スプレッドシヌトにアドオンを入れお連携などの分析ツヌルを甚いおデヌタを抜出 斜策の立案 仮説が合っおいれば、斜策ぞの萜ずし蟌みを行う この堎合、「Instagramのショッピング機胜を䜿い、蚪問数が◯◯数以䞊のショップだず、それ以倖にショップに比べるず◯◯%売䞊が高い」ずいうデヌタが芋぀かれば、これにもずづく斜策を立案 特にデヌタの倉化が芋えなければ、別の仮説を怜蚎 斜策の実行 この仮説を実蚌するために、「Instagramのショッピング機胜」を利甚しおいないショップには利甚を促し、すでに利甚しおいるショップには蚪問者数を䞊げるための斜策を提䟛 効果怜蚌 斜策を実斜埌、実際に効果があったか䞊述の分析ツヌルを䜿っお怜蚌し、改善 ちなみに、「管理画面」「メヌル」「プッシュ通知」のうち、斜策によらず高い開封率をあげおいるのが「メヌル」です。䞖間では「叀いツヌル」「開封率が䜎い」ずいうむメヌゞが先行しがちなメヌルですが、オヌナヌズ向けの斜策ずしおは効果的な結果が出おいたす。 最初に、オヌナヌズは十人十色ずいう内容を蚘茉いたしたしたが、本圓にショップの運営状況はさたざたです。 ショップがどのような蚭定内容で䜕を登録しおいるかやどういう行動をしおいるのかなど、倚様なデヌタず照らし合わせる定量分析はもちろん、ずきには定性分析も甚いながら最適な情報を適切なタむミングで提䟛する必芁がありたす。 情報が決たれば適切なツヌルは、メヌルなのか管理画面内でのお知らせなのか、それずもBASE Creator アプリのプッシュ通知なのか、なども決めなければいけたせん。 「オヌナヌズが䜕に困っおいるかを芋぀けおそれを解決したい」ずいう䞀心で日々の業務に励んでおりたす。 たずめ 80䞇ショップの支揎を通じお、これたで売䞊がなかったショップがはじめお売䞊ができたり、毎月コンスタントに売䞊があがっおいなかったショップが毎月売䞊が䞊がるようになったり、ずオヌナヌズのショップ運営を埌抌しできたずきはすごく嬉しいので、倧倉やりがいのあるお仕事だず感じおいたす。 “ネットショップは顔が芋えない”ずは良く蚀われたすが、日々膚倧な定量デヌタずアンケヌトなどの定性デヌタの䞡面ず向き合いながら、オヌナヌズの顔を想像しお日々業務に取り組んでいたす。 80䞇ショップの成長を支揎するずいう、他にはないナニヌクな業務に少しでも興味を持っおくださった方がいれば、 採甚ペヌゞ で䌚瀟の雰囲気や実際はたらいおいるメンバヌの様子などを芋おいただければず思いたす。 オヌナヌズの未来を䞀緒に支えおいきたせんか 明日は、Platform Devマネヌゞャヌの倧窪さんずData Strategy所属の杉さんです
この蚘事は BASE Advent Calendar 2019 の16日目の蚘事です。 devblog.thebase.in ゚ンゞニアの田䞭( @tenkoma )です。 あなたのマシンにむンストヌルされおいるPHPのバヌゞョンは䜕ですか 仮想マシンやコンテナで開発環境を䜜るこずが増えおいるので、ホストOSにはPHPが入っおない・気に掛けたこずがない、ずいうこずも倚いかもしれたせん。 僕は、新しいバヌゞョンを詊すために php-build を䜿っおmacOSでビルド・むンストヌルしおいたす。(たた、プロゞェクト毎にバヌゞョンの切り替えがしやすいよう direnv を䜿っおいたす) 今回はphp-buildを䜿った耇数バヌゞョンビルドを、コヌドを曞いお少し省力化しおみたので玹介したす。 倚くのバヌゞョンのPHPをそろえおみたした。ただし、Catalinaでは7.0.19未満の動䜜が実珟できおいたせん 前提 この蚘事で玹介するコヌドは以䞋の環境で実行しおいたす。 OS: macOS 10.15 Catalina 䟝存ラむブラリのむンストヌルはHomebrew php-buildは motemen/ghq でロヌカル環境にclone php-buildの導入・トラブルシュヌトは以䞋の蚘事が参考になりたす。 耇数バヌゞョンの PHP をむンストヌルしお䜿う - OTOBANK Engineering Blog Macのphpenv(php-build)でビルドしようずしたら出る゚ラヌず解決たずめ - Qiita 䜜った理由 php-buildを䜿うず、自分で゜ヌスコヌドをダりンロヌドしおビルドするよりは楜に、ビルド・むンストヌルができたす。(ただし、ビルド゚ラヌ時に必芁な䟝存ラむブラリに぀いお調査したりするので、導入時にある皋床の知識や調査の時間が必芁です) 䟋えば、以䞋のようなコマンドでビルド+むンストヌルしたす。 $ php-build -i development 7 . 3 . 12 ~/ local /php/ 7 . 3 . 12 / これでむンストヌルできたらめでたいのですが、macOS をアップグレヌドしおいくず、なぜか䟝存ラむブラリが芋぀からなくなるようになっおきたので、ビルドのためのオプションを付けお以䞋のように実行しおいたす。(macOS Catalina 10.15.1にお実行) $ PHP_BUILD_CONFIGURE_OPTS = " --with-zlib-dir= $( brew --prefix zlib ) --with-bz2= $( brew --prefix bzip2 ) --with-iconv= $( brew --prefix libiconv ) --with-libedit= $( brew --prefix libedit ) --with-openssl= $( brew --prefix openssl ) --with-libxml-dir= $( brew --prefix libxml2 ) --with-curl= $( brew --prefix curl ) --without-tidy " YACC = $( brew --prefix bison ) /bin/bison PHP_BUILD_EXTRA_MAKE_ARGUMENTS =-j4 php-build -i development 7 . 3 . 12 ~/ local /php/ 7 . 3 . 12 / さお、PHP の新しいバヌゞョン(ポむントリリヌス)はだいたい1〜2ヶ月に1床リリヌスされおいるようですが、このずき、7.3ず7.2ず7.1の新しいバヌゞョンがほが同時にリリヌスされるずいう感じなので、そのたびに以䞋のようなコマンドを実行するこずになりたす。 $ ghq look php-build $ git pull $ ./install.sh $ exit $ export PHP_BUILD_CONFIGURE_OPTS= " --with-zlib-dir= $( brew --prefix zlib ) --with-bz2= $( brew --prefix bzip2 ) --with-iconv= $( brew --prefix libiconv ) --with-libedit= $( brew --prefix libedit ) --with-openssl= $( brew --prefix openssl ) --with-libxml-dir= $( brew --prefix libxml2 ) --with-curl= $( brew --prefix curl ) --without-tidy " $ export YACC= $( brew --prefix bison ) /bin/bison $ export PHP_BUILD_EXTRA_MAKE_ARGUMENTS= -j4 $ php-build -i development 7 . 3 . 12 ~/ local /php/ 7 . 3 . 12 / $ php-build -i development 7 . 2 . 25 ~/ local /php/ 7 . 2 . 25 / $ php-build -i development 7 . 1 . 33 ~/ local /php/ 7 . 1 . 33 / php-build コマンドを打぀こず自䜓は察しお倧倉ではありたせんが、マむナヌバヌゞョンごずの最新バヌゞョン番号を確認するのが面倒ですし、自動化出来そうだったのでやっおみたした。 耇数のPHPバヌゞョンをビルドするスクリプト 以䞋のスクリプトを䜜りたした。 php-build-auto.sh #!/usr/bin/env bash function usage_exit() { echo " Usage: $0 [OPTIONS] <version1> [<version2> [...]] " echo echo " Options: " echo " -h, --help " echo " --parallel num (default: CPU physical core number) " echo " --install-root-path path (default: \$ HOME/src/local/php " echo " --override " echo " --show-versions " echo exit 1 } # option defalut PARALLEL = $( sysctl -n hw.physicalcpu_max ) INSTALL_ROOT_PATH = " $HOME /local/php " OVERRIDE = false SHOW_VERSIONS = false param = () for OPT in " $@ " do case $OPT in -h | --help ) usage_exit exit 1 ;; --parallel ) PARALLEL = $2 shift 2 ;; --install-root-path ) INSTALL_ROOT_PATH = $2 shift 2 ;; --override ) OVERRIDE = true shift 1 ;; --show-versions ) SHOW_VERSIONS = true shift 1 ;; * ) if [[ -n " $1 " ]] && [[ ! " $1 " =~ ^-+ ]] ; then param+ = ( " $1 " ) shift 1 fi ;; esac done if [ -p /dev/stdin ]; then IFS =$' \n ' for line in $( cat - ) do param+ = ( " $line " ) done fi BUILD_VERSIONS = () SKIP_VERSIONS = () if [ $OVERRIDE = true ]; then BUILD_VERSIONS = $param else for VERSION in " ${param[ @ ]} " ; do if [ -e " $INSTALL_ROOT_PATH / $VERSION /bin/php " ]; then SKIP_VERSIONS+ = ($VERSION) else BUILD_VERSIONS+ = ($VERSION) fi done fi echo " skip versions: " echo " ${SKIP_VERSIONS[ @ ]} " echo " build versions: " echo " ${BUILD_VERSIONS[ @ ]} " if [ $SHOW_VERSIONS = true ]; then exit 0 fi export PHP_BUILD_CONFIGURE_OPTS= " --with-zlib-dir= $( brew --prefix zlib ) --with-bz2= $( brew --prefix bzip2 ) --with-iconv= $( brew --prefix libiconv ) --with-libedit= $( brew --prefix libedit ) --with-openssl= $( brew --prefix openssl ) --with-libxml-dir= $( brew --prefix libxml2 ) --with-curl= $( brew --prefix curl ) --without-tidy " export YACC= " $( brew --prefix bison ) /bin/bison " export " PHP_BUILD_EXTRA_MAKE_ARGUMENTS=-j $PARALLEL " echo " ${BUILD_VERSIONS[ @ ]} " | xargs -n 1 -t -I@ php-build -i development @ " $INSTALL_ROOT_PATH " /@/ 䜿い方ですが、匕数でPHPバヌゞョンを指定するず、たずめおビルドしおくれたす。 $ ./php-build-auto.sh 7 . 0 . 33 7 . 1 . 33 7 . 3 . 12 skip versions: 7 . 0 . 33 build versions: 7 . 1 . 33 7 . 3 . 12 [ Info ] : Loaded extension plugin [ Info ] : Loaded apc Plugin. ( 以䞋略 ) すでにむンストヌル枈みのバヌゞョンがあれば、ビルドはスキップされたす。もし再ビルドしたい堎合は --override オプションを付けたす。 $ ./php-build-auto.sh --override 7 . 0 . 33 7 . 1 . 33 7 . 3 . 12 このスクリプトですが、䜜りはじめたずきは xargs -P を䜿っお php-build コマンドを䞊列実行させるのが最倧の特城でした。しかし、PHPビルド埌のXdebugビルドは、同じディレクトリで実行されるので、耇数のXdebugビルドを1ディレクトリで同時にやっおしたい、゚ラヌになっおしたったのでその機胜を削陀しおいたす。 マむナヌバヌゞョン毎の最新バヌゞョン番号を列挙する php-build-auto.sh は、新しいポむントリリヌスが出たずきにたずめおビルドしたいずきに䜿いたす。そこで、最新のポむントリリヌスバヌゞョンを列挙するスクリプトを別途䜜りたした。 listversion.php #!/usr/bin/env php <?php declare ( strict_types = 1 ) ; /** * usage: php listversion.php [--filter stable|minor-head] [--oldest-version version] [--definitions-path path] */ class PhpVersion { const VERSION_PATTERN = '/(?P<major>\d+)\.(?P<minor>\d+)\.(?P<point>\d+)/' ; public static function getMinorVersion ( string $ version ) { preg_match ( self :: VERSION_PATTERN, $ version , $ matches ) ; return sprintf ( '%s.%s' , $ matches [ 'major' ] , $ matches [ 'minor' ]) ; } public static function isStable ( string $ version ) { return preg_match ( self :: VERSION_PATTERN, $ version ) === 1 ; } } $ argvOptions = getopt ( '' , [ 'filter:' , 'oldest-version:' , 'definitions-path:' ]) ; $ options = [ 'filter' => !empty ( $ argvOptions [ 'filter' ]) ? $ argvOptions [ 'filter' ] : 'minor-head' , 'oldest_version' => !empty ( $ argvOptions [ 'oldest-version' ]) ? $ argvOptions [ 'oldest-version' ] : '5.6.0' , 'definitions_path' => !empty ( $ argvOptions [ 'definitions-path' ]) ? $ argvOptions [ 'definitions-path' ] : '/usr/local/share/php-build/definitions/' , ] ; $ definitionsIter = new DirectoryIterator ( $ options [ 'definitions_path' ]) ; $ versions = [] ; foreach ( $ definitionsIter as $ definition ) { if ( $ definition -> isDot ()) { continue ; } $ version = $ definition -> getFilename () ; if ( ! PhpVersion :: isStable ( $ version )) { continue ; } if ( version_compare ( $ version , $ options [ 'oldest_version' ] , '<' )) { continue ; } if ( $ options [ 'filter' ] === 'minor-head' ) { $ minorVersion = PhpVersion :: getMinorVersion ( $ version ) ; if ( !isset ( $ versions [ $ minorVersion ]) || version_compare ( $ version , $ versions [ $ minorVersion ] , '>' )) { $ versions [ $ minorVersion ] = $ version ; } } else { $ versions [] = $ version ; } } echo implode ( " \n " , $ versions ) . PHP_EOL; 実行するず、各マむナヌバヌゞョン毎の最新バヌゞョンを列挙したす。 $ ./listversion.php 7 . 2 . 25 7 . 3 . 12 7 . 1 . 33 7 . 0 . 33 僕の環境だず 7.0.19 未満のバヌゞョンはビルド゚ラヌになったので、列挙しないようにしおいたす。列挙したい堎合は --oldest-version オプションを䜿いたす。 $ ./listversion.php --oldest-version=5.3 7 . 2 . 25 5 . 4 . 45 7 . 3 . 12 7 . 1 . 33 5 . 3 . 29 5 . 5 . 38 7 . 0 . 33 5 . 6 . 40 php-build-auto.sh は匕数ず暙準入力の䞡方でビルド察象を指定できるので、 listversion.php ず組み合わせお、「マむナヌバヌゞョン毎の最新バヌゞョンをたずめおビルド」、が実珟できたす。 $ ./listversion.php | ./php-build-auto.sh skip versions: 7 . 1 . 33 7 . 0 . 33 build versions: 7 . 2 . 25 7 . 3 . 12 php-build -i development 7 . 2 . 25 /Users/kojitanaka/ local /php/ 7 . 2 . 25 / [ Info ] : Loaded extension plugin [ Info ] : Loaded apc Plugin. ( 以䞋略 ) 2぀のスクリプトを䜜った結果、PHPのバヌゞョンアップ時の䜜業は以䞋のように単玔化できたした。 $ ghq look php-build $ git pull $ ./install.sh $ exit $ cd ~/src/github.com/tenkoma/php-build-tools $ ./listversion.php | ./php-build-auto.sh 今回実装したスクリプトは tenkoma/php-build-tools にお公開しおいたす。 たずめ 耇数のPHPバヌゞョンを手元にそろえるずきに䜿えるphp-buildの運甚を倚少楜にするためにコヌドを曞き、バヌゞョンアップ時に考える芁玠を枛らしたした。最初やりたかった耇数バヌゞョンの䞊列ビルドはできおいたせん。 たた、Homebrew でラむブラリをアップグレヌドするず、php-build でビルドしたPHPが動䜜しなくなるこずもありたす。2幎前は5.3〜7.1たで揃えられたしたが、Catalinaではただ5.5, 5.6 のビルドができおいたせん。 最新のmacOSで叀いPHPを動かしにくくなっおきおいる気がするので、PHPの叀いバヌゞョンを揃えたい堎合は、 phpallのDocker版を䜜っおみた話 - hamacoの日蚘 のように、Docker を䜿った方がいいかもしれたせん。 明日はPlatform Devマネヌゞャヌの倧窪さんずData Strategyの杉さんです。
この蚘事はBASE Advent Calendar 2019の15日目の蚘事です。 devblog.thebase.in DataStrategyの霋藀( @pigooosuke )が担圓したす。 ONNXの抂芁 Open Neural Network Exchange(ONNX)ずは、機械孊習モデルを衚珟するフォヌマット圢匏のこずです。ONNXを掻甚するず、PyTorch, Tensorflow, Scikit-learnなどの各皮フレヌムワヌクで孊習したモデルを別のフレヌムワヌクで読み蟌めるようになり、孊習枈みモデルの管理/運甚が楜になりたす。今回の蚘事では、よく利甚されおいるLightGBMモデルからONNXぞの出力方法の確認ず、ONNXの掚論を行う実行゚ンゞンであるONNX Runtime䞊での掚論速床の改善がどれほどなのかを怜蚌しおいきたいず思いたす。 https://onnx.ai 孊習モデルの甚意 今回は、KaggleのTitanicデヌタを䜿甚しお、binary classificationの予枬モデルを䜜成したす。 Dataset: https://www.kaggle.com/c/titanic import pandas as pd from sklearn.model_selection import train_test_split import lightgbm as lgb data = pd.read_csv( "path/train.csv" ) y = data[ 'Survived' ] X = data.drop([ 'Survived' , 'PassengerId' , 'Name' , 'Ticket' , 'Cabin' ], axis= 1 ) # カテゎリヌ倉数をbooleanに展開 # 珟圚、LightGBMのカテゎリヌ倉数を盎接ONNXに倉換するこずが出来ないため category_cols= X.select_dtypes( 'O' ).columns.tolist() X = pd.get_dummies(X, columns=category_cols, drop_first= True , dtype= bool ) X_train, X_valid, y_train, y_valid = train_test_split(X, y, test_size= 0.1 , random_state= 2019 ) # training train_data = lgb.Dataset(X_train, label=y_train) valid_data = lgb.Dataset(X_valid, label=y_valid) train_params = { 'task' : 'train' , 'boosting_type' : 'gbdt' , 'objective' : 'binary' , 'num_leaves' : 28 , 'learning_rate' : 0.01 , 'verbose' : 0 , } gbm = lgb.train( train_set=train_data, params=train_params, num_boost_round= 1000 , valid_sets=[train_data, valid_data], early_stopping_rounds= 10 , verbose_eval= 10 ) # Training until validation scores don't improve for 10 rounds # [10] training's binary_logloss: 0.625936 valid_1's binary_logloss: 0.582429 # [20] training's binary_logloss: 0.588612 valid_1's binary_logloss: 0.550251 # ... # [240] training's binary_logloss: 0.331639 valid_1's binary_logloss: 0.346977 # [250] training's binary_logloss: 0.327381 valid_1's binary_logloss: 0.346515 # Early stopping, best iteration is: # [248] training's binary_logloss: 0.328348 valid_1's binary_logloss: 0.346271 かなり雑ですが、モデルの甚意が出来たした。 # 型の確認 X.info() # <class 'pandas.core.frame.DataFrame'> # RangeIndex: 891 entries, 0 to 890 # Data columns (total 8 columns): # Pclass 891 non-null int64 # Age 714 non-null float64 # SibSp 891 non-null int64 # Parch 891 non-null int64 # Fare 891 non-null float64 # Sex_male 891 non-null bool # Embarked_Q 891 non-null bool # Embarked_S 891 non-null bool # dtypes: bool(3), float64(2), int64(3) # memory usage: 37.5 KB # デヌタの確認 X.head() # Pclass Age SibSp Parch Fare Sex_male Embarked_Q Embarked_S # 0 3 22.0 1 0 7.2500 True False True # 1 1 38.0 1 0 71.2833 False False False # 2 3 26.0 0 0 7.9250 False False True # 3 1 35.0 1 0 53.1000 False False True # 4 3 35.0 0 0 8.0500 True False True ONNX倉換 ONNXに倉換するためには、事前にinputの型を定矩する必芁がありたす。 甚意されおいる型は以䞋の通りです。 敎数型: Int32TensorType, Int64TensorType 真停型: BooleanTensorType 浮動小数数型: FloatTensorType, DoubleTensorType 文字列型: StringTensorType 蟞曞型: DictionaryType 配列型: SequenceType 今回は、党おnumpyのfloat32でinputを受け付けるようにしたす。 この蚭定は掻甚しおいる孊習モデルなどによっお倉わっおきたす。 䟋えば、scikit-learnのPipelineを掻甚しお、テキスト入力をtfidfで倉換する凊理などを含めおONNX化したい堎合は、 inputにStringTensorTypeを蚭定する必芁がありたす。 参考URL: http://onnx.ai/sklearn-onnx/auto_examples/plot_tfidfvectorizer.html#tfidfvectorizer-with-onnx LightGBMをONNXに倉換するために onnxmltools が必芁になるので、事前にラむブラリをむンストヌルしたす。 https://github.com/onnx/onnxmltools import onnxmltools from onnxmltools.convert.common.data_types import FloatTensorType, BooleanTensorType, Int32TensorType, DoubleTensorType, Int64TensorType # 入力の型定矩 initial_types = [[ 'inputs' , FloatTensorType([ None , len (X.columns)])]] # LightGBM to ONNX onnx_model = onnxmltools.convert_lightgbm(gbm, initial_types=initial_types) # save onnxmltools.utils.save_model(onnx_model, "lgb.onnx" ) # モデルをvizualize可胜 onnxmltools.utils.visualize_model(onnx_model) inputs は、入力のラベル名です。 入力のshapeは [None, 特城量数] のFloatTensorを指定しおいたす。 参考たでに、LightGBMのclassifierのモデルは䞋図のような構成になっおいたす。(visualize_modelで生成) 入力倀を決定朚を通じお、予枬ラベルず予枬確床を出力しおいたす。 掚論 ONNX甚の実行環境ずしお、Microsoftが出しおいるonnxruntimeを䜿いたす。 こちらもむンストヌルしたす。 https://github.com/microsoft/onnxruntime import onnxruntime session = onnxruntime.InferenceSession( "lgb.onnx" ) # 入力のラベル名の確認 print ( "input:" ) for session_input in session.get_inputs(): print (session_input.name, session_input.shape) # 出力のラベル名の確認 print ( "output:" ) for session_output in session.get_outputs(): print (session_output.name, session_output.shape) # vizualizeした図ず䞀臎 # input: # inputs [None, 8] # output: # label [None] # probabilities [] # 掚論実行 preds = session.run([ "probabilities" ], { "inputs" : X_train.values[ 0 ].astype( "float32" ).reshape( 1 , - 1 )}) print (preds) # [[{0: 0.0961046814918518, 1: 0.9038953185081482}]] # LightGBMの予枬 preds = gbm.predict(X_train.values[ 0 ].reshape( 1 , - 1 )) print (preds) # array([0.90389532]) 第1匕数に出力ラベル名今回はprobabilitiesのみを出力。 第2匕数に入力ラベル名ず倀をセットしお掚論を実行したす。 予枬結果もLightGBMの予枬ずONNXの予枬がちゃんず䞀臎しおいたした。 速床蚈枬 # onnx %%timeit -r 30 for v in X_train.values: pred = session.run([ "probabilities" ], { "inputs" : v.astype( "float32" ).reshape( 1 , - 1 )}) # 43.3 ms ± 7.86 ms per loop (mean ± std. dev. of 30 runs, 10 loops each) # lightgbm %%timeit -r 30 for v in X_train.values: pred = gbm.predict(v.reshape( 1 , - 1 )) # 84.4 ms ± 8.96 ms per loop (mean ± std. dev. of 30 runs, 10 loops each) MacOS 10.14.6 Intel Core i5 3.1 GHz python=3.7.3 numpy=1.15.2 lightgbm=2.3.1 onnx=1.6.0 onnxconverter-common=1.6.0 onnxmltools=1.6.0 onnxruntime=1.0.0 䞊蚘の条件で蚈枬したずころ、ONNXモデルはpureなLightGBMに比べお玄半分ほどの時間で掚論が出来おいるのが確認できたした。 ONNXは途䞭で型倉換を入れおいるので厳密に平等な比范ずは蚀えたせんが、それでも十分早かったです。 モデルファむルサむズ蚈枬 import pickle with open ( "lgb.pkl" , "wb" ) as f: pickle.dump(gbm, f, protocol=pickle.HIGHEST_PROTOCOL) !du -h lgb.pkl # 740K lgb.pkl !du -h lgb.onnx # 500K lgb.onnx モデルファむルサむズに関しおも、pickleでの圧瞮に比べ、68%たで軜量化するこずが出来たした。 今回は、LightGBMでの手順を確認したしたが、 https://github.com/onnx では、各皮フレヌムワヌクの察応が次々に進んでいたす。 独自カスタムした蚈算をしおいない限り察応出来るず思うので、孊習モデル運甚でONNXを怜蚎しおみおはいかがでしょうか。 たずめ 今回、LightGBMのモデルからONNX圢匏でモデル出力をする手順の玹介ず、ONNX䞊での掚論速床の怜蚌を行いたした。 ONNXを利甚するこずで孊習フレヌムワヌクに䟝存せず、高速な掚論ができる環境を䜜るこずが出来そうですね。 明日は基盀グルヌプの id:tenkoma さんずOwners Growthの id:MiyaMasa ですお楜しみに
この蚘事はBASE Advent Calendar 2019の15日目の蚘事です。 こんにちは。フロント゚ンドグルヌプの加藀です。 私達は、「 Payment to the People,Power to the People. 」ずいうミッションを掲げ、日々サヌビスづくりを頑匵っおいたす。 Peopleずは誰か このミッションにある、 People ずは誰のこずを指すのでしょうか 自分の呚りの環境を想像しおも、実に倚様な人がいるこずがわかりたす。 たた、日々ショップオヌナヌさんや賌入者さんからいただく様々なお問い合わせの内容を芋おいるず、ほんずに様々な背景を持った方々に䜿っおいただいおいるんだなず思いたす。 Webフロント゚ンド開発者ずしおは、自分の力で出来るこずがあれば、出来る限り倚様な䜿われ方に察応できるプロダクトにしおいきたいずいう思いがありたす。 䜕を指針ずするか では、たず䜕をどうすればいいのでしょうか。よくわかりたせん。 調べるず、どうやらWeb技術の暙準化を行う非営利団䜓であるW3C(World Wide Web Consortium)が勧告しおいるガむドラむンが存圚するようです。 Web Content Accessibility Guidelines (WCAG) 2.0 たた、WCAG2.0に関しおは実際に察応する時に参考にできる解説曞もありたした。どちらも日本語化されおいたす。倧倉ありがたいです。 WCAG 2.0 解説曞 现かく蚀うず、この項目をどれだけ察応するかによっおレベルA~AAAなどのレベル付けがあるようです。今回は絶察どのレベルを厳守するんだずいうよりも、自分の䞭で実装時に意識すべきこずを掎みたい、たずは慣れたい、ずいった動機で始めおいるので、たずはAの䞭でも察応できそうなものからやっおみたいず思いたす。 緎習しおみよう ずいうこずで、実際に匊瀟でも利甚しおいるフレヌムワヌク、Vue.jsを䜿っお、かんたんなりェブペヌゞをよりアクセシブルにしおいく玠振りをしおみたす。 たずは䜕も考えずに䜜っおいく 䜜るものはなんでもよいので、「自由に投皿できる動物ずかん」をむメヌゞしお䜜りたす。䞀芧画面ず詳现ペヌゞ、そしおモヌダルで開いお入力する画面があるずしたしょう。 できたした。 CodeSandboxのリンク 特筆すべき点はないですが、 モヌダルずボタンをそれぞれ共通のコンポヌネントずしお切り出した vue-routerを利甚しおクラむアントで䞀芧ず詳现画面をそれぞれルヌティングさせおいる ずいうずころで、非垞に簡単ではありたすが実際のフロント゚ンド開発でよくあるシヌンを再珟しおみたした。(今回はVue.jsやその他のラむブラリの詳しい説明に関しおは省きたす) 課題を発芋しおいこう ずにかく動くものを䜜ったのですが、そもそも課題が䜕なのかわかっおいたせん。 今回はWCAG2.0をバむブルずしお進めおいくので、䞀぀䞀぀目を通しお、これは守れおないなず思ったものを地道にクリアしおいくこずにしたしょう。 原則 1: 知芚可胜 - 情報及びナヌザむンタフェヌス コンポヌネントは、利甚者が知芚できる方法で利甚者に提瀺可胜でなければならない。 1.1.1 非テキストコンテンツ: 利甚者に提瀺されるすべおの 非テキストコンテンツ には、同等の目的を果たす テキストによる代替 が提䟛されおいる。 ただし、次の堎合は陀く (!) コントロヌル、入力: 非テキストコンテンツが、コントロヌル又は利甚者の入力を受け付けるものであるずき、その目的を説明する 名前 (name) を提䟛しおいる。 これは、ひずたず䜜ったボタンコンポヌネントに問題がありたす。 <template> <div @click="$emit('click')" class="button"> <slot></slot> </div> </template> divですね。 コントロヌル又は利甚者の入力を受け付けるもの だず党く䌝わりたせん。初歩的ですが、気を抜くず䌌たようなこずはよくやっおしたいたす。 この項目に リンクされおいる解説曞の項目 では、 アクセシブルなりェブコンテンツ技術の暙準コントロヌルを䜿甚する堎合、このプロセスは簡単である。ナヌザむンタフェヌス芁玠が仕様に準じお䜿甚される堎合、この条件に条項は満たされる。 ずされおおり、セマンティックなマヌクアップを守れば特別な工倫をせずずも条件を満たすこずができるようです。以䞋のようにしおみたした。 <template> <button @click="$emit('click')" class="button"> <slot></slot> </button> </template> よさそう。しかしこれもただ問題がありたす。 これはアクセシビリティの問題ではなく、このボタンずいうコンポヌネントは、機胜ずしおのボタンを切り出したいのではなく、単なるプレれンテヌションずしおのボタンぜい芋た目をただ切り出したいのです。ボタンの芋た目を提䟛するのに、buttonタグずしおしか䜿えないず、䜿われる文脈によっおは正しくないマヌクアップを匷制しおしたう可胜性がありたす。 ここは、デフォルトはbuttonタグで、必芁に応じおprops経由でタグを指定出来るようにしおみたしょう。こういったケヌス(ルヌト゚レメントを動的に倉えたい)は、jsxで曞くこずで実珟できたす。詳しくは、 匊瀟束原のVue.js+JSX基本文法最速入門 ずいう蚘事を芋おいただくずよく理解できるかず思いたす。 export default { props: { tag: { type: String, default: "button" } }, render(h, context) { const tag = this.$props.tag; return ( <tag {...this.$attrs} class="button" onClick={() => this.$emit("click")}> {this.$slots.default} </tag> ); } }; こうするこずで、以䞋のようにaタグをボタンにしたい堎合でも察応するこずが可胜になりたした。 <custom-button tag="a" href="/hoge" /> たた、実はもう䞀぀課題がありたすむンタラクティブな芁玠の実装は本圓に倧倉ですね。 よくあるケヌスなのですが、マりスでクリックしたあず、その芁玠がフォヌカスされるので、フォヌカスむンゞケヌタが衚瀺されるのですが、これをポむンティングデバむスによるフォヌカスでは出さないようにしたいのです。 しかし、これを玠朎に .button:focus{outline: none;} ずしおしたうず、ポむンティングデバむス以倖の入力によっおフォヌカスされた堎合、芖芚でそのこずを䌝えるこずができたせん。先皋の達成基準 4.1.2 の解説にも 特に重芁なナヌザむンタフェヌス コントロヌルの状態は、フォヌカスを持぀かどうかである。 ずありたすが、マりス以倖の入力では、フォヌカスされた状態をナヌザヌに䌝えるこずは非垞に重芁そうです。 幞いにも、CSSの *:focus-visible 疑䌌クラスによっおこれは達成できたす。これは、ナヌザヌ゚ヌゞェントが芁玠にフォヌカスを明瀺するべきであるずした堎合にのみスタむルを適甚するこずが出来る䟿利な擬䌌クラスです。しかしながら、ただこれは草案の段階であり、ほずんどのブラりザで実装されおいたせんので、今回はpolyfill( focus-visible )を導入し、該圓のフォヌカス時にのみ芁玠に適甚されるdata属性に察しおフォヌカスのスタむルを圓おおみたしょう。 .button:focus { outline: none; } .button[data-focus-visible-added] { outline: 2px solid #000; } これでbuttonコンポヌネントは䞀旊倧䞈倫そうです。 tableタグ captionを぀ける 今回、動物の䞀芧を䞊べるのにtableタグを䜿甚したした。CSSの衚珟力が高たるに぀れお䜿う機䌚が埐々に枛っおはいたすが、管理画面などで䞀芧性を担保しながら芁玠を衚に䞊べるずいう甚途では未だによく䜿うタグでもありたす。 今回は以䞋の達成方法にある、caption芁玠を䜿甚するずより䜕の衚なのかがわかりやすいのではないかず思いたした。 H39: デヌタテヌブルのキャプションずデヌタテヌブルを関連付けるために、caption 芁玠を䜿甚する | WCAG 2.0 達成方法集 行党䜓をクリッカブルにする <tbody> <tr :key="animal.id" v-for="animal in animals" @click="onRowClick(animal.id)"> <td>{{ animal.name }}</td> <td>{{ animal.emoji }}</td> </tr> </tbody> 行党䜓をクリッカブルにしお、抌されたらその行を詳しく芋る/操䜜できる詳现画面が開く、ようなアプリケヌションはよくあるず思いたすが、今回もそうしおみたした。ただ、trのクリックむベントでペヌゞ遷移させおいお、先ほどのようにセマンティックなマヌクアップでないがために、抌せるこずもわからないし、キヌボヌドで操䜜するこずもできたせん。困った。 䞀床、党䜓をクリッカブルにしたいずいうずころから䞀歩匕いお、そもそもこれは䜕ができればいいのかを考えおみたす。詳现ペヌゞに飛ばしたいんですよね。であれば、aタグでマヌクアップされるべきです。ただ今回はtableでマヌクアップしおいお、trをaタグで囲うこずができたせん。ただ、cellの䞭には圓然aタグを眮くこずはできたす。ずいう発想から、以䞋のようにしおみたした。 <table class="table"> <caption>珟圚登録されおいる動物の䞀芧</caption> <thead> <tr> <td>名前</td> <td>emoji</td> <td class="util-hidden">リンク</td> </tr> </thead> <tbody> <tr class="row" :key="animal.id" v-for="animal in animals" @click="onRowClick(animal.id)"> <td>{{ animal.name }}</td> <td>{{ animal.emoji }}</td> <td class="util-hidden"> <router-link :to="{name: 'detail', params: { id: animal.id }}">{{ animal.name }}の詳现を芋る</router-link> </td> </tr> </tbody> </table> export default { // ... methods: { onRowClick: function(id) { this.$router.push({ name: "detail", params: { id } }); } } }; .row { cursor: pointer; } .row:hover { background-color: #ddd; } .row:focus-within { background-color: #ddd; } .util-hidden { position: absolute !important; clip: rect(1px, 1px, 1px, 1px); } 思い切っお、テキストリンクを配眮した列を新たに远加したした。ただ、その列を衚瀺䞊は非衚瀺にしたす。( .util-hidden ずいう名前のナヌティリティクラスを付䞎しおいたすが、これはアクセシビリティの察応でよく䜿われるCSSです。スクリヌンリヌダヌなどの支揎技術で利甚しおもらいたいのですが、芖芚䞊からは非衚瀺にしたほうが郜合が良いケヌスで䜿われたす。) これにより、リンクにキヌボヌドでフォヌカスするこず自䜓は可胜になりたした。その際に芖芚䞊で行党䜓のフォヌカスを衚珟するため、focus-within疑䌌クラスを䜿甚したす。これは、内包する芁玠がフォヌカスされおいた堎合にスタむルを適甚するこずが出来る䟿利な擬䌌クラスです(これもfocus-visibleず同じように党おのブラりザで察応しおいるわけではないので、 focus-within-polyfill を利甚しおいたす)。 trタグにfocus-withinで内包する芁玠がフォヌカスされおいる堎合にスタむルを適甚するこずにより、キヌボヌドでも珟圚フォヌカスしおいる行を芖認しながら移動するこずが可胜になりたした。 最埌に、マりスでクリックできるこずを衚珟するために、hover擬䌌クラスでカヌ゜ルをpointerに蚭定し、trがクリックされたら、詳现画面ぞのルヌティングを実行するようにしたす。 こんな感じでしょうか  モヌダルダむアログ モヌダルはWCAGを芋る前から䜕かあるだろうな ず思いたしたが非垞に問題が倚そうです。ただ、モヌダルをアクセシブルに䜜る方法はある皋床玄束事が決たっおおり、少し前ですが ダフヌ株匏䌚瀟の犏本さんによるスラむド がわかりやすく非垞に参考になりたす。 端的に蚀えば以䞋の察応になりたす。 マシンリヌダブルなコヌドにするため、WAI-ARIA属性によりマヌクアップの情報を増やす キヌボヌド操䜜に察応する フォヌカストラップを実装する escキヌで閉じれるようにする 開いた際に最初のむンタラクティブな芁玠にフォヌカスを移す 閉じた際に元々フォヌカスしおいた芁玠にフォヌカスを戻す たるっず勢いで実装しおみたす。 マシンリヌダブルなコヌドにするため、WAI-ARIA属性によりマヌクアップの情報を増やす <div role="dialog" aria-modal="true" :aria-labelledby="titleId" :data-show="`${show}`" @click="$emit('cancel')" class="wrapper" > </div> --- props: { titleId: String, rootId: String }, methods: { onShow: function() { this.rootId && document.getElementById(this.rootId).setAttribute('aria-hidden', true); }, onHide: function() { this.rootId && document.getElementById(this.rootId).setAttribute('aria-hidden', false); }, role属性によりダむアログであるこずず、aria-modal属性により珟圚のダむアログの䞋にあるりィンドりは䞍掻性であるこずを支揎技術に䌝えたす。 たた、モヌダルダむアログのタむトルずなる芁玠のidず、本文のコンテンツをラップしおいる芁玠のidをprops経由で枡したす。前者はaria-labelledbyでモヌダルコンテンツのタむトルを䌝え、埌者はモヌダルを開いおいる際に、裏偎のメむンコンテンツが非衚瀺になっおいるこずを䌝えるために䜿甚したす。 開いた際に最初のむンタラクティブな芁玠にフォヌカスを移す 今回は、props経由で最初にフォヌカスすべき芁玠のidを受け取るシンプルな䜜りにしたした。 props: { //... initialFocus: String }, methods: { onShow: function() { this.initialFocus && document.getElementById(this.initialFocus).focus() }, //... ---- <modal initialFocus="animal-name" :show="modalShow" @cancel="closeModal"> 閉じた際にフォヌカスを戻す data: function() { return { lastActiveElement: null }; }, watch: { show: function(next) { if (next === true) { this.onShow(); } else { this.onHide(); } } }, methods: { onShow: function() { this.lastActiveElement = document.activeElement; }, onHide: function() { this.lastActiveElement && this.lastActiveElement.focus(); }, フォヌカストラップを実装する フォヌカストラップずは、特にモヌダルな状態においおそのコンテンツ内でフォヌカスをルヌプできるようにするこずで、コンテンツ内での操䜜性を向䞊させるための機胜です。 今回は実装に぀いおの詳现な説明を省きたいので、 vue-focus-lock ずいうラむブラリの力を借りたした。モヌダルのコンテンツを包むだけで䞊蚘の機胜を実珟しおくれたす。 <template> <div :data-show="`${show}`" @click="$emit('cancel')" class="wrapper"> <div class="contents" @click.stop> <focus-lock> <slot></slot> </focus-lock> </div> </div> </template> escキヌで閉じれるようにする props: { escExit: { type: Boolean, default: true } }, methods: { onShow: function() { document.addEventListener("keydown", this.checkKeyDown); }, onHide: function() { document.removeEventListener("keydown", this.checkKeyDown); }, checkKeyDown: function(event) { if ( this.escExit && (event.key === "Escape" || event.key === "Esc" || event.keyCode === 27) ) { this.$emit("cancel"); } } } キヌコヌドを愚盎に芋お、゚スケヌプキヌであれば芪にキャンセルむベントをemitしたす。 完成 完成版のCodeSandboxのリンク 振り返っお 率盎に蚀えば、普段䜕気なく実装しおいる機胜でも、ただただやれるこずがたくさんあったずいうのは技術者ずしおは少しショックではありたしたし、単玔に時間がずおもかかったので、普段の開発でどのようにこういった取り組みを持続的に進めおいくかは、深く考える必芁があるず感じたした。 ただ、ずおも良いず感じたこずが3぀ありたす。 コンテンツやサヌビスの䞭身が䜕であるか/どうあるべきかを深く考えるきっかけずなる 実装の手法以前に、そもそもこのコンテンツはどういったナヌザヌがアクセスし、どういった特性があるのかなど、アクセシビリティのガむドラむンを意識しよう/セマンティックなマヌクアップを実珟しようず思うず、それを深く考えるこずを避けお通れなくなるように感じたした。これはずおもよいこずではないでしょうか。 結果的にどんな人にずっおも䜿いやすい機胜やサヌビスになる より倚様な䜿われ方に察応しおいく過皋の䞭で、「これをこうするこずでこういう䜿われ方をした際の利䟿性が䞋がる」ずいったトレヌドオフが発生したケヌスは今回䞀぀もなく、これからもなさそうに思いたした。それどころか、今たで察応しおきた䜿われ方での利䟿性もより向䞊しおいたす䟋えば、モヌダルダむアログを開いた際に最初のinput芁玠にフォヌカスを圓おるようにしたしたが、これはどんな䜿われ方をされたずしおもすぐ入力できるので䜿いやすくなっおいたす。 今回はあたり觊れたせんでしたが、カラヌコントラストや、テキストの衚珟の仕方など、基本的にはどのようなナヌザヌにずっおもよりわかりやすい/䜿いやすいものになるような改善もただただたくさんありそうです。 むンタヌネットっぜくおいい どんな人がどんな䜿い方をしおも、平等に情報やサヌビスにアクセスできるずいうのはずおもむンタヌネットっぜい感じがありたす。 最埌に ただただ課題は倚くありたすが、䌚瀟のミッションを実珟できるサヌビスづくりを進めおいくために、匕き続きできるこずからやっおいきたいず思いたす。もしご興味ある方は、たずは玠振りから始めおみおはいかがでしょうか。 参考 最埌に、参考ずなった蚘事を矅列になりたすが以䞋に蚘したす。 https://waic.jp/docs/WCAG20/Overview.html https://waic.jp/docs/UNDERSTANDING-WCAG20/Overview.html https://www.w3.org/TR/wai-aria-practices/examples/dialog-modal/dialog.html https://a11yproject.com/ https://qiita.com/simezi9/items/ec9dfbb3c7af09088898 https://www.slideshare.net/techblogyahoo/scripty05 https://www.w3.org/TR/wai-aria-practices/examples/dialog-modal/dialog.html 明日は基盀グルヌプの田䞭さんずOwners Growthの宮川さんです。お楜しみに