DDD 実践戦闘パート 2: コード構造がどのようなものかを確認する

DDD 実践戦闘パート 2: コード構造がどのようなものかを確認する

DDD の取り組みを実際に開始する前に、DDD 設計後のコードがどのようになるかを見てもらいたいと思います。これは「話すのは簡単、コードを見せてください」というコンセプトに従うすべてのプログラマーが気にする概念だと思います。

そこで、生鮮食品電子商取引システム「Qunmaicai」のサーバーコードの新旧のコード構造を特別に表示し、元の古いコード、つまり「トランザクションスクリプト」のコードがどのようなものであるかを確認できるようにしました(現在、ほとんどの Java プログラマーがコードを書いているようにする必要があります)。DDD 変換と設計後に新しいコードがどのように見えるかを確認できます。次に、分析を通じて、なぜ従来の「トランザクション スクリプト」コードが現実世界の「同型マッピング」ではないのか、そして DDD コードの「同型マッピング」はどこにあるのかを説明できます。

思い出していただきたいのですが、今日のトピックから始めて、次のことを行うには、より多くの時間を費やして、コードと私が書いたテキストのすべての文を深く読み、繰り返し比較したり、何度も読み返したりする必要があるかもしれません。本当に理解すること、この言葉を理解すること。

まず、古いコードのディレクトリ構造のスクリーンショットを見てみましょう。以下の 1、2、3、および 4 のマークされた位置に注目してください (説明、私は Spring-Boot 開発フレームワーク、MyBatisPlus データ永続フレームワーク、および MySql5.6 データベースを使用しています)。

画像.png

画像.png

画像.png

ここにマークされているコード位置 1、2、3、4 に気づきましたか? コード構造は、ほとんどの Spring-Boot アプリケーション フレームワークのコード構造と似ていますか? このコード構造を理解できない可能性があるので、簡単に説明します。

ラベル 1 の位置: コントローラー層のコードがここに配置されます。つまり、すべてのフロントエンド アクセス インターフェイスがここに実装されます。MVC の階層化原理に従って、一般的に言えば、クライアント入力パラメータの一部の解析とサービス層へのビジネス メソッド呼び出し (以下を参照) のみがここに含まれます。一般的に、ここでのコードは次のようになります。

画像.png

ラベル 2 の位置: エンティティ (データ Bean) 層のコードがここに配置されます。実際にはすべて POJO コードであり、すべてのクラスが 1 つずつデータベース テーブルにマッピングされます。一般的に、ここでのコードは次のようになります。

画像.png

番号 3 の位置: マッパー層: mybatis 永続層フレームワークの場合、マッパーとエンティティは共同で ORM (オブジェクト モデルからリレーショナル モデルへのマッピング) を実装します。一般的に、ここのコードは次のようになります (ここの CustomerMapper クラスは、エンティティ クラス Customer のマッピング関係とカスタム データ操作メソッドのみを定義します)。

画像.png

そして次のようになります (MP では、この CustomerMapper.xml ファイルはカスタム SQL 操作メソッドを実装する場合にのみ必要です)。

画像.png

4 番目の位置: サービス層。これはすべてのビジネス ロジックが実装されるコア コードであり、ほぼすべてのビジネス ロジックがここに実装されます。一般的に、インターフェイスと実装の組み合わせの実装が存在します。例: OrderService と OrderServiceImpl はそれぞれ次のようになります。

OrderServiceインターフェースクラス

画像.png

OrderServiceImpl 実装クラス

画像.png画像.png

画像.png

