jQuery初心者がwindowsのイルカ作ってみた

Adways Advent Calendar 2017 9日目の記事です。

http://blog.engineer.adways.net/entry/advent_calendar_2017


おはようございます、17新卒SEの礒部です!
広告運用系の部署にいます。最近体重が5キロ増え、運動しなきゃなぁと思っています。

皆さんこのイルカのキャラクターをご存知でしょうか?

f:id:AdwaysEngineerBlog:20171213145134j:plain

windowsお助けキャラクターのカイル君といいます。
話しかけたり、色々することができる元大人気キャラクターです。

この子をjQueryの勉強をしつつ実装してみたいと思います。
(私はjQuery超初心者です)

実装機能

  • 画面上をランダムに動く
  • クリックすると喋る

実装開始!

イルカの画像は自分で描きました。(これが一番時間かかった)
f:id:AdwaysEngineerBlog:20171213145303g:plain
まずは基本のイルカを配置し、移動範囲を作ります。

<body>
    <div>
        <img id="iruka" src="images/iruka.gif">
    </div>
</body>

このままだと動かないので、どんどんjQueryで要素を追加していきます。
まずは画面上を動くようにしたいので、以下の3つを使用してみます。

setInterval # 指定した間隔で処理を実行する
animate     # スタイルを指定し、アニメーション効果を実行させる
attr        # 要素を変更させる。画像のパスを変更させる
$(function() {
    setInterval("move()",2000); // 2秒間隔で実行
});

function move() {
    var rand  = Math.round(Math.random() * 4);
    if(rand == 0){    //右
        move_right();
    }else if(rand == 1){ //左
        move_left();
    }else if(rand == 2){ //下
        move_bottom();
    }else if(rand == 3){ //上
        move_top();
    }
}

function move_left() {
    $('#iruka').animate({left: '-=100px'},1000);
    $("#iruka").attr("src","images/iruka_left.gif");
}

function move_right() {
    $('#iruka').animate({left: '+=100px'},1000);
    $("#iruka").attr("src","images/iruka_right.gif");
}

function move_top() {
    $('#iruka').animate({top: '-=100px'},1000);
    $("#iruka").attr("src","images/iruka_top.gif");
}

function move_bottom() {
    $('#iruka').animate({top: '+=100px'},1000);
    $("#iruka").attr("src","images/iruka_bottom.gif");
}

2秒ごとにランダムに移動しつつ、画像が切り替わるようになりました。


しばらく眺めていると画面外に消えてしまったので移動範囲を指定してみます。

#range {
    border:3px solid #6e6eff;
    width:600px; 
    height:600px;
}
/* 移動範囲を600pxとする */
position # 親要素からの現在位置をtop・leftの2つ形式で取得する
var range = $('#iruka').position();

if(range.left <= 400){
    move_right();
}else{
    move_left();
}

上記のような分岐を各方向に入れてあげます。画面内にとどまらせることに成功しました。
他にも色々やり方はあると思います。

f:id:AdwaysEngineerBlog:20171213145647g:plain


次に、クリック時に動きを止めてみます。

clearInterval # setIntervalの解除
click         # クリック時に処理を実行させる
stop          # 実行中のアニメーションを中断させる
setTimeout    # 関数の実行タイミングを遅らせることができる
$(function() {
    var move = set_timer();

    $("#iruka").click(function(){
        stop_timer(move);
        $(this).attr("src","images/iruka.gif").stop();
        setTimeout('set_timer();', 3000);
    });
});

function set_timer() {
    var move = setInterval("move()",3000);
    return move;
}

function stop_timer(move) {
    clearInterval(move);
}

上記で、クリック時に3秒間止まるようになりました。


次に、話しかけてくれるようにしてみます。
jquery.balloon.js という、簡単に吹き出しを作成できるプラグインを使ってみます。

balloon  # マウスオーバー時に、吹き出しとして表示
contents # balloonのオプション。表示内容を指定できる

githubからjsファイルをcloneし、実装してみます。

git clone https://github.com/urin/jquery.balloon.js
<script src="jquery.balloon.js"></script>

$("#iruka").click(function(){
    stop_timer(move);
    $(this).attr("src","images/iruka.gif").stop();
    $(this).balloon({contents: 'Enjoy Life Adways!'}); // 吹き出しの表示
    setTimeout('set_timer();', 3000);
});

f:id:AdwaysEngineerBlog:20171213153751p:plain

話してくれました。
contents要素を変えれば、ランダムで話すこともできそうですね。


話せるようになったものの、クリックした後にマウスをホバーし続けないといけない挙動になってしまいました。

f:id:AdwaysEngineerBlog:20171213162821g:plain

元のソースがマウスホバーで動く仕様で作られているのが原因です。
jquery.balloon.jsのソースを見たところ、balloonメソッドで下記の2つのメソッドをマウスホバー時に呼び出していました。なので個別に呼んでみます。

showBalloon # 吹き出しを作る
hideBalloon # 吹き出しを消す
$("#iruka").click(function(){
    stop_timer(move);
    $(this).attr("src","images/iruka.gif").stop();
    $(this).showBalloon({contents: 'Enjoy Life Adways!'});
    setTimeout('$(\'#iruka\').hideBalloon();', 2000);
    setTimeout('set_timer();', 3000);
});

マウスホバーしなくてもクリックで吹き出しが出るようになりました!

f:id:AdwaysEngineerBlog:20171213165003g:plain


本当はセリフを変えてみたり、デザインを変えてみたり色々やってみたかったのですが時間がないのでいったんここまでで。

