本番環境でテストする! github が作った scientist gem を使ってみよう

github/scientist

これは何?

github が開発し、つい先日 ver1.0 がリリースされた gem です。
本番環境で新しいコードを試すためのツールです。
例えば以下のようなコードがあったとしましょう。

class Repository
  def pullable_by?(user)
    self.is_collaborator?(user)
  end
end

このコードを以下のようにリファクタリングしたい、とします。

def pullable_by?(user)
  has_access?(user)
end

しかし、新しいコードが元のコードと全く同じように動いてくれるかどうか心配。。。
そこで scientist の登場です。
以下のように書きます。

def pullable_by?(user)
  science do |experiment|
    experiment.use { is_collaborator?(user) }
    experiment.try { has_access?(user) }
  end
end

さて、このコードが実際に何をするかというと、

  • science ブロックは必ず experiment.use ブロックの結果を返します。
  • 時々、experiment.try ブロックも実行し、結果を比較して記録します。
  • experiment.try ブロック内で例外が発生しても捕捉し、記録だけして処理は続行します。

このような処理によって、新しいコードの処理を安全に 「実験」 することができます!

なぜこんなものが必要なの?

きちんとテストを書いていればこんなものは不要ではないか?あなたは今、そう思っているかもしれません。
しかし、あなたのテストは万全でしょうか?本番で起こりうる様々なケースを本当に網羅できているでしょうか。
本番のデータベースに密かに入り込んでいるかもしれない 「不正なデータ」 まで、完全に予期できていますか?(と、github の人が言ってました。)

使いどころ

ある程度以上の規模のユーザが利用中のシステムにおいては、自動テストシステムよりもはるかに多くのマシンパワーが本番環境に割り当てられ、また、実際のユーザによってありとあらゆる実行経路でコードが処理されていることでしょう。
これをテストに使ってしまおう、というのが scientist です。「実験」 には余分な負荷がかかりますが、いつ実験をするかは自由にカスタマイズが可能なので、

  • 特定の時間帯だけ実験する
  • 特定のサーバだけ実験する
  • CPU に余裕があるときだけ

といったような設定をすることで、「本番環境で、本物のユーザにテストをしてもらう」 ことが可能になるのです。

使えなどころ

「実験」 の副作用を完全に消せるわけではないので、データを書き換えたり、外部システムをコールしたりする処理には一切使用できません。実験できるのは read only な処理に限られます。
公開前の開発中の段階で、ユーザがまだ利用しないような機能に対してはあまり有効ではありません。ちまちまテストを書きましょう。

see also