ユースケース駆動開発実践_詳細設計

ユースケース駆動開発実践ガイドに従うとユースケースモデリング(ユースケース図作成、ドメインモデリング)、概念設計(ロバストネス図の作成、ドメインモデルの更新)と進んだら次は詳細設計(シーケンス図作成、クラス図再生)になります。
前回概念設計まで進んだので、今回は詳細設計に入りたいと思います。ただしシーケンス図は実装に近いのでクラス図の作成のみにしたいと思います。

ドメインモデルを見直す

とりあえず現在のドメインモデルを見直してみます。 f:id:steavevaivai:20190120102452p:plain

これは機能要求の名詞毎の関係性を図示化しただけなので、このまま実装するのにはいくつか不都合が発生します。
それでは、現時点でのドメインモデルで実装する場合に発生しそうな問題点をまとめてみたいと思います。

  • ショッピングカートと注文が似ている
    • 共に品目を集約していますが、購入前のものがショッピングカートに紐付き購入後のものは注文に紐づく様になっている
    • このまま実装しようとした場合、購入時にショッピングカートに紐づく品目を注文に紐づく様に更新が必要になる

とりあえずこの要件定義の内容で特に問題になりそうなのはここな気がします。 それから現在のドメインモデルではクラスの責務がわかりづらいと思うので、クラスが担当すべきだと思う責務もまとめてみたいと思います。

  • クラスの担当すべき責務が明確になっていない
    • 商品の購入状況はどこで管理するか
    • 注文の支払い状況はどこで管理するか
    • カートに入れた商品の金額が変わったことをどう確認するか

本当はもっと問題が出てくると思うのですが、その時点で思いついているものをもとにドメインモデルを更新していきたいと思います。

ショッピングカートと注文の集約について

トランザクションの管理が絡むのですが、集約間のトランザクションをマージするのはデットロックなどが発生する原因なのでバッドケースとされています。そうならないためにも集約間で順番に更新をしたり結果的に整合性が取れていたらワーカスレッドの別の集約の更新を任すといった方法があります。その辺りはここでよくまとめられています。決済周りは時間がかかっても確定した結果を出せるのが重要だと思うのですが、もっと良さそうな方法がないか考えてみます。

ショッピングカートと注文が似ているのですが、これを同じドメインクラスとして扱えないか考えてみます。そのためにはショッピングカートなのか注文なのか区別できる必要があるのですが、その手段として注文の状態として未注文を加えることで解決できるか考えてみます。そうしたら注文の状態として未注文、注文済み、注文キャンセルを持たせてみます。 それから、未注文の場合はショッピングカートと同様の動きをするので商品の追加等の操作が行われたら未注文状態の注文に商品を追加します。

注文の支払い状況はどこで管理するか

現在のドメインモデルの支払い方法の部分に支払い済みかどうか確認するためのメソッドを追加すれば良さそうに思います。ただし支払い方法だと責務が異なると思うので支払い状況に名前を変更したいと思います。

カートに入れた商品の金額が変わったことをどう確認するか

現在の品目のクラスはショッピングカートに追加した時点での金額で、ここでは品目の内容と最新の金額を保持した商品クラスの内容をどう比較するかになります。簡単に思いつく対応方法として品目の集約に商品を加えて品目にカート追加時の金額で計算したものと最新の金額で計算したものを返すなどあるかもしれませんが、この方法だと注文の集約に商品の集約が含まれる形になります。注文の集約から商品は参照するだけにしたらデットロックなどの心配はないと思いますが別の方法で考えたいと思います。

集約間を疎結合に保てる様にするための方法として商品追加時の金額で計算した品目のリストと現在の金額で計算した品目をそれぞれ用意しておいて金額の変更はその差分を見るといった方法があると思います。カート追加時の品目と現在の金額の品目で比較をしやすい様にデータをどう持つかは考える必要がありそうです。

商品の確認画面では商品の名称等の情報があった方が良い気がしますが、ドメインモデルは登録、更新、削除周りで必要そうなものがあれば良い気がするので必要だと感じた時に足せるくらいには考えておきます。参照系と登録、更新、削除を分けるはCQRSの考えでDDDとCQRSで検索したら色々出てくると思います。

それから、商品の詳細情報がドメインモデルから省かれていましたが商品に直接持つには余計な気がするので、商品詳細のクラスを追加して商品に集約させます。

見直した後のドメインモデルは以下の様になりました。 f:id:steavevaivai:20190120174200p:plain

クラス図の作成

ドメインモデルが纏まったら次はクラスに対して属性やメソッドを追加したクラス図を作成します。メソッドまで書くのがベストだと思いますが、とりあえず属性だけ足しておいて以下の様にしたいと思います。 f:id:steavevaivai:20190203123524p:plain 実際必要な属性がこれでは少なかったり、定義した属性は問題(講座の型がStringとか)があると思いますが、ユースケース駆動開発を学ぶのを目的としてこれで進めてみたいと思います。 後、これはクラス図であってデータベースの定義ではないことが注意が必要です。DB上にはパスワードを保持していると思いますが、クラスとして保持する必要が現状なさそうなので省いています。

ER図の作成

ユースケース駆動開発実践ガイドには含まれていなかったと思うのですが、このタイミングでDB上でデータをどう保持するか考えて良いのかと思います。今回のクラス図であれば以下のER図で良いかと思います。 f:id:steavevaivai:20190120212610p:plain クラス図とER図は一致しないと思うのですが、例えばクーポンの使用状況についてクラス図は直接クーポンを注文に集約させていますが、ER図ではused_couponテーブル経由で使用するクーポンを参照する様にしています。クーポン自体は注文の集約上で更新するのはおかしいと思うのでクーポンにorder_idの属性を持たせるのではなく、used_couponにデータをインサートする様にしています。