Giter VIP home page Giter VIP logo

iddd-chat-room's People

Contributors

mikekawasaki avatar

Watchers

 avatar

iddd-chat-room's Issues

Specification Class

Path

core/domain/<aggregate_name>/<aggregate_name>Specification
(core/domain/<aggregate_name>/specification/<usecase_name>Specification)

Responsibility

domain objectに記述できない仕様(repositoryが絡む処理や集約を跨ぐ処理など)を記述する。
各ユースケースを実現する際に必要な使用が一目でわかるようにする。

全メソッドはBoolen型を返し、アプリケーション層でDIして使用する。
(逆にアプリケーション層の責務はエンティティを生成してリポジトリで保存・削除することに集中させる。その際に条件が必要な場合は全てSpecification Classを呼び出すだけにする。)

記述する仕様の例

「ルーム」が作成されてから1時間以上経過していて、最後に送信された「ルーム」内の「メッセージ」が1時間以上前のものであれば、どの「ルーム」でも削除することができる。

  • ルーム削除が目的なのでroomSpecificaitonに記述する。
  • roomRepositoryを呼び出してルームに関する条件を記述する。
  • messageRepositoryを呼び出してメッセージに関する条件を記述する。


Specificationクラスを採用するのはEntityで工夫してうまくいかなかった場合の最終手段。

ルーム削除条件整理

ルームを削除するには、

  1. ルームの作成者の場合
  2. ルームの作成者を問わない場合
    の2通りが存在する。

1. 「ルーム」の作成者であれば、「メッセージ」が1件もない時のみその「ルーム」をいつでも削除することができる。

「ルーム」の作成者であれば

この条件はルームの集約ルートで判断する。
isCreatedByメソッド

「メッセージ」が1件もない時

repository使う。
specificationクラスでhasMessageメソッドで定義。

2. 「ルーム」が作成されてから1時間以上経過していて、最後に送信された「ルーム」内の「メッセージ」が1時間以上前のものであれば、どの「ルーム」でも削除することができる。(作成者は問わない)

「ルーム」が作成されてから1時間以上経過していて、

この条件はルームの集約ルートで判断する。
meetsCreatedDateTimeRequirementToDeleteメソッド

最後に送信された「ルーム」内の「メッセージ」

ルーム内に最後に送信されたメッセージを取得するには、repositoryを使用するため、この取得処理はアプリケーション層(specificationクラス)で行う。

「メッセージ」が1時間以上前のものであれば、

この条件はメッセージの集約ルートで判断する。
meetsSentDateTimeRequirementToDeleteRoomメソッド

Domain Object Diagram v3 20200925225743

変更点

ルームID

ルーム自体がメッセージを持つ必要はないのでは?
→メッセージがルームIDを持てばいい。

ターゲットメッセージID

返信したメッセージIDがわかればスレッド内のメッセージをリストとして保存しなくても良い。
ドメインレベルで普通のメッセージとリプライメッセージを区別するのではなく、アプリケーションレベルで利用時に区別するようにした。
→今後の考え方として、リスト形式で膨大な数のエンティティを持つような構成になったら疑った方がいいかも。

送信者・送信日時

単純に足りてなかったので追加。
送信日時は、DB側のcreated_atをアプリケーションで使うのはDBと密結合になってよろしくないと思ったのでVOを追加してアプリケーション側で早期生成した値を使うようにした。
ただ、DB側にもレコード管理としてcreated_atカラムは作成する予定。つまりレコードはエンティティの生成日時とレコードの作成日時を同時に管理する状態。この判断はどうなのか?

ルーム名・作成日時

単純に足りてなかったので追加。
作成日時については同上。

メッセージ形式の仕様

テキスト(1-1000文字必須入力)+任意で画像(1枚まで)
という仕様に変更した。

返信メッセージの仕様

どのメッセージに対しても合計1000件までメッセージ返信をすることできる。

どのメッセージに対しても合計5件までメッセージ返信をすることできる。
(1000件だと再現性がないため、5件として実際アプリケーション上で仕様が反映されていることを確認できるようにした)

問題点

連続送信されるとスレッド数が1000件を超えても返信できてしまう。

