web-dev-qa-db-ja.com

Subversionの外観はアンチパターンですか?

Subversionでは externals を使用して他のリポジトリの作業用コピーを埋め込むことができるため、プロジェクト内のサードパーティライブラリソフトウェアのバージョン管理を簡単に行うことができます。

これらは、ライブラリの再利用と ベンダーソフトウェア のバージョン管理に理想的であるように見えますが、 それらの批評家 がないわけではありません。

Subversionエクスターナル(または他のツールで類似)は使用しないでください。これらはアンチパターンであるため、不要です。

外部を使用する際に隠れたリスクはありますか?それらがアンチパターンと見なされる理由を説明してください。

68
Ken

私は 前の回答 からの質問の引用の著者です。

ジェイソンは私のような短い発言に疑いを持ち、説明を求めるのは正しいことです。もちろん、その答えのすべてを完全に説明するのであれば、本を書く必要があったでしょう。

マイクはまた、svn:externalに似た機能の問題の1つは、特にそのターゲットソースが所有していないリポジトリにある場合、ターゲットソースの変更があなた自身のソースを破壊する可能性があることであることを指摘することは正しいです。

私のコメントをさらに説明するにあたり、他のツールや機能と同じように、svn:externalのような機能を使用する「安全な」方法があることを最初に述べさせてください。ただし、この機能は誤用される可能性がはるかに高いため、 アンチパターン と呼びます。私の経験では、これは常に誤用されており、安全な方法で使用したり、その使用を推奨したりすることはほとんどありません。バザールに移るつもりですが、私はSubversionチームへの非難を意味しないことに注意してください。

この機能の主な問題は、1つのビルド(「プロジェクト」)のソースを別のビルドのソースに直接リンクしたり、プロジェクトをバイナリ(DLL、JARなど)にリンクしたりすることを奨励し、通常使用することです。それが依存している。これらの使用はどちらも賢明ではなく、アンチパターンを構成します。

他の回答でも述べたように、ソフトウェアビルドの基本原則は、各プロジェクトが正確に1つのバイナリまたはプライマリ成果物を構築することであると考えています。これは、ビルドプロセスへの 懸念の分離 の原則の適用と見なすことができます。これは、あるプロジェクトが別のソースを直接参照する場合に特に当てはまり、これも カプセル化 の原則に違反しています。この種の違反の別の形式は、サブビルドを再帰的に呼び出すことによって、システム全体またはサブシステムを構築するためのビルド階層を作成しようとすることです。 Mavenはこの動作を強く推奨/強制します。これは、私が推奨しない多くの理由の1つです。

最後に、この機能を望ましくないものにするさまざまな実際的な問題があることがわかりました。まず、svn:externalにはいくつかの興味深い行動特性があります(しかし、今のところ、詳細は私にはわかりません)。もう1つは、そのような依存関係がプロジェクト(ビルドプロセス)に明示的に表示され、一部のソース管理メタデータとして埋め込まれていないことを常に必要とすることです。

では、この機能を使用する「安全な」方法は何ですか?作業環境を「構成」する方法など、一時的に一人で使用する場合だと思います。プログラマーがリポジトリー(またはプログラマーごとに1つ)に独自のフォルダーを作成する場所を確認できます。ここで、現在取り組んでいるリポジトリーの他のさまざまな部分へのsvn:externalリンクを構成します。次に、その1つのフォルダーをチェックアウトすると、現在のすべてのプロジェクトの作業用コピーが作成されます。プロジェクトが追加または終了すると、svn:external定義が調整され、作業コピーが適切に更新されます。ただし、私は、チェックアウトを呼び出すスクリプトを使用してこれを行うなど、特定のソース管理システムに関連付けられていないアプローチを好みます。

ちなみに、この問題に最近さらされたのは、2008年の夏に、大規模なsvn:externalを使用していたコンサルティングクライアントで発生したものです。すべてがクロスリンクされて、単一のマスター作業コピーが作成されました。 Ant&Jythonベース(WebLogic用)のビルドスクリプトは、このマスター作業コピーの上に構築されました。最終結果:何もスタンドアロンで構築できず、文字通り数十のサブプロジェクトがありましたが、それ自体でチェックアウト/作業するのに安全なものはありませんでした。したがって、このシステムでの作業では、最初に2 GBを超えるファイルのチェックアウト/更新が必要でした(バイナリもリポジトリに配置されています)。何かを成し遂げることは無益な練習でした、そして私は3か月間試した後去りました(他の多くのアンチパターンも存在していました)。

