読者です 読者をやめる 読者になる 読者になる

実際に効果を出せてきた! ECナビのレコメンデーションシステムのご紹介

DataScience

こんにちは、システム本部データプラットフォームグループ(DPG)エンジニアのEthan Huです。

今回はECナビ(http://ecnavi.jp/)で使用しているレコメンデーションシステムについてご紹介します。

ECナビでのレコメンデーションシステムの利用方法は、ユーザ1人1人に合わせた情報配信を行う事を目的としています。この様なシステムの導入時、社内でも話題に上がるのが「そもそもレコメンデーションシステムって効果あるの?」の声です。

また、レコメンデーションシステムは様々な手法(アルゴリズム)があり、正直どれが良いか検証しないとわからない所が大きいです。

今回は各アルゴリズムの評価、効果検証も考慮したレコメンデーションシステムの構成について紹介します。 

レコメンデーションアルゴリズムについて

その前に、レコメンデーションの手法を簡単に説明します。

レコメンデーションアルゴリズムとして「協調フィルタリング」があります。

協調フィルタリングには大きく分けて、メモリーベース(ユーザ行動履歴)とモデルベース(機械学習等の手法)に分けられ、メモリーベースはアイテムベース(アイテム間の類似度を元に推薦)とユーザベース(ユーザ間の類似度を元に推薦)に分類できます。

ECナビのレコメンドシステムは協調フィルタリングになります。 

f:id:EnzhaoHu:20160801153633j:plain

レコメンデーションシステム構成

ECナビのレコメンデーションシステムでは、メモリーベース・モデルベースの両方のアルゴリズムを使用しています。その為、検証したいアルゴリズムパターンが30個近くなります。

また、今回の構成では、複数のアルゴリズムを同時に検証でき、且つアルゴリズムの追加・更新をしやすい構成を取っています。

検証方法は複数のアルゴリズムを同時に検証できるようユーザのサンプリングを行い、サプリングユーザvs各アルゴリズムパターンでの多変量テストを実施してます。 

f:id:tokosa:20160816171122p:plain

上図がざっくりとしたシステム構成です(かなりざっくりですが)。レコメンドシステムはオンプレとクラウド(AWS)を使用したハイブリッドな構成です。

簡単に各処理の説明を書きます。

  • データクレンジング(前処理)
    ETLサーバでは、学習データの元になるデータの前処理を行ってます。データの前処理後、DWHにLoadします。

  • ユーザサンプリング
    各アルゴリズム検証用にユーザサンプリングを行います。サンプリングでは検証用のユーザが偏らないようにする為と、検証に必要なサンプルサイズを担保する為で、検証する際はとても重要なポイントです。

  • 学習データの作成
    学習データは様々な特徴データを作成する必要がある為、DWHで集計→作成しています。データはログデータがベースになるため、大規模な集計になります。

  • 推薦データの作成
    各アルゴリズムによって学習データから実際に推薦データを作成する方法は様々です。メモリーベースの推薦の場合、DWHで推薦データ処理を行なっていますが、モデルベースの場合AWS EMR(Apache Spark)で処理しています。

レコメンデーションのチューニング

レコメンデーションシステムの実装・リリースは完了しましたが、各モデルの精度をさらに向上させるためチューニング作業を行います。

チューニング作業の一般的な流れは以下のようになります。

  1. モデル実装
  2. 検証(2週間 ~ 1ケ月頃)
  3. 結果FB
  4. モデル最適化調整
  5. 上記 1 ~ 4 を繰り返す

まとめ

この記事では、ECナビで実装したレコメンドシステムについて、おおまかに構築した仕組みについてまとめしました。

実際に検証、利用しているモデルや、その特徴量、パラメータの値については、システムのキモとなるのでブログに載せることはできませんでしたが、ざっと10~30近くのモデルを随時検証・走らせています。

実際レコメンドでの効果は、CTRが1.8倍、CVRで4倍位出てます。

また、高速化を求めてSparkのチューニングも頑張っています。

この辺に興味のある方は、ツイッター(@tech_voyage)に気軽に連絡をください。#ajitingしましょう! そして、ECナビでは仲間を募集しています。 http://voyagegroup.com/crew/recruit/career/

Reference

http://www.kamishima.net/archive/recsysdoc.pdf
https://www.moresteam.com/toolbox/design-of-experiments.cfm

中高生のための夏休みプログラミング教室をお手伝いしてきました

みなさんこんにちは、fluct DR 開発本部の @kanufy です。

今年VOYAGE GROUPに新卒として入社し、fluct DR(Direct Reach)にて、広告配信機能のサーバサイドと日々戦ってます。

さて今回は事業・技術ネタではなく、VOYAGE GROUPとしての取り組みの一貫の話をしようと思います。 8/12, 14と東京工業大学CBECプログラムの一貫で行われた、中高生のための夏休みプログラミング教室に協賛として参加してきました。 その様子をお伝えしたいと思います。

伝えたいこと

  • 中高生ののびしろは無限大なので我々も頑張ろう
  • VOYAGE GROUPは良さそうなイベントには協賛としてスポンサーします!
    • ピザまたは🍣、会場提供も致します!

イベント概要

協賛のきっかけ

東工大の特任講師も務める『リーダブルコード』の訳者で有名な 角さん( @kdmsnr )がツイッターで呟いた一言


に弊社エンジニア @katzchang がやりましょう!と言ったのがはじまり。 弊社ではこのようにわりとカジュアルに協賛が決まったりします(社内で審査・議論は行われます)

1日目@東京工業大学

中高生35名が参加してくれたこのイベント。まずは仲良くなろうということで、角さんがアイスブレイクを行ってくださいました。

  • 学年別に一列になってみよう
  • なまえであいうえお順で一列になってみよう
  • 誕生日順で一列になってみよう etc.

f:id:kanufy:20160815143052j:plain:w300

初対面の子がほとんどなのでみんな最初は緊張してコミュニケーションが取りづらい様子でしたが、回を重ねるにつれ自然と会話が生まれていました。 そして今回驚いたのは女の子の参加者が多いこと!参加者の半数くらいは女の子だったのできっと日本の未来は女子エンジニアが増えている、ハズ?笑

さて、いよいよプログラミング! 今回の教室では、

  • Processing 3 でつくる横スクロールゲーム
  • JavaScript(+ HTML/CSS)でつくるメモアプリ

のどちらかを選んでもらい、東工大のtraPのメンバーがチューターとして付いて学ぶという内容でした。 講義資料は東工大traPのメンバーが作成したもので、初心者のために詳しく説明してあってとてもわかりやすい内容になっていました。

教室の様子

f:id:kanufy:20160815144525j:plain:w270 f:id:kanufy:20160815144538j:plain:w270

みんな集中してプログラミングに打ち込んでいました! お昼はお待ちかねのピザ!

f:id:kanufy:20160815144938j:plain:w300

参加者、保護者の方、東工大生、VOYAGE GROUPと総勢約80名でピザを食べて盛り上がりました。

午後もがっつりプログラミング!女の子の参加者が多いこともあり弊社の女子エンジニアの @kanufy@momoe_yoshinaga もサポートしました〜。 みんな自分の作りたいものが作れたかな?

イベントの最後にはスポンサーとしてスポンサートークの場を設けていただきました。 中高生のためにVOYAGE GROUPの簡単な紹介と、弊社の就活支援事業サポーターズの紹介を行いました。

f:id:kanufy:20160815145819j:plain:w270 f:id:kanufy:20160815145827j:plain:w270

最後に記念写真!みんな笑顔で楽しかったと言ってくれて大盛況でした。

f:id:kanufy:20160815150356j:plain:w500


2日目@VOYAGE GROUP

2日目は1日目やり残したことがある子や、もっとオリジナルにしたい!といった子のために VOYAGE GROUPオフィスにて補習を行いました。カンバン術をつかってTODO管理にもトライ。

f:id:kanufy:20160815151856j:plain:w300

弊社人事からはおやつとしてアイスの差し入れもありました。

f:id:kanufy:20160815172428j:plain:w270 f:id:kanufy:20160815151915j:plain:w270

そしてなんと、この補習の最後にある発表会に参加してくれた子には、角さんの声かけで各所からスポンサーしていただいた技術書が貰えるという豪華な特典付き!

f:id:kanufy:20160815151727j:plain:w400

弊社からもVG賞としてソロシアターを用意しました!実はこれ、弊社の事業のひとつ、LUCY ALTER DESIGN で制作されたものなのです!

www.makuake.com

発表会のようす

さていよいよ発表会!みんな堂々とした発表で会場を沸かせていました。

f:id:kanufy:20160815152332j:plain:w300 f:id:kanufy:20160815152338j:plain:w300

みんな技術書を熱心に選んでいました。今回は一人2冊も選ぶことができました!(残りは東工大traPのみなさんへ)

f:id:kanufy:20160815172352j:plain:w300

栄えあるVG賞を勝ち取ったのは、敵を攻撃できるProcessingのゲームを制作した女の子。オリジナリティを求めつつ、やりたいことをミニマムケースから実現した姿勢がよかったですね!おめでとうございます。ソロシアターお家で使ってくださいね〜(^^)

f:id:kanufy:20160815152427j:plain:w300

最後に

今回のように、VOYAGE GROUPではピザや🍣のスポンサーを行っていたり、無料で会議室を貸し出したりしています。 社内審査がありますが、積極的にスポンサーを行っていますので気になった方はぜひ @tech_voyage や弊社エンジニアまでお声掛けください。

http://livedoor.blogimg.jp/ecnavi_tech/imgs/5/9/596d1dab.png voyagegroup.com

初めての技術力評価会を終えたので感想を書いた

f:id:saxsir256:20160815151542j:plainこんにちは、fluct SSP開発本部の@saxsirです。

今年の4月に入社した新人ですが、職場ではgolangとかAWSとかを使って社内向けのプロダクトをゴリゴリと開発しています。

さて、VOYAGE GROUPでは人事評価制度の一つとして技術力評価会という相互評価の仕組みがあります。 これは年に2回ほど開催されており、直近半年くらいの仕事から何かテーマをピックアップし、別チームのエンジニア2名(評価者)に「私はこんなすごいことをやったんだよ、どやっ」とお話しながら自分の技術力を評価してもらうという場になります。

もちろん、新卒も例外なく技術力評価会を行います。

今回は初めての技術力評価会を終えて私が学んだこと、を社外の方向けに書こうと思います。(言うまでもなく、私は被評価者です)

※以下、「技術力評価会」を「評価会」と略して表記する場合があります

TL;DR

  • 「なぜやったのか」を説明するのは難しい
  • 素振りはいいぞ
  • 評価会とは評価制度であると同時に、成長する仕組みでもある

前提

技術力評価会は90分です。何が言いたいかと言うと、その場で自分がやったことを語り評価者とディスカッションするには全然時間が足りません。

そこで、事前に「評価会資料」というものを作成し、評価者にはそれを読んできてもらってから当日に臨むような流れになっています。

なにをやったのか/なぜやったのか/どうやってやったのか等、いくつかのポイントを含むように(なるべく既存のドキュメントを流用しながら)Markdownで書くようになっています。(テンプレートは一応ありますが、ポイントは抑えつつ各自が書きやすいように書きます)

「なぜやったのか」を説明するのは難しい

たとえば今回私は「クローラーのキューイングを外部キューにした」という内容で評価会をやりました。

評価会資料をつくるかー、と思って書き始めて思ったことは「やったこと」と「どうやってやったのか」はスラスラ書けるけど「なぜ」の部分はすごく難しいということでした。

  1. 「なぜ」外部キューにする必要があるのか?
  2. 無数にある方法の中で、あなたは「なぜ」方法Aを選んだのか?

ということを自分の言葉で説明できなければなりません。

今回の例で言うと、実は私が外部キューにする必要がある!と提案したわけではなく suzuken (@suzu_v) | Twitter が、これはやった方がいいという判断をして、それを私が実装したものです。

開発自体は、まぁドキュメントを調べたり試行錯誤していればできるでしょう。

しかし、その妥当性を他人に伝えるためには(仮に)組織的な決定事項や自分の判断ではないとしても「自分の言葉で」説明できなければなりません。

これが説明できないとちょっと残念だなぁ(なんであなたはそれをやっているの?)となってしまうので、まず大前提の部分でこれができていないエンジニアは一人前とは呼べない。というのが弊社のエンジニア文化なのだなぁと感じた評価会でした。

たとえば、私はこんな図をホワイトボードに書いて

f:id:saxsir256:20160815110637j:plain f:id:saxsir256:20160815110643j:plain

  • そもそもこういう構成になっていて
  • 今回ここを変更したんです
  • で、その理由は云々…(ここが大事)

みたいなことを話しました。(これの前にどういうシーンで使われてるかーとかも図に書いて説明した気がするけど画像がなかった…)

素振りは大事

ここまで読んでいただいて、そもそもクローラー…なんで?そもそも全体の仕組みが分からない…という感じになると思います。 社内でもだいたいそうです。ただ自分は詳しいので、なんとなくそのへんはいいかーという気になって進めてしまいがちです。

なので発表前に素振り、と呼ばれる「論点を明確にするための練習」みたいなことをやる人もいます。 私は初めての評価会ということもあって不安だったので、今回素振りをやりました。

これはとても良かったのでオススメです。

  • 自分では分かりやすいつもりでも、だいたい伝わらない
  • 素振りを見に行くと副次的に、別チームのエンジニアが何をしているのか知ることもできるので楽しい
  • 人の素振りを聞いていると質問力も鍛えられる(評価者目線でも見られる)

ので、結構楽しいです。 素振りは業界一般的にやられていることなのか分かりませんが、これはみんなやるといいんじゃないかなーと思います。

別に評価会とかがなくても別部署の同期に自分がやっていることを飲みながら説明する、とかでもいいと思います。

ちなみに素振り最中の走り書きメモがあったのでペタッと。(字が汚くてすみません…)

f:id:saxsir256:20160815111139p:plain

などなど…話しながら自分でも気づいたりするんですが、人に伝えるのは本当に大変だなぁと… あとは、そこは頑張ってたところだしアピールすれば?と言われると、あーなるほどなぁ(嬉しい)と思ったりもできて素振りは良いです。

評価会は評価されるだけじゃなくて成長する仕組み

これは新卒目線かもしれませんが、評価会という場を通じて普段の行動が変わりました。

たとえば、私は開発に入る前に手元のホワイトボードにシステム全体像ややるべき理由を書いてみて、自分に対して説明できるかどうか考えたりします。

これ自体は元からやったりしていたんですが、それだけだとその思考過程が残らないので、それはチケットなりIssueなりに残すべきです。

これは評価会後、意識的にやろうと変わりました。(元々まとめだけは書いていたが、過程も残すように意識し始めた)

やっておくと、将来の自分がありがたいというのもあるし、これは自分だけじゃなくて後から見る人はチケットなりIssueを見れば経緯がわかるので良いです。

たとえば方法Aも試したけど、こういう理由でダメだったからBになったんだなぁを知ることができるし、もしかしたら将来の時点では事業フェーズ的に方法Aの方が良い、となるかもしれません。

あとは、別に「評価会」と言う名称だけど評価者と議論する場なので、実は自分が知らなかった機能やサービスがあったり、経験的な知見からこの辺りのエラー処理はしっかり見た方がいいよ、とか学びの場にもなります。

基本的にチケットに残す文化なのですが、もうちょっと「過程」を含めてしっかり残すようにしよう…と思った評価会でした。

まとめ

やる前はgkbrしてたけど評価会楽しかった。

弊社のエンジニアの技術力の評価制度はこんな感じですが、みなさんどうなのだろう…

なにか気になるところとかあったらTwitter(https://twitter.com/saxsir256)なりで気軽にメンションください。

チームの読書会、4つの工夫

こんにちは、ECナビ事業本部エンジニアの yukimine です。

2ヶ月程前に デザインパターンをチームで学んで得たもの という記事がありましたがご覧いただけましたでしょうか。
Zucks Affiliate事業本部が、@t_wadaさんと読書会を行ってチームでの共通言語が増えたという記事です。

ECナビ事業本部でも、ベテランから新卒まで様々なエンジニアが、@t_wadaさんに設計・実装を相談をさせていただいたり、ペアプロをさせていただいたりしています。

本記事では、@t_wadaさんとECナビ事業本部の取り組みの一つ、 プログラマが知るべき97のこと 読書会 で取り入れている 4つの工夫 について、ご紹介させていただきます。

4つの工夫とは

  • 事前準備なし
  • アクションにつなげる
  • エンジニア席の横で開催
  • SlackのPublicチャンネルで議事録を残す

です。

デザインパターンをチームで学んで得たもの の二番煎じ感満載ではありますが、この読書会によってECナビ事業本部も チームの共通言語チーム共通のネクストアクション (読書会で学んだ内容をどう行動に落としこむか)を持つことができました。

プログラマが知るべき97のこと ってどんな本?という方はこちら
www.oreilly.co.jp

まずはじめに

増刷おめでとうございます!

(増刷時の修正項目には読書会の中で見つかったものも含まれているとか・・・)

「知見の共有」に読書会を使う

そもそもなぜ、 チームで読書会 をやっているのかをご紹介します。

ECナビ事業本部には様々なキャリアを持ったエンジニアが所属しています。
経験してきた業界(SI系やゲーム系など)や年数も様々です。

そういった中で、プログラマが知るべき97のこと という共通知識を付けることはもちろん、本の内容を題材にした各自の知見を共有することを大きな目的としています。

今回は プログラマが知るべき97のこと を選んだのは 監修者直々の解説を受けられる ことも理由の1つです。 プログラマが知るべき97のこと は@t_wadaさんが監修されています。
監修者直々の解説を受けられる稀有な機会ということで選びました。

読書会の流れ

読書会は次のような流れ(時間配分)で進めています。

  1. 読書タイム(10分)
  2. @t_wadaさんの解説(30分)
  3. 質問タイム、ECナビ事業本部のアクションを決める(20分)

14. コードレビュー を読んだときのSlackの会話を交えながらご紹介します。
(Slackは議事録も兼ねているため、文体が乱れている箇所もあるかと思いますが、ご了承ください。)

流れ1「読書タイム」

1回の読書会で読むエッセイは 2エッセイ です。
ECナビ事業本部のエンジニアが、任意の1エッセイをリクエストし、@t_wadaさんがそれにあった 合わせて読みたいエッセイ を選んでくださいます。
この時点で読書会の価値を感じますね。

Slackの様子
f:id:yuk4420:20160727000650p:plain

流れ2「@t_wadaさんの解説」

@t_wadaさんがエッセイについて、著者の背景や本に書かれていない事例、編集時のコラムを付け加えて解説してくださいます。

@t_wadaさんの解説(の議事録)
f:id:yuk4420:20160727000637p:plain

流れ3「質問タイム、ECナビ事業本部のアクションを決める」

エッセイに関する質問や、ECナビ事業本部としてどのような行動に落としこむかを話し合います。

ECナビ事業本部のアクション
f:id:yuk4420:20160727000702p:plain

1 は実際にGitHubのPullRequestで使われており、2 はGitHub Templateを採用する等、読書会から生まれた共通のアクションがECナビ事業本部には多数あります。

読書会の工夫とは?

冒頭で、読書会の工夫を紹介すると書きましたが、実は「読書会の流れ」の中で全て紹介済みです。
工夫といっても、気を張る必要なくルーチン化できるものばかりを取り入れているからです。

ここからは改めてその工夫を取り上げてみます。

工夫1「事前準備なし」

事前に予習する必要はありません。
その場で読んで、疑問に思った箇所はすぐ@t_wadaさんや周りのエンジニアに聞くことができます。

きのこ本の特徴として、1エッセイが見開き2ページで収まっているので、予習なしでも読書会が円滑に進みます。

@t_wadaさんからコメントをいただきました。

@t_wadaさんからのコメント

読書会に何回か参加できなくても、会に復帰しやすい本を選ぶと、読書会が継続しやすくなりますね。
読書会を継続するのが目的になってしまうと本末転倒ではあるけれども、多くの社内読書会は、仕事が忙しい日に参加できずに脱落していく人が多くなってしまうものなので、1,2回参加できなくとも普通に戻れる構造の本を選ぶと、特に読書会の文化がまだ根付いていないうちは続けやすくなるなと改めて感じました。
シーケンシャルに読んでいかなければならない本は、読書会というフォーマットにはあまり向かないのかなとも思います。

工夫2「エンジニア席の横で開催」

プログラマが知るべき97のこと 読書会の開催場所は、ECナビ事業本部エンジニア席の横で行われます。

これにより 作業で手が離せないエンジニアも耳で参加することができます

移動コスト(それくらい惜しむなよと言われそうですが、やっぱりない方がいいですよね)も削減できて楽です。

読書会開催の目的(なぜやっているのか)からも、 参加しやすい環境 は良いと思います。

実際の様子 f:id:yuk4420:20160726235805j:plain

工夫3「SlackのPublicチャンネルで議事録を残す」

先ほどからスクリーンショットを貼っていますが、 この読書会用に #97things というSlackのPublicチャンネルがあります。

使われ方は、 議事録 を始め、 @t_wadaさんがエッセイに関する参考URLを貼ってくださったり読書会に参加していないエンジニアから反応があったり 、様々です。

Slackのチャンネルで、この読書会があることを知って、参加するようになったエンジニアもいます。

工夫4「アクションに繋げる」

先ほど14番目のエッセイ、コードレビュー から生まれたアクションをSlackのスクリーンショットでご紹介しました。

同じように、いくつものアクションが、毎週この読書会から生まれ、実際に適用されたり、GitHub Issueにあげられたりしています。

私事ですが、一人で技術書を読んだり、読書会に参加したりした後、

「いい話だなー」

と思うことは多々あれど、実際に行動に落とし込むことは少ないです。
それどころか、翌月には、

「あの本の内容、なんだっけなー」

と思っている始末です。

チームにとって、もちろん個人にとっても よいこと をチームの共通アクションにできる。
ECナビ事業本部にとって、この読書会はそんな存在です。

参考までに、この読書会から生まれたアクションをいくつかご紹介します。

エッセイ名 アクション アクションの恩恵
06. リファクタリングの際に注意すべきこと 試行プログラミングを取り入れてみる 手軽に取り組める。実際にmergeされなくても、既存のシステムを深く知る機会になる。
10. ツールの選択は慎重に 自分たちが使っているライブラリのアップデート情報収集を自動化する 自分たちが使っているツールのバグによるリスクを回避できる。
14. コードレビュー レビュアーは、これから見ようと思っているPRに :eyes:(アイコン)をつける 「レビューされず放置されているわけじゃないよ」「見てるよ」をレビューイに手軽に伝えられる
64. プロのプログラマとは? 中間地点でのレビューポイント(設計時など)を作る 手戻りが少なくなる。余裕を持ってレビューができる(リリース前に設計の指摘を受けて焦らないなど)。
92. 顧客の言葉はそのまま受け取らない 顧客(ディレクターなども含む)の言葉を同じ抽象度で復唱するだけでなく、会話に「要するに」「具体的には」という言葉を盛り込み、抽象度の上げ下げも取り入れる 認識のずれを減らせる。

4つの工夫を取り入れた読書会の所感

手前味噌ですが、良い読書会だと思います。

知見の共有があり、それが議事録に残せていて、そこからアクションも生まれている、そんな読書会です。

チームで読書会を開催する際、なにか参考になれば幸いです。

はじめの一歩に、是非。

プログラマが知るべき97のこと

プログラマが知るべき97のこと

  • 作者: 和田卓人,Kevlin Henney,夏目大
  • 出版社/メーカー: オライリージャパン
  • 発売日: 2010/12/18
  • メディア: 単行本(ソフトカバー)
  • 購入: 58人 クリック: 2,107回
  • この商品を含むブログ (345件) を見る

質問など、はてぶコメントでお待ちしております。

P.S.

この読書会から生まれた1番のアクションは 議事録をとる です。

やりながら改善してきたこと をお伝えできれば嬉しいです。

モバイルファーストなサービス開発におけるDockerの活用術

こんにちは!ポイント交換サイト「PeX」の開発を行っていますVOYAGE MARKETINGの加藤です。
Crewからはちゃむと呼ばれています。

少し長くなりますので先に本エントリーの概略を3行でまとめると

  • Docker成分多め
  • 作ってみた
  • 後半でテーマ深掘り

です。
最後までお付き合い頂けると嬉しく思います。

はじめに

タイトルは若干釣り気味ですが、個人的にDockerをwatchし続けています。

先月のDockercon 16で、ついにDocker for  (Mac|Windows)がpublic betaになりましたね。
以前はDocker Toolboxで必要だったVirtualBoxを必要とせず、それぞれのOSでのネイティブ仮想化技術(MacOSはxhyve、WindowsはHyper-V)で動作するようになりました。
ますますDockerが使いやすくなってきていますね。

さて今回のお話の本題に入りたいと思いますが、本ブログをご覧になっていらっしゃるエンジニア・デザイナーの方はどこまでモバイルファーストを意識されていますでしょうか?

VOYAGE GROUPでは幾つものサービスを展開しておりますが、スマートフォン・タブレットでの利用を想定して社内に多数の実機を用意して検証を行っております。

f:id:katzumi:20160721184416j:plain

PCとは違いスマートフォン・タブレットではディスプレイサイズの制約や種類も多いことから実機での検証は欠かせないでしょう。サービスによってはレスポンシブなページを用意したり、アプリケーションで専用のUIを提供していたりするのではないでしょうか?
ここまでは普通に取り組みされていることかと思いますが、でも開発で利用している実機は本当にユーザーの利用している環境とイコールか?というとそうでないと思います。
実際にサービス利用されているPCユーザーとモバイルユーザーの利用環境の違いとして、ディスプレイサイズ以外にネットワーク環境も大きく異なることを忘れてはいけません。
このネットワーク環境の違いは普段PCでサービス開発をしていると意外に忘れがちで、いざ実際にキャリア回線を用意しようとするとコスト面で対応できないケースが多いです。
社内のモバイルの実機もSIMなしでWifi運用していますので、ネットワーク速度は実環境のそれとは異なります。
このネットワーク速度の違いを吸収する為にキャリアのネットワークをシミュレーションするネットワーク機器があったりします。

さて前置きが長くなりましたが、今回は簡易的に回線シミュレーションを行えるツールをDockerで構築してみました。

仕組みについて

構成はごくシンプルです。
Dockerのコンテナで  squidサーバーを立てます。
そのsquidサーバーに対して通信速度を制限したものを回線シミュレーションを行ないたいクライアント側でプロキシとして利用します。

f:id:katzumi:20160715150051p:plain

こちらの通信速度のコントロールはDockerの仮想環境が提供しているリソースの分離(isolation)を利用しています。
リソースの分離(isolation)という言葉はあまり耳慣れない方がいらっしゃるかと思いますが、Dockerを代表とするコンテナ型仮想化の特徴となりますので軽く説明したいと思います。

サーバー仮想化では物理的なCPU、メモリ等のリソースを分割(時分割に近いイメージ)して動くと説明されるケースが多いですが、コンテナ型仮想化ではユーザー・プロセスに対してリソースを分離(空間分割のイメージ)すると明示的に説明されます。
これはサーバー仮想化がハードウェアウェアレベルの仮想化を行ない、仮想マシン(ゲストOS)間でリソースが分離されていることに対して、コンテナ型仮想化はOSの仮想化を行っており、コンテナはホストOSのプロセスとして扱われている中でも複数コンテナが独立して動く仕組み(リソースの分離)が用意されているからです。

この各コンテナのリソースが相互参照できない様に資源管理する仕組みがNamespaceとcgroupというLinux  Kernelが持つコンテナ技術です。
DockerはNamespaceとcgroupを利用しており、CPU、メモリの他にネットワークも分離(仮想化)することができます。ネットワークが分離されていることで、該当のコンテナのみ(ホストOSも含まず)に対して通信速度を変更(制限)することが出来る特性を利用しています。

Traffic control proxy

github.com

こちらが今回作成したDockerfileです。 回線シミュレーションできるパターン毎にプロビジョニング出来る様にDocker ComposeのYAMLを用意しています。 docker run時に環境変数を指定して、コンテナ内部の挙動を変更させられなくもないですが、予めイメージファイルとして組み込んでおいて必要とするコンテナをドカドカと立ち上げる方が、Immutableにできて良いと考えています。 docker-compose.ymlでDockerfileのbuild argsで回線シミュレーションするネットワークタイプを指定しています。

こちらのdocker-compose.ymlのargsの指定を行うには、Docker Composeの1.6からとなり、YAMLの記法のバージョンをv2にする必要があります。 Docker自体のbuild argsのサポートは以前からありましたが、Compose側の対応がされずにいました。

github.com

上記のIssuesで自身も+1してウォッチしていましたが、ようやくのサポートになります。 Docker自身の開発スピードが早すぎて、Composeも含めて周辺ツールの連携が追いついていない印象があります。 今後、Compose自体にもどんどん機能が追加されていくと思われるので、はやくv2のフォーマットに慣れておく必要があると思います。

build argsによってentry pointのシェルに組み込んでいる帯域制限のコマンドを選択して組み入れています。 上記の仕組みの所で説明したcgroupsのサブシステムであるnet_clsを制御するコマンドがtc(Traffic controller)です。

コマンドの意味を全て説明するには本エントリーでは長くなりすぎる為、割愛しますがqdiscと呼ばれるキューイング規則を設定することで帯域制限やパケット遅延や破棄を制御することができます。qdisc等の説明についてはこちらが参考になります。

Linux TC (帯域制御、帯域保証) 設定ガイドライン | GREE Engineers' Blog

Docker上で tcコマンドを使う上での注意点としてはdocker run時に--privileged オプションを指定することです。compose経由の場合はYAMLで既にオプションを指定していますのでそのまま利用できます。

Demo

概要の説明が終わったところで、デモをしていきたいと思います。
簡単に利用出来るようにDocker Hubへ登録しています。
Docker環境があれば以下のコマンドのみで試せます。

$ docker run --rm -it --privileged -p 3128:3128 katzumi/tc-proxy:3g

上記コマンドで3G回線のシミュレーションを行えるProxyが起動します。
Proxyはホストのポート3128で利用出来るようになりますので、検証したい端末からプロキシのポートに指定します。プロキシーのIPは DockerホストのIPを指定します。
Docker環境をDocker Toolboxで構築した場合、ホストIPは以下のコマンドで調べられます。

$ docker-machine ip
192.168.99.100

Docker for Macの場合はDocker Toolboxとは違い、VirtualBoxの仮想環境が不要となりますのでlocalhostのIPがDockerホストのIPとなります。

上記コマンドで回線の種類やProxyのポートを変更する場合、それぞれ以下の様にします。

  • 回線種類の変更
    katzumi/tc-proxy:(回線種類)
    Docker Hubに登録しているイメージはタグ毎に回線種類を分けてbuildしています。
    例)4G 回線
    katzumi/tc-proxy: 4g

  • ポート変更
    (ホストポート):3128
    例) 8080
    8080:3128

