高度にカスタマイズされたソフトウェアをどのように整理しますか?


28

私は、世界中のさまざまな顧客向けに高度にカスタマイズされた大規模なソフトウェアプロジェクトに取り組んでいます。つまり、80%のコードがさまざまな顧客に共通しているだけでなく、ある顧客から別の顧客に変更する必要がある多くのコードがあることを意味します。過去に別のリポジトリ(SVN)で開発を行い、新しいプロジェクトが開始されたとき(大規模な顧客はほとんどありませんが)、過去のプロジェクトがニーズに最適なコードベースに基づいて別のリポジトリを作成しました。これは過去に機能していましたが、いくつかの問題に遭遇しました。

  • あるリポジトリで修正されたバグは、他のリポジトリでは修正されません。これは組織の問題かもしれませんが、5つの異なるリポジトリのバグを修正してパッチを当てるのは難しいと思います。このリポジトリを保守しているチームは世界の別の場所にいて、テスト環境がないことに注意してください、スケジュールや要件を把握していません(ある国の「バグ」は別の国の「機能」かもしれません)。
  • 別のプロジェクトにも役立つかもしれない1つのプロジェクトに加えられた機能と改善は失われ、別のプロジェクトで使用された場合、多くの場合、1つのコードベースから別のコードベースにそれらをマージする大きな頭痛の種を引き起こします)。
  • 1つの開発ブランチで行われたリファクタリングとコードの改善は、ブランチ間でこれらのすべての変更をマージする必要がある場合、失われるか、害よりも害をもたらします。

現在、これらの問題を解決する方法について議論しており、これまでのところ、これを解決する方法について次のアイデアを思いつきました。

  1. 開発を別々のブランチで維持しますが、一般的なバグ修正がマージされる中央リポジトリを持ち、すべてのプロジェクトがこのセントラルリポジトリからの変更を定期的に(たとえば毎日)独自のものにマージすることで、より整理されます。これには、大きな規律と、ブランチ間のマージに多大な労力が必要です。ですから、特に時間のプレッシャーがかかったときに、それがうまくいくと確信していません。

  2. 個別の開発ブランチ放棄し、すべてのコードが存在する中央のコードリポジトリを持ち、プラグ可能なモジュールと構成オプションを使用してカスタマイズを行います。既にコードの依存関係を解決するためにDependency Injectionコンテナーを使用しており、ほとんどのコードでMVVMパターンに従ってビジネスロジックをUIから明確に分離しています。

2番目のアプローチはよりエレガントに見えますが、このアプローチには多くの未解決の問題があります。例:モデル/データベースでの変更/追加の処理方法。エンティティフレームワークで.NETを使用して、エンティティを厳密に型指定しています。ある顧客には必要だが、データモデルを乱雑にすることなく別の顧客には役に立たないプロパティをどのように処理できるかわかりません。サテライトテーブル(特定のエンティティ用の追加の列が元のエンティティへの1:1マッピングで存在する個別のテーブルを持つ)を使用してデータベースでこれを解決することを考えていますが、これはデータベースのみです。これをコードでどのように処理しますか?データモデルは中央ライブラリにあり、このアプローチを使用して顧客ごとに拡張することはできません。

この問題に苦しんでいるのは私たちだけではないと確信しており、このトピックに関する資料がほとんどないことにショックを受けています。

私の質問は次のとおりです。

  1. 高度にカスタマイズされたソフトウェアに関してどのような経験があり、どのアプローチを選択し、どのように機能しましたか?
  2. どのアプローチをお勧めしますか、またその理由は何ですか?より良いアプローチはありますか?
  3. お勧めできるトピックに関する良い本や記事はありますか?
  4. 技術環境(.NET、Entity Framework、WPF、DI)について具体的な推奨事項はありますか?

編集:

すべての提案をありがとう。アイデアのほとんどは、すでにチーム内で持っていたものと一致しますが、あなたがそれらで得た経験と、それらをより良く実装するためのヒントを確認することは本当に役立ちます。