編集:再帰的ビルドの解説-

何年にもわたって(特に過去10年間)、Fortune 500企業や大規模な政府機関向けに、多くのレベルの深いディレクトリ階層に配置された何十ものサブプロジェクトを含む大規模なシステムを構築してきました。 Microsoft Visual Studioプロジェクト/ソリューションを使用して.NETベースのシステム、JavaベースのシステムのAntまたはMaven 2を整理し、Pythonベースのシステムでdistutilsとsetuptools(easyinstall)の使用を開始しました。これらのシステムには、通常OracleまたはMicrosoft SQL Serverの巨大なデータベースも含まれています。

私は、使いやすさと再現性のためにこれらの大規模なビルドを設計することに大きな成功を収めてきました。私の設計基準は、新しい開発者が初日に登場し、新しいワークステーション(おそらく、通常のOSインストールのみのDellから直接)を与えられ、簡単なセットアップドキュメント(通常、インストール手順の1ページだけ)を与えられることです。ワークステーションを完全にセットアップし、ソースから、監視なし、支援なしで、半日以内に完全なシステムを構築できる。ビルド自体を呼び出すには、コマンドシェルを開き、ソースツリーのルートディレクトリに移動し、1行のコマンドを発行してすべてをビルドします。

その成功にもかかわらず、このような大規模なビルドシステムを構築するには、大規模なビジネスクリティカルなアプリケーション/システムを構築する場合と同様に、十分な注意と堅固な設計原則の厳密な遵守が必要です。重要な部分は、各プロジェクト(1つのアーティファクト/成果物を生成する)に1つのビルドスクリプトが必要であり、明確に定義されたインターフェイス(ビルドプロセスの一部を呼び出すためのコマンド)が必要であり、それが耐えなければならないことです。他のすべての(サブ)プロジェクトからの単独。歴史的には、システム全体を構築するのは簡単ですが、1つだけを構築することは困難/不可能です。最近、私は各プロジェクトが本当に独立していることを注意深く確認することを学びました。

実際には、これは少なくとも2層のビルドスクリプトが必要であることを意味します。最下層は、各成果物/成果物を生成するプロジェクトビルドスクリプトです。このようなスクリプトはそれぞれ、プロジェクトソースツリーのルートディレクトリにあります(実際、このスクリプトはプロジェクトソースツリーを定義します)。これらのスクリプトはソース管理について何も知らず、コマンドラインから実行されることを想定しており、プロジェクトの相対パス内のすべてを参照します。ビルドスクリプトに追加し、いくつかの構成可能な設定(環境変数、構成ファイルなど)に基づいて外部依存関係(ツールまたはバイナリアーティファクト、他のソースプロジェクトはありません)を参照します。

ビルドスクリプトの2番目の層もコマンドラインから呼び出すことを意図していますが、これらはソース管理について知っています。実際、この2番目のレイヤーは、多くの場合、プロジェクト名とバージョンで呼び出される単一のスクリプトであり、次に名前付きプロジェクトのソースを新しい一時ディレクトリ(おそらくコマンドラインで指定)にチェックアウトし、そのビルドスクリプトを呼び出します。

継続的インテグレーションサーバー、複数のプラットフォーム、およびさまざまなリリースシナリオに対応するには、さらにバリエーションが必要になる場合があります。

プロジェクトセット全体の特定のサブセットを構築する目的で、スクリプトの2番目の層(最初の層を呼び出す)を呼び出す3番目のスクリプト層が必要になる場合があります。たとえば、開発者ごとに、現在作業しているプロジェクトをビルドする独自のスクリプトがある場合があります。マスタードキュメントを生成するため、またはメトリックを計算するためにすべてを構築するスクリプトがある場合があります。

それにもかかわらず、システムをプロジェクトの階層として扱うことは逆効果であることを発見しました。単独で、または任意の場所(継続的インテグレーションサーバーの一時ディレクトリ)、または任意の順序(依存関係が満たされている場合)で自由にビルドできないように、プロジェクトを相互に関連付けます。多くの場合、階層を強制しようとすると、IDE統合が失敗する可能性があります。