検証したい端末のプロキシ設定ができたらブラウザでアクセスしてみてください。
 Dockerを起動したコンソールログに以下の様な出力がされればOKです。

Proxyを終了する場合はコンソール上でCtrl+Cしてください。

回線スピードによるレスポンスの違い

まずは何もしていない自宅のケーブルテレビのインターネット回線を使った場合のレスポンスです。 f:id:katzumi:20160709194212p:plain

次にtc-proxyの4Gネットワークのコンテナ経由でのレスポンスです。 f:id:katzumi:20160715153337p:plain

比較でわかりやすい様に、1回目の計測の結果を残したまま2回目の計測を行っています。
図のタイムライン上にコメントを入れていますが、レスポンスタイムが大幅に拡大していることがわかると思います。

まとめるとこんな感じです。

計測値 Cable 4G 比率*1
Finish 1.8 s 8.55 s 4.75
Load 1.57 s 6.98 s 4.45
DOMContentLoaded 628 ms 2.39 s 3.81
First response *2 141 ms 761 ms 5.40

2秒かからなかったのが、5倍ぐらい遅い8.5秒となりました。
こちらのレスポンスの違いがサービスの使い勝手に大きく影響します。
又、ページの作りが悪く

  • 外部CSS/JavaScriptをheadタグ内で大量に読み込む
  • レスポンシブデザインで、PC用画像を縮小表示
  • 上記に併せてレンダリングブロックがされるHTML構造

