bundle updateで特定のgemのみ更新する時に気をつけるべきポイント
ちょっと依存関係の厳しいRailsプロジェクトを扱っていて、タイトルのようなことを行いたい要求が出てきたので、さっそくGoogle先生におうかがいを立てました。
やってはいけない手順
たぶんbundle updateコマンドの引数でもって何かしらコントロールできるんだろうと踏んで調べたところ、公式のドキュメントよりも上位に、まさにやりたいことを書いたQiitaの記事が出てきたので、早速コレに従って作業することにしました。
https://gyazo.com/0f6c5d5c9ced72ae43d008daa7dd6e47
内容を要約すると、bundle update --source ${GEM_NAME}としてやれば${GEM_NAME}のパッケージだけが更新されるというもので、コメント欄にも2018年11月の「うまくいった」コメントがあるので、コレで良かろうと思って作業に入ろうとしたところ、詳しい人から待ったがかかりました。
正しいやり方
曰く、特定のgemだけ更新したいときは bundle update --conservative ${GEM_NAME}を使うとの事。
確かに公式のドキュメントにもそのように書かれています。
なので、bundlerで特定のgemだけ更新したいときには--conservativeオプションを付けてbundle updateするようにしましょう。
さて、実用上は教えてもらった--conservativeオプションで十分なのですが、--sourceオプションを指定するときの挙動とどう違っていて、なぜQiitaで紹介されていた方法じゃダメなのかが気になったので少し調べました。
背景を調べる
背景を洗い出すには、本家のIssueとかを追いかければ良いんじゃないか?とアタリを付けて調べてみると、どうやら2012年ごろから知られている手法で、2015年ごろにコレってなんでそうなるの?という議論に発展していたようです。
通称bundler-source-hackと呼ばれていて、--sourceオプション指定時の内部の挙動で、副次的に「ある条件を満たすケースでは特定gemだけ更新できる」という効果が得られていたようです。
「ある条件を満たすケースでは」というのが曲者で、先出の2015年の議論では、最終的にbundler-source-hackについて詳細に調査をして、「なぜそういう挙動になるのか」「--sourceで特定gemだけ更新する技法は正しい方法なのか」という所がまとめられました。
結論としては--conservativeオプションが用意されていることと、先の正しいやり方を見ていただければわかるとおり、--sourceオプションを使って特定gemの更新をするのは誤りで、bundler-source-hackを調査した結果に書いてあるとおりGemfileにリストされていない依存関係がある時に期待している挙動を示さないので、ちょっと大きなプロジェクトでやってしまうと大打撃を受ける可能性があります。
そもそも「特定gemだけアップデートしたい要求が出てくるようなシステム設計がマズい」という向きの話もありますが、動いているサービスに手を入れる場合に、ビジネスへの影響度を考えると保守的な手法を選択したくなる気持ちもよくわかります。(し、現実に保守的な手法を選択しなければならないケースも多くあると思います)
今回の教訓は、Google先生の提示するランキングではなく、公式ドキュメントをちゃんと参照しようぜ!という事に尽きると思います。
#ruby #bundle #rails