どの方向に進むかはまだわかりませんし、(単独で)決定を下すわけではありませんが、チームでこれを伝えて、役に立つと確信しています。

現時点では、テナーはさまざまな顧客固有のモジュールを使用する単一のリポジトリのようです。私たちのアーキテクチャがこれに合っているか、それを適合させるためにどれだけ投資する必要があるのか​​はわかりません。

それで、すべての応答に再び感謝します!


データベーステーブルをコードとして扱うことを検討してください。

Subversionリポジトリにデータベーススクリプトがあるという意味ですでにこれを行っていますが、上記の問題は実際には解決しません。データベースモデルにKey-Valueスタイルのテーブルが必要になるのは、多くの問題があるためです。では、個々の顧客のモデルへの追加をどのようにして許可し、すべての顧客の共有コードリポジトリを維持しますか?
aKzenT

回答:


10

基本的な問題は、コードリポジトリのメンテナンスだけでなく、適切なアーキテクチャの欠如であると思われます。

  1. すべてのシステムで常に共有されるシステムのコア/エッセンスは何ですか?
  2. 各顧客にはどのような機能強化/逸脱が必要ですか?

フレームワークまたは標準ライブラリは前者を包含し、後者はアドオン(プラグイン、サブクラス、DI、コード構造にとって意味のあるもの)として実装されます。

ブランチと分散開発を管理するソース管理システムもおそらく役立つでしょう。私はMercurialのファンですが、Gitを好む人もいます。フレームワークがメインブランチになり、カスタマイズされた各システムがサブブランチになります。

システムの実装に使用される特定のテクノロジ(.NET、WPFなど)はほとんど重要ではありません。

これを正しく行うのは簡単ではありませんが、長期的な実行可能性にとって重要です。そしてもちろん、長く待つほど、対処しなければならない技術的負債は大きくなります。

ソフトウェアアーキテクチャ:組織の原則とパターン」という本が役立つかもしれません。

がんばろう!


3
うん。ただし、建築は技術的なものというよりも心理的なものです。製品に完全に焦点を合わせた場合、コンポーネントがその製品にのみ有用である作業の内訳になります。一方、より一般的に役立つ一連のライブラリの構築に焦点を当てる場合は、より広範な状況で展開できる一連の機能を構築します。もちろん、重要なのは、特定の状況に合わせて、これら2つの極端な状態の間で適切なバランスを見つけることです。
ウィリアムペイン

私たちの支店の多​​くの間で大きな共有部分があると思います(> 90%)が、最後の10%は常に異なる場所にあるので、いくつかのユーティリティライブラリを除いて、顧客固有の変更を想像できないコンポーネントはほとんどありませんビジネスロジックが含まれていません。
aKzenT

@aKzenT:うーん...想像しないで、代わりに測定してください。コードを調査して、カスタマイズが行われたすべての場所を調べ、変更されたコンポーネントのリストを作成し、各コンポーネントが変更された頻度に注意し、実際に行われた変更の種類とパターンについて考えます。それらは表面的またはアルゴリズム的ですか?基本機能を追加または変更していますか?各タイプの変更の理由は何ですか?繰り返しますが、これは大変な作業であり、あなたはあなたが発見したものの意味を好まないかもしれません。
スティーブンA.ロウ

1
これを答えとして受け入れました。なぜなら、アーキテクチャについてさらに考える前にこの決定を下すことはできず、一般的な部分または共通する必要がある部分を特定してから、単一のリポジトリで生きることができるか、フォークが必要かどうかを確認するためです(少なくとも瞬間)。この回答は、この最高のIMOを反映しています。しかし、他のすべての投稿に感謝します!
aKzenT

11

私が働いていたある会社には同じ問題があり、問題に取り組むためのアプローチはこれでした。すべての新しいプロジェクトに共通のフレームワークが作成されました。これには、すべてのプロジェクトで同じである必要があるすべてのものが含まれます。たとえば、フォーム生成ツール、Excelへのエクスポート、ロギング。この共通のフレームワークは(新しいプロジェクトに新しい機能が必要な場合にのみ)改善されるだけで、分岐しないように努力しました。