スレッド内のメッセージ数(上記を満たすだけなら厳密にはメッセージ数を持つ必要はない。返信できるかどうかのステータス)をメッセージに持たせたい。
→実現するにはメッセージの送信を監視するようなイベント駆動的な形にする必要がある。

  1. スレッド内にメッセージが送信される
  2. イベント発火
  3. 送信されたメッセージのターゲットメッセージのエンティティを更新


とりあえずいったん無視。細かいところが形ができたら修正。

ファイルを扱うための集約が不足している

必要になったタイミングでfile集約を追加

認証用の集約が不足している

必要になったタイミングでauthentication集約を追加

DBでの最大文字列1000の定義方法

varchar型は文字コードがutf8mb4は最大文字数が191。
text型は文字数制限できないはず。
とりあえずtext型にして、DB格納前にバリデーションかければいい?
(データベース側で100%保証できないのが不安だが、フロント・バックエンドでにリクエスト時のバリデーションとVOでそれぞれバリデーションをかければシステム的には変な値は入らないと言えるはず。)

ルーム作成の権限(メッセージを1つ送信した場合に付与される)を考慮していない。

→UserAccount Aggregateに権限用のVOを追加。
これを用いてルーム作成のapplicationServiceをAOPで管理する。

rowMessageとreplyMessageの集約を分ける必要がある。

将来の変更可能性を考えたときに、生のメッセージと返信は仕様が大きく異なる可能性があるため。

actors

Screen Shot 2020-09-25 at 230940

usecases per actor

Screen Shot 2020-09-30 at 144130

domain objects

Screen Shot 2020-10-10 at 220644

specification

Screen Shot 2020-09-30 at 143922

Domain Object Diagram v2 20200925105125

問題点

メッセージの集約がメモリ的に膨れ上がる構成になってしまっている。

actors

Screen Shot 2020-09-25 at 104945

usecases per actor

Screen Shot 2020-09-25 at 105014

domain objects

Screen Shot 2020-09-25 at 105034

specification

Screen Shot 2020-09-25 at 105052

Domain Object Diagram v4 20201012091723

変更点

メッセージとリプライで集約を分けた

理由

将来の変更性を見据えて。
現時点でメッセージとリプライは仕様が多少異なっている。(リプライにリプライはできない点)
この仕様のズレはサービスの拡張ととともに大きくなっていく可能性が高い。
したがって、現時点で仕様が異なっているのであれば、将来の変更可能性を見据えて分割するのが自然と判断した。

共通部分は抽象クラスBaseMassageクラスで定義して継承する。

ルーム削除時にルームにあるメッセージを削除するようにした

理由

単純に忘れていたため。
ルーム内にあるメッセージはルームが削除後は不要とし物理削除する。

問題点

actors

Screen Shot 2020-09-25 at 230940

usecases per actor

Screen Shot 2020-09-30 at 144130

domain objects

Screen Shot 2020-10-10 at 220644

specification

Screen Shot 2020-09-30 at 143922

AuthN, AuthZ

Room Aggregate

「ルーム」の作成者であれば、作成後にその「ルーム」の「ルームレベル」を下げることができる。

「ルーム」の作成者であれば、「メッセージ」が1件もない時のみその「ルーム」をいつでも削除することができる。

ユーザーは初期状態ではルームを一つしか作れない。メッセージを一つでも送信すると無制限に作成できるようになる

とりあえずアプリケーション層で例外出すようにしている。ユーザーにロール持たせて管理したい。

Message Aggregate

Product Overview

Overview

「参加者」同士が「ルーム」内で「メッセージ」のやりとりができるSPA。

Concepts

「参加者」

本サービスを利用するアクター(人物)。

「参加者アカウント」

参加者がサービスを利用するためのアカウント。名前とアイコンが設定できる。(ただし、メールアドレスやパスワードはない。)

「ルーム」

参加者が「メッセージ」のやりとりができる場所。

「ルームレベル」

「ルーム」を閲覧できる参加者の閾値(メッセージ送信回数)を示すもの。
例えば、「ルーム」の「ルームレベル」が10の場合、その「ルーム」の内容は10回以上「メッセージ」を送信した参加者のみが閲覧でき、「メッセージ」を送信できる。