上記のコードから、次の点が明確にわかります。

  • コントローラー/エンティティ/マッパーは、基本的にフレームワークのアノテーションと公開ツール コード (json 解析など) を使用して実装された非常に少数のコードです。

  • 明らかに、ビジネス ロジックのほとんどはサービス層の実装クラスに実装されます。

  • サービス層実装クラス コードのロジックは非常に長く、完全に「フラットで簡単」です。ここで示す OrderSeriveImple の create メソッドは、注文を作成するために 135 行を記述しています。コードのスクリーンショットのコメントを見ると、データベースに対して CRUD を実行する方法を段階的に考え、最初にコメントを入力してからコードを書いたことがわかります。この種のコードは、端的に言えば「CRUD + 計算ロジック」を組み合わせたコードです。

  • 実際、この種の「フラットで単純な」コードは、プログラムが理解しやすく、書きやすいです。基本的に、あまりにも多くの脳細胞を「殺す」必要がないため、チームがプロジェクトの実装を開始するのが簡単です。 . 、基本的な Java プログラミング経験 (通常は 1 年以上の経験で十分です) を持つ人を見つけるだけで、ビジネス コードの開発を始めることができます。

  • この種のコードは、「トランザクション スクリプト」コード、または「貧血モデル」コードと呼ばれます。

  • これが「トランザクション スクリプト」と呼ばれる理由は、私の個人的な理解です。20 年前にデータベース ストアド プロシージャ コードを作成したのと本質的には同じです (言語が異なるだけで、コードが実行される場所が異なるだけです)。データベースサーバーからアプリケーションサーバーまで言及されます)。

  • これが「貧血モデル」コードと呼ばれる理由は、Order などのエンティティ レイヤーの POJO オブジェクトにはビジネス動作がカプセル化されていないためです (たとえば、Order クラスは独自の注文番号を生成する必要があります。動作オブジェクトは「貧血」オブジェクトであり、「貧血」オブジェクトに基づいて実装されるビジネスロジックコードを「貧血モデル」コードと呼びます。

ここでのコード分析に基づいて、重要な問題を見つけることができますか。実際、ここのコントローラー/エンティティ/マッパー/サービスと現実世界のビジネス、つまり「コードの世界」の間にマッピングはありません。 」 そして「現実世界」は異質です。具体的には以下のような点が考えられます。

まず、ビジネスモジュール分割の「最も粗い」粒度から、実際にシンプルかつ直感的にモジュールを分割することができ、すべてのビジネスモジュールを1つのプロジェクトに入れるのではなく、業務モジュール(店舗など)ごとに分割することができます。受注管理、製品管理など)を利用してプロジェクトディレクトリを分割、つまりプロジェクトチームをグループ化します。

実際、現在市販されているソフトウェア会社の多くは、業務上の経験や勘に基づいて、プロジェクトを単純かつ大まかに複数のチームに分けて開発しています。しかし、この分割方法は多かれ少なかれ正確である可能性がありますが、認識する必要があるのは、そのような経験と直感に基づく単純で大雑把な分割は、DDD 手法による設計分割 (境界付けられたコンテキストの粒度に分割する) とは異なるということです。 ). この設計 (DDD では「戦略設計」と呼ばれます) には、少なくとも 3 つの欠点があります。

  • ソフトウェア コードをどのように分割するかは厳密には「エンジニアリングの問題」であり、すべてのエンジニアリング問題は多くの場合「わずかな違いが千マイルにつながる可能性がある」です。経験と直観のこの分割では、「境界のあるコンテキスト」という非常に重要な特定が見逃される可能性があります。そして、これらの重要な「境界付きコンテキスト」が省略されているために、いくつかのあいまいな領域が存在し、モジュール間に不必要な結合または不必要な重複が存在することが判明します。
  • DDD の「境界付きコンテキスト」の識別は、それを分割する必要があるモジュールの数を区別するだけではありません (実際、「モジュール」は非常に曖昧な単語であり、マイクロサービスを分割するために使用することも、マイクロサービスを分割するために使用することもできます)必要に応じてコード ディレクトリ構造) )、これらの「境界付きコンテキスト」間の協力関係と境界を特定することも必要です。これらのコラボレーション関係は、どのコードがモジュール A に属し、どのコードがモジュール B に属するか、つまり境界、およびこれらのモジュールが RPC 関係またはローカル呼び出し関係を通じてコラボレーションしているかどうかを「コード ライン レベルで明確かつ正確に」定義します。非同期メッセージ: イベントは連携しているか、直接連携していません。
  • 一般に、DDD の「境界付きコンテキスト」はビジネス サブドメインに対応する必要があり、ビジネス サブドメインの重要性によって境界付きコンテキストの重要性が決まります。特定のソフトウェア システムについて、ビジネス サブフィールドは、ビジネスの観点から、ソフトウェアの中核的な競争力として何を構築する必要があるか、また、何を二次モジュールとして、またはアウトソーシングを通じて実装できるかを決定できます。「境界コンテキスト」モジュールのこれらのさまざまな「重要性」定義により、プロジェクト管理は効率の観点からさまざまなテクノロジー スタックを採用するようになります。例: 現在市場に出ているプログラマーによって給与レベルや採用の難易度は異なります。テクノロジー スタックによって成熟度や適用可能なプログラミング機能も異なります (例: Java は比較的成熟しており、エンタープライズ レベルのアプリケーション開発に適していますが、Python はデータに適しています)処理開発、node.js はサードパーティのインターネット システムへの接続などに適しています)。

