web-dev-qa-db-ja.com

Servicestack-アーキテクチャとすべてのPOCOの再利用

私は ServiceStackのドキュメント REG POCOの使用を参照します。

クリーンで再利用可能なコードを促進するため、ServiceStackはcode-first POCOの使用を常に推奨してきました。

つまり同じPOCOを使用できます:
要求と応答のDTO(クライアントとサーバー上)
JSON、JSV、CSVテキストシリアライザー
OrmLite、db4o、NHibernateのデータモデルとして
Redisに格納されているエンティティとして
キャッシュとセッションに格納されたBLOBとして
MQのサービスで削除および実行されました

私はservicestackが大好きで、それを使ってWebサービスを簡単に作成できます。私は自分のプロジェクトをセットアップする最善の方法を理解しようとしています。

具体的には、データモデルでもある応答オブジェクトを返すというアーキテクチャのアイデアと闘っています(SSによって提案されています)。懸念の分離という考えは、私には強く根付いています。すべてに同じPOCOを使用すれば、将来問題が発生することはありません。代わりに、たとえばビューオブジェクトを返すなどの「安全」ではありませんか?

20

ソフトウェアの最大の敵

最初に、 複雑さと大規模なコードベース はソフトウェア開発の最悪の敵であり、プロジェクト要件(つまり、ソフトウェアから価値を引き出す)を満たすことで、複雑さを管理し、最小限に抑えることを繰り返しますまた、新しい機能と要件でソフトウェアを継続的に強化しているため、摩擦が少なく、進化可能なコードベースを最前線に置く必要があります。ソフトウェアの品質を向上させるために追加するガイドライン、ルール、またはプロセスは、その本質的な複雑さの管理に直接焦点を当てる必要があります。複雑さを軽減するために実行できる最善のことの1つは、コードベースのサイズを削減することです。つまり、反復可能なコードを乾燥させ、ソフトウェアの機能に絶対に不可欠ではない不要な抽象化、間接参照、概念、型、および摩擦を排除します。

