web-dev-qa-db-ja.com

ドメイン駆動設計は反SQLパターンですか?

私はドメインドリブンデザイン(DDD)に飛び込んでいますが、さらに深く掘り下げていくと、得られないことがいくつかあります。私が理解しているように、主なポイントは、ドメインロジック(ビジネスロジック)をインフラストラクチャ(DB、ファイルシステムなど)から分割することです。

マテリアルリソース計算クエリのような非常に複雑なクエリがあるとどうなりますか?この種のクエリでは、SQLが設計されたような、重い集合演算で作業します。ドメインレイヤー内でこれらの計算を行い、その中の多くのセットを操作することは、SQLテクノロジを破棄するようなものです。

インフラストラクチャでこれらの計算を行うこともできません。DDDパターンでは、ドメインレイヤーを変更せずにMongoDBに同じ機能がないことを知らなくてもインフラストラクチャを変更できるためです。 SQL Server、それは起こり得ない。

それはDDDパターンの落とし穴ですか?

46

最近では、読み取り(クエリ)が書き込み(コマンド)とは異なる方法で処理されることがよくあります。複雑なクエリを持つシステムでは、クエリ自体がドメインモデルを通過することはほとんどありません(これは、主にwritesの一貫性を維持する責任があります)。

私たちはSQLをSQLにレンダリングするべきだということは絶対に正しい。したがって、読み取りを中心に最適化されたデータモデルを設計します。そのデータモデルのクエリは、通常、ドメインモデルを含まないコードパスを使用します(一部の入力検証の例外を除いて、 クエリのパラメーター は妥当です)。

39
VoiceOfUnreason

私が理解しているように、主なポイントは、ドメインロジック(ビジネスロジック)をインフラストラクチャ(DB、ファイルシステムなど)から分割することです。

これは誤解の根拠です。DDDの目的は、「これはSQLサーバーにあるため、BLであってはなりません」のように難しいものに沿って物事を分離することではありません。ドメインの内部を別のドメインの内部から完全に分離できるようにし、ドメイン間の共有外部を定義します。

「SQLにいる」ことをBL/DLの障壁と考えないでください。それは、それがそういうことではありません。代わりに、「これが内部ドメインの終わりです」を障壁として考えてください。

各ドメインには、すべてのotherドメインで動作できるようにする外部向けAPIが必要です(data storageの場合) =レイヤー、格納するデータオブジェクトの読み取り/書き込み(CRUD)アクションが必要です。これは、SQL自体が実際にはバリアではなく、VIEWおよびPROCEDUREコンポーネントがバリアであることを意味します。テーブルから直接読み取ることは絶対にしないでください。thatは実装の詳細です。DDDは、外部のコンシューマーとして、心配する必要はないことを示しています。

あなたの例を考えてみましょう:

資材リソース計算クエリのような非常に複雑なクエリがあるとどうなりますか?この種のクエリでは、SQLが設計されたような、重い集合演算を扱います。

これはまさにSQLにあるべきものであり、DDDの違反ではありません。 DDDを作成したのはです。 SQLでの計算では、それはBL/DLのpartになります。あなたがすることは、別のビュー/ストアドプロシージャ/ what-have-youを使用し、ビジネスロジックをthatは外部APIです。実際、データレイヤーは別のDDDドメインレイヤーである必要があります。データレイヤーには、他のドメインレイヤーと連携するためのown抽象化が含まれています。

インフラストラクチャでこれらの計算を行うこともできません。DDDパターンでは、ドメインレイヤーを変更せずにMongoDBに同じ機能がないことを知らなくてもインフラストラクチャを変更できるためです。 SQL Server、それは起こり得ない。

それは別の誤解です:実装の詳細は変更せずに内部的に変更できると言いますその他ドメイン層。インフラストラクチャ全体を交換できるとは言いません。

繰り返しますが、DDDは明確に定義された外部APIで内部を隠すことを念頭に置いてください。それらのAPIがどこにあるかはまったく別の問題であり、DDDはそれを定義していません。これは単にこれらのAPIが存在することを定義し、決して変更しないでください

DDDは、MSSQLをMongoDBでアドホックに置き換えることができるように設定されていません。これらは2つのまったく異なるインフラストラクチャコンポーネントです。

代わりに、DDDが定義するものの類似を使用してみましょう:ガソリン車と電気自動車。両方の車両には、推進力を作成するための2つの完全に異なるメソッドがありますが、同じAPIがあります:オン/オフ、スロットル/ブレーキ、およびホイール車両を推進します。 DDDは、車のエンジン(ガスまたは電気)を交換できるはずであると述べています。車をバイクに置き換えることができるとは言っていません。それが、MSSQL→MongoDBが効果的だということです。

21
Der Kommissar

アプリケーションをホストするために支払いをしている組織が、データベースレイヤーライセンスが高すぎると判断したプロジェクトに参加したことがある場合、データベース/データストレージを簡単に移行できることに感謝します。すべてのことを考慮し、これは起こりますが、頻繁には起こりません

