コンテンツにスキップ

ソフトウェアのバージョンアップを継続的に進めるための設計とプラクティス

ソフトウェアの更新を小さく頻繁に続けるための設計と運用方法を紹介します。依存を薄く保つ設計、段階的なデプロイ、更新の自動化を通じて、バージョンアップを大工事にしない進め方を考えます。

OSS やサードパーティライブラリ、ミドルウェアの更新が後回しになりがちなのは、「動作しているシステムに触りたくない」「障害が怖い」という心理があるためです。

更新を長期間怠ると、既知の脆弱性が残るだけでなく、新機能やバグ修正もいつまでも利用できません。更新を先送りするほど深刻な技術的負債を抱え、開発者体験の悪化や、障害時の原因特定の難しさにもつながります。

バージョンアップを後回しにする「見えない負債」

バージョンアップを先送りにすると、2 つの深刻な問題が生じます。1 つは非推奨 API に依存し続ける問題であり、もう 1 つはビッグバンリリースによるシステム障害です。

非推奨 API に依存し続ける問題

古いライブラリを使い続けると新機能を使えないうえに、バージョンアップすれば置き換わる古い API に合わせて、新しいコードを書かなければならないこともあります。いずれ破棄すると分かっている API のために開発リソースを消費すると、開発者体験を損なうだけでなく、将来の改修コストも雪だるま式に増えます。

ビッグバンリリースによるシステム障害

更新の頻度が下がると 1 回あたりの変更差分が巨大化し、複数のライブラリを一括で更新する「ビッグバンリリース」になりやすくなります。影響範囲が大きいぶん、システムが壊れる可能性も高まります。

一括で大規模に更新すると依存パッケージ同士がかみ合わなくなり、同時に破壊的変更が発生することもあります。本番環境で不具合が起きると、どのライブラリのどの変更が原因かを突き止める必要があるため、原因の特定は極めて困難です。バージョンアップを安定して行いたいのであれば、影響範囲を小さく限定した更新を繰り返すことが重要です。

依存更新を自動化する仕組み

多層化した依存関係のなかで、更新の対象は次のように多岐にわたります。

  • アプリケーションが使う言語ライブラリ
  • コンテナイメージとベース OS
  • DB やネットワーク周りのミドルウェア

依存するソフトウェアが増えるほど、更新の負荷は大きくなります。更新の有無や 1 つ 1 つの更新の影響を人手で確かめようとしても限界があるため、継続的に更新するなら自動化ツールの導入が必須です。

自動化ツールの活用

  • RenovateやDependabotを活用し、リポジトリ内の依存定義を定期スキャンして更新版の Pull Request を自動生成すること。
  • 依存定義ファイルをデフォルトブランチへ集約し、スキャンツールが全容を追跡できるリポジトリ構成を保つこと。

ツールによる自動 PR 生成を導入すると「更新の有無を調べる作業」の工数を削減でき、浮いた工数で「変更差分のレビューと検証」に集中できます。

検索性と走査性

依存定義ファイルをデフォルトブランチへ集約するのは、機械的に更新を検知するうえで検索性と走査性が重要だからです。古いソフトウェアを使っている箇所を検索やスキャンで見つけられれば、更新が必要なソフトウェアを特定できます。検索性や走査性を損なう例の 1 つが、複数ブランチでの運用です。GitHub のコード検索が対象とするのはデフォルトブランチだけなので、ほかのブランチを検索できません。スキャンツールにもデフォルトブランチしか対象としないものがあり、複数ブランチでの運用は走査しにくい構成です。

更新リスクを抑える検証とデプロイ戦略

更新頻度を高めるなら、バージョンを上げてもシステムが壊れないことを確かめられる仕組みが欠かせません。

プラクティス 期待される効果 具体的なアプローチ
CI による自動テスト 非互換性やリグレッションの早期検知 自動生成された PR に対して単体テストや結合テストを自動実行する
段階的デプロイ戦略 障害影響範囲の極小化 カナリアリリースやブルーグリーンデプロイにより、新しい版へ流すトラフィックを制御する
継続的メンテナ監査 放置された OSS の早期排除 コミット頻度や Issue の消化状況から、将来も保守される技術を選定する

事前の自動テストだけですべての不具合を検知しきれないため、デプロイ戦略で影響範囲を限定し、ロールバックやバックアップも備えておきます。表に挙げたカナリアリリースやブルーグリーンデプロイに加えて、問題の検知に使えるシャドウデプロイという戦略もあります。

関連する技術選定の失敗パターン

メンテナンスや運用に関連する話として、次のような技術選定の失敗パターンがあります。

  • メンテナンス性を軽視し、「おもしろそう」という好奇心を優先して技術を選ぶ
  • 先を見据えた運用を考慮できずに、運用できない技術を採用してしまう

失敗が招く結果

メンテナンス性を軽視した選定に陥ると、後々のバージョンアップのコストが高くなるうえに障害が増え、リプレイスが必要になることもあります。運用できない技術を採用すると中長期的に運用コストが増えるため、組織として提供できる価値も増やしにくくなります。自ら開発したものを自ら運用する DevOps の考え方に立ち返ることが大切です。ソフトウェア開発サイクルの一部分ではなく、広い領域に責任をもって活動することによって、継続して価値提供するための意思決定と技術力が鍛えられます。

まとめ

ソフトウェアのバージョンアップは、たまにある大工事ではありません。セキュリティの向上や新機能、バグ修正の恩恵を受け続けるために、日々の開発サイクルへ組み込んで続けるのが理想です。

  • 依存関係の更新をためらわず、差分を小さく保つこと。
  • Renovate などのツールで更新検知と PR 作成を機械化すること。
  • 自動テストと段階的デプロイで、万が一の不具合にも迅速に対処できる仕組みを整えること。
  • 技術選定ではメンテナンス性を考慮し、運用できる技術を選ぶこと。

小さな更新を後回しにすると、後々のバージョンアップのコストが高くなります。反対に、更新を小さく刻む体制を整えれば、安全性と開発生産性を長期間にわたって高く保てます。