私たちの仕事では、多くの基本機能を共有するいくつかの異なる.netアプリケーションがあります。クリーンなn層アーキテクチャを使用してこれらのアプリケーションを構築しましたが、同じ機能を何度か再実装したことに気づいた瞬間に達しました。これは明らかにDRYに違反しているので、修正したいと思います。すでに一般的なグルーコード(IoC、ログ、設定の接続)にある程度成功しているNugetを使用していますが、すべてのアプリケーション間でデータとビジネスレイヤーを共有したいと考えています。 UIは実際に必要なビジネスレイヤーの部分のみを処理するという考え方です。
これは最初は簡単な問題のように見えますが、開発が進行中の場合はいくつかの落とし穴が生じる可能性があり、どのように進めればよいかわかりません。すべてを統括する1つのビジネスレイヤーを作成するとします。簡潔にするために、これを「Foundation」と呼びます。 Foundationを使用するようにアプリケーションを移植すると、すべてが順調に実行されます。 Foundationはnugetを介してライトUIレイヤーに配布されており、見栄えが良いです。しかし、その後、アプリケーションに機能を追加し始め、問題が発生します。
プロジェクトAに取り組んでいて、Foundationの変更が必要な新機能を追加するとします。ファンデーション(Foundation-A)に変更を加え、それらを不安定なパッケージとしてnugetフィードにプッシュします。プロジェクトAは最新のnugetパッケージを取得し、すべて良好です。その間、別の開発者がプロジェクトBに取り組んでいます。彼はソース管理から最新のFoundationを取得しますが、安定したブランチからそれを取得するため、プロジェクトAの変更はありません。彼は変更を加えてFoundation-Bを作成しました。そして、すべてが良いです。しかし、実際にコードを共有できるFoundation-AとFoundation-Bの実装機能を見つけたので、それらを組み合わせます。一方、Foundation-Cは、独自の変更により、そこに浮かんでいます。最終的に、Foundation-Bは本番稼働の準備ができたので、それをプッシュします。しかし、その後、プロダクションA、B、Cを新しいファンデーションで更新する必要があるため、nugetパッケージを更新してデプロイします(何も壊れない限り)。
これはうまくいくように見えますが、異なるデータベーススキーマで作業し、FoundationリポジトリのさまざまなブランチとProject A、B、Cリポジトリ間ですべての同期を維持することが心配です。おそらく手作業が多くかかるため、エラーが発生する可能性があります。これをできるだけ自動化したいと思います。
ここで使用しているスタックは、C#、継続的インテグレーションを備えたTFS、Nugetです。私たちのアプリケーションはすべて、さまざまなタイプのASP.NETアプリケーションです。状況を簡単にするために、さまざまなSCMを検討していきます。
Nugetをさまざまなソースコードブランチで正常に保つ方法を探しています。間違ったNugetパッケージを参照するため、開発コードを誤って本番環境にプッシュしたくありません。
Foundation(Foundation-A)に変更を加え、それらを不安定なパッケージとしてnugetフィードにプッシュします。
ここからが問題の始まりです...それを行わないでください。
Foundation v1.0への変更は、Foundationのすべての利用者にとって本質的に価値があるはずです。それ以外の場合は、Foundationに属しません。そのため、nugetパッケージを作成するときは、Foundationの正式な安定バージョン(v1.1など)として実行するか、まったく実行しないでください。
プロジェクトBは通常どおりにFoundationの機能強化を構築する必要がありますが、安定したFoundation(v1.2)をnugetにプッシュする前に、(優れたソース管理の方法で)トランクの変更(v1.1)をマージする必要があります。
Foundationの機能強化を使用できる他のプロジェクトは、必要に応じてそれらのnuget参照をアップグレードしたり、必要に応じて古いバージョンを使用したりできます。
@ Giedrius に同意します。これは、Foundationの分岐/マージが適切に処理された場合、パッケージ管理の問題が問題になるという意味で、ソース管理/分岐の問題のように思えます。
重複するコードをより抽象的な方法で適用できる関数にリファクタリングし、それらを独自のライブラリまたはフレームワークに配置します。それらを疎結合にし、アーキテクチャにとらわれないようにします。問題は発生しません。インスピレーションが必要な場合は、.NETフレームワークがインターフェイス、ジェネリックス、Dispose()
などのソフトウェアパターンなどを使用して概念を抽象化する方法を調べてください。
また、すべての重複コードが実際に重複しているわけではないことも覚えておいてください。それの一部はグルーコードまたはアーキテクチャを維持するために他の方法で必要なコードであるため、あまりにもDRYであることを気にしないでください。
コードの再利用
長年にわたって支持されてきたコードの再利用に対するいくつかのアプローチがありました。各アプローチには場所があり、さらに重要なのはissuesですが、.NETでコードを再利用するための実行可能な方法は次のとおりです。
共通ライブラリ。複数の場所で必要なコードは共通のライブラリに入れられ、コードベースの他のすべての部分はこのコードへの単一の参照を持ちます。主な欠点は、多くの無関係な関数が含まれているこのライブラリに依存して、プロジェクトの大部分が終了することです。これは、品質保証の観点からは悪い考えです。
共通ソースコード。複数の場所で必要なコードは1回記述され、共通のディレクトリ構造のソースファイルに配置されます。このコードを必要とするすべてのプロジェクトは、このファイルをソースファイルの1つとしてインクルードします。これにより、コードの再利用が可能になり、1回の書き込みで多くを使用できるという利点があります。しかしながら。その欠点は、プロジェクトのさまざまな部分をこのコードのさまざまなバージョンでコンパイルできるようになることです。これにより、品質保証によって検出および特定するのが非常に難しい、いくつかの微妙な欠陥が発生する可能性があります。
サービス。共通コードはサービスとして実装され、他の側面からアクセスできます。これには、デプロイメントに単一のサービスがあり、依存関係を回避できるという利点があります。ただし、レイテンシと障害が発生します。この種のアプローチは、高可用性とフォールトトレランスがすでに理解および管理されている大規模な分散製品でうまく機能します。
NuGETの管理
ここには、はるかに興味深い問題があります。複数の構成の管理。ここでのアドバイスは、異なるコードバージョンで多様な顧客ベースを管理するのではなく、構成ファイルで管理することです。管理する構成データの少なくとも3つのレイヤーがあります。顧客には決して見られない基本(内部)製品構成。顧客が変更する可能性のあるデフォルトの構成オプションと、顧客が変更した構成オプションの最終層。これらの異なるレイヤーを分離することで、お客様の構成を破壊することなくアップグレードを展開できます。
問題は、nuget /ソース管理/分岐ではなく、グルーコードに陥るところにあると思います。
Robertはいい答えをしています。全体像を見るために、これらの一般的なユーティリティが各プロジェクトにどのような依存関係をもたらすかについて考えることをお勧めします。
http://ayende.com/blog/3986/let-us-burn-all-those-pesky-util-common-librarieshttp://blog.jordanterrell.com/ post/CommonUtility-Libraries-Dead.aspx
地獄を回避する最善の方法は、グルーコードをオープンソース化することです。このようにして、ビジネスロジックが公開されないように気を付け始めます。具体的なプロジェクトの依存関係がグルーコードに組み込まれることはなく、社外であってもだれでも再利用できるほど抽象的です。コードで十分です-コミュニティからの情報も得られます。
ソリューションはシンプルです。個別のプロジェクトを作成し、個別のものとして管理します。それは、独自の要件、テスト、規則、ドキュメント、計画、担当者などです。これにより、品質が高く維持され、重大な変更が発生する可能性があります。問題が発生する前に最初に評価されます。
またはさらに良い:組織内で「オープンソース」にする。したがって、誰でもコードを変更できますが、完全なコミット権限を持つのは選択された少数の人々だけです。そして、それらの人々は品質と正しい機能を保証する責任があります。