21章 依存関係管理
単一のリポジトリー(モノリポ)を持つ大規模組織は、ソースコントロールのポリシーを用いて、別々のリポジトリーを使う場合と比べ圧倒的に先までスケールアップ可能であり、それがGoogleのアプローチである。
(中略)
互いをよく知らず必ずしも協力し合っているわけではないプロジェクト間の相互依存関係こそが、依存関係における問題
モノリポは全てを解決する
そうかもしれんが。。。
「他の全てが等しいならば、依存関係管理の問題よりソースコントロールの問題を選べ」
激しく同意
このような問題は一般に、ある依存関係が何らかの要件を欠くと動作しなくなる(†1) にもかかわらず、他の依存関係がその同じ要件に適合しないために起こる。
†1.この要件は、言語バージョン、下位レベルのライブラリーのバージョン、ハードウェアバージョン、オペレーティングシステム、コンパイラーフラグ、コンパイラーバージョン等のどの要件でもありうる。
IDEや言語のバージョンを上げたほうが調査や改修時の選択肢も広がっていいのでは…と思うものの、動作しなくなるリスクで踏み切れずにリプレース時に上げましょうになってるアプリがそこそこある…外的要因でアップデートせざるを得なくなることもあるので早めに対処しないと…
早めに対処するために依存先を減らす、というのをこまめにやってますね(焼け石に水かもしれない)
21.1 何故依存関係管理がそれほど難しいのか
ダイアモンド継承を思い浮かべて、それそれ、まぢ根が深いんだよなーっておもいながらも、それがGoogleくらいの大きな組織だと影響が大きすぎるんだろうなってあらためておもった。
ビルド内に複数の(独立分離した)バージョンの依存関係を組み込むことができる言語もある
nodeのパッケージマネージャがダイアモンド依存関係にどんな対応策を取っているかが細かく紹介されている記事
コンパイル言語の場合はどうしているんだろう
と思ったら21.2に詳しく書いてある
21.2 依存関係のインポート
セキュリティの脆弱性が発見されたり、プラットフォームが変化したり、
依存関係のネットワークが発展したりといった諸々の事情が合わさると、
元々の意図と関係なくその依存関係のアップグレードを強いられることがある。
つい最近セキュリティのアップデートするためにライブラリとcliのバージョンを上げたいので影響調査してくれという依頼が来たばかり。単体テストがないので影響調査が重たいのがつらい…
React黎明期のときは、簡単に互換性ぶち壊すライブラリがたくさんあったな...
こうした互換性の問題がプログラミングの問題ではなくソフトウェアエンジニアリングの問題である点を認識しておくことが重要だ。(中略)依存関係は時間の経過とともにどのように変化し、更新に追随していくのかという点と、機能を単に動作させるだけでなく保守について案ずるように開発者を仕向けることが難しい点に関係している
1章の最初で「プログラミングとソフトウェアエンジニアリングの決定的な違いは時間、スケール、トレードオフ」「ソフトウェアエンジニアリングは時間で積分したプログラミング」と書かれていたけど、一番典型的なのはこの依存性管理の問題かもしれない
その場で動けば良いんだったらあまり気にすることはない
大規模になるほど細かいライブラリは自分たちで実装して、基盤的なところだけOSSやAPIレベルで互換性があるようにつくるっていうのがあるのはわかる。(自動車、宇宙航空、Googleなど)
だが、そこまで大規模で長期にわたってお金を産み続けるソフトウェアをつくれる機会ってなかなかないんだよなーともおもった。
バイナリ互換性に依存していたとしても、プログラミングを今のところとりあえず動作させるという行動はうまくいきはする... (中略) ライブラリをアップグレードしない限りは
これよくある光景かなと思ったなー。とりあえず動くはnowはOKだけど、持続可能ではないのでいつかツケを払うときがくるということか...
そのツケを今か後かなんだけど、あとになると依存関係も多くなり対応するときにはよりコストがかかりそう
機能追加や仕様変更のときに再設計 & リファクタリングすることが大事ってことなんかな?
依存するコードを局所化する
コアドメインになればなるほど外部ライブラリには依存しないようにする
生産性の点でフレームワークに依存しないことは難しい。開発され続けるフレームワークをどうにかして選ぶしかない
最大公約数的にたくさんの機能を提供するFWに依存し、依存先を減らす戦略も有効
何らかの補修が必要な場合に備えてそのパッケージを保守する少なくとも2人のエンジニアがOWNERSに必ず登録されているようにする
OWNERSは9章に出てくる、全てのディレクトリに置いてあるコードオーナーの管理ファイル
我々のthird_partyポリシーは、これらの残念ながらよくあるシナリオ向けには機能しない
毎度のことながら社内のポリシーやルールがエンジニアリングをちゃんと理解した上で作られて運用されていることに惚れ惚れする
安定性を明示的に優先していない上流プロジェクトはリスクであるということだ
これはつまり、上流プロジェクトは安定性を考慮して依存先を選んでいる(=運用でカバー)ということだろうか
21.3 理論上の依存関係管理
何も変化しない
用途を限定したハードウェアだと非常に有効なのが不幸
汎用ソフトウェアでも選ばれてしまうことが多かったのはこれが原因だと思う
「枯れた技術」って良い言葉ですよね
ゆえに、"必要なもの全てをバンドルしろ"は機能するときがあるんだよなーっていうのをかんじる。。。RailsやJSがこうなっていることの便利さなんだよなー。コントロールしたい領域を増やそうとするとこうなる。(ただし、難しさを遅延しているだけにすぎないかもしれない)
SemVer制約はNP完全であるっていうの、少し考えればわかるけど、まぢかー!っていう感じだった。。。デスヨネー。
21.4 SemVerの制限
あらゆる形式のAPIへのパブリック/プライベートアクセスについて十分な制御のできるプログラミング言語を選ぶべき
このへんの理由でC#がJavaより扱いやすいっていうのはあったなー。適切に使っている人が少ないっぽい感じはあったが。
SemVerに村を焼かれたレベルで細かく書いてあって、ビルドツール作る会社や自社内ライブラリの数が巨大な会社はやっぱりちがうなーっておもった。
この節は愚痴という感じ
ForInternalUseByLibBaseOnlyDoNottouchThisIReallyMeant
「押すなよ、絶対に押すなよ」
押すよねそれは
Railsではドキュメントが作成されていないAPIは内部APIで、予告なく破壊的に変更される可能性がある、というルールがあって、使う側の自己責任ということになっている
RailsはOSSだから自己責任が通用するが、社内ライブラリだとそうもいかない
各社がコミッターを雇ったり標準化に関わったりするのは自社の都合を入れやすいから
SemVerは機能するのか
読んでいて「提供側が更新内容をバージョンという情報に圧縮するのがそもそも間違い」だが「更新が依存関係を壊すかどうかは利用側次第」で、それぞれをコントロールしている人間が違うのだから統一的な解決手段はないよな、と思った
なので急進派としてコントロールしている人間を揃える=live in head という発想が出るのはわからんでもない
Googleによるディストピア(コードを書く人間は全員Google社員である、レベルの)が築かれるくらいしか解決策はないように思う
逆説的に、自由に誰でも開発できることとのトレードオフと言えるかも
21.5 無限のリソースがある場合の依存関係管理
社内と社外のバージョンは時間の経過とともにゆっくりと分岐
社内で使っているライブラリをOSSで公開してもリリース以降メンテナンスしなくなったみたいなことは経験ある
社内版とかOSS版とか分けてしまうとコストが高くなりがちなのかな?
それでCentOSなくなっちゃったんですかね
ElasticsearchやTerraformがタダ乗りで割を食った話
GitLabとかはうまくいっているように見える
長期間サポートする計画 (と権限)なしに物をリリースしてはいけない
胸がいたい...
AppEngineの事例が涙なしに語れない事情のかたまりだ。。。
21.6 結論
デファクトスタンダードはSemVerだけど、Live at headでいいからみんなテストするんだ!っていうのもたしかにいいよね。なんかGentoo Linuxっぽさがあるなw
21.7 要約
「依存関係の提供にはコストがかかる。」の一言につまっているな。。。
みんなからのコメント
Googleにしかできないとしたら、それはなぜか?
社内ライブラリの利用プロジェクトにはCIが整備されているとか、社内ライブラリのheadバージョンを簡単に利用できる仕組みがあるからとか?
依存関係がある、壊れやすいという嗅覚 (スキル) が必要なのかも
壊れやすそうなところは薄く作るし、壊れたことを検知するためのテストなんかも書く必要がある
こういう嗅覚があまりないチームだと依存関係を放置して、「動かない」とか「サポート終了」みたいなきっかけで対応するからコストも高くなりがちなんだろうな
そして不具合も多い傾向
現場でどこまでできているか?
最近社内ライブラリのような大きなものをつくらなくなってしまったが、前職ではたしかに似たようなことはやっていたなっていう気持ち。(live at headにちかい)
一方でSemVerをまもっているときに本当に不意な変更がないのかっていわれると、ランタイム側との相性の問題とかも含めてどこまでテストできているのかってめっちゃ難しいんだよな。。。
特定のモジュールに依存している...
Rubyのgemとかほかのライブラリ (Ruby以外の) に依存しているケースがありつらい
nokogiri とかでめっちゃ苦労した記憶しかない
JVM言語の強み: ネイティブ依存のライブラリが基本ない
この本があるのになぜ実践する企業はすくないのか?
そこそこな規模で使ってくれている利用ユーザーが近くにいないとか?
ランタイムとの整合性にかんしてはどこまでテストすればいいのかを把握するのがすでに人間には無理なのではないかと思うことがある。
再設計、リファクタリング、依存関係のライブラリのアップデートなど、やらないとどうなるか?って想像力 (スキル) が足りてない OR いつかやる (経験上、「いつかやる」やらない) と思っている
この章に関してはそもそもちゃんとした解決策を提供してない
それの乗り越え方はなにか?
SemVerをまもるっていう観点だと、各種仕様やバグチケットからAIがリスクベースにテストケースを生成してくれるみたいなツールとかSaaSがうまれると産業的にはよくなりそう。
WebAPIで利用してもらっている場合にはログから自動テストをつくってテストがパスするかをみてみるとか?(秘匿情報っぽい気もするのでそのへんの扱いをクリアしないといけないけど)
ステップを小さくするとしたらどうできそうか?
アルファ版をリリースしてコンパイルと自動テストだけでもいいからためしてもらって、試してもらうことになにかインセンティブをつけるとか?
OSSだったらスポンサーやコントリビューターに名前を載せるとかでもいいのかもしれない。