Slack で役に立たない Bot を運用するときの知見とか

この記事は Slack Advent Calendar 2014 - Qiita の 11 日目の記事です。

Slack のようなチャットツールを導入したら Bot を運用するのが人間の性なので、皆さんのチャンネルでも Bot がワイワイ活気付いてる姿が見られるかと思います。 Slack Advent Calendar 2014 - Qiita を眺めていても、Bot の話がいくつかあるようですね。僕が属している会社の Slack チームでも、jewelpet という役に立たない Bot がいます。

今日は Slack で動いている役に立たない Bot の機能紹介と、それを運用して得た役に立たない知見を紹介します。

機能紹介

社内向けなので身内ネタも多い。

jpi

hubot image meエイリアスです。hear を使って jpi という文字列に反応するようにしています。jewelpet image hoge よりも短く jpi hoge と書けるので、画像コミュニケーションが捗ります。

hubot/scripting.md at master · github/hubot · GitHub

社内マップ

会議室の名前と部屋の位置の対応が覚えにくいのでよく使う。

f:id:jewel12:20141210201723p:plain

see: Acme-VOYAGEGROUP-ConferenceRoom/ConferenceRoom.pm at master · monmon/Acme-VOYAGEGROUP-ConferenceRoom · GitHub

JSON

便利な気がする

f:id:jewel12:20141211210748p:plain

返事

f:id:jewel12:20141211202217p:plain

f:id:jewel12:20141211202450p:plain

寿司

他にカンパチや太巻きがあります。

f:id:jewel12:20141211211016p:plain

ウィキ

f:id:jewel12:20141211211716p:plain

コナミコマンド

f:id:jewel12:20141211202759p:plain

ジャバ

f:id:jewel12:20141211202957p:plain

f:id:jewel12:20141211204102p:plain

ガチャ

f:id:jewel12:20141211203250p:plain

進捗

f:id:jewel12:20141211203500p:plain

いい話カウンター

f:id:jewel12:20141211203832p:plain

ユニックスタイムスタンプ

長い

f:id:jewel12:20141211204401p:plain

回文

f:id:jewel12:20141211204618p:plain

ビール

f:id:jewel12:20141211204738p:plain

距離

f:id:jewel12:20141211205151p:plain

あなたとダウンロード

f:id:jewel12:20141211205351p:plain

優柔不断

f:id:jewel12:20141211205727p:plain

コンパイル速度

f:id:jewel12:20141211205904p:plain

その他

  • 株: jewelpet 株 CODE 
  • n 秒後にコメント: jewelpet timer 10 コンパイル時間
  • あとは夕会の通知とかありそうな感じのは大体あります

知見

200 人以上が利用している社内 Slack チームで、鬱陶しいことに上記の様な糞 Bot が運用されていることを紹介しました。

Slack の利用人数が多くなってくると多くの人の目に糞 Bot の糞機能が触れられるようになるため、なるべく角が立たないように運用したくなるかと思います。糞 Bot が運用されている状況を観察して得た知見は、怒られにくくするには愛着がわきやすい Bot を作るのが大切ということです。下手なことを言っても仕方ないと思わせる、そんな可愛さが必要です。

jewelpet には次のような可愛さがあります。

  • バグは極力直さない
    • バカな子ほど可愛いという諺がある
  • 便利な機能は極力付けない
    • バカな子ほど可愛いという諺がある
    • ChatOps とかもってのほか
  • 特定のユーザーしか使えない機能など、あざとい機能もある

この可愛さのお陰で、今のところ怒られずに運用できているみたいです。可愛いは正義!

おまけ: ロギング

役に立たない Bot を運用することの知見からは外れるのですが、Slack で Bot を運用するときはロギング用チャンネルを作って、そこにログを吐いていくと便利です。例えば hubot-cron のようなプラグインを利用するとき、誰が設定した・設定を外したというようなことが分かります。あと検索もできる。

f:id:jewel12:20141211220008p:plain

なんか Slack Advent Calendar というよりも Hubot Advent Calendar という感じでしたが、11 日目の Slack Advent Calendar でした。

ISUCON 2014 の思い出

