足湯で進捗最高! 熱海の温泉旅館おんやど恵さんで開発合宿してきた!

f:id:chocopie116:20170530114420j:plain

風呂グラミングの実績解除した @chocopie116 です。

熱海の温泉宿に開発合宿に行ってきました。 去年立ち上がったばかりのチームに所属するエンジニアメンバー5人で行きました。 開発合宿興味あるけど準備とか大変そう!自分も風呂グラミング実績解除したい!といった方々のご参考になればと思い書きます。

tl;dr

f:id:chocopie116:20170530191952j:plain

  • オフィスから離れた環境で集中できた
  • 美味しいゴハンと温泉で最高にリフレッシュできた
  • 思ってたより近い(都内から宿までドア・ツー・ドアで1時間半)

スケジュール

f:id:chocopie116:20170531192625j:plain おおまかには以下のようなスケジュールで進めました。

5/29(月)

  • 10:30~11:40 移動(渋谷〜熱海)
  • 11:40~13:00 昼食 & 宿への移動(熱海駅〜宿タクシーで20分)
  • 13:00 宿にチェックイン
  • 13:00~ 18:30 開発タイム
  • 18:30~ 宿の夕食・入浴

5/30(火)

  • 8:00 朝風呂
  • 8:30 宿の朝食
  • 9:30~13:00 開発タイム
  • 13:00~14:00 昼食(外出)
  • 14:00~19:30 開発タイム
  • 19:30~ 宿の夕食・入浴

5/31(水)

  • 8:00 朝風呂
  • 8:30 宿の朝食
  • 9:30~12:00 開発タイム(チェックアウト後も使える)
  • 12:00~13:30 (宿~熱海駅でタクシー)

利用した宿について

f:id:chocopie116:20170531185440j:plain

今回 おんやど恵さんの開発合宿プランを利用させていただきました。

www.onyadomegumi.co.jp

  • ネットワーク快適(無線)
  • 足湯(24h利用可能)
  • 鍵付き会議室の貸出(24h利用可能)
  • 温泉(24h利用可能)
  • ケーブル類(電源タップ等 無料)・サブディスプレイ(27インチ オプション)貸出
  • 施設とてもきれい

オーナーさんがソフトウェアの開発者から旅館経営に転身されたキャリアをお持ちのようで細かな気配りが嬉しかったです。 PCと、PCの充電器しか持っていきませんでしたが、快適な環境で開発をすることができました。

開発合宿について

f:id:chocopie116:20170529120954j:plain

今回合宿でやることは、事前にGitHub issueにまとめておき、当日は簡単な作業のゴールだけ共有した上で作業に着手できました。 各々新規機能開発を進めたり、リファクタリングを進めたり、認証機能のマイクロサービス化の検証をする等もくもくしていました。
いつもより目の前の作業に集中できる分疲れを感じることもありましたが、さっと足湯につかってリフレッシュして作業に戻れるのは個人的にポイント高かったです。

オフィスに足湯ほしい気持ちが高まりました。

まとめ

温泉旅館での開発合宿は控えめにいって最高でした。
合宿で集中して頑張っておいでと快く送り出してくれたチームのメンバーに感謝です。
またオフィスを抜け出して、風呂グラミングで最高な進捗を出していきたいです。

VOYAGE GROUPで利用されているプログラミング言語のトレンドを調べてみた

こんにちは。株式会社ZucksでZucks Ad Networkの開発に携わっている南大津です。

エンジニア採用の募集事項に「業務で使われている言語」がよくありますが、どの言語がどれくらい使われているかは、入社前にはなかなか把握し難い部分ではないでしょうか。
そこで今回は、VOYAGE GROUPで開発に利用されているプログラミング言語のトレンドについて調べてみたので、ご紹介できればと思います。

ソースコード管理について

VOYAGE GROUPでは多くの子会社、サービスが存在していますが、そのほとんどのソースコードはvoyagegroupという1つのGitHub Organizationアカウントで管理されており、現在約400個のリポジトリが作成されています。

私が入社した2009年頃には、ソースコード管理といえばSubversionがメインでした。
その後徐々にGitHubでソースコード管理を行うサービスが増えていったのですが、当初は主に子会社毎にOrganizationアカウントを作成して利用していました。子会社毎にOrganizationアカウントが分かれていると、グループ会社間で知見が広まりづらかったり、アカウント管理を個別に行う必要があったりするため、1つのOrganizationアカウントに統一する流れが起き、今の形に落ち着いています。

今回はこのvoyagegroup Organizationに登録されているソースコードから、VOYAGE GROUPにおけるプログラミング言語の利用状況について調査してみます。*1

最近のトレンドを調べてみる

GitHubにはリポジトリで利用されている言語の割合(バイト数による算出)を表示してくれる便利機能が存在しています。

f:id:smileeeen:20170515194305p:plain

上記のようにリポジトリのステータスバーに表示されているもので、クリックをすると言語ごとの割合が確認できるようになっています。

GitHubでこの情報の算出に使われているライブラリがLinguistという名前で公開されているので、こちらのコマンドラインツールを使ってみます。

