5

プロジェクトは svn の下にあり、すべてが順調に進んでいます。最近、主要な顧客から、コーディングなどを必要とする非常に具体的なカスタマイズを行うように依頼されました (構成または展開を使用して行うことはできませんでした)。私たちは、2 つの独立した開発ラインを維持することにしました。

  • trunkブランチは、一般のお客様向けに展開されている標準バージョンです
  • ブランチはこのarsh顧客向けであり、現在進行中のものとは別に開発中です。trunk

現在、arshから定期的に更新を受け取る必要がtrunkあり、 で実装されている機能arshが で役立つ場合がありtrunkます。この関係は双方向ですが、一方の方向 (からtrunkarsh) は非常に一般的ですが、もう一方の方向は不定期です。

これを行う最良の方法は何ですか?ワークフロー ? ベストプラクティス ?洞察?

編集: PHP 5.3、MySQL、Apache、Linux を使用しています。

4

2 に答える 2

3

ベストプラクティス?#ifdef(または、実行時構成またはその他のコンパイル時または実行時条件によって、条件付きで含まれているか、条件付きで依存関係が注入されている同じインターフェイスの個別の実装)!

並列バージョンをブランチとして維持することは、どのバージョン管理システムでも苦痛です。並列バージョンは、適切な条件付きコンパイルまたはランタイム構成手法を使用して維持するのが最適です。

ブランチ A をブランチ B にマージし、ブランチ B をブランチ A に戻す場合、両方のブランチはまったく同じになることに注意してください。これは、3 方向マージの固有のプロパティです。これはまさに機能ブランチに必要なものですが、さまざまな顧客のために並行バージョンを維持するのにはまったく適していません。

さまざまな顧客のバージョンを保持するには、代わりに条件付きコンパイルを使用してください。

  • オブジェクト指向コードでは、通常、共通のロジックを持つ基本クラスと、条件付きでプロジェクトに含まれるか、条件付きでインスタンス化されるバリアントに固有のロジックのみを持つバリアントごとのカスタム派生クラスを持つことができます。
  • ほとんどのプログラミング言語は何らかの形式の条件付きコンパイルをサポートしていますが、Java は顕著な例外です。

このアプローチにより、すべてのバリアントのテストを実行するか、すべてのバリアントを継続的インテグレーション サーバーでビルドしてテストすることにより、いずれのバリアントの機能も壊していないことを誰もがすぐに確認できます。

あなたはPHPに言及しています。そこにはコンパイル手順がないため、構成はランタイムのみになります。おそらく、条件付きで適切なテンプレートに含まれる顧客固有のオーバーライドを含むディレクトリを作成します。

注: 私は現在、この方法で 20 を超える顧客向けにカスタマイズされた C++ プロジェクトに取り組んでおり、問題なくスケーリングします。顧客ごとの正確なコードはありません。代わりに、オプションの一連の機能があり、さまざまなサブセットがさまざまな顧客に出荷されます。これにより、最大のバリアントを作成してテストできるため、すべての機能をテストするのが少し簡単になります。これは、多数の機能に成長する場合に役立ちます。特に、プロジェクトのビルドに時間がかかる場合 (継続的インテグレーション ビルドは約 1 時間実行され、夜間ビルドは 8 時間、すべての顧客バリアントのビルドには 1 日以上かかります)。

于 2013-03-11T14:28:45.567 に答える
0

言語については言及しませんが、オブジェクト指向言語を使用していると仮定して、カスタム機能を同じインターフェイスおよび/または基本クラスの個別の実装に保持し、実行時にファクトリを使用してどの実装を行うかを決定することを検討してください。走る。例 (C# の場合):

public interface IProcessor {
    void ProcessFile(string fileName);
}

public abstract class BaseProcessor : IProcessor {
    void IProcessor.ProcessFile(string fileName) {

        // Do shared stuff here like logging, validation, etc.

        ProcessFileForClient(fileName);
    }
    protected abstract void ProcessFileForClient(string fileName);
}

public class NormalProcessor : BaseProcessor {
    protected override void ProcessFileForClient(string fileName) {
        // Do your normal routine here
    }
}

public class AcmeProcessor : BaseProcessor {
    protected override void ProcessFileForClient(string fileName) {
        // Do your custom stuff here
    }
}

// This can be as complex as you need - you should probably use an IoC/DI framework,
// but this is a simple example.
public static class ProcessorFactory {
    public static IProcessor GetProcessor(string clientCode) {
        switch (clientCode) {
            case "Acme": return new AcmeProcessor();
            default: return new NormalProcessor();
        }
    }
}

この方法には、カスタム コードを通常のコードの邪魔にならないようにしつつ、基本クラスで必要なだけ共有できるという利点があります。

于 2013-03-11T14:39:09.497 に答える