となっていると、更に体感速度が悪くなり利用者へのストレスがより高まる原因となります。

回線スピードによっては見過ごされがちなHTML上の問題点が、顕著に現れますので回線スピードを併せて確認することが大事かと思います。

より便利なツール達

HTMLの問題点をより詳細に深掘りしたい、毎回ネットワーク設定を変えて確認するのは面倒くさいという貴方に、オススメのツールを紹介いたします。

  • PageSpeed Insights
    HTMLのレスポンススピードを確認して適切にアドバイスをしてくれます。
    Googleはページランクの要因にページ表示速度を見ていると公表していますが、どういった指標でページ表示スピードを判定しているかがわかります。
    又、モバイルでのUX(ユーザー・エクスペリエンス)もチェックしてくれますので、そちらも併せて改善しておくと良いでしょう。

  • Chrome ブラウザ
    今更敢えて紹介しなくても良いくらいメジャーなブラウザですw
    今年の4月にブラウザシェア1位(国内は2位)を獲得したようです。
    Demoのレスポンス計測にも利用していましたが、実はこれ単体で回線速度を変更することが出来るのです!!(ドヤァ

今までの流れを全く無視してGoogle Chromeの回線速度の変更の仕方をご説明したいと思います。
やり方としてはレスポンス計測の画面からタイムラインの上部にあるプルダウン(初期表示はNo throttling)から変更できます。
レスポンス計測の画面を表示するにはメニューから表示 > 開発/管理 > デベロッパー ツールで表示して、デベロッパーツールが表示されたら、Networkを選択します。

f:id:katzumi:20160717103704p:plain

プルダウンを開くとPresetsにいくつかの回線種類が予め登録されていますのでそちらを選択します。
tc-proxyとの違いとしては予め用意されている回線種類に対してのそれぞれの通信速度と遅延が微妙に異なります。
ここら辺は日本とキャリア回線の規格の違いや回線品質による実効速度をどう見るか?によるものとProxy経由にすることのオーバーヘッド分が含まれていると思います。
あと一つ大きな違いとして、Google Chromeでは通信速度を上りと下りとで細かく制御していますが、tc-proxyはアウトバウンドの帯域を一括して制限しています。
ネットワークインターフェースを追加して帯域制限を分けられなくはないと思いますが、今回は簡易版ということで。。

あれ?今回のネタはDockerと関係なくない?

うん。そうなんだ。
済まない。

今回のネタはcgroupとDockerを組み合わせてた活用方法を紹介するつもりでしたが、リソースを制御するという地味な話題になるので取っ付き易いネタを提供したという裏話*3がありました。。
NamespaceとcgroupはLinux標準で使える機能ですが、Dockerを使うことでより簡単にリソース制御を行えることを「実証してみた」というお話でした。

Dockerでのリソース・コントロールの使いドコロ

こちらが裏テーマになりますが、cgroupとDockerを組み合わせた活用方法についてお話をしたいと思います。
例えば以前のRedisのバージョンではmaster-slave間のデータの再同期が発生した場合にI/O、ネットワーク帯域を使いきってしまう問題がありました。ミドルウェア側でリソースの制限を行う手段がなく、バージョンアップされるまで多くの開発者を悩ませ続けていました。
そういった場合にコンテナに閉じ込めてリソースを分離させて、cgroupでCPU、メモリ、ディスクI/Oやネットワークの制限をすることでシステムを安定的に稼働させる手段を提供できるかと考えています。
アプリケーションやミドルウェア側で、細かくリソースの上限を設定出来ないケースでもQoS(Quality of Service)を実現することが出来ます。
特にシステムがマルチテナントでサービスを提供している場合に、一つのテナントが大暴れしても他のテナントに対して影響を及ばさない様にするにはDockerは相性が良いと考えています。

感想など

最後に本エントリーを投稿するにあたっての感想で締めくくりたいと思います。

  • Google Chormeは
    Webアプリを確認するにはGoogle Chromeは使いやすいと改めて認識しましたw
  • DockerHubのAutobuild時にbuild argsが使えないのが残念
    DockerHubにイメージを登録しましたが、Autobuildの際にブランチやタグを切らないと使えないのが残念でした。
    元々バージョンが異なるものをイメージとして登録することがほとんどなので、今回の様にプロビジョニングの違いをイメージとして扱うことは稀なことかも知れません。
  • キャリアの通信速度制限は絶望的遅さ
    キャリア回線でパケットを使いすぎた際のアレを実装してみました。
$ docker run --rm -it --privileged -p 3128:3128 katzumi/tc-proxy:4g-limit

是非その絶望的な遅さを体感してみてください。パケットのご利用はご計画的にw

*1:Cableを1とした場合

*2:トップページ単体のレスポンスタイムです。

*3:今回紹介したGoogle chrome以外にもXCodeやAndroid エミュレータでも通信速度を変更する機能が標準サポートされていることを後から気づいたというのは内緒の話

バッチ処理の通知・アラート管理

こんにちは、nekoyaです。

システムを日々運用していく中で、その処理結果の記録や異常検知の仕組みは地味ながらも大切な存在です。

各種監視ツールからの通知や、ブラウザから利用可能なWebインタフェースなど、その形態も様々です。

今回はその中から、バッチ処理の結果通知について、我々のチームが実践している方式をご紹介します。

loggerを通して記録する

まず前提として、通知する内容はプログラマ自身が出力することが基本になります。

自分はここ数年はPythonをメインに使っていて、標準のloggingモジュールを通して

import logging

logger = logging.getLogger(__name__)
logger.info('hello!')

のようにログを吐いておくと、スクリプトの終了時にそれまで出力したログがいい感じに集約されて通知されるようにしています。

ログレベル

ログを出力する際は「そのログがどのレベルに属するか」を併せて指定します。

Pythonのloggingにもいろいろなレベルが定義されていますし、Log4j的な実装は様々な言語に浸透していると思われます。

あまり種別が増えすぎると煩雑になるので、我々はこの4つのレベルを使うようにしています。

  • debug
    • debugモードで実行した場合のみ出力される
  • info
    • 後で参照するために残す正常な処理結果の情報
  • warn
    • 処理は継続するが把握すべき異常があった
  • critical
    • 処理を継続できないか、バッチが目的を達成できない異常があった

何をどのレベルで出力するかは開発者次第ですが、大まかな基準は上記のようになっています。

また、スクリプトが途中で異常終了した場合はエラー内容をcriticalで出力し、併せてstacktraceを出力する仕組みを用意しています。

通知の仕組み

スクリプトが終了した時点で、それまでに出力された最も高いレベルのログに合わせて通知が飛びます。

通常はwarn, criticalが発生した場合に、スクリプトをverboseモードで実行した場合はnoticeでも通知します。

通知内容にはスクリプトの実行中に発生した全てのログと、以下の項目が含まれます。

  • 検知した最大ログレベル
  • 実行ホスト
  • 実行スクリプト名
  • 実行開始と終了日時

例えば、こんな具合です。

----------------------------------------
   From: system@localhost
     To: warn@localhost
Subject: [warn] nekoya.dev.local - alert_sample.py
----------------------------------------
script /home/nekoya/alert_sample.py running at 2016-07-01 16:46:34
----------------------------------------
2016-07-01 16:46:34 [INFO] --- find friends ---
2016-07-01 16:46:34 [DEBUG] - found id: 3
2016-07-01 16:46:35 [DEBUG] - found id: 5
2016-07-01 16:46:35 [DEBUG] - found id: 8
2016-07-01 16:46:35 [INFO] found 3 friends
2016-07-01 16:46:35 [INFO] --- send message ---
2016-07-01 16:46:39 [WARNING] failed id: 5
2016-07-01 16:46:41 [INFO] sent 2 messages
----------------------------------------
finished at 2016-07-01 16:46:41

こうしたメッセージをメールやSlackで受けています。

Slackは文字数制限が厳しい上に、クライアントによって上限が異なったりして途中で途切れたりすることもありますが「その場合はメールで全文が確認できるからいいよね」ぐらいの温度感で回しています。

手軽にWebHookで済まさずにAPIを使ってSnippetにするみたいな方法もありそうですが、現時点ではそこまではしていません。

アラートの送信先

こうした通知に送信するか、どこに送信するかは「そのスクリプトを実行している間に発生した中で最も高いレベルのログ」で判断しています。

メッセージにはスクリプトの開始から終了までに出力した全てのログが含まれるので、どのように処理がなされたかの流れが追えます。

通常はwarnかcriticalが発生した場合のみ送るようになっており、バッチをverboseモードで実行した場合には異常がなくても常に通知が送られます。

Slackに送るメッセージはcriticalの場合はグループメンションを付けるようにしています。メールはレベルごとの送信先をプロジェクトの設定ファイルに記述しておいて、スクリプトの実行状況によってそれぞれのアドレスに送っています。

常駐プロセスのアラート管理

この通知の仕組みは「スクリプトの実行開始から終了までのログをひとつの通知にまとめること」を大前提としています。

HTTPのリクエストを処理し続けるWebアプリケーションのように常駐するプロセスにはそのまま適用はできません。

こうしたアプリケーションではログの出力を随時やらせておいて、一定期間ごとにそのログを集約・通知するスクリプトを別で回します。

「アプリケーション自身に一定期間ごとにログを集約して通知する」みたいな処理を担わせることも不可能ではありませんが、

  • アプリケーション本来の仕事に集中させたい
  • サーバ台数が増えても通知はまとめてやって欲しい

といった理由から切り分けています。

アラートに対する温度感

ログを出力する際のレベル分けは前述のとおりですが、それぞれのレベルのアラートを受けた際には下記のような温度感で動きます。

  • critical
    • すぐに何らかの対応が必要
  • warn
    • 営業時間ベースで何らかの対応をする
  • notice
    • アラートではなく、正常終了の記録を残す目的で使う

上記でいう「対応」とは、全ての問題をその時点で解決することではありません。

「一時的なイレギュラーなのでスルーしていい」とか「明日出社後に対応しよう」といった判断を下すことも立派な対応のひとつです。

アプリケーション以外のアラート

今回のトピックからは少し外れますが、

  • 監視ツールからのアラート
  • cronからのメール

なども同様の運用に乗せています。

cronで実行したスクリプトの標準出力などは内容によって送信先を変えることが出来ないため、原則として全てcritical扱いにします。

そうなると「あれもこれも/dev/nullに捨ててしまおう」という流れになりがちですが、cronジョブの記述においては>/dev/nullは基本的に禁止しています。

「何らかの出力がある時点でそれは想定外の事態であり、アラートとして受け取るべきである」という考えに基づいています。

サービスの維持に必要ではないものや、一時的な実験などでは例外的に記述を認めることもありますが、あくまでイレギュラーであることを意識した上で実施します。

なお、シェルスクリプトの中で個別のコマンドに対して>/dev/nullを設定することは禁止しておらず、Slackにメッセージを流すコマンドも用意しており、そのあたりで柔軟性を確保しています。

運用の勘所

アラート運用において大きな課題は「通知件数が増えると慣れてしまって見なくなる」というものです。

特に警戒すべきは「定常的に発生するwarning」です。

例えばログ集計を実施するスクリプトを例に挙げます。

  • 異常な行があればwarnで記録する
  • その行はスキップして処理を継続する

という実装をしたとしましょう。

開発時に「何かあれば気付けた方がよい」という思いでwarnを発生させたところ、何らかの事情で日常的に異常な行が混ざることが発覚します。

この時に前述の実装をそのままにしておくと、「このスクリプトから来るwarnは無視してよい」といった空気が醸成されてしまいます。

その結果、他の部分で発生したwarnのログに誰も気付かずに問題を放置してしまうといった事態が起こりえます。

様々なアラートに関して言えることですが、狼少年化を防ぐために状況に合わせて異常を検出する閾値を変えたり、出力するログの内容やレベルを見直し続けることが大切です。

言うは易しの典型みたいなもので、年数を経たプロジェクトやチームだとメンバーが慣れてしまって、特にやり取りしなくても「これはスルーでOK」とか「これはいつものやつ」みたいになってしまいがちです。

これに対しては新しくチームメンバーが増えた時がチャンスで、新鮮な視点からの疑問や未知のアラートに対する不安などを忌憚なく話してもらえると見直しのいいきっかけになります。

アラートを見ることでコードを書くだけではない、プロジェクトが生きている様子を実感できたり、新たな課題の発見にもつながるので「アラート受けるの不安だわ」みたいに思わずにあらゆる開発者は積極的にアラートを受けていきましょう。

毎週のように依存パッケージを上げ続ける努力

皆さんこんにちは。fluctにてfluct SSPという広告配信システムの管理画面を中心にクライアントサイドの開発を行っております、大関です。

依存パッケージの更新、どうしてますか?

今や数多くの言語でパッケージマネージャが提供されており、みなさんも日常的にコミュニティによるパッケージエコシステムを活用していることと思います。

ですが、この依存パッケージの更新については、どのようにしていますか? セキュリティfixなどを除き、以下のようなことになっていることが多いのではないでしょうか?

  • チームの「いい人」が頑張って更新し続ける
    • その人の謎の情熱が消えると更新されなくなってしまう
  • たまに気がついたら頑張る
    • 「いい人」が頑張るタイプの亜種
    • 気が付かなかったら更新されない
  • 更新はリスクなので塩漬けにする
    • プロダクトは定期的に作り直す前提
    • CIでテストを回し続けているのに更新しないなんて……とモヤモヤも溜まったりする

日々の運用としては、これで問題ないように見えますが、継続的にサービスを運営する観点から言えば、古いバージョンのパッケージに依存し続けることは以下の様なリスクがあります。

  • コミュニティドリブンのライブラリ・フレームワークは往々にして最新版しかサポートされない
    • バグは最新版で修正されるがバックポートはされるかは別問題
    • 長期メンテナンス版があっても、長期メンテナンス版の最新版を使わないかぎりサポートされない
    • 古いバージョンのドキュメントはアーカイブされずに消えることがある
    • 最新版だと使える機能が使えないことによるフラストレーションの増加
    • 最新版だと直っているバグなのに回避策を考える努力
  • いざ更新しなければならなくなった時の変更の規模は、最新版から離れれば離れるほどに大きくなる

これらを考慮すると、経験則・慣習に依るものではありますが、更新されないパッケージはリスクとなる、と私は考えています。

ですが、チームの「いい人」に任せているだけでは継続しない。自分が「いい人」になっても、自分が燃え尽きたら、それ以降に継続する保証はありません。では、どうすればよいのでしょうか?

対策: 持ち回りで継続的に更新する

依存パッケージの更新にあたって問題となるのは以下の点です.

  • 依存パッケージの更新がたまにしか行われない場合、更新自体のリスクが大きくなる
    • そもそも作業コストが大きくなる
    • 実際に更新する段になって課題を初めて知るので、作業コストが往々にして想定から膨らみやすい
  • 更新が個人の熱量に依存してしまう

つまり、

  • 小刻みに更新し、変化に対応することで、時間の堆積に伴うリスクを減らす
    • 仮に更新できなくても、何が必要かを継続的に収集する
  • チームの定例作業に組み込んで属人性を減らす

ことができれば、更新のコストは軽減できます(CIや自動テストの導入は今や必須なので敢えて言いません)。

そこで私達のチームでは、各チームメンバー交代の当番制で、依存パッケージの更新を行うことをpackage gardeningと呼び、毎週実施することにしました(ネーミングは炭坑の庭師 - steps to phantasienで紹介されていた、当時のChromium Projectの依存先のWebKitのバージョンアップ作業の名前がカッコいいので拝借しました)。

手順

具体的な手順は以下の通りです。これを毎週の始めに作業します。 (npm経由の場合を挙げます)。

1. 初期化

  1. リポジトリから最新のmasterをpullする
  2. セットアップ処理を走らせて、依存のインストール込みで、最新のmasterでの環境を一度再現する
    • rm -rd ./node_modules/ && npm install

2. 古いパッケージの洗い出し

  1. npm outdatedで更新を確認する
  2. 1の結果のうち、「package.jsonに記述されているもの」の更新を確認する
    • release noteやchangelogを見に行く
    • なければコミットログをざっと確認する

3. 更新

  1. ロックファイルを削除する
    • 一度 rm npm-shrinkwrap.jsonする
  2. package.json側の指定を、パッケージごとに更新する
    • 「自分たちは、このバージョンまでは更新内容を確認し、使っている」意志の表明として更新しています
  3. 一通り更新が終わったら、依存パッケージのディレクトリを削除し、再生成する
    • rm -rd ./node_modules/ && npm install
    • 間接依存しているパッケージも込みで依存関係を作り直すため
  4. ロックファイルを再生成し、リポジトリにコミットする
    • 開発用パッケージ込みでロックしたいので npm shrinkwrap --dev します

4. 更新の後始末を行う

  • パッケージの更新の結果、ビルドが通らない場合
    • 直す
    • または更新を諦めて, 専用のissueで対応する
  • パッケージの更新の結果、テストが落ちる場合
    • 直す
    • または更新を諦めて, 専用のissueで対応する
  • パッケージの破壊的変更が多すぎる
    • 頑張って追従する
    • または更新を諦めて, 専用のissueで対応する
  • コードの改善・リファクタリングに使えそうな新機能はissueを作る
    • 基本的には、必須ではなく「気がついたらfileしよう」にしている
    • lintなどコードの健全性に関係するものは、ほぼ必須で回っている

5. pull requestの作成

  • 更新のあった依存パッケージの変更をまとめてpull requestする

6. code reviewで問題がなければmasterにmergeする

マージしましょう

7. チームメンバーへの周知

周知して、次の週に。 お疲れ様でした。

以上を1サイクルとして、毎週回します。

f:id:saneyuki_s:20160624135226p:plain

補足

どのくらい大変な作業なのか?

コードベースや作業に慣れるまでは、0.5~1営業日まるまるかかることも有りましたが、慣れてくると平均して1~2時間程度で1サイクルが終わるようになっています。

パッケージの更新量ってどんなもの?

量としては平均5~10パッケージ程度です。 毎週継続的に更新を続けるので、minorやpatch verの更新が殆どになっています。 これにより、一度に多くの更新を行うのを避けることが出来るようになりました。

パッケージの追加・削除は当番以外できないのか?

さすがに追加・削除にまで当番制を敷くと、開発の上で必要なパッケージの追加・更新ができない

greenkeeper.ioを使わないのはなぜか?(2016年6月27日 16:50 UTC+9に追記)

はてなブックマークのコメントで「greenkeeper.ioを用いていないのは何故か?」という質問が何件か有りましたので、それについて回答します。

もちろん、人力に依存する(努力している)箇所を減らしていきたいのは事実です。 ですが、

  • 「まとめ」にて挙げるように、副次効果としてチームメンバーのコードベースへの理解のトレーニング効果が明らかになったため、現在のところ、それも重視している
  • 更新した結果のパッチ・pull requestの導入の有無をreviewするreviewerをローテーションの効果は薄いと判断した
    • そもそもreviewer役をやる時点で、依存パッケージについて理解が一定度あるという前提なので、ローテーションしてもトレーニングとしては薄い
  • pull requestの作成も確かに手間ではあるが、行っている内容は、バージョンアップの結果として、どのような影響が起こるのかの予測・確認、および既存のコードベースに対して加えることの可能なリファクタリングなどの機会の発見も含んでいるので、更新通知そのものに対しては強い切望があったわけではない
  • npm系パッケージに限らずやっていきたいので、特定のパッケージマネージャの更新のみbot化するのは今のところ避けておきたい
    • 言語が増えるごとに依存するサービスを増やすことになると逆に不便なので避けておきたい
      • monolithic repository構成で、web applicationのserverとclientが別のサブディレクトリに入っている状況でも、依存パッケージを記述したマニフェストファイルを解釈してくれるかがツールごとに別だったりすると更に不便なので慎重にいきたい

という理由にて「導入していない」のが現状での判断になっています(将来的に、チームの練度や人数、スタンスの変化によって導入する判断を下すことはもちろんありえます)。

まとめ

実際に、毎週の更新を行うことで、依存パッケージの更新という作業のリスクが大きく軽減することができました。

開始当初の目的では意図していなかった副次効果として、「サーバー・クライアントなどの専門性・分業はあれども、自分たちの開発しているプロダクトが何に依存して成り立っているのかを認識できる」という副次効果も有りました。

また、依存パッケージの数に対してチームとして責任を持つようになるので、「無闇矢鱈に便利そうなパッケージを追加してしまう」ことに対して慎重になるという効果があったと考えています。

お知らせ

弊社には AJITO という社内バーがあり、毎夜のようにエンジニアが現れ、酒を嗜み、軽食をつまみつつ、エンジニアリング談義を行っています( #ajitingで既にご存知の方も多いと思います)。「私も一緒に(こういう)エンジニアリング談義をしたい!」という方がいらっしゃいましたら、是非とも弊社エンジニア or @tech_voyageに、お声掛けいただければと思います。

また、fluctを含むVOYAGE GROUPアドテクユニットでは、一緒に働いてくださる仲間を募集しております。VOYAGE GROUPや広告配信に興味を持たれましたら、お気軽にご連絡ください。

f:id:saneyuki_s:20160624132725j:plain