github.com

$ git-linguist --help
    Linguist v5.0.10
    Detect language type and determine language breakdown for a given Git repository.

    Usage:
    git-linguist [OPTIONS] stats|breakdown|dump-cache|clear|disable"
    -f, --force                      Force a full rescan
    -c, --commit=COMMIT              Commit to index

git管理されているディレクトリ上で、 git-linguist stats コマンドに特定のコミットハッシュ値を渡すとその時点における言語別容量を返却してくれます。
現在と過去のある時点での言語別容量を比較すれば、最近よく使われている言語の傾向が見えないかなと考え、2017年になってからのvoyagegroup Orgnizationにおける言語別容量の増減を調べてみました。

GitHub APIの呼び出しにはphp-github-apiを利用させていただきました。

github.com

調査に利用したソースコードは下記になります。*2

<?php

require_once 'vendor/autoload.php';

$orgName        = 'voyagegroup';
$diffTargetDate = '2017-01-01T00:00:00Z';
$tmpDir         = '/tmp/techlog';

$client = new Github\Client();
$client->authenticate('【SET ACCESS TOKEN】', null, Github\Client::AUTH_HTTP_TOKEN);

$paginator = new Github\ResultPager($client);
$orgApi    = $client->api('organization');
$repoApi   = $client->api('repo');

$allRepoLangsDiff = [];

foreach ($paginator->fetchAll($orgApi, 'repositories', [$orgName]) as $repo) {
    if (!shouldAggregateRepo($repo)) {
        continue;
    }

    $repoName = $repo['name'];

    $headCommitHash = getLatestCommitHash($repoApi, $orgName, $repoName);
    $pastCommitHash = getLatestCommitHash($repoApi, $orgName, $repoName, ['until' => $diffTargetDate]);

    if ($headCommitHash === $pastCommitHash) {
        continue;
    }

    exec(sprintf(
        'cd %s && git clone --single-branch -n git@github.com:%s/%s.git',
        $tmpDir,
        $orgName,
        $repoName
    ));

    $repoLangsDiff = getRepoLangs($tmpDir, $repoName, $headCommitHash);

    if ($pastCommitHash) {
        $negPastRepoLangs = array_map(function ($v) {
            return -$v;
        }, getRepoLangs($tmpDir, $repoName, $pastCommitHash));

        $repoLangsDiff = sumRepoLangs($repoLangsDiff, $negPastRepoLangs);
    }

    exec(sprintf('rm -r %s/%s', $tmpDir, $repoName));

    $allRepoLangsDiff = sumRepoLangs($allRepoLangsDiff, $repoLangsDiff);
}

function shouldAggregateRepo($repo)
{
    return $repo['size'] > 0
        && !$repo['fork']
        && preg_match('/\A[-.\w]+\z/', $repo['name']) === 1;
}

function getLatestCommitHash($repoApi, $orgName, $repoName, $condition = [])
{
    $commits = $repoApi->commits()->all($orgName, $repoName, $condition);
    return $commits ? $commits[0]['sha'] : '';
}

function getRepoLangs($tmpDir, $repoName, $commitHash)
{
    exec(
        sprintf(
            'cd %s/%s && git-linguist -c %s stats',
            $tmpDir,
            $repoName,
            $commitHash
        ),
        $linguistOutput
    );
    return $linguistOutput ? json_decode($linguistOutput[0], true) : [];
}

function sumRepoLangs($langs, $addLangs)
{
    return array_map(function ($row) {
        return array_sum((array)$row);
    }, array_merge_recursive($langs, $addLangs));
}

// check $allRepoLangsDiff

結果は以下のようになりました。*3

増加している言語
rank 言語 容量変化(MB)
1 Jupyter Notebook 16.2
2 Python 4.0
3 C# 3.5
4 C 2.4
5 C++ 1.3
6 Ruby 1.0
7 Objective-C 0.7
8 CoffeeScript 0.5
9 Go 0.4
10 Scala 0.3
11 ShaderLab 0.3
12 Smarty 0.3
13 TypeScript 0.3
14 Shell 0.3
15 Makefile 0.2
16 HCL 0.2
17 Puppet 0.1

1位のJupyter Notebookに関してはZucks Ad Networkの解析チームで活用しており、純粋なコード量が多いというよりは、Base64エンコードされた画像ファイルもソースコードの容量として含まれている場合があるため、割合が多くなっていると考えられます。
最近ではPythonが人気のようですね。
3位にランクインしたC#はVR室で開発しているUnity製のアプリがメインでした。

減少している言語
rank 言語 容量変化(MB)
1 PHP -8.2
2 HTML -5.3
3 Perl -5.2
4 JavaScript -3.7
5 CSS -3.0
6 Perl6 -0.4
7 Java -0.1

PHPが減っているのはちょっと意外だったので詳しく見てみると、一部のリポジトリで他リポジトリに分割済みのソースコードの削除作業が行われていました。
このリポジトリの増減を除くと、全体で減少していると判定されていた言語の増減は下記のようになりました。

