web-dev-qa-db-ja.com

マスターブランチ上で数百のカスタマイズされたブランチを維持する

現在、PHPアプリケーションの共有リポジトリに1つのマスターブランチがあります。私たちのソフトウェアのサブスクライバーである500を超えるクライアントがあり、そのほとんどがさまざまな目的でカスタマイズされています。別のブランチ。カスタマイズは、別のテキストフィールド名、まったく新しい機能またはモジュール、またはデータベース内の新しいテーブル/列にすることができます。

私たちが直面する課題は、これらの何百ものカスタマイズされたブランチを維持し、クライアントに配布するときに、時々新しい機能を提供してマスターブランチを更新し、マスターブランチの変更をカスタムブランチにプッシュして更新することです。それらを最新バージョンに更新します。

残念ながら、これによりカスタムコードで多くの競合が発生することが多く、すべての競合を解決するためにすべてのブランチに何時間も費やしています。これは非常に非効率的であり、これらの競合を解決するときにミスが珍しくないことがわかりました。

マージ中の労力が少なくなるmasterブランチでクライアントリリースブランチを最新の状態に保つより効率的な方法を探しています。

145
Fernando Tan

あなたは枝を完全に乱用しています!バージョン管理の柔軟性ではなく、アプリケーションの柔軟性によってカスタマイズをカスタマイズする必要があります(これは、ご存じのように、この種の使用を目的としたものではありません)。

たとえば、テキストフィールドラベルをテキストファイルから取得し、アプリケーションにハードコード化しないでください(これが国際化の仕組みです)。一部の顧客が異なる機能を使用している場合は、アプリケーションをmodularにして、厳密な内部境界を厳密で安定したAPIで管理し、必要に応じて機能をプラグインできるようにします。

コアインフラストラクチャとすべての共有機能は、保存、保守、テストonceのみが必要です。

これは最初から行うべきでした。すでに500種類の製品バリエーション(!)がある場合、これを修正することはhugeジョブ…ですが、継続的なメンテナンス以上のものではありません。

500のクライアントを持っていることは素晴らしい問題です。ブランチでこの問題を回避するために前もって時間を費やしていた場合、クライアントを取得するのに十分長い間取引を続けることができなかったかもしれません。