最後に、プロジェクトの大規模な階層を構築することは、単純にパフォーマンス集約的すぎる可能性があります。たとえば、2007年の春に、Antを使用して構築した控えめなソース階層(JavaとOracle)を試してみましたが、Java OutOfMemoryExceptionでビルドが常に中止されたため、最終的に失敗しました。これはオンでした。 2 GB RAM使用可能なすべてのメモリを使用できるようにJVMを調整した3.5 GBのスワップスペースを備えたワークステーション。アプリケーション/システムはコード量の点では比較的簡単でしたが、再帰的なビルド呼び出しは、私がどれだけのメモリを与えても、最終的にはメモリを使い果たしました。もちろん、実行するのにも永遠にかかりました(中止されるまでに30〜60分が一般的でした)。非常にうまくチューニングする方法を知っていますが、最終的に、私はツール(この場合はJava/Ant)の制限を単に超えていました。

ですから、自分自身で、ビルドをスタンドアロンプ​​ロジェクトとして構築し、それらを完全なシステムに構成してください。軽量で柔軟性を保ちます。楽しい。

編集:アンチパターンの詳細

厳密に言うと、アンチパターンは一般的な解決策であり、問​​題を解決するように見えますが、重要なギャップを残したり、追加の問題(多くの場合、元の問題よりも悪い)を引き起こすため、解決しません。解決策には必然的に1つ以上のツールと、それらを当面の問題に適用するための手法が含まれます。したがって、ツールまたはツールの特定の機能をアンチパターンとして参照することはストレッチであり、人々はそのストレッチを検出し、それに十分に公平に反応しているようです。

一方、技術ではなくツールに焦点を当てることは、当業界では一般的な慣行のように思われるため、注目を集めるのはツール/機能です(StackOverflowに関するここでの質問のカジュアルな調査は、簡単に説明できるようです)。私のコメントとこの質問自体は、その実践を反映しています。

ただし、この場合のように、そのストレッチを行うことが特に正当化される場合があります。一部のツールは、それらを適用するための特定の手法にユーザーを「導く」ように見え、 ツールの形状は考えた (わずかに言い換えられた)と主張するところまでです。 svn:externalはアンチパターンであることをお勧めするのは、その精神の大部分です。

問題をより厳密に述べると、アンチパターンは、プロジェクトをソースレベルで結び付けるビルドソリューションを設計するか、プロジェクト間の依存関係を暗黙的にバージョン管理するか、そのような依存関係を暗黙的に変更できるようにすることです。結果。 svn:externalのような機能の性質上、これらの悪影響を回避することは非常に困難です。

プロジェクト間の依存関係を適切に処理するには、これらのダイナミクスと基本的な問題に対処する必要があり、ツールと手法は別の道をたどります。考慮すべき例は Ivy です。これは、Mavenと同様の方法で役立ちますが、多くの欠点がありません。 Javaビルドの問題の短期的な解決策として、Antと組み合わせたIvyを調査しています。長期的には、中核的な概念と機能をオープンソースツールに組み込んで、マルチプラットフォームソリューションを促進します。

70
Rob Williams

これはまったくアンチパターンではないと思います。私はグーグルでいくつかの簡単な検索を行い、基本的に何も思いつきませんでした... svn:externalsの使用が悪いまたは有害であると文句を言う人はいません。もちろん、注意しなければならない注意事項がいくつかあります...そして、それはあなたがすべてのリポジトリに大量に振りかける必要があるものではありません... 。彼はアンチパターンとして非難することを除いて、実際にはsvn:externalsについて決して議論しませんでした。そのような抜本的な発言は、その人が発言をするようになった方法についてのサポートや少なくとも推論なしで常に疑われています。

とはいえ、外観の使用にはいくつかの問題があります。マイクが答えたように、それらはリリースされたソフトウェアの安定したブランチを指すのに非常に役立ちます...特にあなたがすでに制御しているソフトウェア。ユーティリティライブラリなどの多くのプロジェクトで内部的に使用しています。ユーティリティライブラリベースを拡張して動作する小さなグループがありますが、そのベースコードは多くのプロジェクトで共有されています。さまざまなチームがユーティリティプロジェクトコードをチェックインするだけで、100万のブランチを処理したくないので、svn:externalsは非常にうまく機能します。一部の人々にとって、それらは答えではないかもしれません。ただし、「使用しないでください...」という文言や、これらのツールがアンチパターンを表すものであることに、私は強く反対します。