言語 容量変化(MB)
JavaScript 4.0
PHP 1.1
CSS 0.4
Perl6 0.0
HTML -0.6
Perl -0.5
Java -0.1

JavaScriptは増加の2位タイ、PHPは6位というのが実態により近い値のようです。

プログラミング言語別割合の算出

折角なので、GitHub APIのList Languages APIを使ってVOYAGE GROUP全体でのプログラミング言語別割合も集計してみます。

調査に用いたソースコードは下記になります。

<?php

require_once 'vendor/autoload.php';

$orgName = 'voyagegroup';

$client = new Github\Client();
$client->authenticate('【SET ACCESS TOKEN】', null, Github\Client::AUTH_HTTP_TOKEN);

$paginator = new Github\ResultPager($client);
$orgApi    = $client->api('organization');

$totalLangs = [];

foreach ($paginator->fetchAll($orgApi, 'repositories', [$orgName]) as $repository) {
    $repoLangs  = $client->api('repo')->languages($orgName, $repository['name']);
    $totalLangs = array_map(function ($row) {
        return array_sum((array)$row);
    }, array_merge_recursive($totalLangs, $repoLangs));
}

// check $totalLangs

上記を用いて、voyagegroup Orgnizationに存在する全リポジトリの情報を合算してまとめたものが下記になります。*4

rank 言語 容量(MB) 割合(%)
1 PHP 219.9 27.84%
2 HTML 92.1 11.66%
3 Jupyter Notebook 89.2 11.29%
4 Perl 64.7 8.20%
5 JavaScript 64.0 8.10%
6 Python 59.7 7.56%
7 Java 29.4 3.72%
8 CSS 28.6 3.62%
9 Makefile 25.9 3.28%
10 Objective-C 23.3 2.94%
11 Ruby 18.1 2.29%
12 C 16.6 2.10%
13 C++ 16.1 2.03%
14 Smarty 6.7 0.85%
15 ActionScript 6.7 0.85%
16 C# 5.6 0.71%
17 Scala 3.5 0.44%
18 Tcl 2.5 0.31%
19 Perl6 2.3 0.29%
20 Shell 2.0 0.26%
21 Swift 1.9 0.24%
22 Go 1.7 0.22%
23 TypeScript 1.3 0.17%
24 Erlang 0.9 0.12%
25 R 0.8 0.10%
26 Roff 0.8 0.10%
27 CoffeeScript 0.7 0.09%
28 GLSL 0.7 0.09%
29 PLSQL 0.7 0.09%
30 Objective-C++ 0.5 0.07%
31 Kotlin 0.5 0.07%
32 ApacheConf 0.3 0.04%
33 Scheme 0.3 0.04%
34 Protocol Buffer 0.3 0.04%
35 Puppet 0.3 0.03%
36 HCL 0.2 0.03%
37 XS 0.2 0.02%
38 XSLT 0.2 0.02%
39 Groovy 0.1 0.02%
40 Vue 0.1 0.01%

色々な言語が使われていますが、結果としてはPHPが断トツの割合を占めていました。
調査前、私もPHPが20%くらいで一番多いかなと想像していたのですが、予想を上回る27%超えとなりました。
10年以上続いている弊社のメディアECナビがメインでPHPを利用しているなど、PHPを利用しているサービスが多いためだと考えられます。

3位のJupyter Notebookの容量が大きくなりがちなのは前述の通りです。