ISUCON 2014 という、いい感じにパフォーマンスチューニングしてスピードアップさせるコンテストの予選に参加しました(詳しくは http://isucon.net/archives/cat_1024989.html)。ポータルに送った時のスコアは 15000 くらいで、一番良かった時は 19000 くらいでした。結果としては惨敗です。

チーム名は「ドラゴンチャーハン」で、@lesamoureuses と @tana_ra と僕が適当に集まって社内チームを組みました。

この記事のまとめとしては、ISUCON 楽しかった!が、惨敗で悔しいので来年も頑張りたい!です。

反省メモ

以下は社内振り返りのために殴り書きしたメモをもう少し読みやすくしたもの。読みにくいと思いますが、来年参加する人の参考になればラッキーです。

予選に向けた練習

ISUCON 2014 夏期講習の AMI を使って練習(去年の予選)しました。

ISUCON 夏期講習 2014 を開催しました : ISUCON公式Blog

2 回集まって練習し、前半はアプリケーションの把握、後半(前日)はチューニング。 前日に Varnish とかを使ってスコアが大きく上がってワイワイしてました。

役割分担

フロントエンドや DB 周りの調整を @lesamoureuses さん、アプリケーション周りでコード書くのを @tana_ra と僕。 このメモはアプリケーション側をいじってた僕の目線で書かれています。

チューニング要点

  • Varnish で /mypage をキャッシュしたり、前日に用意していた秘伝のタレ(設定ファイルの調整)をプロファイリング後に入れる
  • できるだけメモリに乗っけるようにコードを書き換える
    • ストレージが HDD であることと、メモリが 7.5 GB くらいあると聞いた時点で、I/O を発生させないようにする方針になった
    • 後述のインテグレーション失敗で全部はできなかった

序盤

  • 午前中
  • 人数分のインスタンス起動・webapp 以下を Git 管理
  • プロファイリングの準備
    • Nginx の設定を前日に用意したものに
    • LTSV で吐いて、ログを解析しやすくする
    • rack-lineprof を入れる
  • プロファイリング
    • 当然 /report が遅い。 次いで /mypage が遅い
    • /report のレスポンスは加点しないということレギュレーションに書いてあったが見落としていたため、ここをチューニングする方針になった
  • アプリケーションの理解・戦略を考える
    • Google Doc で共同編集しながら、リクエストパスとその挙動をまとめたり、メソッドごとの挙動をまとめたりした

中盤

  • 16 時ごろまで
  • Redis のセットアップ
  • Ruby から Redis を使う方法など変更の方針を共有
  • Redis を選んだのは前日に練習で使っていたのと、reds-objects に Redis::Counter というのがあって、ログイン失敗回数をインクリメントしていくのに便利そうだと考えたため(Redis について全然知らなかった)
    • 実際はひとつのキーに対してしかインクリメントできないものだったため使えなかった
    • この時点で memcached にしても良かったし、Ruby の Hash にぶち込む実装にしても良かった
  • 再起動時してもデータの変更内容を保存しておかないといけないことにサポートチャットで気付いた
    • Redis に入れてるデータが消えないようにするスクリプトを作成するなどの作業
    • 永続化のノウハウが無さすぎた
  • ここら辺で /report のレスポンスを高速化する必要がないことに気付く
  • アプリケーション側は Redis データ永続化とアプリ変更の2人に分かれた
    1. 永続化担当には MySQL のデータ(初期データ)を Redis に持っていくところもやってもらう
    2. コード変更側は永続化と初期データが Redis に入っているのを前提で、アプリコードの SQL を駆逐する
    3. 初期データが入っていないので /report のチェックが落ちる
    4. コードが合ってるのか間違ってるのか分からないまま進めたら、1 と 2 を統合しても案の定 /report のチェックが落ちる
    5. Redis に入れた初期データが間違ってるのかコードが間違ってるのかわからなくなってパニクる
    6. あきらめムード

後半

  • 16 時すぎくらい
  • 変更済みコードではデバッグが厳しいとわかったので app.rb をまっさらにして、小さい部分から変更していく
    • 決断が遅かった
  • 残りの時間ないでできることはギリギリまでやって終了

時間があればできたと思うもの

  • 主にアプリケーション周り
    • 一番最初に考えていた、SQLを駆逐した状態のコードにする
    • login_log は INSERT 結果を待たずにすぐ返す
    • attempt_login で banned, locked の処理は並列化できる(並列化のコストがありそう)
    • KVS を Ruby の Hash にしたり memcached にしたりの検証
    • @lesamoureuses さんは Varnish 周りや my.cnf 、カーネルパラメータ周りをやりたかったみたい
  • SQL を駆逐するつもりしかなかったのでインデックスを張ってない
    • 最初にアプリケーション全体に手を加えるという博打をやらずに、インデックス張ったりに手を出してもよかった

知見・反省点

  • 中盤まで /report のことしか考えてなかったので、レギュレーションをちゃんと読む。もはやみんなで音読するレベル
  • 仕事のやり方みたいな話だが、大きな変更をするときは小さい仕事に分割してちょっとずつ進める
    • 実際に3人で本番を想定して練習することがなく、役割分担が不慣れだったということもある
    • 練習が足りない
  • 前日に Varnish とか Redis を触りだすレベルだったので、もっと持ちネタを増やして望む

YAPC::Asia Tokyo 2014で当日スタッフをしました

去年に引き続き、当日スタッフをしてきました。

YAPC::Asia 2013に参加したです! - ミントフレーバー緑茶

スタッフと言っても例年通りコアスタッフの方々がしっかり準備してくださっているので、椅子を運んだりマイクを運んだりカキ氷を運んだりするくらいであんまり偉そうなことはしません。イベントは準備がキモですね。イベントホールの状況はコアスタッフでウルトラスーパー PHPer であるところの uzulla さんの記事がよくまとめられてて最高です。

スタッフとしてのYAPC::Asia 2014 レポート(Without about my talk) - uzullaがブログ

イベントホールスタッフを 3 グループに分割して、担当部分じゃないところは他のトークを見に行ったら良い。という提案を uzulla さんがしてくださったので、去年よりトークを見る時間ができて良かった。

以下は自分が見た発表&スライドについて。社内で YAPC フィードバック会があるので、もうちょっと発表スライドを読んでいきたい。

コマンドラインツールについて語るときに僕の語ること」 @deeeet さん

YAPC::Asia 2014でコマンドラインツールについて語ってきた | SOTA

自分にとって目新しいところはなかったけど、スライドがすごく見やすい&分かりやすい。

オープンソースの開発現場 - Perl 5.20 のSubroutine Signaturesが来るまでの奮闘の軌跡」 @lestrrat さん

YAPC::Asia Tokyo 2014 オープンソースの開発現場 - Google スライド

Subroutine Signatures を追加するまでのドラマが紹介されていた。皆が使っている既存のものに手を入れるということはそれぞれの人にとって賛否両論ある。自分にとっては良かれと思ってやっていることもいろいろな人にいろいろなプライオリティがあるから、否定されることもある。そんな中で自分のやりたいことを実現するには、コードを書いて実装するというだけではなく、やりたいことが実現するように仕向けていく人間力・政治力という、本質的ではなさそうなものが残念ながら必要になる。

大切なのは「自分以外の人は別のプライオリティを持っている」ということを認識し、それを持った上で立ち止まらず進み続けることかなと思う。他人が別のプライオリティを持っているということを知ると、他人がどんなプライオリティを持っているかという点を考慮しながら人間力・政治力を振るうために役立つし、人間力を発揮しなくても、他人の意見は他人の意見として過度に傷つかずに無視して我を通すか諦めるかして次に進むことができそう。

個人的には、既に動いている機能に手を加えるようなアグレッシブな変更よりも、質問の時に弾さんが言っていたように sub じゃなくて fun を作ってみるという手もありだったのになぁと思う(予約語が増えて、既に fun を使っているようなコードにダメージがあるかもしれないが)。有力そうな Subroutine Signatures の実現方法のひとつが序盤でバッサリと切られていたというのは残念。

HASH COLOR

f:id:jewel12:20140802174509p:plain

ちょっとしたHTMLはGitHub Gistに置いてbl.ocks.orgで表示するのがお手軽です - Qiita で bl.ocks.org を知り、何か試してみたくなって、入力に応じて色を変えまくるやつ作った。ずっと入力してると気分悪くなる。

http://bl.ocks.org/jewel12/f20ed3003e57cf558e2e

bl.ocks.org は gist の HTML を表示するだけというシンプルさが最高だと思う。

SlackのCUI

https://github.com/jewel12/slacui

チャンネル一覧とチャンネルを指定して読むことしかできない。 percol / peco でチャンネルを絞り込むと少しは便利に使えるけど、毎回API叩くから遅くて使いものにならない。

lacui channels | peco | cut -f1 | xargs slacui read

コンパイルログとかに何かしら色をつけたい

最近はHaskellの本を読んでいて写経したり色々試したりするのだけど、コンパイルログの見辛さによって、静的型付け言語の強みであるコンパイル時エラー検出の力が出せていないような気がした(ghcに--colorオプションとかある?)。

社内LTもあることだし、自動で色付けするマシーンを作ろうと思いたって作り始めた。テキストに自動で色をつけるというと、テキストをルールでパースして色をつけるというやり方になるかと思う。しかしいちいちパースルールを書くのもだるいし、テキストを適当に標準入力から突っ込むと適当に色付けしてくれるものが欲しい。

自分が知っている自動色付け方法はCoding in colorという、シンタックスハイライトされない部分にも色を付けて見やすくしてやろうというもの。

Coding in color — Hacking Programs : Code, Programming Idea, Tutorial, Showcase, Experience — Medium

function等のキーワード以外の単語を名前順にソートして、予め用意しておいた色のリストに割り当てていくというやり方になっている。例えばtypoしたときに色が違っていたりするので気付きやすいという利点がある。

他にどうやってログに色付けするかも考えつかなかったのでパクろうと思いHaskellで書いてみようとしたが、自分は想像以上にHaskellに精通しておらず、色々調べながら進めていたら就業時間後の2日かけても出来上がらなかった。余談だけど、System.Console.Rainbow (https://github.com/massysett/rainbow) のコードを読むのはMonoidとかを実際に使っていて、初心者には勉強になった。例えば "text" <> blue <> bold で太い青色文字列 "text" を表わすとして、この組み合わせは "text" <> bold <> blue でもいいみたいな。

今すぐHaskell力を上げるのは厳しいことがわかったので、色付けプログラムをRubyで書いてみたらプロトタイプがLT発表日のお昼休みで出来上がった。

https://gist.github.com/jewel12/b33f73635bbbed2b9e97

入力を空白でsplitしていったものを単語として扱っていて、Coding in colorと同じように着色していった結果。

f:id:jewel12:20140520011450p:plain

自分のコンソールではカビが生えたような彩色になってしまった。

元のログはこんな感じ。

f:id:jewel12:20140520014208p:plain

他にも色付けする方法ないかと無い知恵を絞ったところ、語の頻度によって、高頻度になるに連れて色を強調していくという方法をとってみた(逆にどうでも良い語だともとれるので強調しないというのもあり)。

f:id:jewel12:20140520011602p:plain

カビよりも落ち着いた感じになったが、たいして読みやすくなったようには思えない。"Not in Scope"の塊で色がついてるのはいい感じがする。頻度で色付けする方法の辛いところは、テキストファイルを全部読み込まないといけない点で、コンソールに流れるログに色付けはできない。

個人的には色をつけるだけでもなんとなく読みやすくはなったと思う。カッコ内は1語だったり複合語を考慮したりと適切な粒度の塊に色付けすればもっと見やすくなる予感はある。なんか適当に色付け方法を考えて試してみて、偶然いい感じになってくれたらと期待してたけど、まずここに色をつけて欲しいというふうに自分で色付けしてみてから、それに合わせて色付け作戦を練っていくアプローチが真っ当だったっぽい。

ご意見ご感想お待ちしております。

タスク切り替えにはコストがかかる

ゴールデンウィークに親と待ち合わせしていて、早めに着いたからジョエルオンソフトウェアを買って読んでいた。暇つぶしだから面白そうなところだけかいつまんで読むつもりだったけど、基本的に全部面白い。PART 2まで読み終わって一番面白かったのは23章の「人のタスク切り替えは有害であるとかんがえられる」。

Human Task Switches Considered Harmful - Joel on Software

よくタスクを平行してやるよりも直列で進めたほうが早く終わると感じる。フロー状態をぶつ切らないとかマジカルナンバーのように人間が同時に物事を把握できる量はそんなにないとか色々理由付けられると思うけど、この章のCPUのマルチタスキングを例にして解説しているところがわかりやすくて面白かった。

タスクの切り替えにはコストがかかる。ゴールデンウィーク前にしていた仕事の細部が思い出せない。昼休み前に自分はどんな構成のコードを書こうと思って途中まで書き進めていたんだっけ。という具合に人はすぐに物を忘れるので、思い出すのに時間がかかる。残念ながらパイプライン処理のようにタスクをこなす超人にはなかなかなれない。他のことが気になっても、できるだけ今のタスクが終わってからにできないかというのを意識するようになった。

ただ、期日が決まっている中で直列にタスクをこなすのは止めた方が良いときもある。タスクAとBがあって、序盤ではAもBも2日で終わるという(たいして根拠の無い)予測をしていて、2つ合わせて4日かかると思っていた。予定通りAを2日でこなし、Bにとりかかって1日目の夕方に、どうもBは4日必要なタスクだったと気付く。この時点で明日には終わらないから締め切りを3日伸ばしてくれとお願いすることになる。一方、最初にAを2日かけて終わらすのではなく、Aに1日、Bに1日というやり方だったら2日目で締め切りが伸びるということを伝えることができる。AとBが終了する日数は同じとしても、土下座するタイミングは速いほうが迷惑はかからない。すごい極端な話ではあるけど。

数日かかる大きいタスクは数時間単位に分割して、細かいタスクを直列に実行する。大きいタスクは直列に実行するのではなく、進めてない方のタスクをたまに様子見したりすると良いかなと思う。