次に、モジュール内でコードの階層構造が分割されますが、MVCの考え方に従うと、最終的にはコントローラー/エンティティ/マッパー/サービスのような分割方法に戻ります。そして、この分割方法と「現実世界」との間の同型写像関係は何でしょうか? それは言えます、いいえ!

したがって、最終的には、この従来のコード アーキテクチャは現実世界との「同型マッピング」を考慮していないと結論付けることができます。この「同型マッピング」の欠如が、「実際のビジネスはそれほど変わっていないのに、なぜ特定の要件によってソフトウェアコードに天地を揺るがすような変更が生じるのか?」という疑問を抱く根本的な理由です - DDD 手法が使用されますこの問題を解決するために!

DDD 設計を使用した後の新しいコード構造がどのようになるかを見てみましょう。以下は、新しいコードの構造のスクリーンショットです (以下の 1 ~ 8 の数字にも注意してください)。

画像.png

上記のコード ラベルの位置を次のように 1 つずつ説明します (ここでのディレクトリのソートは、コードの設計順ではなく、IDEA 開発ツールによって自動的にアルファベット順にソートされることに注意してください)。

ラベル 1 の位置: エッジ層 (エッジ) コードがここに配置されます。「Qunmaicai」アプレットのフロントエンド インターフェースが開発されており、これはフロントエンドとバックエンドの分離プロジェクトであるため、フロントエンド コードを変更するつもりはありません。そのため、追加の「インターフェース適応」があります。 " コードはここで機能します。一般に、この種のコードは「エッジ層」と呼ばれます。エッジ層に配置されるコードは、フロントエンド インターフェイス適応およびサードパーティ システム インターフェイス適応のためのこのコードと似ています。この種のコードは、「フロントエンドのためのバックエンド」(BFF) と呼ばれることもあります。理論的には、この BFF レイヤー コードはフロントエンド チームが開発でき、テクノロジー スタックとして Node.js を選択し、開発には js または ts 言語を使用できます。

ラベル 2 の位置: ここに表示されているのは「ベース層」(ファンデーション) です。DDD のシステム アーキテクチャでは、限定されたコンテキスト (具体的な概念は後で紹介します。ここでは、サブシステムまたはビジネス モジュールの分割に似ていることだけを理解する必要があります) は、「ビジネス サブドメイン」に従って「ビジネス サブドメイン」に分割できます。 「コア層ではなく、ベーシック層」と「ビジネスバリュー層」です。一般的に「ビジネス価値層」は、中核となるビジネスモジュールに相当し、ソフトウェアシステムの競争力の中核となる部分であり、DDDの概念に厳密に従った戦術設計が要求され、テスト駆動開発モデルの採用や、プログラマは仕事に取り掛かり、「ベース層」は通常、ビジネス関連の基本クラス、ツール クラス、コンパニオン システム ドッキングなどの非コア ビジネス モジュールです。 「ベースレイヤー」は「基本リソースレイヤー」ではありません。基本レイヤーは非コアの位置にあるビジネスモジュールを指しますが、基本リソースはデータベースやミドルウェアなどの技術コンポーネントを指します。

