メソッドパラメータとしての識別子とドメインオブジェクト


10

メソッドと関数のパラメーターとしてのオブジェクトと一意のIDの使用について賛成または反対の客観的な引数はありますか?(および他のオブジェクトのメンバー?)。特に静的型付け言語のコンテキスト(C#/ Java / Scala)

オブジェクト自体の長所:

  • よりタイプセーフな呼び出し。IDを使用すると、引数の順序が誤ってしまうリスクがあります。これは、そのクラスのIDのみを格納するクラスごとに「ミニ」クラスを保持することで軽減できます。
  • 永続化から一度取得し、再度取得する必要はありません
  • (:courtsey - IDと、IDタイプが変更された場合、INTを言う>長い、そして...ミスの可能性が軒並み変更を必要とするhttps://softwareengineering.stackexchange.com/a/284734/145808

IDを使用するメリット:

  • ほとんどの場合、実際のオブジェクトは必要ありません。uniqueidで十分です。そのため、IDがあれば、永続化から取得する時間を節約できます。

これらのテクニックの混合は、私が見る限り、両方の長所と短所の両方を持っています。

これが具体的に定義された問題であることを考えると、「私は思う」または「好き」タイプではなく、客観的な答えがあることを願っています... :-)。

編集:コメンターの提案に関するコンテキスト-唯一の制限は静的に型付けされた言語です。このアプリケーションは汎用アプリケーションですが、特定の使用シナリオに基づいて回答を得ることもできます。

編集:もう少しコンテキスト。書籍管理システムがあるとします。私のモデルは:

Book: { id: Int, isbn: String, donatedBy: Member, borrowedBy: Member }
Member: {id: Int, name: String}

Table- wishlist: { isbn: String, memberId: Int}
Table- borrows:  { id: Int, memberId: Int}  

Method: 
isInWishList( book: Book, member: Member ) vs isInWishList( bookId: Int,  memberId: Int)

handleBorrowRequest( memberId: Int, book: Book ){ 
   //the login system doesn't actually get the entire member structure, only the member id. I don't need the full member yet. can run a query to verify that the memberId has less than max allowed books for borrowing. 
}

完全なメンバーではなく、IDのみを保持したいのはなぜですか?本に関する情報を入手したとき、だれがその本を寄贈したか、または借りたかについて知る必要はほとんどありません。彼らの完全な情報を取得して、donatedByフィールドとborrowedByフィールドにデータを入力するのは、やり過ぎです。

もちろん、これらは私のポイントにすぎません。私は何かが欠けていると確信しているので、賛成/反対のポイントは何であるか知りたいと思いました。


もう少しコンテキストを付けて質問を編集できますか?シナリオが何であるかは明確ではありません。私はするつもりだと思いますが、あなたが遅延ロードのプロキシオブジェクトを意味する「ミニクラス」で(Hibernateのような)ORMシステムによって、その管理されているオブジェクトの話をしていること。
ダリアン、

2
おそらく関連していますか?programmers.stackexchange.com/questions/284634/…–
hjk

ここにコメントとして追加(フル機能の回答に展開するのに十分なコンテキストが得られるまで):コードで ID値をハードコーディングしていない限り(大きなno-no)、ID値をロードする必要がありますどこから?「ほとんどの場合」もかなりあいまいな
IMHO

@hjkありがとうございます。あなたはポイントを持っています-あなたはまだどこかからID値をロードする必要があります。ただし、それはDBに「触れる」ことではなく、DBの使用量と帯域幅を最小限に抑えることです。本を借りたいすべての人のIDを取得できますが、実際に詳細をすべて取得する必要はありません。
2015年

それはいくつかの事柄に依存すると思われます:(1)ユースケースが実際の属性(列)を必要とするか、IDのみを必要とするかどうか。(2)IDから属性へのクエリを簡単にするいくつかのキャッシングまたはパフォーマンス向上テクニックを使用しているかどうか、およびそのようなキャッシングスキームを壊すほどユースケースが重いかどうか。
rwong

回答:


8

環境と問題のコンテキストに応じて、データベースに移動する必要性が軽減され、その結果(IMO)、IDのみを使用するための引数が失われます。

たとえば、PHPのDoctrine2 ORMはEntityManager::getReference、提供されたIDを使用してエンティティに遅延ロードされたプロキシを生成します。他にいくつのORMがそれを行うのかはわかりませんが、あなたが言及する「ミニクラス」の概念とほぼ一致します。ほとんどの目的と目的では、これは完全に水和されたエンティティであるため、他のオブジェクトと同じように渡し、使用できます。

そうでない唯一のケースは、無効なIDが指定された場合であり、その場合はとにかくデータベースに移動して検証する必要があります。さらに、エンティティを取得するコストを削減するために、ほとんどのORMは(第1レベルと第2レベル)のキャッシュ機能を何らかの形で利用できます。

データベースへのアクセスの必要性とコストを削減すると、エンティティーをパラメーターとして使用するというプロの仕事がほとんどなくなります。

  1. タイプセーフ。
  2. 発信者が必要とする知識が少ない。6か月後の開発者は、間違ったエンティティのIDを誤って渡すことができません。
  3. リファクタリングコストの削減。メソッドがエンティティからの2つの情報を要求するように変更された場合、呼び出し元を変更して提供するためのコストはかかりません。
  4. メソッドごとに必要な検証が少なくなります。多くのメソッドは、指定されたエンティティがデータベースに存在すると想定できるため(ORMからのものであるため)、IDを検証する必要はありません。
  5. (場合によっては)データベース呼び出しが少なくなる。idを3つのメソッドに渡し、それぞれがそれを検証するか、エンティティでより多くのデータをフェッチする必要がある場合、1つのメソッドがエンティティをフェッチし、2つがエンティティを操作する場合の3倍のデータベース呼び出しになります。

もちろん、IDのみを渡したい場合もあります。たとえば、(ドメイン駆動設計では)境界のあるコンテキスト境界を越える場合などです。アカウントを構成する概念が異なる2つの境界のあるコンテキスト(たとえば、財務と顧客の関係)を検討する場合、コンテキストAのアカウントをコンテキストBに渡すことはできません。代わりに、アカウントID(ドメインの言語)は渡される。


キャッシングは、アプリケーションの複数のインスタンスが実行されている状態では適切にスケーリングされません。私は自分のキャッシュを用意しています。ポイントは素晴らしいですが。
2015年

IDに対するもう1つのポイントは、IDを使用すると、実際にオブジェクトを取得するために、検証以外に永続性を呼び出すことを意味することです。
2015年

3

この種の質問については、プログラマとしての意図を最も適切に伝えるソリューションに委任し、「Future Greg」の仕事を最も簡単にします。

オブジェクトを引数として使用すると、6か月後にメソッドを正しく呼び出すことが容易になり、このアプリケーションの詳細な説明を忘れてしまいました。「この本はこの人のウィッシュリストの例にありますか」を基に、isInWishListメソッドが本とメンバーの整数IDを比較するだけで十分だとしましょう。実際には、この1つの方法では、2つのデータが必要です。次に、この1つの方法から一歩戻り、ソフトウェアシステム全体を見てみましょう。動作するために必要なのは、ブックIDとメンバーIDだけだと思います。とにかく、isInWishListこの1つのメソッドを呼び出すだけではなく、他にも何かを行う必要があるため、を呼び出す前に、データベースから本とメンバー全体を取得します。多分あなたはそうしますが、ほとんどの場合、あなたはもっとする必要があります。

そのため、データベースから両方のオブジェクトを完全にフェッチしてマッピングすることにより、実際にパフォーマンスが低下することはありません。理論的には必要なデータベース呼び出しは少なくなりますが、実際には、これは単に真実ではないことがわかります。これらのIDをクエリ文字列のパラメーターとしてサーバーに返す場合は、ええ、データベースからウィッシュリストをフェッチするだけで済みます。しかし、これはアプリケーション全体の非常に狭いビューです。ウィッシュリストをチェックするだけでなく、他の操作を実行しているシナリオもあります。たとえば、ウィッシュリストに本を追加する場合などです。重複するアイテムを追加したくない。

新しいプログラマーまたはあなたの未来の自己が理解するのに最も簡単なソリューションを探してください。これはBookMemberオブジェクトとオブジェクトを渡すことです。実際のパフォーマンスの問題を見つけた後でのみ、IDを渡すだけで本当に心配する必要があります。

または、Javaのような静的に型付けされた言語はメソッドのオーバーロードを提供するので、ケーキを手に入れて食べることもできます。

public boolean isInWishList(int bookId, int memberId) {
    // ...
}

public boolean isInWishList(Book book, Member member) {
    return isInWishList(book.getId(), member.getId());
}

この質問に対する本当の答えは、両方のメソッドを記述し、厳密に型指定されたバージョンから整数のみのバージョンを呼び出し、ボブはあなたの叔父です。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.