この観点から、 [〜#〜] yagni [〜#〜] は、価値を提供するために不可欠なことに焦点を当てることにより、シンプルで無駄のないコードベースを確保するために従うべき最良の原則の1つです。

包括的なルールを避ける

私は、ソフトウェアの不必要な複雑さの主な原因の1つと考える「包括的ルール」を避けます。このルールは、多くの場合、自由に無意識に適用され、正当化されることなくコードベースに感染します。人工的な制限を課すたびに、それを満たすためにその範囲内で発生する摩擦と慣性を作成します。そのため、適用するルールは慎重に慎重に適用し、付加価値のある場所に限定する必要があります。

無効なルールとパターンに注意してください

ソフトウェアデザインパターンでさえ、多くの場合 プログラミング言語の欠陥 であり、1つの言語で役立つものは不要であり、より表現力があり強力な言語でよりエレガントに解決されます。 「ルール」と同様に、あるドメインの注意ガイドラインは他のドメインには適用されない場合があります。したがって、「ルール」自体よりも重要なのは、それが実際に提供する値と、それが防止しようとしている具体的な副作用です。その真の価値を理解したら、最適化して最大値を導き出し、YAGNIと一緒に、いつ選択的に適用するかを知ることができます。

シンプルなPOCOライフ

お気づきのように、ServiceStackは、同じPOCOをどこでも無差別に再利用して、異なるライブラリやコンポーネント間でインターフェースを取り、自由に通信できるようにすることで、そのシンプルさと再利用の多くを実現しています。これにより、モデルの最大の価値と再利用が可能になり、通常は目的固有のタイプを必要とするさまざまなドメイン間のマッピングの摩擦が軽減されます。

重いORMモデルは貧弱なDTOです

DTOとしてデータモデルを再利用しないことは、周期的な依存関係を持つデータモデルと、意図しないN + 1データアクセスをトリガーする可能性のある密結合と埋め込みロジックを備えたプロキシオブジェクトを奨励するHeavyORMに適用されるため、これらのモデルはDTOとして使用するのに適していません。それらを目的固有のDTOにコピーして、サービスが返すことができるようにして、問題なくシリアル化できるようにします。

POCOの削除

OrmLite または Redis に格納されている複雑なデータモデルは、クリーンで切断されたPOCOを使用できるこれらの問題のいずれにも悩まされていません。それらは疎結合であり、POCOの「形状」のみが重要です。つまり、プロジェクトの移動や名前空間の変更は、シリアル化、RDBMSテーブル、Redisデータ構造、キャッシュプロバイダーなどへの格納方法に影響を与えません。 OrmLiteはDTOのサブセットのみを入力できるため、特定のタイプと組み合わせることなく、データを読み取るために使用するものとは異なるタイプを使用してOrmLiteにデータを挿入することも、「正確な形状」である必要もありません。基になるテーブルで使用可能なフィールド。また、テーブル、ビュー、またはストアドプロシージャの区別もありません。OrmLiteは、結果セットを指定されたPOCOの一致するフィールドにマップし、他のフィールドを無視します。

事実上、これはServiceStackのPOCOが非常に復元力があり、相互運用可能であることを意味します。そのため、OrmLiteで同じDTOを問題なく再利用でき、その逆も可能です。 DTOモデルとデータモデルがわずかにずれている場合は、 シリアル化されないように非表示にする か、以下の属性を使用してOrmLiteに保存できます。

public class Poco
{
    [Ignore]
    public int IgnoreInOrmLite { get; set; }

    [IgnoreDataMember]
    public int IgnoreInSerialization { get; set; }
}

それ以外の場合、それらを分離する必要がある場合、例えば返すよりも多くのフィールドがRDBMSテーブルに追加されたか、DTOに代替ソースから入力された追加のフィールドが含まれるか、または単にサービスにそれらを異なるように投影させたい場合。その時点(YAGNI)で、DTOのコピーを取得してサービス実装に追加できるため、DTOをさまざまな懸念事項に妨げられることなく、個別に拡張できます。その後、を使用してそれらの間で簡単に変換できます
ServiceStackの組み込みの自動マッピング 、例:

var dto = dbPoco.ConvertTo<Poco>();

組み込みの自動マッピングも非常に耐性があり、さまざまなタイプのプロパティを強制することができます。文字列、さまざまなコレクションタイプなどへ/から。

データ転送オブジェクト-DTO

したがって、外部依存関係のないクリーンでシリアル化可能なPOCO(OrmLite、Redis、またはalt ServiceStackソースなど)を使用している場合は、それらをDTOとして喜んで再利用し、必要に応じてさまざまなモデルに自由にリファクタリングできます。ただし、データモデルをDTOとして再利用する場合でも、サービスが返すすべてのタイプを含むServiceModelプロジェクト(別名DTO .dll)で維持する必要があります。 DTOはロジックと依存関係がない必要があります。したがって、ServiceModelプロジェクトが参照する依存関係はimpl-free ServiceStack.Interfaces.dllのみです。これは、PCL .dllであるため、すべてのプラットフォームから自由に参照できます 。NETモバイルおよびデスクトッププラットフォーム

これは、サービスがホストされている場所のベースURLとともに、サービスコンシューマーがを消費するために知っている必要なすべてであるため、サービスが返すすべてのタイプがDTO.dllにあることを確認する必要があります。サービス。 。NET Service Clients のいずれかと一緒に使用して、コード生成、ツール、その他の人工機械なしでエンドツーエンドのTyped APIを取得できます。クライアントが代わりにソースコードを好む場合は、 ServiceStackリファレンスの追加 を使用して、選択したプラットフォームと言語でサーバーが入力したDTOにアクセスできます。

サービス

サービスは、複雑さをカプセル化する究極の形式であり、最高レベルのソフトウェア再利用を提供します。それらはその機能をパッケージ化し、サービスコールのコストよりも複雑になることなく、消費者がリモートで利用できるようにします。

DTO Interface vs Service Implementation

DTOはサービスコントラクトを定義するものであり、サーバー実装から分離することは、サービスがその機能(無制限の複雑さの可能性がある)をカプセル化し、リモートファサードの背後で利用できるようにする方法です。それはあなたのサービスが提供するものをそれを実現する方法の複雑さから分離します。サービスのAPIを定義し、サービスが提供する機能とその利用方法を見つけるために知っておく必要のある最小限の情報をサービスコンシューマーに通知します(C/C++ソースコードのヘッダーファイルと同様の役割を維持します)。明確に定義されたサービスコントラクトは実装から分離されており、相互運用性を強化して、サービスが特定のクライアント実装を強制しないようにし、任意のプラットフォーム上の任意のHTTPクライアントがそれらを利用できるようにします。 DTOは、サービスのワイヤー形式の形状と構造も定義し、ネイティブデータ構造にクリーンに逆シリアル化できるようにして、サービス応答を手動で解析する手間を省きます。

並行クライアント開発

契約全体をキャプチャするため、クライアントはサービスを実装する前にアプリケーションを開発できます。これは、アプリケーションを具体的なDTOモデルにバインドでき、サービスクライアントを簡単にモックしてバックエンドサービスまでテストデータを返すことができるためです。実装されています。

ルールに関する限り、その実装から切り離された明確に定義されたサービスコントラクト(DTO)を確実にすることは、サービスとは何か、およびサービスが提供する価値の本質に非常に重要です。

リクエストおよびレスポンスDTO

どのDTOがデータモデルとして再利用するのに適しているかについては、動詞である外部サービスAPIの定義以外の目的で要求DTOを使用したくないそれは理想的には コールセマンティクスと応答タイプでグループ化 、例:

public class SearchProducts : IReturn<SearchProductsResponse> 
{
    public string Category { get; set; }
    public decimal? PriceGreaterThan { get; set; }
}

RDBMSテーブルは通常、名詞として定義されたエンティティです。つまり、サービスが返すものです。

public class SearchProductsResponse
{
    public List<Product> Results { get; set; }        
    public ResponseStatus ResponseStatus { get; set; }
}

サービスが返すものを定義するResponse DTOでさえ、データモデルとしての再利用には適していません。私は通常、サービス応答に個別のDTOを使用します。これにより、既存のサービスを自由に拡張して、既存のクライアントを壊すことなく追加のデータやメタデータを返すことができます。

リクエストとレスポンスのDTOを除いて、サービスが返す他のすべてのTypesは、データモデルとして再利用する候補となります。これは、私が頻繁に行うことで、ServiceModelプロジェクトに保持されます。上記の理由のため。

48
mythz