私は私たちの会社のためにいくつかの内部アプリを開発する小さなチームの一員です。私たちはよりアジャイルになる過程にあり、これには特に多くの自動テストが含まれます。現在、私たちが最近取り組んだ1つまたは2つのアプリについて、通常、小さな可逆的な変更を行い、多くのテストを実行し、人間の介入なしで非常に高速に展開する状況にあります。
私たちは、私たちが「本当の」CIをやるのにはまだまだ長い道のりがあると思います。上記の1つまたは2つのアプリについては、おそらくすぐにそれに非常に近づくでしょう。しかし、私はレガシーコードの大部分にCIを使い始めた将来のある時点で、セットアップがどのようになるかを想像するのに苦労しています。
いくつかのスタンドアロンアプリがあり、それらはすべて異なるサーバーに個別に展開できるとします。それらの多くで使用され、それらの間で一貫して使用したいいくつかの共有コードもあります。これには、ユーティリティ関数、すべてのアプリの一部に一貫したインターフェイスなどを強制するコード、およびデータベースのORM定義(すべてのアプリで共有)が含まれます。
2つの代替案があり、どちらも非常に簡単でもエレガントでもありません。
このジレンマから抜け出す方法はおそらく、CIのリンプバージョンを実行することです。この場合、個々のコンポーネントは広範囲にわたってテストされ、迅速に展開されますが、ユーティリティとデータベーススキーマの大きな「フラグデイ」リリースに固執します。しかし、適切なCI/CDには多くの利点があり、私たちには見逃されているようです。これは見た目が良いソリューションではありません。上司がボックスにチェックを入れたことを満足させることは望んでいませんが、業務慣行を改善したいと考えています。
適切なCIのコードをどのように編成する必要がありますか。また、レガシーコードと将来の新規コードの両方について、アーキテクチャの計画と設計について学ぶための重要な教訓は何ですか?
コードをモノリシックシステムとしてではなく、一連のパッケージとして想像してください。一部のパッケージは他のパッケージに依存しています。 jQueryなど一部は会社の外部にあります。その他はあなたの会社によって開発され、公開されます。あなたの会社が開発した他のものは、最終的には非公開になります。
たとえば、Pythonでウェブアプリケーションを開発する場合、Flask(人気のあるPythonウェブフレームワーク)、および外部と内部の両方の他のパッケージに依存している可能性があります。
Flaskの開発者が新しいバージョンをリリースすると、CIはどうなりますか?そう、何も。行ってプロジェクトファイルを編集するのはあなた次第です。これからは、Flaskのバージョンxではなく、バージョンy。これを実行すると、CIはyourプロジェクトが変更されたと見なし、アプリケーションがFlaskの新しいバージョンで動作することを確認するすべてのテストを起動します。うまくいかない場合でも、Flask自体のバグを実際に明らかにする非常にまれなケースを除いて、おそらくyourアプリケーションを修正します。
同じロジックを、社内で作成された任意のコードに適用できます。共有ライブラリはPythonpackageになり、pypi
(Pythonのパブリックパッケージのリポジトリ)を介して共有されるか、会社内でのみ使用できるプライベートpip
サーバーに保存されます。
次に、何がビルドを壊したかを特に明確にします。パッケージAの新しいバージョンを公開すると、CIは対応するテストを実行し、バージョンにリグレッションが含まれているかどうかを示します。次に、パッケージBにパッケージAの新しいバージョンを使用するように依頼する段階で問題が発生した場合、パッケージAの新しいバージョンと互換性がないためにビルドを破壊したのは、パッケージBと同じです。 、アプリがFlaskまたはjQueryの新しいバージョンと互換性がない可能性があります。
依存関係を自分で実際に管理する必要がないことに注意してください。パッケージングシステムが管理します。介入が必要な唯一の問題は、参照の更新です。これは、特定のパッケージが別のパッケージの異なるバージョンを使用することを通知するアクションです。コードベースで頻繁に使用されるパッケージを変更した場合、それを使用するすべてのプロジェクトを追跡して変更するには、しばらく時間がかかります。
バージョン管理に関しては、それは本当に重要ではありません。 Gitを使用するチームとSVNを使用するチームがいる場合があります。 2つのチームがpypi
を使用し、内部パッケージ用に特定のpip
サーバーを選択することに同意するとすぐに、すべてが正常になります。同様に、FlaskまたはjQueryの開発者がGit、SVN、SourceSafe、またはTFSを使用しているかどうかは気にする必要はありません。
注:Pythonの例を使用しましたが、同じロジックを他の言語にも適用できます。 Node.jsにはnpm
、. NET Framework言語にはNuGet
などがあります。プライベートパッケージマネージャーも設定できます。
さらに読む: パッケージ、依存関係、チーム間の相互作用 、この質問に基づいた私の記事。
company社内に単一のパッケージサーバーを設置する必要はありません。異なるチームが独自のサーバーを展開できます。唯一の制約は、他のチームがパッケージを使用するためにサーバーの場所を知っている必要があることです。
すべての個々のコンポーネントリポジトリ(2番目の代替案)の「ラインナップ」をモノリシックな方法で処理することもできます(可能なアプローチについては このQに対する私の回答 を参照)、それらを単一のメガとして扱います。 -プロジェクト。これは、ある意味で、コンポーネント間の依存関係の管理の問題を無視することができます(はるかに複雑なIMHO)。
共有コードコンポーネントに対するすべての変更は、それらに依存するすべてのコンポーネントに影響を与えると見なされます。これにより、共有コンポーネントで広範なテストを行う代わりに、実際のアプリのテストに集中できます(IMHOは、これらの共有コンポーネントを使用するアプリを常に保証できるわけではありません)。
CIシステムは、プロジェクトで行う作業の編成をサポートします。したがって、必要に応じてさまざまな統合プロジェクトを作成できます。それぞれのプロジェクトには、もちろん、どのリポジトリルートからチェックアウトするか、どこにデプロイするかなど、まったく異なる設定があります。
そうは言っても、相互に緊密な依存関係があるモジュールがある場合、これらのモジュールは理想的には同じリポジトリーにある必要があります。
「タイトな依存関係」とは具体的なことを意味するものではありませんが、大まかな規則として、それらの間で統合テスト(ユニットテストではなく)を実行する必要がある場合は、おそらくタイトな依存関係と呼ぶ価値があります。
「理想的に」とは、それらを同じリポジトリに保持することの利点が、通常、欠点を上回ることを意味します。しかし、もちろん、あなたはあなたのコードをよりよく知っているので、決めるのはあなた次第です。