その他ではPerl、JavaScript、Python、Javaといった辺りがVOYAGE GROUPでは人気があるようです。最近のトレンドから考えるとそろそろPythonがPerlを抜き去りそうですね。
個人的にはMakefileが3%を超えてトップ10入りしているのも、VOYAGE GROUPらしいのかなと感じるところでした。(参考:プロビジョニングツールはMakeで決まりだろ // Speaker Deck

おわりに

最近のトレンドに関しては差分確認期間中に削除されているコードも存在するため、正確には分かりづらい部分がありましたが、少しはVOYAGE GROUPで利用されているプログラミング言語の実態を感じていただけたでしょうか。また1年後には状況が大きく変化しているかもしれません。

皆さんの周りではどういった言語が使われているでしょうか。
この言語をVOYAGE GROUPで広めていきたい!といった想いの方がいらっしゃいましたら是非採用エントリーをお待ちしています。 voyagegroup.com

*1:一部の古くからあるサービスなど、現在でもSubversionを利用しているものや、子会社ごとのGitHub Organizationアカウントで管理されているものもわずかに存在しますが、今回は調査の対象外とします

*2:GitHub APIとgit-linguistコマンドでは、言語判定が若干異なるケースがあるようだったので、直近の言語別容量もgit-linguistを利用して取得しています。

*3:容量変化が±0.1MB未満のものは表から除外しています

*4:容量が0.1MB未満のものは表から除外しています。サードパーティ製のソースコードは一般的なパスにあれば除外されているようですが、含まれているものもあるかもしれません

ErgoDox EZのキースイッチが家にあるもので何とか交換できた話

どうも世界60億超のErgoDoxファンの皆さんこんにちは。@tamakiii です。

ErgoDox EZを使い始めてはや一年。これまで何の不調もなく健康なプログラミングライフを助けてくれてきたキーボードですが、ここに来てちょっとした不調に遭遇しました。今回はそのときの出来事について書こうと思います。

ちなみに、VOYAGE GROUPには好きなキーボードを経費精算できる制度があります。HHKBが人気みたいですが、Sculpt Ergonomic KeyboardMistel Barocco なんかを使っている人もいるようです。

f:id:tamakiii:20170419185254p:plain

tl;dr

  • ある日突然 “b” キーがなかなか打てなくなった
  • キーリピートも効かない
  • 基盤の問題ではなかった
  • 使用頻度の低いキーのキースイッチと交換した
  • 本体を分解しなくてもなんとかなった
  • 専用の器具がなくてもなんとかなった

出来事

問題は上に書いたような感じです。前日まで一切兆候がなかったのでビビりました。 ”b” キーは使用頻度が高いので非常に困りました。

当然、他のPCに繋いだりケーブルを替えてみたりしましたがどれもダメ。どうやらキーそのものに問題がありそうだという事で検索してみたところ、こちらのページを発見しました。

ErgoDox の壊れたキースイッチを交換する - Okapies' Archive http://okapies.hateblo.jp/entry/2016/12/03/010105

通常、キースイッチの交換には専用の工具が必要らしいのですが、こちらのページではバインダークリップを使った方法が紹介されていました。 が、残念ながら家にあったバインダークリップはどれも大きめで、上手く行きませんでした。そこで家にあったもので何とかならないか思考錯誤してみましたら、なんとかなったのでした。

用意するもの

f:id:tamakiii:20170419132433p:plain

  • 毛抜き(キーキャップを外す用)
  • ピンセット(キースイッチを外す用)
  • 適当な細い棒(作業補助用/クリップやドライバーなど)

やること

使用頻度の低いキーとキースイッチを交換(暫定措置) f:id:tamakiii:20170419132913p:plain

作業開始

(言うまでもありませんが、以下の作業は自己責任でお願いします)

f:id:tamakiii:20170419014104j:plain 用意した毛抜きでキーキャップを外して行きます。専用の引き抜き工具がなくても割と何とかなります。作業の邪魔になるので、対象の左右のキーキャップも外します。

f:id:tamakiii:20170419014209j:plain 左右も外した様子。四つ角に穴が空いているのが見えます

f:id:tamakiii:20170419014237j:plain 四つ角の穴のひとつにこんな風にピンセットを差し込んで、外側に押し込んでやるとツメが外れます。写真は左ふたつのツメを外したところ

f:id:tamakiii:20170419014301j:plain このまま右側ふたつを外そうとすると、左側のツメが元に戻ってしまうので、適当な細い棒を左側に差し込んでおきます

f:id:tamakiii:20170419014334j:plain 差し込んだ棒を抑えながら、右側のツメを外すと

f:id:tamakiii:20170419014444j:plain このように外れました   (゚∀゚)ラヴィ!!

f:id:tamakiii:20170419014504j:plain 中はこのようになっていて、金色の電極部分は基盤にはんだ付けされているそうなので、これを壊さないように注意が必要です

f:id:tamakiii:20170419014545j:plain 外したキースイッチはこんな感じ

f:id:tamakiii:20170419014602j:plain 挿げ替え対象も同様に外して、あとは戻すだけで作業完了です

おわりに

f:id:tamakiii:20170419014858j:plain あまり需要のない記事でしたが、私自身けっこう困ったので、そのうち同じような状況になってしまった人の役に立てたら何よりです。

では。

分子に1を足し、分母に2を足すだけで予測が良くなる話

コインを投げを観測し、コインの表になる確率を予測するとき、みなさんはどのように予測するでしょうか。 (コイン投げに限らず、表か裏のように二値になるような予測であれば、例えば、広告のクリック率や、単語の出現率、ナンパの成功率でもなんでもいいです。)

コインが表になる確率が0から1まで一様だ(まんべんなく出る)とすれば、n回投げてs回表を観測したら、平均であるs/nをその確率として予測するのではないでしょうか。

この方法をもっと複雑な言い方をすれば最尤推定(maximum likelihood; ML推定)とよびます。コインが表になる確率が一様という事前確率まで分かっている前提ならば、これは最大事後確率推定(maximum a posteriori estimation; MAP推定)ともいえます。なんか最強っぽいですよね。

他に方法があるのでしょうか。スムージングという方法もあります。スムージングの中でも最も単純なのが ラプラススムージング とよばれる方法です。最尤推定の式の分子に1を加算して、分母に2を加算する方法です。

シミュレーションで確認

ではどちらがいいのでしょうか? 実際にシミュレーションして確認してみましょう。

以下のプログラムではまず真の確率 p を求めておき、そのpの確率に基づきn回コイン投げをして、その観測に基づき、最尤推定とスムージングによる推定をするようになっています。そして真の確率 p と答え合わせをします。最尤推定の方が近かった場合には+1を、あいこだった場合には+0.5をします。このゲームをt回繰り返し、最終的に最尤推定の勝率を表示します。

import random

# --------------- 初期設定
t = 100000 # 確率あてゲーム回数
n = 3    # コイン投げ数
a = 0.01  # スムージングパラメータ(分子)  
b = 0.02  # スムージングパラメータ(分母)

# --------------- 最終結果用変数初期化
win_sm = 0   # ラプラススムージングが勝った回数
sum_ml = 0.0 # 最尤推定の誤差の合計
sum_sm = 0.0 # スムージングの誤差の推定

# --------------- 確率あてゲーム(t回繰り返し)
for i in range(t):
    p = random.random() # 真の表(おもて)の確率
    
    # ------------ コイン投げによる施行
    s = 0  # 表(おもて)の回数を初期化
    for j in range(n): 
        if p > random.random(): # 乱数が真の表の確率以下なら
            s += 1              # 表になる
    
    # ------------ 推定 
    ml = float(s)/n   # 最尤推定
    sm = (s+a)/(n+b)  # スムージングによる推定
    
    # ------------ 結果判定
    diff_ml = (p-ml)**2   # 最尤推定の二乗誤差
    diff_sm = (p-sm)**2   # スムージングの二乗誤差
    if diff_sm < diff_ml:    # ラプラススムージングの誤差のほうが小さければ、
        win_sm += 1          # ラプラススムージングの勝ち++
    elif diff_ml == diff_sm: # 同じならばあいこ
        win_sm += 0.5        # あいこのときは +0.5
    sum_ml += diff_ml # 最尤推定の二乗誤差を集計する
    sum_sm += diff_sm # スムージングの二乗誤差を集計する

    # ------------- 表示 (デバッグ用)
    if t <= 50:
        print "s/n: %d/%d, p: %f, ml: %f, sm: %f" % (s, n, p, ml, sm)

# ---------- 最終結果表示
win_sm_rate = float(win_sm)/t
diff_ratio = sum_sm/sum_ml
print "win sm rate: %f, sum_sm/sum_ml: %f" % (win_sm_rate, diff_ratio)

実行結果

s/n: 0/3, p: 0.046582, ml: 0.000000, sm: 0.200000
s/n: 2/3, p: 0.526964, ml: 0.666667, sm: 0.600000
s/n: 2/3, p: 0.420249, ml: 0.666667, sm: 0.600000
s/n: 2/3, p: 0.259805, ml: 0.666667, sm: 0.600000
s/n: 1/3, p: 0.387191, ml: 0.333333, sm: 0.400000
s/n: 1/3, p: 0.187301, ml: 0.333333, sm: 0.400000
s/n: 1/3, p: 0.530644, ml: 0.333333, sm: 0.400000
s/n: 1/3, p: 0.072210, ml: 0.333333, sm: 0.400000
s/n: 3/3, p: 0.968749, ml: 1.000000, sm: 0.800000
s/n: 0/3, p: 0.224703, ml: 0.000000, sm: 0.200000
s/n: 0/3, p: 0.053139, ml: 0.000000, sm: 0.200000
s/n: 0/3, p: 0.184094, ml: 0.000000, sm: 0.200000
s/n: 0/3, p: 0.108546, ml: 0.000000, sm: 0.200000
s/n: 2/3, p: 0.509613, ml: 0.666667, sm: 0.600000
s/n: 3/3, p: 0.284755, ml: 1.000000, sm: 0.800000
s/n: 0/3, p: 0.009353, ml: 0.000000, sm: 0.200000
s/n: 1/3, p: 0.500349, ml: 0.333333, sm: 0.400000
s/n: 1/3, p: 0.044538, ml: 0.333333, sm: 0.400000
s/n: 0/3, p: 0.080180, ml: 0.000000, sm: 0.200000
s/n: 0/3, p: 0.471813, ml: 0.000000, sm: 0.200000
win sm rate: 0.600000, sum_sm/sum_ml: 0.693820

最後の win sm rate: 0.600000 が最尤推定の勝率を表しています。ゲームの回数 t が20回というのはちょっと少ないので何度も実行するとこの勝率はかなり大きく変化します。そこでゲームの回数を思い切って t = 100000 くらいに設定してみましょう。

win sm rate: 0.597200, sum_sm/sum_ml: 0.595932

ラプラススムージングの勝率は6割程度もあるようですね。なんと、分子に1を足して、分母に2を足すというラプラススムージングの方が良いのです。

コイン投げを3回しか観測していないから悪いんじゃないか、という話もあります。ではコイン投げの回数nを20まで増やしてみましょう。

win sm rate: 0.529480, sum_sm/sum_ml: 0.911000

ラプラススムージングの勝率はかなり0.5に近づきましたが、まだ勝っていますね。では1000まで増やしてみましょう。(ちょっと時間がかかります)

win sm rate: 0.502880, sum_sm/sum_ml: 0.998269

ラプラススムージングの勝率はほとんど0.5に近づきましたが、まだ勝っていますね。実際1000回もチャンスをくれることというのもないかもしれませんが…。

分子に1を足して分母に2を足すだけで、予測が良くなってしまう、そんなお話でした。

なぜなの

最尤推定や最大事後確率推定では、最も尤度が高い確率を選んだにも関わらず、分子に1を足して分母に2を足すだけのラプラススムージングに負けてしまいました。この敗因は、最も高いところだけしか見ていないこと にあります。

次のグラフは、コイン投げで、表が1回、裏が4回のときのβ分布です。

f:id:nakano-tomofumi:20170407144144p:plain

最尤推定である、1/5 = 0.2 のところで最大となっていますが、面積的にはどうでしょうか? 0.2より大きい確率(右側)の方がずっと広いことがわかります。

尤度で重みを付けたpの期待値を求めてみましょう。

f:id:nakano-tomofumi:20170407152830p:plain

分母には重みである尤度の合計を持ってきています。分母と分子の二項係数は共にキャンセルされるので、消してあります。

これを maxima で解いてみましょう。

(%i1) beta_expand:true$

(%i2) integrate(p*p^s*(1-p)^(n-s),p,0,1)/integrate(p^s*(1-p)^(n-s),p,0,1);
Is s + 2 positive, negative or zero?

positive;
Is s - n - 1 positive, negative or zero?

negative;
WARNING: redefining MAXIMA::SIMP-UNIT-STEP in DEFUN
WARNING: redefining MAXIMA::SIMP-POCHHAMMER in DEFUN
Is s + 1 positive, negative or zero?

positive;
                                     s + 1
(%o2)                                -----
                                     n + 2

s や n に関して質問がありますが、なんと、ラプラススムージングが出てきました。ラプラススムージングは期待値だったのです。

まとめ

分子に1分母に2を足そう。

最も大きいところだけでなく、全体を見渡そう。

補足

事前確率について一様な場合について議論しました。一般的に事前知識に関して全く知識がない場合には無情報事前分布としてこのような一様分布を仮定します。

一方で、CTRって1%くらいだよね、とか、ナンパって全然成功しないよね、とか、今回の検証ケースではないにしても、他の情報にてある程度分かっている場合もあります。そのときには、共役事前分布を仮定して、経験ベイズ(エビデンス近似;第二種の最尤推定)といった方法で、ラプラススムージングにおける1と2に変わるパラメータ(超パラメータ;ハイパーパラメータ)を求めることを行います。二項分布に関して経験ベイズ法で超パラメータを抽出した話は下記の資料を御覧ください。

www.slideshare.net

このような技術を、fluct (SSP) ではアドネットワークを選択するバンディットアルゴリズムのパラメータに利用したり、fluct Direct Reach (DSP)では広告枠毎のCVRの予測のためのパラメータや、オーディエンスの属性推定などのパラメータとして利用しています。

まとまってない文章を晒すのに抵抗があったけど、メモを垂れ流したら仕事がうまく回りだした件について

Zucks Ad Networkでデータ解析をしています、@yuu_itoです。

気づいたら3月も半ばですね。花粉で目がしょぼしょぼします。

メモを取ることについて書いていきます。

きっかけ

技術調査のために論文を集めGoogle Docsにまとめていた時、 とりあえずまとめた後に共有しますねと連絡したら、 メモはGitHub Issueへのコメントで書いておいたら?というのが始まり。

f:id:u110:20170313092305p:plain

やってみて気づいたこと

まとまっていない状態の文章を晒すことに抵抗があったのですが、やってみると嬉しいことがありました。

1. Issueに気づいた人がコメントをくれる。

弊社ではGitHubとSlackを連携してIssueの更新をSlackに通知しています。 取り組んでいること、考えていることを書いていると

  • 「なんかデータの傾向がイメージと違った」→「それ~だからかも」
  • 「計測しているデータ、不要なものも含まれている」→ 「あ、それ実はこっちのテーブルが~」

のように、気づいた人からコメントをもらえました。 メモのひとつが小さいと何か言えそうな人のコメントもしやすいと思います。

経過がSlackに流れていることでチームメンバーが自分のやっていることを知っているので 次のアクションについて話しても説明が不要だったりしました。 (まとめるとはなんだったのか)

2. 経過がわかるので迷走したら振り返ることができる。

本当にこれはよくあることなのですが、のめり込みすぎて「結局何したかったんだっけ?」という状態に陥っても そのとき考えていること、疑問に思っていたことなども含めてメモに書いておくと 今までの作業の流れをはっきりを振り返ることができ、どの時点で問題があったのか気づくことができました。

f:id:u110:20170313092315p:plain

まとめ

  • 経過がわかるようにメモを書き出しておくと良いことがある。
  • 人に見えるとこに書いておくと、ヒントをもらいやすい。
  • 方針に迷ったり、悩んでるときこそ、考えていることを書き起こすと良い。

たまにSlackのチャンネルはメモがずっと並んでしまいますが、 自分の所属するチームでは許容してもらえてると認識しています。

インフラチームと開発チームの垣根をなくすためにAWSのCI環境を構築した話

こんにちは、VOYAGE GROUP システム本部の @s-tajima です。

PHPカンファレンス2016 の「老舗メディアが改善に取り組んでいる話」でもお話した通り、長年オンプレミス環境で稼働してきたECナビを、AWSに移転しようというプロジェクトが進行しています。

そしてなんと先日、約24時間のメンテナンスを経てECナビの本体(Webサーバ, 管理画面サーバの一部, データベースサーバ)がAWSに移転しました!

AWS移転において得た知見, 構築したシステム等は数多くありますが、今回はCloudFormationとTravis CIを用いて 生産的安全手軽 なAWSのCI環境を構築したお話です。

背景

ECナビは、500万人を超える会員を抱えたVOYAGE GROUPが運営している中でも特に大きなメディアの1つです。
今回、そんなECナビのインフラ調達期間の削減、検証環境構築の簡易化、レガシー環境からの効率的な脱却等、ユーザーさんに価値を届けるスピードを加速させるための施策の1つとしてAWSに移転することを決めました。

17年もの長い期間オンプレミスで稼働してきたシステムのため移転に必要な作業は数多くあり、その中の一作業であるAWS環境の構築 だけに それほど大きな手間を掛けるわけにはきません。

このような背景を考慮して、ECナビのAWS環境の構築は

  • ユーザーさんに価値を届けるスピードを加速させるという目的を阻害しない 生産的 な環境
  • 多くのユーザーさんを抱えるメディアとしてそれに見合った 安全 な環境
  • 大きな手間をかけず 手軽 に実現できる環境

を目指して進めようと考えました。

生産的な環境 とは

オンプレミス環境での運用時、よく見られた光景が

  • ECナビ開発チーム「新しいサーバー使いたいわ。インフラチームさん用意してー。」
  • インフラチーム「はいはい。でもちょっと忙しいから来週まで待ってね。」
  • ECナビ開発チーム「(う、サーバーがもらえないと先にすすめない。。)」

というものです。 ECナビ開発チームのメンバーからすると、 自分でコントロールのできない待ち時間となり、時間のロスが発生してしまっています。

このようなやり取りは、弊社以外でも多く見れるかと思います。
オンプレミス環境で運用していると、データセンターの運用や物理機器の調達等を特定のチームで担当したほうが効率がよい場面が多く、自然とこのような分業が進んでしまうのかと思います。

AWSに移転した後、さきほどのやりとりが

  • ECナビ開発チーム「新しいEC2インスタンス使いたいわ。インフラチームさん用意してー。」
  • インフラチーム「はいはい。でもちょっと忙しいから来週まで待ってね。」

となってしまうとオンプレミス時代のような時間のロスがそのまま残ってしまいます。
本来はECナビ開発チームのメンバーが新しいサーバーを使いたくなった時には、待ち時間なく自ら環境を作成できるようになるとよさそうです。

今回はこのような時間のロスをせずに済む生産的な環境を目指しました。

安全な環境 とは

では、前述のような生産的な環境を実現するために、単純にメンバーみんなに権限だけ渡して
各自の好きなようにAWSリソースの操作をしてもらうようにして終わりでよいでしょうか?

もちろんこのようなやり方でうまくいく場合もあるかと思いますが、 そのような環境では、

  • オペレーションミスによって本番用のEC2を誤ってターミネートしてしまった。
  • いつの間にか本番用のRDSがインターネットのどこからでもアクセスできるように設定されてしまっていた。
  • 設定した経緯がわからず、不要だと判断し削除したSecurityGroupの接続許可設定が、
    実は使われている頻度は少ないがとても重要なものだった。

といった事故が起きてしまう心配が残ります。

ここまで極端な例はなかなか起きないとしても、 多くの人が好き勝手にAWSリソースを操作でき、その変更内容の管理ができていないような環境では多くのユーザーさんを抱えるメディアとしてそれに見合った安全な環境を提供できてるとは言えないと考えました。

理想としては、

  • AWSリソースの操作はレビューを通してから行う
  • AWSリソースの操作があったタイミングで通知を行う
  • AWSリソースの操作の内容は記録に残し、後から履歴や経緯を追える

ということができるような安全な環境を目指しました。

手軽に実現できる環境 とは

ここまでの要件を満たせるような環境は、サーバーを用意し、便利なツールを導入し、さらに必要であれば自らコードを書くことで(つまり時間さえかければ)いくらでも実現できるでしょう。

しかし、自前でこのような環境を用意しようとすると権限管理、バックアップ、冗長化、監視等、障害時の対応等、本当に必要だった要件に加えて考えなければいけないことが次から次へと出てきます。

このあたりを可能な限りマネージドサービスにまかせてしまうことで、手軽に環境が用意できることを目指しました。

実現方法

ここまでの要件を満たすために、今回はこのような環境を構築しました。

f:id:s_tajima:20170217133520p:plain

この構成では以下のような流れでAWSリソースを操作します。

  1. GitHubで管理されたCloudFormationのテンプレートを修正し、Pull Requestを作成 (作業者)
  2. Pull Requestの作成/更新をフックにビルドを実行 (Travis CI)
    • 2.1 ValidateTemplateを実行
    • 2.2 CreateChangeSetを実行
  3. Pull Requestの内容とChangeSetの内容をレビュー (レビュアー)
    • 問題がなければLGTM
    • 問題があれば指摘して2からやり直してもらう
  4. ExecuteChangeSetを実行 (作業者)
    • 4.1 CloudFormationがAWSリソースを操作
  5. AWSリソースの変更結果を通知 (CloudFormation -> Lambda -> Slack)
  6. 変更の結果を確認 (作業者 or/and レビュアー)
    • 問題がなければ次に進む
    • 問題があれば2からやり直し
  7. Pull Requestをマージ (作業者)

いくつかのポイントを説明します。

まず1つ目のポイントは、AWSリソースの操作にCloudFormationを使い、そのテンプレートをGitHubのリポジトリで管理している点です。 このリポジトリには、弊社のメンバーであれば誰でもPull Requestを送ることができます。 そのため、必要だと思ったメンバーが自らテンプレートを書き、それを適用することですぐに必要なリソースを構築することができるようになっています。

変更作業の前にPull RequestやChangeSetのレビューを受けることで、意図しない変更や経緯のわからない変更がされてしまうことを防ぎます。

ChangeSet(変更セット)についてはこちらに詳しく記載してあります。
https://aws.amazon.com/jp/blogs/news/new-change-sets-for-aws-cloudformation/

また、CloudFormation操作の通知はSlackに飛ばされるようになっていて、もちろんCloudTrailもAWS Configも有効にしてあります。
このように、 生産的安全 な環境を実現しました。

2つめのポイントは、Travis CIを利用している点についてです。 これは言うまでもなく 手軽 にCIの環境を手に入れるための手段です。 しかしそれだけではなく、Travis CIを 安全 に利用するための工夫をしています。

Travis CIに登録してあるIAMユーザーの権限は、 ValidateTemplate, CreateChangeSet に限定しています。
そのため、もし仮にTravis CIからIAMのクレデンシャル情報が漏れてしまっても、その情報だけでは ExecuteChangeSet を実行できないためAWSリソースを自由に操作することはできません。

また、テンプレートを編集できるメンバーは ExecuteChangeSet と必要なリソースの参照の権限しか持ちません。
CreateChangeSet の実行をTravis CIからのみに絞ることで、本CIフローから外れたAWSリソースの操作が行われてしまうのを防いでいます。

まとめ

以上、CloudFormationとTravis CIを用いた 生産的安全手軽 なAWSのCI環境の構築のお話でした。

冒頭の自己紹介の通り、僕はシステム本部所属のインフラチームのメンバーなのですが、PHPカンファレンスの資料にあるような交換留学の一環で現在はECナビの開発チームのメンバーと共にECナビの環境改善に全力を注いでいます。
今回の話もインフラチームと開発チームの垣根をなくすためのとてもよい施策になったと思っています。

お知らせ

現在、(ECナビを含む)メディア領域、システム本部ではそれぞれ一緒に働く仲間を募集しています。

どちらのチームにも、まだまだ解決したい課題がたくさんあります。
ご興味のある方はぜひお気軽にご連絡ください。

#再演 します。「エンジニアの技術力評価は難しい? - 5年間運用してきた技術力評価制度の改善の歴史 ‒」現役の評価者/被評価者も参加予定!

こんにちは、月日が経つのは早いものでCTO歴が6年半を越えたmakogaです。

ご縁があり、今年の1/12(木)にRegional SCRUM GATHERING Tokyo 2017で登壇しました。内容はエンジニアの技術力評価を5-6年掛けてどう改善してきたかです。

翌日スライドを公開したところ、多くの方に見てもらえ、はてブTwitterなどでたくさんのコメントもいただきました。

コメントを読むと、さまざまな考え方があると感じます。また、当日の懇親会や後日会った方との意見交換はとても楽しいものでした。今後も技術力評価会を改善していくにあたり、もっとたくさんの方と意見交換していきたいと思い、今回 #再演 イベントを開催することにしました。

また、当日の質疑応答では「うちでやろうとすると、評価するのを嫌がるエンジニアが出てくると思うのですが、そういうのはなかったですか?」というような質問がありました。それを社内のSlackにpostしたところ下記のようなやりとりがありました。

f:id:voyagegroup_tech:20170214175119p:plain

Regional SCRUM GATHERING Tokyo 2017ではVOYAGE GROUPからの参加は私だけでしたが、今回の #再演 イベントでは現役の評価者/被評価者も参加予定です。「評価されるって実際どうなの?」「評価者大変じゃない?」など、参加者の方々から疑問を投げかけてもらえると盛り上がるのではないかと期待しています。

エンジニアの評価や育成、組織における制度設計・運用などに興味がある人たちとの交流を楽しみにしていますので、まずは気軽に下記connpassイベントをクリックし「このイベントに申し込む」をポチっと押してみませんか!

connpass.com