ラベル 3 の位置: 複数の境界付きコンテキストがここに表示されます。すべての名前は、xxxcontext などのディレクトリにちなんで付けられます。「ベースレイヤー」と「ビジネスバリューレイヤー」の両方に、複数の「境界付きコンテキスト」が出現します。境界のある各コンテキストは、担当する異なるプロジェクト チームに分離したり、異なるマイクロサービス センターに分離したりすることもできます。繰り返しますが、「境界付きコンテキスト」については、ここでは深く理解する必要はなく、モジュール分割の一種であることを理解するだけで十分です (後で詳しく説明します)。

ラベル 4 の位置: 「ビジネス価値層」のコードがここに表示されます - つまり、ソフトウェア システムの競争力の中核となる必要があるモジュールです。以下には複数の「限定されたコンテキスト」も存在します。

5 番目の位置: DDD 戦術設計ソフトウェアの階層化された「ダイヤモンド アーキテクチャ」の下に、「ドメイン」層のコードがここに配置されます。これはビジネス ロジックのコア コードでもあり、すべての「輻輳」モデル コードです。ここからは、「限定されたコンテキスト」内のコードの構造について説明します。これらのコードの設計方法の詳細については後ほど説明しますが、ここでは「コア ビジネス ロジック」がここに配置されているということだけを理解する必要があります。

番号 6、8 の位置: DDD 戦術設計ソフトウェアの階層化された「ダイヤモンド アーキテクチャ」の下で、「境界付きコンテキスト」がさまざまな外部呼び出し要件を満たすことを可能にし、他の「境界付きコンテキスト」を呼び出したり通信したりする必要がある場合に使用できるようにします。 , このモジュールのビジネスロジックとは関係のないさまざまな外部要因の変化によって引き起こされる、このモジュールのコードロジックの「乱流」については、「ノースバウンドゲートウェイ」と「サウスバウンドゲートウェイ」という概念が導入されました。それぞれの説明は次のとおりです。

ラベル 6 には「Northbound Gateway」のコードが含まれており、ローカルとリモートの 2 つの一般的なディレクトリに分かれています。「ノースバウンド ゲートウェイ」の機能は、境界付きコンテキストがさまざまなアプリケーション サービスを出力できるようにすることです。ローカル ディレクトリの下には、この制限されたコンテキストによって提供される「アプリケーション サービス」があり、これはドメイン内のさまざまな「輻輳モデル」コードをカプセル化する完全なビジネス ロジックです。一方、リモート ディレクトリの下には、ローカル ディレクトリ用のアプリケーション サービスがあります。 RPC 呼び出し、クロスサーバー メッセージ イベント サブスクリプションなどの「リモート呼び出し」を満たすためのコードのカプセル化には、ビジネス ロジックがありません。

ラベル 8 には、「サウスバウンド ゲートウェイ」のコードが含まれており、「ポート」と「アダプター」という 2 つの一般的なディレクトリに分かれています。「サウスバウンド ゲートウェイ」の機能は、この制限されたコンテキストがそれを介して外部リソースを要求できるようにすることです。一般的な 3 種類の外部リソース リクエストには、データ永続層 (リレーショナル データベースまたは非リレーショナル データベース) へのアクセス、他の境界コンテキスト サービスの呼び出し (マイクロサービス アーキテクチャでは、多くの場合 RPC リモート呼び出し)、および他の境界コンテキストへのメッセージのパブリッシュが含まれます。外部リソースに対するこれらのリクエストは、外部リソースの基礎となる技術が異なるため、さまざまな方法で実装される可能性があることは誰もが知っています。基盤となるテクノロジーに対する「ドメイン層」の依存関係を分離するために、ポート層とアダプター層が分離されます。Java 言語実装では、ポート層は実装コードを含まず、メソッド定義のみを含むインターフェースであり、アダプタ層は実装であり、異なる永続層 (異なるリレーショナル データベース oracle/mysql など) で実装されます。異なる nosql データベース (redis/mongodb など)。次に、IoC (依存性反転) 原則に従って、Java では「依存性注入」を使用して、アダプター ディレクトリ内の特定の実装をドメイン層のコードに接続します。