jQuery、痒いところにまで手の届く予約関数が多くて勉強していて非常に楽しいですね!
またjQuery縛りで何か作ってみたいです。

研修レベルの内容ですが、レベルの高い記事は大先輩にまかせるとして息抜きとしてこの記事を楽しんでいただけたら嬉しいです。
それではまた!

f:id:AdwaysEngineerBlog:20171213154924p:plain

VMware-vSphereで仮想マシンのvMotionをSlackに通知する

Adways Advent Calendar 2017 8日目の記事です。

http://blog.engineer.adways.net/entry/advent_calendar_2017


こんにちは、アドウェイズの天津です。商用インフラ全般を担当しています。

今回はオンプレ基盤で使用しているVMware vSphere でのvMotionをSlackに通知させた事例を書きます。

なぜSlack通知が必要だったか

弊社ではvSphereでESXi複数台でクラスタを組んでおり、DRSによる負荷平準化を設定しています。
DRSによるvMotionは自動で実施されるのですが、大きめの仮想マシンの場合、vMotion時に静止時間が長く、アプリケーションに影響が出ることがあります。
アプリケーションでエラーが発生し、原因切り分けを行う際に毎回vMotion履歴をvCenterにログインして確認としていましたが社外にいる場合もあるためリアルタイムSlack通知を実装しました。

構成

f:id:AdwaysEngineerBlog:20171212152642p:plain

VMware vCenter Server からvMotionをSNMPトラップで流し、受信サーバで整形してSlackに通知する構成です。

Slack通知のために必要なこと

  • SNMPトラップ受信サーバの設定
  • vCenter ServerでのSNMPトラップ送信設定
  • vCenter ServerでのvMotionイベントの通知設定
  • SNMPトラップのSlack通知スクリプトの作成

それでは説明していきますね。vSphere 5.5での設定となります。

SNMPトラップ受信サーバの設定

まずはvCenterServerと通信できるネットワーク内にSNMPトラップを受信するサーバを建てましょう。
詳しい説明は割愛しますが、net-snmpのインストールと設定で動作すると思います。
vSphereのMIBファイル(こちらから ダウンロード できます)も忘れずに設置してください。

https://code.vmware.com/web/sdk/55/vsphere-management

vCenter ServerでのSNMPトラップ送信設定

vCenterの「管理」 - 「設定」 - 「全般」 - 「SNMPレシーバー」にIPアドレス、ポート番号、コミュニティストリングを設定します。

f:id:AdwaysEngineerBlog:20171212152708p:plain

イベントが発生した場合、SNMPトラップ受信サーバに送信されるようになりますので、ログを確認してみて下さい。

vCenter ServerでのvMotionイベントの通知設定

ここが今回のポイントです。

vCenter ServerにてvMotionイベントを通知するようにアラーム定義を設定していきます。
アラーム定義は「状態変化」に対して通知が可能となっているため、状態変化を定義する必要があります。
今回は全仮想マシンの通知とするためvCenter Server のアラーム定義を設定します。
vMotionイベントにはDRSによるものと手動によるものがありますので2つとも設定します。

DRSの通知

「管理」-> 「アラーム定義」より新規作成します。(緑の+ボタンで作成)

  • 1 全般
    • アラーム名:任意
    • 説明:任意
    • 監視対象:仮想マシン
    • 監視内容:「仮想マシンのパワーオンなど、このオブジェクトで起きる特定のイベント」を選択
    • このアラームを有効にする:オン

f:id:AdwaysEngineerBlog:20171212152741p:plain

  • 2 トリガー

トリガーとなるイベントと条件を下記のとおり設定しましよう。

状態変化を定義するのはこの項目です。 「開始」を警告として設定し、「完了」を正常とするのがポイントです。

f:id:AdwaysEngineerBlog:20171212152751p:plain

DRSを検知するためユーザ作業を除く条件もつけておきます。

  • 3 アクション

アクションで「警告」から「正常」に状態変化したタイミングに対してsnmptrap通知を設定します。

f:id:AdwaysEngineerBlog:20171212152758p:plain

手動vMotionの通知

DRSのものとトリガーのみ異なります。

f:id:AdwaysEngineerBlog:20171212152808p:plain

確認