まず、クライアントに十分な料金を請求してほしい[〜#〜] all [〜#〜]カスタムバージョンを維持するためのコスト。私は、クライアントがカスタマイズを再度行うために料金を支払うことなく新しいバージョンを入手することを期待していると想定しています。まず、95%のブランチで同じであるすべてのファイルを見つけることから始めます。その95%は、アプリケーションの安定した部分です。

次に、ブランチ間で数行だけ異なるすべてのファイルを見つけます。これらの違いを取り除くことができるように構成システムを導入してみてください。したがって、たとえば、テキストフィールドラベルが異なる何百ものファイルがあるのではなく、任意のテキストラベルを上書きできる1つの設定ファイルがあります。 (これは一度に行う必要はありません。クライアントが初めて変更したいときに、テキストフィールドラベルを構成可能にするだけです。)

次に、戦略パターン、依存性注入などを使用して、より難しい問題に移動します。

クライアント自身のフィールドに列を追加するのではなく、データベースにjsonを保存することを検討してください。これらのフィールドをSQLで検索する必要がない場合は、これでうまくいく場合があります。

ファイルをブランチにチェックインするたびに、メインと比較して、空白を含むすべての変更を正当化する必要があります。多くの変更は不要であり、チェックイン前に削除できます。これは、1人の開発者がコードのフォーマット方法についてエディターで異なる設定をしているためと考えられます。

最初に、多くの異なるファイルを含む500のブランチから、ほとんどのブランチにいくつかの異なるファイルのみがあることを目指しています。 まだ生きるために十分なお金を稼ぎながら。

何年にもわたって500のブランチがまだあるかもしれませんが、それらの管理がはるかに容易であれば、勝利しました。


Br3w5のコメントに基づく:

  • クライアントごとに異なる各クラスを取ることができます
  • クラスの外部からクラスで呼び出されるすべてのメソッドを定義する「xxx_baseclass」を作成します
  • Xxxがxxx_clientName(xxx_baseclassのサブクラスとして)と呼ばれるようにクラスの名前を変更します
  • 依存性注入を使用して、クラスの正しいバージョンが各クライアントに使用されるようにします
  • そして今、賢い洞察のためにbr3w5が思い付きました!静的コード分析ツールを使用して、複製されたコードを見つけ、基本クラスに移動するなど

簡単な粒度を得た後でのみ上記を行い、最初にいくつかのクラスでそれを追跡します。

93
Ian

今後、インタビューで Joelテスト の質問をしてください。難破船に入らないほうがよいでしょう。


これは、ああ、どうやって言うか...本当に、本当に悪い問題があります。この技術的負債の「金利」は非常に高くなるでしょう。回復できない可能性があります...

これらのカスタム変更は「コア」とどのように統合されていますか?それらを独自のライブラリにして、単一の「コア」を持ち、特定の顧客ごとに独自の「アドオン」を持つことができますか?

または、これらはすべて非常にマイナーな構成ですか?

私は解決策は次の組み合わせだと思います:

  • ハードコーディングされたすべての変更を構成ベースのアイテムに変更します。この場合、誰もが同じコアアプリケーションを持っていますが、ユーザー(またはあなた)は必要に応じて機能をオン/オフにしたり、名前を設定したりします。
  • 「クライアント固有」の機能/モジュールを個別のプロジェクトに移動するため、「プロジェクト」を1つ持つ代わりに、モジュールを備えた「コアプロジェクト」を1つ持つことができ、簡単に追加/削除できます。または、これらの構成オプションも作成できます。

500以上のクライアントでここに到達したかのように、どちらも簡単なことではありません。これを分離するための変更は、非常に時間がかかる作業になると思います。

また、クライアント固有のすべてのコードを簡単に分離および分類する上で、重大な問題が発生すると思います。

変更のほとんどが特に言葉の違いである場合は、言語のローカリゼーションについて this のような質問を読むことをお勧めします。複数の言語を完全に実行している場合でも、サブセットだけを実行している場合でも、ソリューションは同じです。 これ は具体的にPHPおよびローカリゼーションです。

39
enderland

これは、あらゆるVCSで攻撃できる最悪のアンチパターンの1つです。

ここでの正しいアプローチは、カスタムコードを構成によって駆動されるものに変換することです。その後、各顧客は、構成ファイル、データベース、またはその他の場所にハードコードされた独自の構成を持つことができます。機能全体を有効または無効にしたり、応答の外観をカスタマイズしたりできます。

これにより、1つのマスターブランチを本番コードで保持できます。

17
Daenyth

ブランチの目的は、メインブランチの安定性を壊す危険を冒すことなく、開発の1つの可能な道を探ることです。それらは最終的に適切なタイミングでマージされるか、行き止まりにつながる場合は破棄されるべきです。あなたが持っているのはそれほど多くのブランチではなく、同じプロジェクトの500forksであり、重要なチェンジセットをそれらすべてに適用しようとするのは厄介です仕事。

代わりにすべきことは、コアコードを独自のリポジトリに配置し、設定によって動作を変更したり、動作を注入したりするために必要なエントリポイントを 反転依存関係 で許可することです。

クライアントのさまざまな設定は、外部で構成された状態(データベースなど)によって互いに区別することも、必要に応じてコアをサブモジュールとして追加する個別のリポジトリとしてライブすることもできます。

13
back2dos

すべての重要なことは、ここで良い答えによって提案されています。プロセスの提案として5ペンスを追加します。

この問題を長期的または中期的に解決し、コードの開発方法であるポリシーを採用することをお勧めします。柔軟な学習チームになるようにしてください。誰かがソフトウェアを構成可能にする代わりに500のリポジトリを持つことを許可した場合は、今までどのように作業してきたかを自問するときがきました。これからはこれから行います。

つまり:

  1. 変更管理の責任を明確にします。顧客が何らかの適応を必要とする場合、whoがそれらを販売し、whoがそれらを許可し、whoがコードの方法を決定します変わりますか?変更が必要なものがある場合、ねじはどこに回すのですか?
  2. 役割を明確にします。チームのwhoは新しいリポジトリの作成を許可されていますが、whoは許可されていません。
  3. チームの全員が、ソフトウェアに柔軟性を与えるパターンの必要性を理解していることを確認してください。
  4. 管理ツールを明確にします。どの顧客がどのコードを採用しているかをどのようにしてすばやく知ることができますか。一部の「500のリスト」は迷惑なように聞こえますが、必要に応じて「感情的な経済」をいくつか示します。クイックタイムで顧客の変更を伝えることができない場合は、リストを開始する必要があるかのように、さらに迷い、引き込まれているように感じます。次に、そのリストを使用して、他の人の答えがあなたに示した方法で機能をグループ化します。
    • マイナー/メジャー変更ごとに顧客をグループ化する
    • サブジェクト関連の変更ごとにグループ化
    • マージしやすい変更とマージしにくい変更でグループ化
    • いくつかのリポジトリに加えられた同じ変更のグループを見つけます(そうです、いくつかあります)。
    • おそらくあなたのマネージャー/投資家と話をするために最も重要です:高価の変更と安いの変更によるグループ化。

これは、チームに悪いプレッシャーを与えることを意味するものではありません。まず自分でこれらのポイントを明確にして、サポートを感じた場合はいつでも、チームと一緒にこれを整理することをお勧めします。すべての経験を向上させるために、テーブルに友好的な人々を招待してください。

次に、この時間を小さな炎で調理する長期の時間枠を確立してみます。提案:毎週少なくとも2つのリポジトリをマージするようにしてください少なくとも1つを削除。日常的に監視していると、2つ以上のブランチをマージできることがよくあります。そうすれば、1年で最悪(最も高額?)のブランチを処理でき、2年でこの問題を軽減して、明らかに優れたソフトウェアを作成できます。しかし、最終的にはこれに「時間をかける」人はいないので、これ以上期待しないでください。しかし、あなたはソフトウェアアーキテクトであるため、これをもう許さない人です。

これが私があなたの立場にあった場合に私がそれを処理しようとする方法です。しかし、私はあなたのチームがそのようなことをどのように受け入れるのか、ソフトウェアがこれを本当に許可するのか、あなたがどのようにサポートされるのか、そしてあなたがまだ学ばなければならないことを知りません。あなたはソフトウェアアーキテクトです-ちょうどそれのために行きます:-)

