ジョエル流の不具合報告の仕方
僕は Joel Spolsky の書いた記事が好きなんですが、不具合報告の仕方を説明した記事が今までに一番役にたってるので、それを紹介します。元記事を見つけようとしたけど、見つけられなかった...
ジョエルによると、不具合報告に必要なことは以下の3つだけ。
- 期待していた挙動
- 実際に起ったこと
- それを再現する手順
これらを報告するだけで十分な不具合報告になる、という話です。
これを実際に実践してみると、確かにすごく使えるルールだと感じます。逆にこれらの情報が満たされていないと、バグ修正が大変になってしまう。
あと、このルールが洗練されてるところがすごく好きですね。必要なものは入っていて、かつ不必要なものが何もない。実に美しい。
このルールを利用して、自分たちの組織での不具合報告のルールを作ることもできる。
また、不具合報告にこれらのどれかが含まれてなければ、「再現手順をください!」とお願いすることもできる。
ここに含まれてないものは、不具合報告には必要ないのでは?という議論もすることができる。たとえば不具合が起きる法則みたいなものは、特に不具合報告になくても困らないけど、テスターさんによってはこういうのをがんばって法則を見つけようとしたりするので、それはしなくてもいいのでは、みたいな話ができる。法則を見つけてもらうよりは、再現手順を一つ報告してもらえば、不具合の原因が判明すれば、法則や影響範囲もわかるので。でも再現手順はできるだけ簡単に再現できるものを見つけてもらえるとありがたいですね。
今回これを書いたのは、これを忘れてバグの発見に手間取ってしまったんですが、ジョエルのルールに従って、再現手順を聞いておけばすぐに解決できたなー、という事例があったので共有しました。
団結力と結束力
Effective DevOps の毎日読書会を最近ヌーラボさんとしています。 今日は 9.3.5 チームの団結力 という章を読んだんですが、この章では「団結力」と「結束力」という言葉が使い分けられてます。
これらの使い分けはこの本の中での使い分けだと思うので一般性はないと思いますが、以下のように意味づけされていました。
団結力: チームメンバーがチームに貢献したいと思う度合い
結束力: チームメンバーを一つに束ねる力(共通の関心、利益)
団結力があると、メンバー間の信頼感があり、知識の共有が進み、共感が捗る。団結力はあるほうが良い。 団結力を高めるために結束力を利用できるが、結束力が高まりすぎるとエスノセントリズム(選民意識っぽい感じになってチーム外部に排他的な態度を取るようになる状態)になってしまってよくない。
エスノセントリズムはチーム間の協力ができなくなってdevops的にマイナスなので、結束力を極端に高めないほうが良い、とのこと。
「「読まなくてもいい本」の読書案内」の感想
「読まなくてもいい本」の読書案内 ――知の最前線を5日間で探検する
- 作者: 橘玲
- 出版社/メーカー: 筑摩書房
- 発売日: 2015/11/25
- メディア: Kindle版
- この商品を含むブログ (4件) を見る
確かAmazonで評判が良かったか何かで知ったので読んでみた。
内容は多方面にまたがっていて、刺激的な話ばかりだったのでスラスラと一気に読めてしまった。 知らなかった内容も多くて、今後興味を向けたい分野の参考にもなった。
話題はいくつかのグループに分かれていて、なんでそういうグループ分けにしたのかはわからない。ただ、それぞれの話題で共通する話題もあり、入口から入って最後まで進んでいくのに混乱しない構成であるのは確か。
自分の中で面白かった話題をいくつか挙げていく。
マンデルブロについての話
マンデルブロという名前はフラクタルやアルゴリズムで絵を描くときに聞いたことはあったけど、具体的にどういう人なのかは知らなかった。
実は複雑系やカオス理論といわれる分野で業績を残していた人だったらしいです。世の中の様々な事象は正規分布になっている、というのがよく言われますが、これでは説明できないことも多い。代わりにべき分布という考え方を導入して、その問題を解決したんだそう。ロングテール現象もべき分布なら説明できる。統計や複雑系の分野は今でもすたれてないので、勉強してみる価値がありそうだと思った。
ゲーム理論
ゲーム理論についても、基本的な考え方については勉強したことがあったけど、よくわかってなかった。それが非常に強力な考え方であることや、いろいろな分野に応用され続けていることなどを知れたのはよかった。これも勉強する価値がありそう。
政治体制について
政治体制の位置関係を知れたのもよかった。政治体制というのは人類が進化してきた結果として発達してきたもので、大きく分けて3種類の立場がある。平等主義のリベラリズム、自由主義のリバタリアニズム、共同体主義のコミュニタリアニズム。それ以外に進化の過程から出てきたのではない功利主義という政治体制がある。
これらの立場はMECEになってるぽくて、今までの人生で目にしてきた政治体制は確かにこれらのどれかに含まれる感じだ。なのでどういう主張が出てきたとしても、これらのどこに重点を置いた主張なのか、ということを考えれば分類して特徴を知ることができてしまうので、非常に強力そう。
面白いのは、進化の過程で出てきた3つの立場の主張は人間の本質的な欲求なのだけど、それら全てかなえる政治体制というのはありえないということが論理的に言えてしまう。この本はその点を明快に説明している。なので、それぞれの立場で妥協をしないといけないのだけど、それぞれの幸福度を最大にして妥協するにはどうしたらいいか、ということを考えるのが功利主義という考え方。 どういうトレードオフにするのが最も幸福度が高いか、というのは頭のいい人なら日常的にやっていることだけど、それをつきつめて考える主張なので、功利主義というのは頭のいい考え方なことは間違いない。
意識について
ほかには無意識と意識に関しての実験の話が面白かった。僕らは常日頃、自分の行動は自分の意志の結果として行動している、と考えているけど、実験の結果、僕らが行動する時には意識の介在する余地はあまりなく、だいたい無意識に決定を下しているということがわかったそう。
面白いのは無意識に選択した結果行った行動について、なぜそうしたのかを質問すると、ありそうな理由をでっちあげるという点。僕らの行動は自分の意志で行ったものじゃなくて、無意識が判断して行っている。じゃあ僕らの意識が何をしているのかというと、あとづけの理由を考えて、自分の行動に矛盾がないと信じ込ませていること。僕らは自分にうそをつきつづけて、自分を納得させ続けている。 だとするなら、自分の行動の理由を深く考え続けることにはそんなに意味はない、といえるのではないだろうか。犯人探しや反省をやりすぎても意味がなくてそれよりは、そう選択した原因と、次はどうするのがいいかを考えることのほうが有意義そうだ。
最近の科学の流行を知るのに良い本
いくつかの分野について、パラダイムの歴史を知ることができるので、科学の歴史を俯瞰するのには役立つ本だと思う。 ただ、科学は現在進行形で進み続けているものなので、5年後、10年後にはそれらの成果を踏まえてアップロードする必要があるだろう。なのでこの本は今読んでおくことに価値があると思う。
また、本書では筆者のおススメの分野も紹介されているが、今後何を学んでいくかは読者が選択する自由がある。内容を妄信するのでなく、自分の選択の参考にする、というスタンスで接するのが、本書との良い付き合い方かなと思う。
ISUCON5予選でスコア19450出しました
サーバチューニングの勉強になればとISUCON5の予選に参加してみたところ、予想外に予選通過できてしまいました。 初めてISUCON参加してみての感想を一言で言うと、めちゃくちゃ疲れるけど楽しかったです。 参考までに、僕が行った作業内容を書いてみます。
ベンチマークの実行を成功させる
まずベンチマークを実行できるところまで持っていきます。ここまではなんとかがんばるしかないですね。
mysql, nginx,unicornの設定チューニングする
前回参加者のブログを参考に、あらかじめ準備していたチートシート通りに設定しました。 systemdの使い方がわからなくてサービスを再起動方法をググったりして、わりと手間がかかりました。
設定内容は以下のとおり。
my.cnf
innodb_buffer_pool_size = 2G innodb_flush_log_at_trx_commit = 2
nginx.conf
worker_processes 5; worker_rlimit_nofile 4096; log_format ltsv 'host:$remote_addr\t' 'vhost:$http_host\t' 'port:$server_port\t' 'time:$time_iso8601\t' 'method:$request_method\t' 'uri:$request_uri\t' 'protocol:$server_protocol\t' 'status:$status\t' 'size:$body_bytes_sent\t' 'referer:$http_referer\t' 'ua:$http_user_agent\t' 'forwardedfor:$http_x_forwarded_for\t' 'forwardedproto:$http_x_forwarded_proto\t' 'apptime:$upstream_response_time\t' 'reqtime:$request_time'; #access_log off; access_log /var/log/nginx/access.log ltsv;
unicorn
プロセス数を5に
プロセス数はあとで増やすなど試してみたんですが、効果がなかったので5に戻しました。 ログ解析をするために、ltsv形式で出力しようというのは事前に決めてました。
ここまでである程度スコアが上がったのを確認して、次に戦略を立てるためにログ解析の準備をしました。
ログ解析の準備をしてログ解析する
sonotsさんが前回のISUCONでltsvのログをスクリプトで整形しと書いてたので、このアイデアをそのまま使わせてもらいました。
https://gist.github.com/sonots/9ae0167d31d7f4b42c9a
実際の作業ではボトルネックになってる箇所を見やすいように、URLをグループごとに見れるように、スクリプトを調整しました。
あとはアクセスログを退避してクリアするスクリプトも作っておきました。 これでベンチマークを動かすごとに、詳細なログ解析が得られるようになりました。 これを見てると / へのアクセスの処理にほとんどの時間がかかってて、静的ファイルへのアクセスはほとんど影響してないことがわかりました。なので今回の問題は、静的ファイルを素早くさばくことよりアプリケーションの処理を高速化するのが効果的だろうと判断しました。 このログ解析の仕組みは最後までチューニング方針の決定に役立ってくれたので、準備しておいたかいがありました。
アプリケーションのチューニング内容
アプリケーションのチューニングでやったことは、とくに大きな構成の変更はせず、参考実装のボトルネックを潰していった感じです。 N+1問題を潰したり、mysqlのindexを追加して行ったりしたら順調にスコアが上がっていってくれました。 今回の課題はアプリケーションのボトルネックを潰すのがメインだったので、アプリケーションエンジニアの自分にとっては普段やってる仕事と同じような感じで作業していけました。
反省点
- shellやエディタが普段の環境とちがうまま作業してしまって非効率でした。dotfileをgithubに置いておいて適用したほうがよかった。
- N+1問題が起こってるところをgrepで見つけていたのが良くなかったので、N+1問題を検出する仕組みを準備しておくべきだった。
- kazeburoの術によるとnginx設定はまだ足りないものがある感じ。( https://gist.github.com/sonots/62179703d429d36b1a57 )本選までに勉強しておこう。
良かった点
- ログ解析ツールが役に立った stat.rbは役に立った。実行結果を分析できるので、効率的にボトルネックに対処できた。
- mysql, nginxのチートシートは役に立った
- 予習したおかげで、設定ファイルの場所などで戸惑わずにすんだ。
作業ごとのスコアの遷移を掲載しておきます。 だいたいアプリケーションの修正とindexの追加に時間を使っていて、順調にスコアが上げれてましたね。
12:00くらい 初回ベンチマーク実行 => スコア 146 12:30 * nginx worker process を5に * unicorn worker process を 5に => 881 12:35 my.cnf修正 innodb_buffer_pool_size = 1G innodb_flush_log_at_trx_commit = 2 => 889 13:01 my.cnf修正 innodb_buffer_pool_size = 2G => 911 13:12 vimrcをいつも使ってるサーバからコピペ。vimプラグインは面倒なので持ってこなかった。 13:30 ログを解析したところ / に時間がかかってることがわかったので /を高速化する 13:40 footprints, relationsにindex追加 => 2248 14:19 is_friend? をone -> anotherの向きのみ見るように修正 => 2762 14:30 tail -f してたのをやめた => 2911 14:55 friend_idsを最初に取っておくように => 4352 15:06 comment取得にもfriend_idsを使うように => 4828 15:43 comment取得をsqlだけで取得するように。commentsにindex追加 => 12413 16:04 /friends のSQLをor使わないように修正 => 12432 16:17 /friendsをリファクタリング => 12480 16:26 nginx, unicornのworkerプロセスを5 -> 10に => 12313 効果ないので8に変更 => 効果ないので5に戻した 16:55 footprintのindexをuser_id, owner_id, created_at に変更 => 12460 17:08 一部erubis => slimに変更 => 見た目には正しく変換できてるように見えるがbenchmarkerでエラーになるので中止。 17:46 トップページでfriendsがcountしか使われてなかったので、sqlでcountを取得するように修正 => 13145 18:06 get_userが何度もviewから呼ばれてるので、開始時に取得するように修正(途中) => 14468 18:17 viewからentryを何度もSQLで取得してたので、一括して取得するように修正 => 15476 18:31 /entriesでコメント数を取るために何度もSQL実行してたのを一括して取得するように修正 => 16704 18:45 /footprints, /friendsでget_userを何度も実行してたのを一括して取得するように修正 nginxのaccess log をoffに => 19450
入門Reactの感想
Reactの学習のために、入門Reactを、ひと通りざっと読んだ。
入門 React ―コンポーネントベースのWebフロントエンド開発
- 作者: Frankie Bagnardi,Jonathan Beebe,Richard Feldman,Tom Hallett,Simon HØjberg,Karl Mikkelsen,宮崎空
- 出版社/メーカー: オライリージャパン
- 発売日: 2015/04/03
- メディア: 大型本
- この商品を含むブログ (2件) を見る
読むまでのReactの知識は、Hello, Worldを以前試したことがある程度だったが、問題なく読み進めることができた。ただし、インストールの手順などを丁寧に説明してはくれないので、JavaScriptでの開発経験は求められると思う。本の内容を一言で言うと、Reactの構成をひと通り説明している本だった。
- 1章 イントロダクション
- 2章 JSX
- 3章 コンポーネントのライフサイクル
- 4章 データフロー
- 5章 イベント処理
- 6章 コンポーネントの合成
- 7章 Mixin
- 8章 DOM操作
- 9章 フォーム
- 10章 アニメーション
- 11章 パフォーマンスチューニン
- 12章 サーバサイドレンダリング
- 13章 Reactファミリー
- 14章 ビルドとデバッグ
- 15章 テスト
- 16章 アーキテクチャパターン
- 17章 その他のユースケース
Reactがカバーする範囲の線引を明確にしてくれたのが、個人的に一番ありがたかった。 おおまかに言うと、ReactがカバーするのはDOMの操作とイベント処理で、ルーティングやMVCのモデルなどはReactの範囲外になる。そのあたりは他のフレームワークなりと組み合わせてまかなう必要がある。16章で、Backbone.RouterやFluxなど、Reactと組み合わせて使うライブラリの候補を挙げてくれてる。
また、データの流れを一方向にする仕組みや、props, stateの使い分けの基準がよくわからなかったが、そのあたりをわかりやすく説明してくれている。コンポーネントのフック関数一覧を、呼ばれるタイミングを交えて詳しく書いてくれてるのもありがたい。
本書を読み終えた段階で、今後Reactを勉強するのに困らない、下準備ができたと感じた。 ReactはMVCでいうところのVを担当するライブラリなので、サーバとのデータのやりとりや、プログラムのモジュール構成といったものは、別の仕組みで補う必要があり、Reactだけではプログラムは完結しない。Reactを組み込んだプログラムの設計方法を今後調べていくつもり。
Rubyのcaseを使ってFizzBuzzを書く
Shinosaka.rb #4におじゃましてきました。
今日はFizzBuzzを書くという課題でした。
FizzBuzzは何回か書いたことがあったので、あたらしい書き方ができないか考えてみたんですが、case式を使えば今までにないFizzBuzzを書けるんじゃないかと思ったんですが、あまりうまくいきませんでした。
それがこのコードなんですが、イメージしてたのはこういうのではなくて、caseのところになんか判定するやつを書いておいて、when のところには15, 3, 5 だけ書いておけばいいようにしたかった。
そういうのをしたかったんですが、Rubyのドキュメント読みなおしてみると、whenの引数をレシーバとして === を実行し、caseの引数を右辺値として実行した結果を評価するとのことで、caseのところにlambdaを置いておくというのではうまくいかなそうなことがわかりました。caseのパラメータをレシーバにしてくれれば良かったんですが...
それで他に手は無いかなと考えてみました。
Fixnum#===
をオーバーライドした解です。
case式は非常にすっきりしていい感じです。Refinementsを使っているので、Integer#===の挙動が変わるのはこのファイルだけということも保証されてます。
でもちょっと大げさな感じなので、できればlambdaを使ってなんとかしたい。
そこでこんなふうに実装してみました。
なかなかいいですね。caseにlambda渡すのは諦めて、whenにlambdaを渡すようにしました。 でも個人的に、caseの引数に何も渡してないのが不満。lambdaにiを閉じ込めてるからいいといえばいいんですが、それならifで良くない?という気がしてしまいます。
そこで、curry
メソッドを使って以下のように書き換えてみました。
caseにiを渡して評価するようにしました。Proc#=== は Proc#call と同じメソッドなので、
matcher.curry[15][i]
のように実行されているわけですね。 でも今度はcurryと書いてるのがうっとおしくなってきました。curryを使うんじゃなくて、lambdaを返すlambdaを定義してみましょうか。
whenの後ろがスッキリしました。その分lambdaの定義が読みにくくなってしまいましたが...まあいいでしょう。満足しました。
新しいFizzBuzzの書き方を思いつけて良かったです。ありがとうございました。
(2014/5/1追記)
curryの使い方を勘違いしてました。curryは引数を一つづつとるlambdaを返すんだから、予めcurryしておけばスッキリ書けた。
これでOKですね。curryを使うと、上に書いた、入れ子になってるlambdaと同等のlambdaを出力してくれる。
rubygems-bundlerのしくみ
https://github.com/mpapis/rubygems-bundler
rubygems-bundlerを入れると、bundle exec
がいらなくなるということを知りました。
どうやってbundle exec
を省略できるようにしてるのかわからなかったので、調べてみました。
結論としては、gem
がインストールした実行ファイルの shebang を書き換えることで、フックしてます。
たとえば rbenv を使ってて、rakeをインストールすると、 /home/hoge/.rbenv/versions/2.1.1/bin/rake
のようなパスに実行ファイルが作られます。
このファイルのshebangは、通常
#!/usr/bin/env ruby
なんですが、gem regenerate_binstubs
を実行すると、これらのファイルのshebangだけを
#!/usr/bin/env ruby_executable_hooks
と書き換えてしまいます。
この ruby_executable_hooks
というのが各Gemの中に lib/rubygems_executable_plugin.rb
というのを探して、あればそれを実行します。
rubygems-bundler
の rubygems_executable_plugin.rb
は、カレントディレクトリからルートにむかって Gemfile
を探し、あればそのファイルを使って Bundler.setup
を呼び出します。
こうして bundle exec
をつけずに rake を実行しても、 bundle exec
をつけて呼び出したのと同様の効果を実現してます。
gem regenerate_binstubs
コマンドを提供している executable-hooks
は、Gemがインストールされるときにフックを走らせることで、以後は、実行ファイルを提供するGemがインストールされるごとに、自動で shebang を書き換えます。