私は質問の引用の著者です。これは以前の回答からのものです。
ジェイソンが私のような短い発言を疑い、説明を求めるのは正しい。もちろん、その答えのすべてを完全に説明したとしたら、本を書く必要がありました。
Mike が指摘するように、svn:external
-like 機能の問題の 1 つは、ターゲット ソースの変更が自分のソースを破壊する可能性があることです。特に、そのターゲット ソースが所有していないリポジトリにある場合はそうです。
私のコメントをさらに説明するにあたり、最初にsvn:external
、他のツールや機能と同様に、-like 機能を使用する「安全な」方法があることを述べさせてください。ただし、この機能は悪用される可能性がはるかに高いため、これをアンチパターンと呼んでいます。私の経験では、それは常に誤用されており、そのような安全な方法で使用したり、その使用を推奨したりすることはほとんどありません. さらに、Subversion チームを中傷するつもりはないことに注意してください。私は Subversion が大好きですが、Bazaar に移る予定です。
この機能の主な問題は、あるビルド (「プロジェクト」) のソースを別のビルドのソースに直接リンクすること、またはプロジェクトをバイナリ (DLL、JAR など) にリンクすることを奨励し、通常使用されることです。それが依存するもの。これらの使用はどちらも賢明ではなく、アンチパターンを構成します。
他の回答で述べたように、ソフトウェア ビルドの基本原則は、各プロジェクトが正確に 1 つのバイナリまたは主要な成果物を構築することであると考えています。これは、関心の分離の原則をビルド プロセスに適用したものと見なすことができます。これは、あるプロジェクトが別のプロジェクトのソースを直接参照している場合に特に当てはまり、カプセル化の原則に違反しています。この種の違反のもう 1 つの形式は、サブビルドを再帰的に呼び出してシステム全体またはサブシステムを構築するビルド階層を作成しようとすることです。Maven では、この動作を強く推奨/強制しています。これは、私が推奨しない多くの理由の 1 つです。
最後に、この機能を望ましくないものにするさまざまな実際的な問題があることを発見しました。1 つには、svn:external
いくつかの興味深い行動特性があります (ただし、詳細は今のところわかりません)。もう 1 つの理由として、そのような依存関係をプロジェクト (ビルド プロセス) に明示的に表示する必要があり、ソース管理メタデータとして埋もれないようにする必要があることが常にわかります。
では、この機能を使用する「安全な」方法は何ですか? 作業環境を「設定」する方法など、一時的に 1 人だけで使用する場合だと思います。プログラマーがリポジトリ内に独自のフォルダー (またはプログラマーごとに 1 つ) を作成し、svn:external
現在取り組んでいるリポジトリの他のさまざまな部分へのリンクを構成する場所を確認できました。次に、その 1 つのフォルダーをチェックアウトすると、現在のすべてのプロジェクトの作業コピーが作成されます。プロジェクトが追加または終了すると、svn:external
定義が調整され、作業コピーが適切に更新されます。ただし、チェックアウトを呼び出すスクリプトでこれを行うなど、特定のソース管理システムに縛られないアプローチを好みます。
記録として、私がこの問題に最近遭遇したのは、2008 年の夏にsvn:external
、大規模な規模で使用していたコンサルティング クライアントで発生しました。Ant および Jython ベース (WebLogic 用) のビルド スクリプトは、このマスター作業コピーの上に構築されました。最終的な結果: スタンドアロンで構築できるものは何もなく、文字通り数十のサブプロジェクトがありましたが、単独でチェックアウト/作業するのに安全なものはありませんでした。したがって、このシステムでの作業には、最初に 2 GB を超えるファイルのチェックアウト/更新が必要でした (バイナリもリポジトリに入れました)。何かを成し遂げることは無益な練習であり、私は 3 か月試した後に辞めました (他にも多くのアンチパターンが存在していました)。
編集: 再帰的なビルドについて説明します -
何年にもわたって (特に過去 10 年間)、私はフォーチュン 500 企業や大規模な政府機関向けに、何層にも及ぶディレクトリ階層に配置された何十ものサブプロジェクトを含む大規模なシステムを構築してきました。私は Microsoft Visual Studio プロジェクト/ソリューションを使用して .NET ベースのシステムを整理し、Java ベースのシステムには Ant または Maven 2 を使用し、Python ベースのシステムには distutils と setuptools (easyinstall) を使用し始めました。これらのシステムには、通常、Oracle または Microsoft SQL Server の巨大なデータベースも含まれています。
使いやすさと再現性のために、これらの大規模なビルドを設計することに大きな成功を収めました。私の設計基準は、新しい開発者が初日に現れ、新しいワークステーション (おそらく典型的な OS インストールだけでデルから直接) を与えられ、簡単なセットアップ ドキュメント (通常はインストール手順の 1 ページだけ) を与えられるというものです。また、ワークステーションを完全にセットアップし、完全なシステムをソースから、監視も支援もなしに、半日以内で構築できます。ビルド自体を呼び出すには、コマンド シェルを開き、ソース ツリーのルート ディレクトリに移動し、1 行のコマンドを発行してすべてをビルドする必要があります。
その成功にもかかわらず、このような大規模なビルド システムを構築するには、大規模なビジネス クリティカルなアプリケーション/システムを構築する場合と同様に、細心の注意を払い、堅実な設計原則を厳守する必要があります。重要な部分は、各プロジェクト (単一の成果物/成果物を生成する) には単一のビルド スクリプトが必要であり、明確に定義されたインターフェイス (ビルド プロセスの一部を呼び出すためのコマンド) を備えている必要があることであることがわかりました。他のすべての (サブ) プロジェクトから単独で。歴史的に、システム全体を構築するのは簡単ですが、1 つの部分だけを構築するのは難しい/不可能です。各プロジェクトが真に独立していることを注意深く確認することを学んだのはつい最近のことです。
実際には、これは、少なくとも 2 つのビルド スクリプト層が必要であることを意味します。最下層は、各成果物/アーティファクトを生成するプロジェクト ビルド スクリプトです。そのような各スクリプトは、そのプロジェクト ソース ツリーのルート ディレクトリに存在し (実際、このスクリプトはそのプロジェクト ソース ツリーを定義します)、これらのスクリプトはソース管理について何も知らず、コマンド ラインから実行されることを期待し、プロジェクトのすべてを相対パスで参照します。ビルド スクリプトに追加し、いくつかの構成可能な設定 (環境変数、構成ファイルなど) に基づいて、外部の依存関係 (ツールまたはバイナリ アーティファクト、他のソース プロジェクトではない) を参照します。
ビルド スクリプトの 2 番目のレイヤーもコマンド ラインから呼び出すことを目的としていますが、これらはソース管理について認識しています。実際、この 2 番目のレイヤーは多くの場合、プロジェクト名とバージョンで呼び出される単一のスクリプトであり、名前付きプロジェクトのソースを新しい一時ディレクトリ (おそらくコマンド ラインで指定) にチェックアウトし、そのビルド スクリプトを呼び出します。
継続的インテグレーション サーバー、複数のプラットフォーム、およびさまざまなリリース シナリオに対応するには、さらにバリエーションが必要になる場合があります。
プロジェクト セット全体の特定のサブセットを構築する目的で、(最初のレイヤーを呼び出す) スクリプトの 2 番目のレイヤーを呼び出すスクリプトの 3 番目のレイヤーが必要になる場合があります。たとえば、各開発者は、現在取り組んでいるプロジェクトを構築する独自のスクリプトを持っている場合があります。マスター ドキュメントを生成するため、またはメトリックを計算するために、すべてを構築するスクリプトが存在する場合があります。
とにかく、システムをプロジェクトの階層として扱おうとすると逆効果になることがわかりました。プロジェクトを相互に結び付けて、単独で、または任意の場所 (継続的インテグレーション サーバー上の一時ディレクトリ) または任意の順序 (依存関係が満たされていると仮定) で自由にビルドできないようにします。多くの場合、階層を強制しようとすると、試みる可能性のある IDE 統合が壊れます。
最後に、プロジェクトの大規模な階層を構築すると、パフォーマンスが過度に集中する可能性があります。たとえば、2007 年の春に、Ant を使用して構築した適度なソース階層 (Java と Oracle) を試みましたが、構築は常に Java の OutOfMemoryException で中止されたため、最終的に失敗しました。これは、利用可能なすべてのメモリを使用できるように JVM を調整した 3.5 GB のスワップ スペースを持つ 2 GB RAM のワークステーション上にありました。アプリケーション/システムは、コード量の点では比較的些細なものでしたが、再帰的なビルドの呼び出しにより、どれだけ多くのメモリを割り当てても、最終的にはメモリが使い果たされました。もちろん、実行にも永遠に時間がかかりました (中止されるまでに 30 ~ 60 分が一般的でした)。私は非常にうまく調整する方法を知っていますが、最終的にはツール (この場合は Java/Ant) の限界を超えていました。
ビルドをスタンドアロン プロジェクトとして構築し、それらを完全なシステムに構成してください。軽くて柔軟に保ちます。楽しみ。
編集:アンチパターンの詳細
厳密に言えば、アンチパターンは、問題を解決するように見えても解決しない一般的なソリューションです。これは、重要なギャップを残すか、追加の問題 (多くの場合、元の問題よりも悪い) を導入するためです。ソリューションには、1 つまたは複数のツールと、それらを目前の問題に適用するための手法が必ず含まれます。したがって、ツールまたはツールの特定の機能をアンチパターンと呼ぶのはストレッチであり、人々はそのストレッチを検出して反応しているように見えます。
一方、私たちの業界では技術よりもツールに焦点を当てるのが一般的であるように思われるため、注意を引くのはツール/機能です (ここで StackOverflow に関する質問を簡単に調査すると、簡単に説明できるようです)。私のコメントとこの質問自体は、その慣行を反映しています。
ただし、この場合のように、そのストレッチを行うことが特に正当化される場合があります。一部のツールは、ツールが思考を形作ると主張するところまで、それらを適用するための特定のテクニックにユーザーを「導く」ように見えます(わずかに言い換えられています)。それがアンチパターンであると私が提案するのは、主にその精神にありsvn:external
ます。
問題をより厳密に述べると、アンチパターンとは、プロジェクトをソース レベルで結合することを含むビルド ソリューションを設計すること、プロジェクト間の依存関係を暗黙的にバージョン管理すること、またはそのような依存関係を暗黙的に変更できるようにすることです。結果。のような機能の性質上、svn:external
これらのマイナスの結果を回避することは非常に困難です。
プロジェクト間の依存関係を適切に処理するには、基本的な問題とともにこれらのダイナミクスに対処する必要があり、ツールと手法は別の道をたどります。考慮すべき例はIvyです。これは Maven と同様の方法で役立ちますが、多くの欠点はありません。Java ビルドの問題に対する私の短期的な解決策として、Ant と組み合わせた Ivy を調査しています。長期的には、マルチプラットフォーム ソリューションを促進するオープンソース ツールにコア コンセプトと機能を組み込むことを検討しています。