手動でvMotionを実行してみましょう。 うまく設定されていれば SNMPトラップ受信サーバの ログに下記のようなメッセージが書き込まれます。
(下記はrsyslogdによるログ書き込みのため、改行コードが8進数(#011、#012)に変換されています

Dec  4 18:46:47 snmptrapd-001 snmptrapd[53668]: 2017-12-04 18:46:47 192.168.200.8(via UDP: [192.168.0.1]:52727->[192.168.0.2]) TRAP, SNMP v1, community public#012#011VMWARE-PRODUCTS-MIB::vmwVC Enterprise Specific Trap (VMWARE-VC-EVENT-MIB::vpxdAlarmInfo) Uptime: 11 days, 23:38:59.22#012#011VMWARE-VC-EVENT-MIB::vmwVpxdTargetObjType.0 = INTEGER: vm(3)#011VMWARE-VC-EVENT-MIB::vmwVpxdOldStatus.0 = STRING: 赤#011VMWARE-VC-EVENT-MIB::vmwVpxdNewStatus.0 = STRING: 緑#011VMWARE-VC-EVENT-MIB::vmwVpxdObjValue.0 = STRING: vMotion_Notif - イベント: 仮想マシンが移行されました (7260303)#012サマリ: 仮想マシン amatsu-test-001 が ESXi-A、Storage-A から ESXi-B、Storage-A に移行されました#012日付: 2017/12/04 9:46:46#012ユーザー名: ADWAYS.NET\amatsu_satoshi#012仮想マシン: amatsu-test-001#012ホスト: ESXi-A#012リソース プール: Test-Cluster#012データストア: Storage-A#012データセンター: Test-Datacenter#012引数:#012    sourceDatacenter.name = Test-Datacenter#012    sourceDatastore.name = Storage-A#012    sourceHost.name = ESXi-B#012#011VMWARE-VC-EVENT-MIB::vmwVpxdTargetObj.0 = STRING: amatsu-test-001

改行変換処理したものが下記です。(#011をタブに、#012を改行に置き換えています)

Dec  4 18:46:47 snmptrapd-001 snmptrapd[53668]: 2017-12-04 18:46:47 192.168.200.8(via UDP: [192.168.0.1]:52727->[192.168.0.2]) TRAP, SNMP v1, community public
    VMWARE-PRODUCTS-MIB::vmwVC Enterprise Specific Trap (VMWARE-VC-EVENT-MIB::vpxdAlarmInfo) Uptime: 11 days, 23:38:59.22
    VMWARE-VC-EVENT-MIB::vmwVpxdTargetObjType.0 = INTEGER: vm(3)    VMWARE-VC-EVENT-MIB::vmwVpxdOldStatus.0 = STRING: 赤   VMWARE-VC-EVENT-MIB::vmwVpxdNewStatus.0 = STRING: 緑   VMWARE-VC-EVENT-MIB::vmwVpxdObjValue.0 = STRING: vMotion_Notif - イベント: 仮想マシンが移行されました (7260303)
サマリ: 仮想マシン amatsu-test-001 が ESXi-A、Storage-A から ESXi-B、Storage-A に移行されました
日付: 2017/12/04 9:46:46
ユーザー名: ADWAYS.NET\amatsu_satoshi
仮想マシン: amatsu-test-001
ホスト: ESXi-A
リソース プール: Test-Cluster
データストア: Storage-A
データセンター: Test-Datacenter
引数:
    sourceDatacenter.name = Test-Datacenter
    sourceDatastore.name = Storage-A
    sourceHost.name = ESXi-B
    VMWARE-VC-EVENT-MIB::vmwVpxdTargetObj.0 = STRING: amatsu-test-001

SNMPトラップのSlack通知スクリプトの作成

上記の通知内容を整形して通知します。今回はbashで書きました。「OID」と「サマリ」が含まれる行を処理しています。
弊社ではSlack通知に cubicdaiya さんのslackboard https://github.com/cubicdaiya/slackboard を使用して送信していますが、curlで直接Slackに送信してもいいと思います。

#!/bin/bash

Temp_trap="/tmp/temp_trap.log"
CHANNEL="amatsu-vminfo"
SLACKBOARD="192.168.0.101:29800"

echo -n > $Temp_trap

while read LINE; do
  echo $LINE >> $Temp_trap
done

# OIDの取得
OID=`head -4 $Temp_trap | tail -1 | cut -f2 -d " "`

##### VMware vCenter Event MIB Trap #####
case $OID in
  *VMWARE-VC-EVENT-MIB* | *VMWARE-PRODUCTS-MIB* ) 
     if grep "DRSvMotion_Notif"  $Temp_trap > /dev/null ; then
       # DRS
       Message=`grep サマリ $Temp_trap | sed 's/、/ /g' |awk '{printf("vMotion(DRS): \`%s\` : %s -> %s (%s)", $4, $6, $12, $10)}'`
     elif grep "vMotion_Notif"  $Temp_trap > /dev/null ; then
       # operation
       Message=`grep サマリ $Temp_trap | sed 's/、/ /g' |awk '{printf("vMotion(ope): \`%s\` : %s -> %s ( %s -> %s)", $3,  $5, $8, $6, $9)}'`
     fi

     if [[ ! -z ${Message} ]]; then
       # send Slack
       echo -e "${Message}" | /usr/local/bin/slackboard-cli -s ${SLACKBOARD} -c ${CHANNEL} > /dev/null &
     fi
     ;;
esac

exit 0

通知スクリプトの設定

作成したスクリプトをSNMPトラップ受信時のハンドルとして登録します。

動作確認

手動でvMotionしてみましょう。 下記のようにSlackに通知が実行されるはずです。

f:id:AdwaysEngineerBlog:20171212152825p:plain

これでいつでもどこにいてもvMotionがリアルタイムで把握できますね。

終わりに

今回、SNMPトラップをトリガーにしてSlackにvMotionを通知しましたが、任意のスクリプトを動かすことができるため、vMotionの前後に動かしたいスクリプトがあれば仕込むことができます。
vMotionに影響を受けるアプリケーションやミドルウェアがある場合、事前作業の自動化や回復処理の自動化ができそうですね。

最後までお読みいただきありがとうございました。

ポケ森ではじめた5W1H思考

Adways Advent Calendar 2017 7日目の記事です。

http://blog.engineer.adways.net/entry/advent_calendar_2017


お疲れ様です。インフラの田中です。

この度、どうぶつの森 ポケットキャンプ(ポケ森)をプレイして学んだ、5W1H思考について執筆させて頂くことになりました。

「どうぶつの言いなりになるゲームなんてやってられない」と思い、ポケ森にログインしなくなって2週間たった寒い日のこと。
私は、書店で『シンプルに結果を出す人の5W1H思考』という本に出会いました。
その本には、なぜ私がポケ森に飽きたのか、そして、どうすればポケ森を楽しくプレイできるのかヒントが書かれていました。

目的のそのまた目的まで突き詰める

本には課題に着手する際、おおきく3つのレベルで思考が必要だと書いてあります。

  • What/How ・・・何をやるのか
  • Why ・・・なぜやるのか
  • Big-Why ・・・物事の理想的なありかた(どうありたいか)

これをポケ森にあてはめたところ、
私がポケ森をプレイする目的(Why)は、「どうぶつのおねがいをかなえたいから」であり、
実行手段(What/How)は、「毎日釣りをしたり、昆虫採集をしたり、キャンプ場にどうぶつたちの求める家具を置くこと」と考えました。

  • 図:ナチュラルな家具で揃えたいのに、キュートタイプのどうぶつを呼ぶために泣く泣くハイカラな家具を置いていた当初のキャンプ

f:id:AdwaysEngineerBlog:20171211173002p:plain

では、なぜ「どうぶつのおねがいをかなえたいのか(Big-Why)」!! 私は全く考えたことがありませんでした。

この真の目的"Big-Why"を考えていなかったことが、ポケ森をプレイしなくなった原因でした。
では私がポケ森で本当に実現したかったことは何なのか、よく考えてみたところ
「可愛いキャンプを創って、フレンドにいいね!をもらうこと」であるという考えにいたりました。

f:id:AdwaysEngineerBlog:20171211173032p:plain

Big-Whyを考えることについて、本にはさらに以下のように書かれてありました。

Why(目的)をさかのぼることによって、より本質的な課題が設定でき、 思考のすそ野(選択肢やそのくみあわせ)を広げることができます。

f:id:AdwaysEngineerBlog:20171211173042p:plain

上図のように、Big-Whyを明確にしたことで、What/Howの視野が広がり、
釣りや昆虫採集に時間を費やすのではなく、フレンドのバザーでどうぶつに依頼された商品を買うこと、
どうぶつたちのために家具をそろえるのではなく、自分が欲しい家具をそろえて、
家具に見合ったどうぶつたちをキャンプ上に招待することを考えるようになりました。

5W1Hにあてはめた戦略プラン

可愛いキャンプ場を創ることが真の目的だと分かり、ポケ森にやる気スイッチが入った私は、
クリスマスの家具を並べて季節感を加えたいという欲を持ち始めました。

クリスマスイベント攻略にあたって、本を読んだところ、
課題解決するには、情報を整理する必要があり、5W1Hは、

思考の漏れや重なりを防ぎ、さらに発想・思考領域を広げるときに役立つ手法

である、と書いてありました。

そこで、クリスマスイベント攻略プロジェクトを5W1Hの表にあてはめてみました。

  • 表:クリスマスイベント攻略プロジェクトの概要改
    • ※クリスマスの家具は「クリスマスのもと」というクリスマスイベント限定の クラフト素材アイテムを集めて作ることができます。
When 2017/12/26(クリスマスのもとの配布期限)まで
Where キャンプ場
Who フレンド向けに
Why 可愛いキャンプにしていいねをもらうため
What クリスマスの家具をそろえる
How クリスマスのもと※を集めて
How much 1100個

この表を作成したことにより、このままではまずいということに気づき、焦り始めました。

クリスマスのもとは、どうぶつのおねがいを叶えると1〜3個程度獲得できますが、私のログイン時間を考えると1日20個程度しかもらえず、このペースでは12/26までに家具をそろえることができません。

さらに、真の目的「可愛いキャンプにしていいねをもらう」を達成するには、12/26にクリスマスキャンプが完成しても遅いのです。
せめて、一週間前には完成させて、いいねをもらう猶予があるべきです。

ここで、私は「さかのぼり思考」で、「可愛いキャンプにしていいねをもらう」ために、本当にクリスマスの家具を全部揃える必要があるのかという疑問に至りました。

「可愛いキャンプ=クリスマスの家具がすべて揃っているキャンプ」
ではなく、
「可愛いキャンプ=クリスマスらしい雰囲気のキャンプ」
が重要なのではないかという考えになりました。

上記のことを踏まえ、表を以下のように修正しました。

  • 表:クリスマスイベント攻略プロジェクトの概要改
When 2017/12/18まで
Where キャンプ場
Who フレンド向けに
Why 可愛いキャンプにしていいねをもらう
What クリスマスを仕様にする
How クリスマスのもとを集めて
How much 500個

必要なクリスマスのもとが500個になったことで、真の目的の達成が現実味を帯びてきました。

  • 表:私が求めるクリスマスの家具
イメージ 家具名 クリスマスのもと
f:id:AdwaysEngineerBlog:20171211174150j:plain クリスマスチェックのラグ 50個
f:id:AdwaysEngineerBlog:20171211174218j:plain クリスマスなついたて 50個
f:id:AdwaysEngineerBlog:20171211174622j:plain リボンのクリスマスツリー 100個
f:id:AdwaysEngineerBlog:20171211174704j:plain クリスマスのだんろ 300個

平日は通勤時間のみのプレイですが、どうぶつたちのおねがいを効率よく対応しながら、だんろ以外の家具を揃えることができました。

f:id:AdwaysEngineerBlog:20171211174124j:plain

さらにだんろを加えれば、よりクリスマスらしいキャンプになるはずなのですが、だんろを作るにはクリスマスのもとがあと249個必要です。
残り1週間で、今回学んだ5W1H思考を利用してなんとか可愛くていいね!をしてもらえるキャンプを創り上げたいと思っています。

応援よろしくお願いします。

追記(2017/12/20)

5W1H思考とフレンドの協力により、クリスマスのもとが理想より多く集まりました! そして、集めた家具で 『呑んで歌ってライブバー feat.とたけけ』 を作りました!

ライブエリア レストランエリア
f:id:AdwaysEngineerBlog:20171221092435j:plain f:id:AdwaysEngineerBlog:20171221092448j:plain

今後も引き続き、5W1H思考でポケ森に励んでまいります!

ID: 4686 2435 410

参考文献 渡邉 光太郎『シンプルに結果を出す人の 5W1H思考』すばる舎,2017年,p.199

シンプルに結果を出す人の 5W1H思考

シンプルに結果を出す人の 5W1H思考

イイ感じなスクラムチームになってきたお話

Adways Advent Calendar 2017 6日目の記事です。

http://blog.engineer.adways.net/entry/advent_calendar_2017


こんにちは!ひよっこスクラムマスターのりょーまです。
気づいたら5年目になっており、周りが後輩だらけになってしまいました。
どんどん成長していく彼らを微笑ましく思い、また触発されている日々であります。

さて今回はそんな後輩の一人、まっちゃんが投稿したスクラムにおける4つのイベントに出てくるチームが、「この後どうなったか知りたい!」 という声が1万件くらいあったので、振返りも兼ねて記していきたいと思います。

blog.engineer.adways.net

スクラム(アジャイル)開発をされている方々や、これからチャレンジしてみようと考えている方々の参考や、ディスカッションのネタになれば幸いです。

※エモい話が含まれるのでアレルギーがある方は注意してくださいね!


スクラムをやる目的

これは非常にシンプルで、価値の高いプロダクトをつくるためです。
表現の仕方は他にもあるかもしれません。スピードを上げたい、品質を良くしたい、等々。
とにかく、今の開発サイクルをもっとよくして、イイ感じに回していきたいんです。

それだけです。
スクラムはそのための手段で、かつ有効な手段であろうと認識しているため、うちのチームでも採用することにしました!


チームのスペック

  • スクラムチーム
    • 10人
    • 若手~ベテラン
  • スクラム暦
    • 半年くらい

デイリースクラムの様子

f:id:AdwaysEngineerBlog:20171208184621p:plain


で、どうなったの

まず結論から言うとイイ感じなチームになってきました。
スクラムチームのメンバー全員が口を揃えてこう言ってます。言わせてないよ。多分。
続き、読みたくなりましたよね?

では、どんな過程で、どんなイイ感じなチームになってきたかをご説明させて頂きます。


ちゃんとスクラムになってきた

スクラム経験者には共感して頂けると思うのですが、普通にスクラム回す事自体がかなり難しいです。
理解は容易、習得は困難と言われていますがまさにその通りで。。
故に途中で諦めちゃうチームが多いようですね。
では、どうやってちゃんとスクラムってきたのか。
大きく分けて三つあります。


その1:スクラムマスターがスクラムについて詳しくなる事

人に動いてもらうためにはその理由、やる意味が必要です。
それをやる事で何かが良くなるんだ!ってイメージがあるかないかで進み具合が大きく変わってくると思います。(まあこれは、スクラムに限らず何でもそうですよね笑)

そんなイメージを持たせるのはやはりスクラムマスターの役割です。そのために、とにかく勉強しました。方法はシンプルで読書アジャイルコミュニティへの参加です。
※参考書籍、参加コミュニティはページ下部にまとめておきます

もうこればっかりは、コツとか要領じゃなくてどれだけインプットできるかだと思います。たくさんインプットする事で自信がつき、自信がつくことでメンバーを思い切って巻き込む事が出来ますね。

スクラムマスターとしてある程度知識がついてきたところで


その2:メンバーがスクラムについて詳しくなる事

上記にもあるように納得がないまま進めてしまうと、やらされているスクラムになり、これは失敗する可能性が高いと思います。
という事でメンバーにもスクラムを一から勉強してもらいました。
それがまっちゃんが書いたスクラムにおける4つのイベントの内容です。
まずは基礎!ということで各イベントの目的や流れを勉強して貰いました。
この勉強方法、少し工夫したので紹介させて頂きます。以下がそのステップです。


スクラム理解ワークショップ

目的:スクラムチーム全員のスクラム基礎理解
テーマ:各スクラムイベント(プランニング、振返り、デイリースクラム、レビュー)

  • ステップ1:個人で勉強する
    • 基本はスクラムガイド。そこから書籍やweb等自由に調べる。
  • ステップ2:メンバーでペアを組み、ディスカッションをする。共通の結論を出す。
  • ステップ3:ペアを入れ替え、ステップ2と同じ事をする。
  • ステップ4:ステップ3のペアで、スクラムマスターに勉強内容の発表をする。
  • ステップ5:スクラムマスターはレビュー&ケーススタディ的なQを出す
  • 以上をスクラムイベント毎に実施(計4サイクル)
  • 一週間毎に一イベント
    ※Qはページ下部にまとめておきます

この勉強方法のねらいはスクラム理解は勿論の事、アウトプットをすることで認識のずれに気づき、そしてそれをすり合わせていくところにあります。
本を読むだけだったり、詳しい人のプレゼン聞くだけだったり、要はインプットのみだとどうしても認識に個人差が出てしまいます。
対面で意見を言う、一緒に考える、このアクションはスクラムにおいて非常に重要な文化となります。

この勉強方法はメンバーからも好評で、良いスタートを切れたなと記憶しています。
そしてなにより私自身が一番勉強になりました。何回レビューしたんだ笑

メンバーもスクラムを理解したところで


その3:実践→改善→実践→改善

あとはやってみるだけです。いくらルールを完璧に理解したところでやってみない事には何も分かりません。
各イベント、やってみるとなんかしっくりこないなーって場面に出くわすのでその都度チームで改善していきました。
基礎を勉強したことでどういったものが理想かをチーム全体が理解しているので、チームで意思決定ができようになります。
チームで意思決定をするので、意見が言えなかったり、誰かに責任が寄ったりする事がなく、心理的安全性の高いチームになってきます。
心理的安全性の高いチームなので、、と以降正のサイクルですね。


忍耐&忍耐

以上がチームのスクラムの型が出来上がるまでの大まかなステップです。
文字に起こすとシンプルですが、ここまでくるのに実質3~4ヶ月はかかりました。
時間がかかるよ大変だよという事を伝えたいのではなく、
時間をかけてやるべきだよという事をお伝えしたいです。
スクラムにしろ、その他のアジャイルプラクティスにしろ、チームの文化を大きく変える事には変わりないので、そもそもすごく難しい事です。すぐに結果はでないので、粘り強さは求められます。


ルールを守る事で柔軟性が出てくる

スクラムって何となく、自由とか、柔軟にってイメージがあると思います。実際間違ってはいないのですが、そうなるためのルールというものがしっかりと設計されています。
ルールは守るためにあります。
守れてきたら、徐々に緩くしたり、変えたりと自分達のチームに合うようにカスタマイズしていくと良いと思います。
プログラミングでも一緒ですよね。


チームワークが格段に良くなってきた

ちゃんとスクラムになってきた事が先か後かはわかりませんが、チームワーク、めちゃくちゃ良くなって来ました。


メンバーが勝手に協力し合あってる

例えばどんな行動かというと

  • 解決方法がわからない課題に対してチームで取り組む
  • 遅れている、未着手なストーリー(案件)を進んで巻き取る
  • 自分のためだけでなく、チームとしての価値を考え、行動している

これは、誰が何をしていて、どんな目的で、どういった手段で解決するかをチームのメンバー全員がある程度把握しているためできることです。

そういったことチームであーだこーだ話し合うのがスプリントプランニングというわけです。スクラムイベントに関してはこちらへ。

振返り、プランニングの様子

f:id:AdwaysEngineerBlog:20171208171848j:plain


チームへの貢献意欲

また、チームに貢献したい! と各メンバーが思えてる事もとても重要です。エモくなってきましたね、もうすぐ終わるので我慢してください。

いくらロジックが完璧で効率的なフローがあっても、この部分が欠けていると人はなかなか動きません。
これはどうしたらいいかというと、とにかくコミュニケーションを取るしかないと思っています。スクラムイベントの他に、1 on 1、ブレスト、ランチ、雑談、等々対面で話す機会はいくらでも作れます。
これを続けていく事で、人やチームに対して関心や興味を持ち、尊重するようになってきます。
こういった関係の質を形成した上で初めて思考行動の質が上がってきて、結果に繋がっていきます。
これはダニエル・キム氏の組織の成功循環モデルを参考にしてます。


結果的に、スピードが上がってきた

これは本当に少しずつですが、早くなってきました。要因は以下のようなものになります。

  • 知識やスキルの依存が徐々に解消されてきている
  • 見積もりが早く、正確になってきている
  • 認識のずれが減り、戻りが少なくなってきている
  • 改善サイクルが生まれてきた

楽しくなってきた

↑みたいなイイ感じのチームになってきたので、当然楽しくなってきました。
楽しいとか嬉しいって感情が働く理由としてあるのは凄く大きなーパワーになります。
また、中々一人では感じないものなので、チームっていいなって思う毎日であります。


大切にしているマインドセット

スクラムマスターの役割はスクラムを成立させ、良いチームにするところにあります。
そのために、私が大切にしている軸が三つあります。


とりあえずやってみる、ダメならやり直せばいい

シリコンバレーの企業文化でfail fastというものを良く聞きますよね。
同じ意味で、まずはやってみようっていうマインドセットです。
勿論、何でもかんでもやって無駄な時間を過ごせとまでは言わないですが、無駄を経ることで最適・最高ってものに近づけると信じてます。
これはしつこいくらいに言ってます笑


振返りは手段、改善が目的

振返りをただやるのではなく、実施~結果を出す事を大切にしています。
振返りをして、問題提起をするまでは良くある事なのですが、その先放置って結構あることだと思います。
そうならないためにも、できる計画を立て、少しずつでも成果物を出していく事が大切だと思います。


チームのため、そして自分のため

チーム開発において、チームのためを考える事は絶対外せません。
が、それだけだとモチベーションが上がり切らないですし、厳しく言えば失敗の言い訳にもできちゃうわけです。
なので、自分のためにもなるかという観点でメンバーの目標を一緒に考えています。


さいごに

ここまでいろいろ書かせて頂きましたが、スクラムマスターとしてもひよっこですし、チームとしてもまだまだ至らないところだらけです。
来年は堂々とうちのチームすげーぞと言えるように、今後の目標をふわっと宣言し(まだチームで話してないので)、お開きとさせて頂きます。

  • よりスピーディにしていく
  • よりユーザのニーズに応える
  • よりチームにあったスタイルに変えていく
  • より楽しくする
  • にわとりになる

ここまで読んで頂きありがとうございました!
明日以降もアドウェイズのアドベントカレンダーをお楽しみください!


参考書籍、参加コミュニティ


スクラム理解Qリスト(一部)

  • スプリントプランニング

    • プロダクトバックログとスプリントバックログの違いを説明してください(責任者も問う)
    • スプリントプランニングが毎回時間通りに終わりません。考えられる要因を挙げてください。
    • 中途半端に終わった↑の状態でスプリントをスタートしたらどうなると思いますか。
    • スプリントごとで設ける目標の事ををなんと言いますか。また、なぜ必要なのでしょうか。
    • 良いスプリントプランニングとはどういうものでしょうか
  • スプリントレビュー

    • スプリントレビューに招待するステークホルダーはどんな人を呼ぶべきですか
    • スプリントレビューを行なってみたところ、有意義な場になりませんでした。考えられる問題点を挙げてください。
    • スプリントレビューで得られる事は何ですか

AWS Glueを使ってS3→データ加工→S3をやってみた

Adways Advent Calendar 2017 5日目の記事です。

http://blog.engineer.adways.net/entry/advent_calendar_2017


こんにちは、12月7日担当の足立です。

12月7日はクリスマスツリーの日みたいですね。

1886(明治19)年のこの日、横浜・明治屋に日本初のクリスマスツリーが飾られた。らしいです。

さて、本題に入ります。

今回はAWS Glueを業務で触ったので、それについて簡単に説明していきたいと思います。

AWS Glueとはなんぞや??

f:id:AdwaysEngineerBlog:20171207170557p:plain

AWS Glue は抽出、変換、ロード (ETL) を行う完全マネージド型のサービスで、お客様の分析用データの準備とロードを簡単にします。AWS マネジメントコンソールで数回クリックするだけで、ETL ジョブを作成および実行できます。AWS Glue では、AWS に保存されたデータを指定するだけで AWS Glue によるデータ検索が行われ、テーブル定義やスキーマなどの関連するメタデータが AWS Glue データカタログに保存されます。カタログに保存されたデータは、すぐに検索、クエリ、ETL で使用できます。AWS Glue では、データ変換とデータのロードプロセスを実行するコードが生成されます。

ざっくりAWS Glueで出来ること(認識範囲内)を説明すると

  • CrawlerでS3等からデータを抽出してデータカタログへ
  • データカタログでカラム名・型変更可
  • Jobで変換
    • コンソール上でポチポチするだけで自動である程度コードが生成される
    • 細かな変換がしたい場合 PySpark, Pythonで可
  • Jobでロード(S3等に変換したデータをアップロード)

今回のゴール

f:id:AdwaysEngineerBlog:20171207170636p:plain

流れ

  • 二つ用意したバケットのsample_glue_for_read/blog_sample_glue.csvからAWS GlueのCrawlerを使ってcsvからデータ抽出
  • データカタログから不要なカラムの削除
  • Jobを使ってデータ加工しsample_glue_for_resultに出力

やること

下記の内容のcsvから不要なカラムidとdummyを削除して
finalist_nameの個数 == 投票数とし、並びかえたものを出力したいと思います。

id,finalist_name,dummy
1,ジャルジャル,
2,かまいたち,
3,カミナリ,
4,マヂカルラブリー,
5,ミキ,
6,さや香,
7,とろサーモン,
8,和牛,
9,ゆにばーす,
10,ミキ,
11,とろサーモン,
12,和牛,
13,和牛,
14,とろサーモン,
15,とろサーモン,

AWS Glue実践

準備(IAMロールの作成)

マネジメントコンソール上で IAM→ロール→ロールの作成

  1. ロールの作成画面で「AWS サービス」を選択
  2. このロールを使用するサービスを選択で「Glue」を選択
  3. 次のステップへ
  4. ポリシーの選択一覧画面で「AmazonS3FullAccess」 「AWSGlueServiceRole」の二つを選択
  5. 次のステップへ
  6. ロール名の入力、今回は「AWSGlueServiceRoleDefault」と入力
  7. ロールの作成

詳しくはこちらを参照 dev.classmethod.jp

実践

AWS Glueのページへ

東京リージョンはまだないので、今回はバージニア北部リージョンで実践していきたいと思います。

Crawler設定・実行

CrawlerでS3からファイルを抽出し、Data catalogに入れるために設定をしていきたいと思います。

f:id:AdwaysEngineerBlog:20171207170935p:plain

CrawlersのAdd crawlerから

f:id:AdwaysEngineerBlog:20171207170947p:plain

Crawler nameにsample_glueと入力

f:id:AdwaysEngineerBlog:20171207171003p:plain

Data storeをS3に選択 Include pathに今回はs3://sample-glue-for-readと入力
右のフォルダアイコンからバケット指定出来ます。

f:id:AdwaysEngineerBlog:20171207171031p:plain

Noを選択

f:id:AdwaysEngineerBlog:20171207171046p:plain

準備で作成したIAMロールAWSGlueServiceRoleDefaultを選択

f:id:AdwaysEngineerBlog:20171207171113p:plain

今回はRun on demandを選択

f:id:AdwaysEngineerBlog:20171207171125p:plain

Add databaseを押してDatabaseを作成

作成したsample_glue_dbを選択

確認ページでFinishを押してCrawlerの設定終了

Crawler一覧画面で作成したsample_glueを選択し、Run crawlerで実行する。

Data catalogの確認

メニューバーのData catalog→Databases→Tablesから

Run crawler実行で作成されたsample_glue_for_readを選択

f:id:AdwaysEngineerBlog:20171207171215p:plain

上記は詳細の一部ですが、無事にcsvが抽出成功していることが確認出来ました。

Jobの作成・実行

f:id:AdwaysEngineerBlog:20171207171246p:plain

Add jobでJobを作成

f:id:AdwaysEngineerBlog:20171207171258p:plain

上記のように入力して次へ

f:id:AdwaysEngineerBlog:20171207171321p:plain

先ほど確認したData catalogのsample_glue_for_readを選択し次へ

f:id:AdwaysEngineerBlog:20171207171332p:plain

Create tables in your data targetを選択

今回は加工したデータをS3のsample-glue-for-resultバケットにアップロードするのがゴールなので、

S3を選択

Target Pathにs3://sample-glue-for-resultを入力

f:id:AdwaysEngineerBlog:20171207171352p:plain

iddummyは不要なので使わないように×を押します。

確認ページでFinishを押します。

すると、AWS Glue側で自動でコード生成してくれます。

これを元にコーディングしていきたいと思います。

自動生成コードに少し手を加えたコードがこちらになります。

import sys, unicodedata
from awsglue.transforms import *
from awsglue.utils import getResolvedOptions
from pyspark.context import SparkContext
from awsglue.dynamicframe import DynamicFrame, DynamicFrameWriter
from awsglue.context import GlueContext
from awsglue.job import Job
from pyspark.sql import Row

## @params: [JOB_NAME]
args = getResolvedOptions(sys.argv, ['JOB_NAME'])

sc = SparkContext()
glueContext = GlueContext(sc)
spark = glueContext.spark_session
job = Job(glueContext)
job.init(args['JOB_NAME'], args)
## @type: DataSource
## @args: [database = "sample_glue_db", table_name = "sample_glue_for_read", transformation_ctx = "datasource0"]
## @return: datasource0
## @inputs: []
datasource0 = glueContext.create_dynamic_frame.from_catalog(database = "sample_glue_db", table_name = "sample_glue_for_read", transformation_ctx = "datasource0")
## @type: ApplyMapping
## @args: [mapping = [("finalist_name", "string", "finalist_name", "string")], transformation_ctx = "applymapping1"]
## @return: applymapping1
## @inputs: [frame = datasource0]
applymapping1 = ApplyMapping.apply(frame = datasource0, mappings = [("finalist_name", "string", "finalist_name", "string")], transformation_ctx = "applymapping1")
## @type: DataSink
## @return: datasink2
## @inputs: [frame = applymapping1]


# ===書いたコード(ここから)===

def is_japanese(string):
    for ch in string:
        name = unicodedata.name(ch) 
        if "CJK UNIFIED" in name \
        or "HIRAGANA" in name \
        or "KATAKANA" in name:
            return True
    return False

result_list = []

df_list  = applymapping1.toDF().filter("finalist_name is NOT NULL").collect()

for row in df_list:
    if is_japanese(row['finalist_name']):
        result_list.append(Row(finalist_name=row['finalist_name']))
        
df = spark.createDataFrame(result_list)
df  = df.groupBy("finalist_name").count().sort("count", ascending=False)
dyf = DynamicFrame.fromDF(df, glueContext, 'sample_glue')

print "==========="
print dyf.show()
print "==========="

# ===書いたコード(ここまで)===

datasink2 = glueContext.write_dynamic_frame.from_options(frame = dyf, connection_type = "s3", connection_options = {"path": "s3://sample-glue-for-result"}, format = "csv", transformation_ctx = "datasink2")
job.commit()

本来なら

df  = applymapping1.toDF().filter("finalist_name is NOT NULL")
df  = df.groupBy("finalist_name").count().sort("count", ascending=False)
dyf = DynamicFrame.fromDF(df, glueContext, 'sample_glue')

上記の3行だけで出来ると思ったのですが、.filter()を使ったら

どこからか謎の文字列が入り込んできてしまいました。

今回はマルチバイト文字だけを扱うので、こちらの記事を参考にゴリゴリにコードを書き、欲しいデータのDataFrameを作成しました。

(なんで.toDFした時には入ってないのに.filter()すると謎文字列入るんだろう。。)

f:id:AdwaysEngineerBlog:20171207171451p:plain

Run jobでJobを実行させます。

Jobのログ確認方法

f:id:AdwaysEngineerBlog:20171207171528p:plain

Jobの実行ログ等はCloudWatchに出力されます。

先ほどのコードの中にprintでDynamicFrameの中身を確認できるようにしたので確認したいと思います。

printの結果は/aws-glue/jobs/errorに書き出されます。

f:id:AdwaysEngineerBlog:20171207171545p:plain

DynamicFrameの中身にそれっぽいデータがちゃんと入っていることが確認できました。

次はS3にcsvファイルがちゃんと書き出されているか確認したいと思います。

実践結果

S3のsample-glue-for-resultに書き出したので見てみます。

f:id:AdwaysEngineerBlog:20171207171612p:plain

あれっ?1つのcsvファイルじゃなくて5つ出来てる!!
ログで確認したデータ良い感じだったのに。。

f:id:AdwaysEngineerBlog:20171207171620p:plain

中身を見てみると、、、

合体してくれれば想定通りのファイルだったのに

最後のファイルなんて空ファイル。

結果: データが分散されて複数のファイルで出力される

感想

AWS Glueを扱うためにPythonを初めて書いたのでとても新鮮でした。

形にはなったものの、イメージ通りに最後まで作り上げることが出来なかったのが心残りです。

ちゃんと1つのcsvで出力して、「とろサーモン」さん優勝おめでとうございます!まで持っていく予定でした。

「こうすれば1つファイルに纏められるよ」という方がいらっしゃいましたら教えていただけると幸いです。

お詫び

2017年度のM1ファイナリストを使わせて頂いたのですが、

誤字をしないためにネットから引っ張ってきたら

敗者復活枠のスーパーマラドーナさん抜きのテストデータを作ってしまいました。

深くお詫び申し上げます。