そのフレームワークに基づいて、顧客固有のコードは個別のリポジトリで維持されました。有用または必要な場合、バグの修正と改善がプロジェクト間でコピーアンドペーストされます(質問に記載されているすべての注意事項とともに)。ただし、グローバルに役立つ改善は、共通のフレームワークに組み込まれます。

すべての顧客に対してすべてを共通のコードベースに保持することにはいくつかの利点がありますが、一方でif、プログラムを顧客ごとに異なる動作にする無数のコードがある場合、コードの読み取りが難しくなります。

編集:これをより理解しやすくするための逸話:

その会社のドメインは倉庫管理であり、倉庫管理システムのタスクの1つは、入荷する商品の無料保管場所を見つけることです。簡単に聞こえますが、実際には、多くの制約と戦略を守らなければなりません。

ある時点で、管理者はプログラマーに、保管場所を見つけるための柔軟でパラメーター化可能なモジュールを作成するように依頼しました。これは、いくつかの異なる戦略を実装し、その後のすべてのプロジェクトで使用されるべきでした。気高い努力の結果、複雑なモジュールが作成され、理解と保守が非常に難しくなりました。次のプロジェクトでは、プロジェクトリーダーはそのウェアハウスでそれを動作させる方法を理解できず、このモジュールの開発者はいなくなったため、彼は最終的にそれを無視し、そのタスクのカスタムアルゴリズムを作成しました。

数年後、このモジュールが最初に使用されていた倉庫のレイアウトが変更され、すべての柔軟性を備えたモジュールは新しい要件に適合しませんでした。そこで、カスタムアルゴリズムに置き換えました。

LOCは適切な測定値ではありませんが、とにかく、「柔軟な」モジュールのサイズは〜3000 LOC(PL / SQL)でしたが、同じタスクのカスタムモジュールは〜100..250 LOCでした。したがって、柔軟にしようとすると、コードベースのサイズが非常に大きくなり、期待した再利用性が得られませんでした。


ご意見をいただきありがとうございます。これは、最初に説明したソリューションの拡張であり、これについても考えました。ただし、ほとんどのライブラリはいくつかのコアエンティティを使用しており、これらのコアエンティティは通常1人または複数の顧客向けに拡張されているため、このコアリポジトリに配置できるライブラリは非常に少ないと思います。たとえば、「Customer」エンティティが定義され、ORMが1つのライブラリにマッピングされ、他のほとんどすべてのライブラリとプログラムで使用されています。しかし、すべてのクライアントには「顧客」に追加する必要がある追加のフィールドがあるため、このライブラリをフォークする必要があります。したがって、すべてのライブラリはそれに依存します。
aKzenT

3
数え切れない「if」を避けるための私たちのアイデアは、依存関係の注入を広範に利用し、さまざまな顧客向けに完全なモジュールを交換することです。しかし、これがどのように機能するかはわかりません。このアプローチはどのように機能しましたか?
aKzenT

+1、これは基本的にこれをうまく処理したプロジェクトの私の経験と一致します。「異なる顧客向けのif」アプローチを使用する場合は、2つのポイントがあります。2.しないようにしてください!おそらく、構成固有のモジュールを使用するよりも、1%の確率で(理解しやすく/保守しやすい)より良いオプションになるでしょう。
vaughandroid

@Baqueta:明確にするために、構成オプション(ifs)ではなく、顧客ごとのモジュールを使用することをお勧めしますか?お客様ではなく機能を区別するというアイデアが気に入っています。したがって、両方の組み合わせは、構成オプションによって制御されるさまざまな「機能モジュール」を持つことになります。顧客は、独立した機能モジュールのセットとしてのみ表されます。私はこのアプローチがとても好きですが、これをどのように設計するのか分かりません。DIはモジュールのロードと交換の問題を解決しますが、顧客間で異なるデータモデルをどのように管理しますか?
aKzenT

