web-dev-qa-db-ja.com

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

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

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

  • よりタイプセーフな呼び出し。 IDを使用すると、引数の順序が誤ってしまうリスクがあります。これは、そのクラスのIDのみを格納するクラスごとに「ミニ」クラスを保持することで軽減できます。
  • 永続化から一度取得し、再度取得する必要はありません
  • IDを使用して、IDタイプが変更された場合、たとえばint-> longの場合は、間違いが生じる可能性があるため、全面的に変更する必要があります。(courtsey: 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フィールドに入力するのは、やり過ぎです。

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

10
0fnt

環境と問題のコンテキストに応じて、データベースに移動する必要性が軽減され、その結果(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つのメソッドのフェッチの3倍のデータベース呼び出しです。エンティティとその上で動作している2。

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

8
Andy Hunt

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

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

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

新しいプログラマーまたはあなたの未来の自己が理解するのに最も簡単な解決策を探してください。これはBookおよびMemberオブジェクトを渡すことです。actualIDを渡すだけで本当に問題が発生する場合のパフォーマンスの問題。

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

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

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

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

3
Greg Burghardt