7
peter_the_oak

すべての否定者とは対照的に、実際のビジネスニーズを想定してみましょう。

(たとえば、成果物はソースコードであり、顧客は同じ事業分野に属しているため、互いに競合しているため、ビジネスモデルは秘密を守ることを約束します)

さらに、あなたの会社がすべてのブランチを維持するためのツールを持っていると仮定しましょう。つまり、5日間のリリースの遅延を想定して、マージに専念する100開発者とするか、または50日のリリースラグは問題ありません)、または自動マージがすべてのブランチでcore specextension specの両方に対して本当にテストされているような素晴らしい自動テスト、およびしたがって、「きれいに」マージしない変更のみが人間の介入を必要とします。顧客がカスタマイズだけでなくそのメンテナンスにも支払う場合、これは有効なビジネスモデルである可能性があります。

私の(そして不利な発言者の)質問ですが、あなたは専用の人が各顧客への配達に責任がありますか?たとえば、1万人の企業であれば、その可能性があります。

これはプラグインアーキテクチャで処理できる場合があります。たとえば、コアがトランクであり、プラグインがトランクまたはブランチに保持され、各顧客の構成が一意の名前のファイルであるか、顧客に保持されているとします。ブランチ。

プラグインは実行時にロードするか、コンパイル時に組み込むことができます。

本当に多くのプロジェクトがこのように行われ、基本的に同じ問題が依然として適用されます-単純なコアの変更は統合するのが簡単で、競合の変更はロールバックする必要があるか、または多くのプラグインに変更が必要です。

プラグインが十分でない場合があります。それは、コアの内部を非常に多く調整する必要があるため、プラグインインターフェイスの数が多すぎて処理できない場合があります。

理想的には、これはアスペクト指向プログラミングによって処理されます。ここで、トランクはコアコードであり、ブランチはアスペクトです(つまり、追加のコードと、エクストラをコアに接続する方法の指示です)。

簡単な例として、カスタムfooがコア_klass.foo_の前または後に実行されるように指定するか、それを置き換えるか、またはラップして入力または出力を変更できるように指定できます。

そのためのライブラリはたくさんありますが、マージの競合の問題は解消されません。クリーンなマージはAOPによって処理され、競合には依然として人間の介入が必要です。

最後に、このようなビジネスは本当にbranch maintenanceに関係する必要があります。つまり、顧客固有の機能Xが一般的であるため、すべての顧客が支払いをしているわけではありませんが、コアに移行する方が安価です。

5
Dima Tisnek

あなたは症状を見ることによって病気の根本的な原因を解決していません。 「コード管理」アプローチを使用すると症状が出ますが、長期的には問題を解決できません。根本的な原因は、「適切に管理された」製品の機能、機能、およびそれらの拡張機能とバリエーションの欠如です。

あなたの「カスタム」コードは、製品の機能と機能データフィールドの変更の拡張を表すだけですその他。

カスタム機能がどれほど広範で、どのように異なるか、どのように文脈的に類似しているかにかかわらず、製品のコードベースの「サニタイズ」に大きく影響します。

コーディングとバージョン管理の方法だけでなく、これは製品管理、製品アーキテクチャ、およびデータアーキテクチャが役立つ場所です。真剣に。

結局のところ、コードはクライアントへのビジネスおよび製品の機能/サービスの提供に他ならないからです。それはあなたの会社が払われているものです。

これをうまく処理するには、コードの観点ではなく、「機能」の観点から行う必要があります。

あなた、あなたの会社、そして製品は、すべての人にとってすべてではありません。 500クライアントのまともな収益基盤ができたので、今度はあなたが何をしようとしているのかを製品化する番です。

そして、あなたがいくつかのものを提供しているなら、組織化された方法で製品機能をモジュール化することは理にかなっています。

あなたの製品はどれだけ幅広く、深く行きますか?さもなければ、これは「サービス品質」の問題と「製品の希釈と断片化」につながります。

[〜#〜] crm [〜#〜] または [〜#〜] erp [〜#〜] または注文処理/発送またはMicrosoft Excelになりますか?

既存の拡張機能は、大規模なソフトウェアメジャーがスタートアップから取得したmerges製品を取り込む方法を統合し、調和させる必要があります。

強力な製品管理とデータアーキテクチャの担当者が以下をマッピングする必要があります。

  • マスターブランチ、その製品機能、および機能ベース
  • カスタム拡張機能、タイプ、バリエーション
  • 「カスタムフィールド」の意義とバリエーション

コアアプリケーションのグランドコンテキストで、これらすべてのルーズプロダクトスレッド/ブランチの同化と調和のロードマップを作成します。

PS:私とつながる、私はあなたがこれを修正するのを助けることができる人を知っています:)

3
Alex S