そう、機能ごとのモジュール、そして顧客ごとの構成/機能の選択。DIが理想的です。残念ながら、お客様ごとの大幅なカスタマイズの要件を単一のデータライブラリと組み合わせる必要はありませんでしたので、そこに大いに役立つかどうかは
わかり

5

私が取り組んだプロジェクトの1つは、多数の製品リリースでサポートされている複数のプラットフォーム(5つ以上)でした。あなたが説明している課題の多くは、わずかに異なる方法ではありますが、私たちが直面したものでした。独自のDBがあるため、その分野では同じような問題はありませんでした。

私たちの構造はあなたのものに似ていましたが、コード用の単一のリポジトリがありました。プラットフォーム固有のコードは、コードツリー内の独自のプロジェクトフォルダーに入りました。共通のコードは、それが属する層に基づいてツリー内に存在していました。

構築中のプラットフォームに基づいて、条件付きコンパイルを行いました。それを維持するのは少し苦痛でしたが、プラットフォーム固有のレイヤーに新しいモジュールが追加されたときにのみそれを行う必要がありました。

すべてのコードを単一のリポジトリに置くことで、複数のプラットフォームとリリースで同時にバグ修正を簡単に行うことができました。すべてのプラットフォームに自動ビルド環境があり、新しいコードが関連のないプラットフォームを破壊した場合のバックストップとして機能しました。

私たちはそれをやめさせようとしましたが、プラットフォームが他の点では一般的なコードにあったプラットフォーム固有のバグに基づいた修正が必要な場合がありました。モジュールを見栄えよくせずに条件付きでコンパイルをオーバーライドできる場合は、最初にそれを行います。そうでない場合は、モジュールを共通の領域から移動し、プラットフォーム固有にプッシュします。

データベースについては、プラットフォーム固有の列/変更を含むいくつかのテーブルがありました。テーブルのすべてのプラットフォームバージョンが機能のベースラインレベルを満たしていることを確認し、プラットフォームの依存関係を心配することなく共通コードが参照できるようにします。プラットフォーム固有のクエリ/操作は、プラットフォームプロジェクトレイヤーにプッシュされました。

したがって、あなたの質問に答えるには:

  1. たくさん、そしてそれは私が一緒に働いた最高のチームの一つでした。当時のコードベースは約1M locでした。アプローチを選択することはできませんでしたが、うまく機能しました。後から見ても、物事を処理するより良い方法を見たことはありません。
  2. 私の答えで言及したニュアンスで提案した2番目のアプローチをお勧めします。
  3. 私が考えることができる本はありませんが、私はスターターとしてマルチプラットフォーム開発を研究します。
  4. 強力なガバナンスを確立します。これは、コーディング標準に準拠していることを確認するための鍵です。これらの標準に従うことは、物事を管理しやすく維持するための唯一の方法です。私たちはフォローしているモデルを破る熱心な嘆願のシェアを持っていましたが、それらのアピールのどれも上級開発チーム全体を揺るがしませんでした。

あなたの経験を共有してくれてありがとう。理解を深めるために:あなたのケースではプラットフォームはどのように定義されていますか。Windows、Linux、X86 / x64?または、さまざまな顧客/環境に関連するものがありますか?4)であなたは良い点を挙げています。私たちが抱えている問題の1つだと思います。私たちには非常に優秀で有能な人たちのチームがありますが、物事を行う方法については誰もがわずかに異なるアイデアを持っています。明確にアーキテクチャを担当する人がいなければ、共通の戦略に同意することは難しく、何も変更せずに議論で自分自身を失う危険があります。
aKzenT