いわば、両方の長所を活用できます。データベースで複雑な関数を最適化することを検討している場合は、インターフェースを使用して、計算の代替実装を注入できます。問題は、複数の場所でロジックを維持する必要があることです。

建築パターンからの逸脱

純粋にパターンを実装したり、特定の領域から逸脱したりすることに不満を感じるときは、決断する必要があります。パターンは、プロジェクトを整理するのに役立つ、テンプレート化された方法です。この時点で、時間をかけて評価します。

  • これは正しいパターンですか? (多くの場合そうですが、時々それはちょうど悪い適合です)
  • この方法で逸脱すべきですか?
  • これまでのところ、どれだけ逸脱していますか?

一部のアーキテクチャパターンは、アプリケーションの80〜90%に適していますが、残りのビットにはそれほど適していません。規定されたパターンからの時折の逸脱は、パフォーマンスまたはロジスティックの理由で役立ちます。

ただし、累積偏差がアプリケーションアーキテクチャの20%以上とかなり大きい場合、それはおそらく不適切な適合です。

アーキテクチャを続行することを選択した場合は、自分で賛成し、規定の方法から逸脱した場所と理由を文書化してください。チームに新しい熱狂的なメンバーを迎えたら、パフォーマンス測定や正当化を含むそのドキュメントをそのメンバーに向けることができます。これにより、「問題」を修正するために繰り返し要求される可能性が低くなります。そのドキュメントは、蔓延している逸脱を阻害するのにも役立ちます。

18
Berin Loritsch

SQLが得意とするセット操作ロジックは、DDDと問題なく統合できます。

たとえば、いくつかの集計値、タイプごとの製品の総数を知る必要があるとします。 SQLで実行するのは簡単ですが、すべての製品をメモリにロードしてすべて追加すると遅くなります。

新しいドメインオブジェクトを紹介するだけです。

ProductInventory
{
    ProductType
    TotalCount
    DateTimeTaken
}

と私のリポジトリ上のメソッド

ProductRepository
{
    List<ProductInventory> TakeInventory(DateTime asOfDate) {...}
}

確かに、多分私は今、自分のDBが特定の能力を持っていることに依存しています。しかし、技術的にはまだ分離があり、ロジックが単純である限り、それは「ビジネスロジック」ではないと主張できます。

8
Ewan

このジレンマを解決する方法の1つは、SQLをアセンブリ言語として考えることです。SQLを直接コーディングすることはほとんどありませんが、パフォーマンスが重要な場合は、Cによって生成されたコードを理解できる必要があります。/C++/Golang/Rustコンパイラー。高レベル言語のコードを変更して目的のマシンコードを生成できない場合は、アセンブリに小さなスニペットを書き込むこともできます。