「メッセージ」

参加者が「ルーム」に対して送信するもの。形式にはテキストと画像がある。

「スレッド」

ある「メッセージ」に対して別のメッセージを返信できる場所、またそのメッセージのまとまり。

Specification

参加者アカウント

  • 未ログインユーザーは「参加者アカウント」を作成することができる。
  • 入力項目は名前(1~16文字)とアイコン(画像)で両方必須。
  • メールアドレスやパスワードは必要なく、Cookieにランダム文字列(参加者アカウントID)を設定して利用中のアカウントを判別するようにすること。
  • 参加者としてこのサービスを利用する場合は、この「参加者アカウント」がなければいけない。

ルーム

  • 参加者は「ルーム」を作ることができる。
  • 入力項目はルーム名(1~16文字)と「ルームレベル」で両方必須。
  • 参加者は最初「ルーム」を1つしか作成することができないが、「メッセージ」を1回でも送信すると、無制限に作成できるようになる。
  • 参加者はその「ルーム」が作成されてから1時間以上経過していて、最後に送信された「ルーム」内の「メッセージ」が1時間以上前のものであれば、どの「ルーム」でも削除することができる。
  • 参加者は「ルーム」の作成者であれば、「メッセージ」が1件もない時のみその「ルーム」をいつでも削除することができる。

ルームレベル

  • 「ルームレベル」には0〜100の整数を設定することができる。
  • 参加者は「ルーム」の作成者であれば、作成後にその「ルーム」の「ルームレベル」を下げることはできるが、上げることはできない。
  • 参加者は「ルームレベル」の値にメッセージ送信数が満たない参加者はその「ルーム」を閲覧することができず、「ルーム」に「メッセージ」を送信できない。(ただし、その「ルーム」の作成者のみ例外で「ルームレベル」に関係なく閲覧・送信ができる。)
  • メッセージを削除することで、メッセージを送信済みのルームが閲覧・送信できない基準になった際は、閲覧・送信はできないが既にそのルームに送信されたメッセージは残る。

メッセージ

  • 参加者は「ルーム」の中で「メッセージ」を送ることができ、その形式にはテキストまたは画像がある。(文字数は1~1000文字、画像は任意で1枚)
  • 参加者は自分で送信した「メッセージ」を最初に送信してから15分以内なら編集することができる。(テキストのみ編集可。画像は削除不可。)
  • 参加者は自分で送信した「メッセージ」を「スレッド」に「メッセージ」が1つもなければ削除することができる。
  • 参加者は「ルーム」内の「メッセージ」を最新のものから見ていくことができる。

スレッド

  • 参加者はどのメッセージに対しても「スレッド」に合計5件までメッセージを送信することができる。
  • スレッド内の「メッセージ」の形式は普通の「メッセージ」と変わらないが、「スレッド」にある「メッセージ」にさらに「スレッド」を立てることはできない。

Add Specification to Room Aggregate

DeleteRoom UseCase

「ルーム」の作成者であれば、「メッセージ」が1件もない時のみその「ルーム」をいつでも削除することができる。

  • 「ルーム」の作成者であれば
    →これはAOPで管理する?
  • 「メッセージ」が1件もない時

「ルーム」が作成されてから1時間以上経過していて、最後に送信された「ルーム」内の「メッセージ」が1時間以上前のものであれば、どの「ルーム」でも削除することができる。(作成者は問わない)

  • 「ルーム」が作成されてから1時間以上経過していて
  • 最後に送信された「ルーム」内の「メッセージ」が1時間以上前のものであれば

CreateMessage UseCase

「ルームレベル」の値にメッセージ送信数が満たない参加者はその「ルーム」を閲覧することができず、「ルーム」に「メッセージ」を送信できない。(ただし、その「ルーム」の作成者のみ例外で「ルームレベル」に関係なく閲覧・送信ができる。)

  • 「ルームレベル」の値にメッセージ送信数が満たない参加者はその「ルーム」に「メッセージ」を送信できない。

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.