@aKzenT-はい、プラットフォームとして物理ハードウェアとOSを意味しました。大規模な機能セットがあり、その一部はライセンスモジュールで選択できました。そして、幅広いハードウェアをサポートしました。それに関連して、コードツリーのその層に独自のディレクトリを持つデバイスの束を持つ共通層ディレクトリがありました。ですから、私たちの状況は、あなたがいる場所からそれほど遠くはありませんでした。私たちの上級開発者はお互いに活発な議論を交わしていましたが、ひとたび集合的な決定が下されると、誰もがラインを踏むことに同意しました。

4

私は同じような問題を抱えた年金管理アプリケーションで長年働きました。年金計画は企業間で大きく異なり、計算ロジックとレポートを実装するための高度な専門知識と、非常に異なるデータ設計が必要です。アーキテクチャの一部について簡単に説明することしかできませんが、それで十分なアイデアが得られるかもしれません。

コアシステムコード(上記の80%の共有コード)を担当するコア開発チームと、年金システムの専門知識を持ち、クライアントの学習を担当する実装チームの2つのチームがありました。クライアントの要件とコーディングスクリプトおよびレポート。

Xmlで定義されたすべてのテーブルがありました(これは、エンティティフレームワークがタイムテストされ一般的に使用される前のことです)。実装チームはXmlのすべてのテーブルを設計し、コアアプリケーションはXmlのすべてのテーブルを生成するように求められます。各クライアントに関連付けられたVBスクリプトファイル、Crystal Reports、Wordドキュメントなどもありました。(他の実装の再利用を可能にするためにXmlに組み込まれた継承モデルもありました)。

コアアプリケーション(すべてのクライアント用の1つのアプリケーション)は、そのクライアントへの要求が来たときにすべてのクライアント固有のものをキャッシュし、シリアル化して渡すことができる共通データオブジェクト(リモートADOレコードセットのようなもの)を生成しました周り。

このデータモデルは、エンティティ/ドメインオブジェクトほど滑らかではありませんが、柔軟性が高く、汎用性があり、1組のコアコードで処理できます。おそらくあなたの場合、共通フィールドのみでベースエンティティオブジェクトを定義し、カスタムフィールド用の追加のディクショナリを使用できます(エンティティオブジェクトに何らかの種類のデータ記述子のセットを追加して、カスタムフィールドのメタデータを保持します)。 )

コアシステムコード用と実装コード用に別々のソースリポジトリがありました。

コアシステムには、いくつかの非常に標準的な一般的な計算モジュール以外のビジネスロジックはほとんどありませんでした。コアシステムは、スクリーンジェネレーター、スクリプトランナー、レポートジェネレーター、データアクセス、トランスポートレイヤーとして機能しました。

コアロジックとカスタマイズされたロジックをセグメント化するのは難しい課題です。ただし、各クライアントに対してシステムの複数のコピーを実行するよりも、複数のクライアントを実行する1つのコアシステムを使用する方が良いと常に感じていました。


フィードバックをお寄せいただきありがとうございます。辞書にフィールドを追加するというアイデアが気に入っています。これにより、エンティティの単一の定義を使用して、クライアント固有のすべてのものを辞書に入れることができます。しかし、ORMラッパー(Entity Framework)で動作させる良い方法があるかどうかはわかりません。また、すべての機能/モジュールのモデルを用意するのではなく、グローバルに共有されるデータモデルを用意するのが本当に良い考えかどうかもわかりません。
aKzenT

2

私はより小さなシステム(20 kloc)で作業しましたが、DIと構成はどちらもクライアント間の違いを管理する優れた方法ですが、システムの分岐を回避するには十分ではないことがわかりました。データベースは、固定スキーマを持つアプリケーション固有の部分と、カスタムXML構成ドキュメントを介して定義されるクライアント依存部分に分割されます。

Mercurialには単一のブランチがあり、それはまるで成果物であるかのように構成されていますが、架空のクライアント向けにブランド化および構成されています。バグ修正はそのプロジェクトのメインラインであり、コア機能の新しい開発はそこでのみ行われます。実際のクライアントへのリリースは、それからの分岐であり、独自のリポジトリに保存されます。手動で記述されたバージョン番号を使用してコードに対する大きな変更を追跡し、コミット番号を使用してバグ修正を追跡します。