同様に、データベースとSQLの領域では、さまざまなSQLライブラリ(その一部は [〜#〜] orm [〜#〜] です)です。 SQLAlchemy およびDjango PythonのORM、 [〜#〜] linq [〜#〜] .NETの場合、より高いレベルの抽象化を提供します可能な限りパフォーマンスを達成するために生成されたSQLコードを使用します。また、使用されたDBに移植性を提供します。たとえば、最適なDB固有のSQLを使用する操作により、PostgresとMySQLなどでパフォーマンスが異なる可能性があります。

また、高水準言語と同様に、SQLがどのように機能するかを理解することが重要です。たとえ上記のSQLライブラリを使用して行われたクエリを並べ替えるだけでも、目的の効率を達成できます。

追伸私はむしろこれをコメントにしたいと思いますが、私はそれについて十分な評判がありません。

3
Kyrylo Shpytsya

いつものように、これはいくつかの要因に依存するものの1つです。 SQLでできることはたくさんあります。それを使用する上での課題と、リレーショナルデータベースのいくつかの実用的な制限もあります。

Jared Goguenがコメントで述べているように、SQLのテストと検証は非常に難しい場合があります。これにつながる主な要因は、(一般的に)コンポーネントに分解できないことです。実際には、複雑なクエリを完全に考慮する必要があります。もう1つの複雑な要因は、SQLの動作と正確性がデータの構造と内容に大きく依存していることです。つまり、考えられるすべてのシナリオをテストする(またはシナリオを決定する)ことは、多くの場合、実行不可能または不可能です。 SQLのリファクタリングとデータベース構造の変更も同様に問題があります。

SQLからの移行につながったもう1つの大きな要因は、リレーショナルデータベースが垂直方向にしか拡張できない傾向があることです。たとえば、SQL Serverで実行するためにSQLで複雑な計算を構築すると、それらはデータベースで実行されます。つまり、その作業のすべてがデータベース上のリソースを使用しています。 SQLで行う作業が多ければ多いほど、データベースはメモリとCPUの両方の面で必要になります。多くの場合、他のシステムでこれらのことを行うと効率が低下しますが、そのようなソリューションに追加できる追加のマシンの数に実際的な制限はありません。このアプローチは、モンスターデータベースサーバーを構築するよりも安価でフォールトトレラントです。

これらの問題は、当面の問題に当てはまる場合と当てはまらない場合があります。利用可能なデータベースリソースで問題を解決できる場合は、SQLが問題領域に適している可能性があります。ただし、成長を考慮する必要があります。今日は問題ないかもしれませんが、数年後には、追加のリソースを追加するコストが問題になる可能性があります。

2
JimmyJames

それはDDDパターンの落とし穴ですか?

まず、いくつかの誤解を明らかにしましょう。

DDDはパターンではありません。そして、実際にはパターンを規定していません。

Eric EvanのDDD 本の序文は次のように述べています:

主要なソフトウェア設計者は、ドメインモデリングとデザインを少なくとも20年間重要なトピックとして認識してきましたが、驚くべきことに、何をする必要があるか、どのように行うかについてはほとんど書かれていません。明確に定式化されたことはありませんが、哲学はオブジェクトコミュニティの底流として浮上しています。これは、私がドメイン駆動設計と呼んでいる哲学です。

[...]

成功に共通の特徴は、設計の反復を通じて進化し、プロジェクトのファブリックの一部となった豊富なドメインモデルでした。

この本は、設計の決定を行うためのフレームワークと、ドメイン設計について議論するための技術用語を提供します。これは、広く受け入れられているベストプラクティスと私自身の洞察と経験を組み合わせたものです。

したがって、これは、ソフトウェア開発とドメインモデリングに加えて、これらのアクティビティをサポートするいくつかの技術用語(さまざまな概念とパターンを含む用語)にアプローチする方法です。また、まったく新しいものでもありません。

覚えておくべきもう1つのことは、ドメインモデルはではないOOあなたのシステム-それはそれを表現する、またはそれの一部を表現する1つの方法にすぎません。ドメインモデルは問題について考える方法ですあなたはソフトウェアを使って解決しようとすることです。それは、物事を理解し、認識する方法であり、それについて話す方法です。それは概念ですが、漠然とした意味ではありません。深く洗練されており、ハードワークと知識収集の結果です。さらに洗練され、時間とともに進化する可能性が高く、実装に関する考慮事項が含まれます(モデルの一部が制約される可能性があります)。これはすべてのチームメンバー(および関連するドメインの専門家)によって共有され、システムがシステムを密接に反映するように、システムの実装方法を促進する必要があります。

OO開発者はおそらくモデルをOO言語で表現し、多くの表現をドメインの概念はOOPでより適切にサポートされていますが、モデルの一部を別のパラダイムで表現する必要がある場合があります。

私が疑問に思っているのは、非常に複雑なクエリがあるとどうなるかです[...]?

さて、一般的に言えば、ここには2つのシナリオがあります。

前者の場合、ドメインの一部の側面には実際には複雑なクエリが必要であり、おそらくその側面はSQL /リレーショナルパラダイムで最もよく表現されるため、適切なツールをジョブに使用します。それらの側面をドメインの考え方やコミュニケーションの概念で使用される言語に反映します。ドメインが複雑な場合、これはおそらく独自の境界コンテキストを持つサブドメインの一部です。

他のシナリオは、SQLで何かを表現する必要があると認識されている必要性は、制約された思考の結果であるというものです。人やチームが常にデータベース指向の考え方をしている場合、慣性のためだけに、別の方法で物事に取り組むことは難しいかもしれません。これは、古い方法が新しいニーズに対応できず、箱から出して考える必要がある場合に問題になります。 DDDは、設計へのアプローチとして、ドメインに関する知識を収集して抽出することにより、その箱からあなたの道を見つける方法の一部です。しかし、誰もが本のその部分を無視しているようであり、記載されている技術用語とパターンのいくつかに焦点を当てています。

2

リレーショナルデータモデルがデータを正規化してファイルシステムに効果的に格納する可能性を提供したため、メモリが高価なときにSequelが普及しました。

メモリは比較的安価なので、正規化をスキップして、使用する形式で保存したり、速度を上げるために同じデータを大量に複製したりすることもできます。

データベースを単純なものと見なすIO device、データをファイルシステムに格納する責任-はい、多くのアプリケーションをSQLクエリに書き込まれた重要なビジネスロジック-SQL Serverが単なる別のプリンターであると想像してみてください。

PDFジェネレーターをプリンタードライバーに埋め込みましたか、それともプリンターから印刷されたすべての販売注文のログページを印刷するトリガーを追加しましたか?

アプリケーションが特定のデバイスタイプに結び付けられたくないので、答えはノーだと思います(そのようなアイデアの効率についてさえ話していません)。

70年代から90年代のSQLデータベースは効率的でしたか? -よくわかりません。一部のシナリオでは、非同期データクエリは、SQLクエリの複数の結合よりも必要なデータを速く返します。

SQLは複雑なクエリ用に設計されたのではなく、効率的な方法でデータを格納し、格納されたデータをクエリするためのインターフェイス/言語を提供するために設計されました。

複雑なクエリを使用してリレーショナルデータモデルを中心にアプリケーションを構築することは、データベースエンジンの悪用だと思います。もちろん、データベースエンジンプロバイダーは、ビジネスを自社の製品に密接に結び付けたときに満足します-この限界をより強固にするより多くの機能を提供することに満足するでしょう。

0
Fabio