CARTA TECH BLOG アドベントカレンダー 12月15日分の投稿です。
みなさんこんにちは、サポーターズの @y_chu5 (ちゅうこ) です。 普段はTypeScriptでWebフロント、ScalaでAPIサーバーのコードを書いたり、CIを整備しています。
さて、みなさんはこんな経験はないでしょうか。
『cloneして動かそうとしたらビルドが通らない』、『何もしてないのにテストが落ちるようになった』、『キャッシュ消したらアプリが壊れた』…
この記事では、OSSを使う側、作る側両方に立ってみて見えたバージョン固定の重要さを少しお話したいと思います。
これからお話する内容は、例えば言語だったり、また対象がライブラリやアプリケーション、CI設定やDockerfileなどに性質は違うにしろ、ある程度共通している内容となっています。 この記事の考えと、各ベストプラクティスを組み合わせていい感じにしてもらえたらなと思います。
前提としてはテストがあってCI(Continuous Integration)を回していることが前提の記事です。
はじめにまとめを…
- 緩すぎるバージョン指定で生殺与奪の権を他人に握らせるな
- 依存先の最新情報をキャッチアップしてバージョンを定期的に上げていこう
- 例えばライブラリやDocker Image、CIのOSなど
- CIではlatestでもビルドできてると最高
- 固定運用とlatest運用両方あるともっと最高
バージョンを固定しないことで起きる問題
この令和の時代、バージョン固定が出来ない環境は限られているので、意識せずともバージョン指定をもちろん行っているとは思いますが、以下のようなバージョン指定をしていないでしょうか?
例えば
- >7 みたいな最低バージョン指定(これ正しくはなんて言うんでしょうかね、識者教えて下さい)
- latest固定
この指定は開発者視点に立ってみると、非常にリスクのある指定であると考えられます。
最低バージョン指定の記載の場合を考えてみます。
例えばマイナーバージョンやパッチバージョンでAPIや挙動が変わらない、なんていうのは誰が保証したでしょう。 一応 セマンティックバージョニング というものを信用するのであれば動作などは保たれるのでしょうが、正しく運用されている例をなかなか見ません。 そういうこともあり、依存先がOSSのライブラリみたいな時は、急にインタフェースが変わっていた、動作が変わっていたなんでことザラにあります。 また悪意のあるコードが新たに追加された場合、いつの間にかその影響を受けてしまうなんてことも考えられます。
ではlatestにした場合はどうでしょう。
これも最低バージョンと同じような影響を受けるのはもちろん、大規模な変更が加わるメジャーアップデートの影響も受けることがあるでしょう。 今あなたが見ていたlatestは時間経過とともにlatestではなくなるのです。
この様に時間経過やアップデートのような外的要因から自分のソフトウェアが壊れることは、緩いバージョン指定では回避できていないことがわかります。
その影響はもちろん、使う側も受けることでしょう。使う側の動作が保証されていないのです。
ということで、本当に動作する環境のスナップショットを取る意味でも、バージョン固定を行うのが良さそうに思えます。
バージョンを固定したことで起きる問題
さて、上記の問題回避のためバージョン固定を行いました。 CIやテスト、ビルドなども安定し、動作保証も出来て非常に良い事だらけです。
しかし固定したことで新しいバージョンの存在を知ることがなくなってしまいました。 固定しなければ、キャッシュ削除やCIの失敗などでテストが落ちて…みたいなことでアップデートに気づくことは出来たでしょう。
その気づけなかったアップデートには例えばセキュリティアップデートのような重要なものが含まれるみたいなこともあるでしょう。 他にもアップデートの際、コードの変更を必要とするインタフェースの変更みたいなものが多く含まれていたら、もうアップデートは諦めたくなりますね。
そんなソフトウェアは、使う側に、あまりにもバージョンが古すぎて、より新しい環境での動作が保証されていないんじゃないか、またメンテナンスされていないんじゃないか、みたいな不安を与えてしまうかもしれません。
ということで、バージョンの固定は動作を保証してくれるメリットはありつつも、塩漬けによるデメリットやリスクをはらんでいるようです。
ではこの問題に対してはどう立ち向かえばよいでしょうか。 例えばアップデートに気づくことが出来るだけでも十分問題に立ち向かえそうに思えます。
それでは実際に私が実施しているTipsをご紹介します。
依存先のライブラリのアップデートを定期的に観測する方法
Tips1. RenovateやDependabotを使用する
例えば依存先がライブラリである場合は、RenovateやDependabotを使用することで、新しいバージョンを検知しPRを作ってくれます。 Dependabotに関してはGitHubでコード管理している場合、セキュリティアップデートの内容なども見ることが出来ます。
これによってライブラリの新しいバージョンを、自分で調べなくても知る機会が生まれます。
Tips2. 定期的に上げるタイミングを作る
これに関してはある程度開発体力がある場合に限られる内容ではありますが、
https://techblog.cartaholdings.co.jp/entry/2016/06/27/080000
の記事にように、定期的に自分で上げ続ける努力をするのもいいでしょう。 Tips1の様に自動でどんどん上げなくとも、定期的に細かく自分たちで上げ続けることによって、例えばマイナーバージョンやメジャーバージョンを一気に上げなければならない、ということは回避できるはずです。
と2つTipsを紹介しましたが、最後にこれらのTipsを更に活かす方法があるのでご紹介します。
Tips3. latestでもビルドする
既に課題点は述べているので、latestも運用することをおすすめします。 なぜならばlatestも同時に運用することで、以下のような開発におけるメリットが得られるためです。
- 動作することの保証があらかじめ見えるため、バージョンアップのコストを削減できる
- 動作しなかった場合、修正のヒントが得られる
この手法を導入するには例えば、対象のメンテナンス頻度にもよりますが、普段使用しているCIなどのテストで同時に走らせると良いでしょう。 CIの時間だったり、コストだったりなどが懸念点であれば、週イチだったり月イチみたいな頻度で定期的にCIを走らせるだけでも十分に効果を発揮します。
メンテナンス頻度が低いものでも月イチでlatestのCIが回っていたら、使う側としても安心感が得られることでしょう。
まとめ
と以上をまとめると
- 緩すぎるバージョン指定で生殺与奪の権を他人に握らせるな
- 依存先の最新情報をキャッチアップしてバージョンを定期的に上げていこう
- 例えばライブラリやDocker Image、CIのOSなど
- CIではlatestでもビルドできてると最高
- 固定運用とlatest運用両方あるともっと最高
となるのです。
このtipsはOSSに限らず普段の業務上の開発でも使えるtipsだと思うので、是非参考にしてみてください。