顧客間で同じコアライブラリを区別しましたか、または完全なツリーを分岐しましたか?メインラインから個々のフォークに定期的にマージしますか?そして、はいの場合、毎日のマージルーチンのコストはどれくらいかかりましたか、また、時間のプレッシャーが始まるときにこの手順がバラバラになるのをどのように回避しましたか(プロジェクトのある時点で常にそうです)。非常に多くの質問でごめんなさい:p
aKzenT

主にクライアントの要求がシステムの整合性を構築する前に来るため、ツリー全体をフォークします。メインシステムからのマージは、mercurialおよびその他のツールを使用して手動で行われ、通常、重大なバグまたは大規模な機能の更新に限定されます。マージのコストと、多くのクライアントが独自のシステムをホストしているため、頻繁ではない大きなチャンクの更新を維持しようとしています。
ダンモネゴ

興味があります:IIRC mercurialはgitに似たDVCSです。Subversionまたは他の従来のVCSと比較して、ブランチ間でこれらのマージを行う利点はありましたか?私は、subversionを使用して、2つの完全に分離された開発ブランチ間の非常に苦痛なマージプロセスを終了し、gitを使用した方が簡単かどうかを考えていました。
-aKzenT

Mercurialとのマージは、以前のツールであるVaultとのマージよりもはるかに簡単です。主な利点の1つは、mercurialがアプリケーションの変更履歴を中心に置くことで本当に優れていることです。これにより、どこで何が行われたかを簡単に追跡できます。私たちにとって最も難しい部分は、既存のブランチを移動することでした。2つのブランチをマージする場合、mercurialでは両方のルートが同じである必要があるため、セットアップするには最後の完全な手動マージが必要です。
ダンモネゴ

2

あなたが説明した問題を直接経験していないのではないかと心配していますが、コメントがあります。

2番目のオプションは、コードを(可能な限り)中央レポジトリにまとめ、カスタマイズ(再び可能な限り)を設計することであり、長期的に見ればほぼ間違いありません。

問題は、そこにどのように到達するか、どのくらいかかるかです。

この状況では、一度に(一時的に)リポジトリにアプリケーションの複数のコピーを置いても問題ありません。

これにより、カスタマイズを直接サポートするアーキテクチャに徐々に移行することができます。


2

2番目のアプローチはよりエレガントに見えますが、このアプローチには多くの未解決の問題があります。

これらの問題は次々に解決できると確信しています。行き詰まった場合は、特定の問題についてSOで質問してください。

他の人が指摘しているように、1つの中央のコードベース/ 1つのリポジトリーを用意することをお勧めします。私はあなたの質問例に答えようとします。

例:モデル/データベースでの変更/追加の処理方法。エンティティフレームワークで.NETを使用して、エンティティを厳密に型指定しています。ある顧客には必要だが、データモデルを乱雑にすることなく別の顧客には役に立たないプロパティをどのように処理できるかわかりません。

いくつかの可能性がありますが、それらはすべて実際のシステムで見たものです。どちらを選択するかは、状況によって異なります。

  • ある程度乱雑に生きる
  • 「CustomAttributes」(名前と型を記述する)および「CustomAttributeValues」(数値の場合でも、たとえば文字列表現として格納される値用)の表を導入します。これにより、インストール時または実行時にこのような属性を追加し、各顧客に個別の値を設定できます。データモデルで各カスタム属性を「可視的に」モデル化することを主張しないでください。

  • これで、コードでの使用方法が明確になります。これらのテーブルにアクセスするための一般的なコードと、その属性を正しく解釈するための個別のコード(おそらく、あなた次第の別のプラグインDLL)が必要です

  • もう1つの方法は、各エンティティテーブルに大きな文字列フィールドを与え、個々のXML文字列を追加できるようにすることです。
  • いくつかの概念を一般化して、異なる顧客間でより簡単に再利用できるようにしてください。マーティン・ファウラーの本「分析パターン」をお勧めします。この本はソフトウェア自体のカスタマイズに関するものではありませんが、あなたにとっても役立つかもしれません。