ラベル 7 位置: これは「公開言語」(公開言語、pl) レイヤーです。率直に言うと、「発行言語」とは、「ノースバウンド ゲートウェイ」がサービスを出力するときに、入出力パラメーターの構造定義、イベント メッセージの形式定義、等。境界付けられたコンテキスト内の「ドメイン」層の内部オブジェクト構造を外部に「漏らす」必要がないため、この「リリース言語」層が必要です。

DDD に従ってコード構造設計を説明した後でも、次の質問に答える必要があります。DDD が現実世界に対して「同形マッピング」を実行した後のコード ロジックはどこにあるのでしょうか?

答えは、「ドメイン」レイヤー内です。いわゆる「ノースバウンド ゲートウェイ」、「リリース言語」、および「サウスバウンド ゲートウェイ」レイヤーの機能は、外部リクエストとリクエストされたリソースの基礎となるテクノロジーが「ビジネス ロジック」の「同型性」を「妨害」することを防ぐことだけを目的としています。 「.化」マッピング!

これは、「ドメイン層は DDD の「ビジネス ロジック」マッピングの中核であり、残りはこれらの「コア ビジネス ロジック」の階層的な「パッケージ化」にすぎない、ということと同じです。

したがって、技術的な観点から見ると、ドメイン層の設計方法を理解することが、DDD の戦術設計レベルで最も重要なスキルであることは明らかです。なぜなら、「Northbound Gateway」、「Release Language」、「Southbound Gateway」の 3 つの層のコード開発はすべて従来のルーチンであり、「業務知識」の内容はほとんどなく、ロボットによる実装(つまり自動生産)も可能であるためです。コードツールを介して)。

最後に、繰り返し言及されている DDD の戦略的デザインと戦術的デザインの違いを説明しましょう。

一般に、DDD の戦略設計は、どのような境界コンテキストが存在するかを特定し、境界コンテキストの関係と境界を明確に定義することであり、基本的には完成しています (ただし、エッジ層が必要かどうか、ソフトウェア システムが必要かどうかなど、いくつかの調整作業はまだあります)どのサードパーティ外部システムとインターフェースするかなどですが、あまり考える必要がないため、これらはもはや「設計」とは言えません)。

DDD戦術設計の核心は、「ドメイン」層内の「アグリゲーション」と「ドメインサービス」の設計、つまり「コアビジネスロジック」の設計を完了することです。詳しい遊び方は後ほど紹介します。

この記事は、複数の記事を公開するブログOpenWriteによって公開されています。

OpenAI、ChatGPTを全ユーザーに無料公開 音声 プログラマーがETC残高を改ざんし年間260万元以上を横領 Spring Boot 3.2.0が正式リリース Google従業員が退社後の偉い人を批判 に深く関与Flutter プロジェクトと策定された HTML 関連標準 Microsoft Copilot Web AI が 12 月 1 日に正式にリリースされ、中国 Microsoft のオープンソース ターミナル チャットをサポート Rust Web フレームワーク Rocket が v0.5 をリリース: 非同期、SSE、WebSocket などを サポートRedis は、純粋な C 言語コードを使用して Telegram Bot フレームワークを実装します 。オープンソース プロジェクトのメンテナーであれば、「この種の応答にどこまで耐えることができますか?」という問題に遭遇します。 PHP 8.3 GA
{{名前}}
{{名前}}

おすすめ

転載: my.oschina.net/u/5587102/blog/10143202