65
Jason Coco

Svn:externalsを使用する場合の主なリスクは、参照されたリポジトリがコードを破壊したり、セキュリティの脆弱性を導入したりする方法で変更されることです。外部リポジトリもあなたの管理下にある場合、これは許容できる場合があります。

個人的には、私が所有するリポジトリの「安定した」ブランチを指すためにsvn:externalsのみを使用しています。

19
Mike

古いスレッドですが、外部を変更するとコードが壊れる可能性があるという懸念に対処したいと思います。以前に指摘したように、これはほとんどの場合、外部プロパティの誤った使用が原因です。外部参照は、ほとんどすべての場合、外部リポジトリURIの特定のリビジョン番号を指す必要があります。これにより、別のリビジョン番号を指すように変更しない限り、外部は変更されません。

エンドユーザープロジェクトで外部ライブラリとして使用する内部ライブラリの一部については、重大な変更を強制しないMajor.Minorバージョンでライブラリのタグを作成すると便利です。 4ポイントのバージョン管理スキーム(Major.Minor.BugFix.Build)を使用すると、BugFix.Buildの変更でタグを最新の状態に保つことができます(ここでも、重大な変更はありません)。これにより、リビジョン番号なしでタグへの外部参照を使用できます。メジャーまたはその他の重大な変更の場合、新しいタグが作成されます。

外観自体は悪くありませんが、それによって人々が外観の悪い実装を作成することを妨げるものではありません。それらを安全かつ効果的に使用する方法を学ぶのに、多くの調査をする必要はなく、いくつかのドキュメントを少し読むだけです。

18
ulty4life

プレーンな外部がリポジトリを破壊する可能性があるためアンチパターンである場合、明示的なリビジョンを持つものはそうすべきではありません。

svn book からの抜粋:

外部定義は、ローカルディレクトリをバージョン付きリソースのURL **(および場合によっては特定のリビジョン)にマッピングしたものです。

これはすべて、機能を使用する目的に依存すると思います。それ自体はアンチパターンではありません。

9
smoothdeveloper

Subversionの外観には明確な欠陥がありますが、現在のプロジェクトが依存するライブラリ(自社とベンダーの両方)を含めるために、それらをかなりうまく使用しているようです。だから私はそれらを「アンチパターン」とは考えていません。私にとって重要な使用ポイントは次のとおりです。

  • それらは、他のプロジェクトの特定のリビジョンまたはタグ(決して先頭ではない)を指します。
  • それらは、独自のソースコードなどから離れた現在のプロジェクトに挿入されます(たとえば、「サポートファイル」と呼ばれるサブディレクトリに)。
  • それらは、他のプロジェクトの「インターフェース」ファイル(インクルードフォルダーなど)とバイナリライブラリ(つまり、他のプロジェクトの完全なソースを取得していない)のみを参照します。

私もこの取り決めの主要なリスクとより良いアプローチに興味があります。

8
luapyad

aはbと言っても、aabwhyと言わない限り、これはそうです。

Subversionの外部参照で見られる主な欠陥は、作業コピーを更新するときにリポジトリが存在することが保証されないことです。

Subversionの外部参照を使用して悪用することができ、機能自体はそれだけですa機能a patternantipatternとは言えません。

私はあなたが引用した人の答えを読みました、そして私は同意しないと言わなければなりません。プロジェクトがリポジトリからファイルバージョンXYZを必要とする場合、外部Subversion参照で簡単にそれを提供できます。

はい、必要な参照のバージョンを具体的に指定しないことで、間違って使用できます。それはあなたに問題を与えますか?たぶん!

それはアンチパターンですか?まあ、それは異なります。あなたが引用するテキストの作者によって与えられたリンクをたどれば、すなわち。 ここ 、それでは違います。悪い解決策を提供するためにcanを使用することは、そうすることの全体の方法、アンチパターン。それがルールだったとしたら、プログラミング言語は概してアンチパターンであると言えます。なぜなら、すべてのプログラミング言語であなたは悪い解決策を作ることができるからです。