また、特定のコードについては、特に顧客固有のスクリプトを追加するために、スクリプト言語を製品に導入することもできます。そうすれば、コードと顧客固有のコードの間に明確な線を作成するだけでなく、顧客がシステムをある程度自分でカスタマイズできるようにすることもできます。


カスタムプロパティを格納するためにCustomAttributesまたはXML列を追加する際に発生する問題は、それらの機能が非常に制限されていることです。たとえば、これらの属性に基づいて並べ替え、グループ化、またはフィルタリングを行うことは非常に困難です。私はかつて、余分な属性テーブルを使用するシステムに取り組んでいましたが、これらのカスタム属性の維持と処理がますます複雑になりました。このため、これらの属性を、元のテーブルと1:1でマッピングされる追加のテーブルの列として配置する代わりに考えていました。ただし、これらの定義、クエリ、および管理の方法に関する問題は依然として同じです。
aKzenT

@aKzenT:カスタマイズ性は無料ではありません。使いやすさとカスタマイズ性のトレードオフが必要です。私の一般的な提案は、システムのコア部分がカスタム部分から何らかの方法で依存する依存関係を導入せず、逆方向のみを導入することです。たとえば、顧客1にこれらの「余分なテーブル」を導入する場合、顧客2にそのテーブルと関連コードをデプロイすることを避けることができますか?答えが「はい」の場合、解決策は問題ありません。
ドックブラウン

0

そのようなアプリケーションを1つだけ作成しました。販売されたユニットの90%は現状のまま販売され、変更はなかったと思います。各顧客には独自のカスタマイズされたスキンがあり、そのスキン内でシステムを提供しました。modがコアセクションに影響を与えたときに、IF分岐を使用してみました。同じセクションにmod#2が入ったとき、将来の拡張を可能にするCASEロジックに切り替えました。これは、マイナーリクエストのほとんどを処理しているようです。

それ以外のマイナーなカスタムリクエストは、ケースロジックを実装することで処理されました。

MODが2つの過激なものである場合、クローン(個別のinclude)を構築し、CASEをラップして別のモジュールを組み込みます。

コアのバグ修正と修正がすべてのユーザーに影響しました。本番に進む前に、開発中に徹底的にテストしました。変更を伴う電子メール通知を常に送信し、金曜日に生産の変更を投稿することはありません。

私たちの環境は、クラシックASPとSQL Serverでした。私たちはスパゲッティコードショップではありませんでした...すべてがインクルード、サブルーチン、関数を使用したモジュール式でした。


-1

Aと80%の機能を共有しているBの開発を開始するように求められたら、次のいずれかを行います。

  1. Aを複製して変更します。
  2. AとBの両方が共有する機能を、使用するCに抽出します。
  3. AをBとそれ自体の両方のニーズを満たすのに十分な構成可能にします(したがって、BはAに組み込まれます)。

1を選択しましたが、状況にうまく合わないようです。あなたの使命は、2と3のどちらがより適しているかを予測することです。


1
簡単に聞こえますが、実際にこれを行う方法は?「if(customer1)」で煩雑になることなく、ソフトウェアをどのように構成可能にしますか。これはしばらくすると維持できなくなります。
aKzenT

@aKzenTそのため、2つと3つを選んで選択しました。設定を通してcustomer1のプロジェクト支援customer2のニーズを作るために必要な変更の種類は、コードがunmaintainableするつもりされている場合は、3行わない
モシェRevah

「if(customer1)」ではなく「if(option1)」を実行することを好みます。このようにN個のオプションを使用すると、多くの顧客を管理できます。たとえば、N個のブールオプションを使用すると、2 ^ N個の顧客を管理できます。N個の「if」のみで、2 ^ N個の「if」を必要とする「if(customer1)」戦略では管理できません。
フィル14年
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.