spec
base
apps
config
logging
auth
exception.handler
cache
util
common
user
presentation
domain
part
application
domain
layer
validation
validation
infrastructure
datastore
webclient
async
...
service
repository
context
XxxQuery
XxxCommand
library
model
aggregate
...
part
...
exception
component
rule
XxxRule
category
...
filesystem
poi
XxxResponse
XxxController
XxxRequest
(Query)
(Command)
...
XxxRepository
batch
XxxBatch
context
業務ロジックの実装基盤となる横断的関心事の定義
-
各レイヤーを示すアノテーション
-
FWが提供するアノテーションを包含するアノテーションを準備することで定義指定の揺れを解消する
-
例:@TransactionalreadOnly=true) と@Serviceを組み合わせるのではなく @ReadOnlyService を作る
各レイヤーを示すアノテーションFWが提供するアノテーションを包含するアノテーションを準備することで定義指定の揺れを解消する...
-
Bean Validationの検証順序とそれに関わる Interface群
-
!! 独自のValidationは apps.common パッケージに作成する
Bean Validationの検証順序とそれに関わる Interface群!! 独自のValidationは apps.common パッケージに作成する
独自の例外クラス群
-
アプリケーションに使用する定義(いわゆる Config)
アプリケーションに使用する定義(いわゆる Config)
-
ログ出力機能(AOP)
-
FW基本機能で対応できないところをカバー
ログ出力機能(AOP)FW基本機能で対応できないところをカバー
-
認証・認可
-
Spring Securityで使用するロジック
認証・認可Spring Securityで使用するロジック
例外処理をハンドリング
キャッシュ管理ライフサイクル制御
-
機能要件・非機能要件に共通して使用するロジック
-
POIなど外部ライブラリを使用する際の共通機能
-
!! 機能要件における共通関数は common.domainに含め、本パッケージに作成しない
機能要件・非機能要件に共通して使用するロジックPOIなど外部ライブラリを使用する際の共通機能!! 機能要件における共通関数は common.domainに含め、本パッケージに作成しない
-
いわゆる Utilなどの共通部品【ではない】
-
全ての Contextおよびレイヤーからも利用可能とするクラス群
いわゆる Utilなどの共通部品【ではない】全ての Contextおよびレイヤーからも利用可能とするクラス群
-
ビジネスロジックの実現が主たる関心事
-
POJOで実装してライブラリを含めて外部ライブラリの依存を持たない
-
システム全体として依存することを許容したものを除く(例:lombok、Bean Validation(などの検証ライブラリ)、Jackson)
-
副作用のある実装は禁止
ビジネスロジックの実現が主たる関心事POJOで実装してライブラリを含めて外部ライブラリの依存を持たない...
-
Contextを横断するドメイン知識を扱う基本型Model(≒ かなり限定的な利用)
Contextを横断するドメイン知識を扱う基本型Model(≒ かなり限定的な利用)
-
Atomic DesignのAtom/Molecule に相当する Contextを横断して使用するModel
-
複数のContextで使用するModelの基本型となるクラス(料金、名称、ID かつ 業務ロジックを省いた汎化したクラス)
-
通常、業務ロジックはContext毎のModelとして実装するため、想定としては非機能要件で使用するビジネスロジックを実現するクラス群
Atomic DesignのAtom/Molecule に相当する Contextを横断して使用するModel複数のContextで使用するModelの基本型となるクラス(料金、名称、ID かつ 業務ロジックを省いた汎化したクラス)通常、業務ロジックはContext毎のModelとして実装するため、想定としては非機能要件で使用するビジネスロジックを実現するクラス群
-
独自の型となる Bean Validation
-
Bean Validationの標準仕様にないもの(例:@NotBlank)を独自に作成するようなケース
-
Spring Boot を使用する場合は Hibernateが依存関係に含まれているため本パッケージが必要となるケースは限定的?
独自の型となる Bean Validation...
-
操作ユーザーに関する機能
-
認証前、認証後によって異なる振る舞いを業務機能として扱う
-
!! 本ケースだけ別枠にするのは悩ましいところだが独立させた構成にする
操作ユーザーに関する機能認証前、認証後によって異なる振る舞いを業務機能として扱う!! 本ケースだけ別枠にするのは悩ましいところだが独立させた構成にする
-
業務や境界付けられたコンテキスト
-
業務:例)発注・請求・利用者管理
-
境界付けられたコンテキスト:例)トランザクションの集約対象として同一に扱うコンテキスト
-
同一Context内で永続化まで完結した塊として、他Contextへのアクセスはしない
-
境界横断の厳密度は要件次第なので現実的な落とし所を適宜プロジェクトで決定する
-
厳しい:
-
他Contextを利用するときはWebAPI経由にする
-
結果整合性も選択肢
-
緩い:
-
他ContextのServiceを使用する(同一DBストアで同一トランザクションで扱う)
-
他ContextのRepositoryを直接参照はしない(必ずService経由)
業務や境界付けられたコンテキスト業務:例)発注・請求・利用者管理境界付けられたコンテキスト:例)トランザクションの集約対象として同一に扱うコンテキスト同一Context内で永続化まで完結した塊として、他Contextへのアクセスはしない...
-
リソース単位
-
パッケージ名:リソース名
-
集約ルートに相当するリソース単位
-
CRUD
-
ERや業務を元に分割
-
集約ルート配下の詳細情報へのアクセスも含める
-
リソースの情報に更に付加したケースも許容
リソース単位パッケージ名:リソース名集約ルートに相当するリソース単位CRUDERや業務を元に分割集約ルート配下の詳細情報へのアクセスも含めるリソースの情報に更に付加したケースも許容...
-
コンポーネント単位
-
パッケージ名:コンポーネント名
-
クライアント実装に使いやすい単位
-
主に情報参照
コンポーネント単位パッケージ名:コンポーネント名クライアント実装に使いやすい単位主に情報参照...
-
システム外部との境界
-
システムの外部に向けた表現がレイヤーの主たる関心事
-
ビジネスロジックを実行するための必要最低限の事前条件の充足を担保する(できるだけロジックはModelへ集約させる)
システム外部との境界システムの外部に向けた表現がレイヤーの主たる関心事ビジネスロジックを実行するための必要最低限の事前条件の充足を担保する(できるだけロジックはModelへ集約させる)
-
ビジネスプロセス単位
-
パッケージ名:ビジネスプロセス名
-
ビジネスプロセス(業務フロー)単位
-
イベント発行・イベント受信
ビジネスプロセス単位パッケージ名:ビジネスプロセス名ビジネスプロセス(業務フロー)単位イベント発行・イベント受信...
-
WebAPIのエントリーポイント
-
集約ルートとなるリソースだけでなく、詳細情報についてもアクションは可能
-
https://host/resource1/{rootid}/{detailId} というアクションも許容
-
detailIdがシステム内で一意であるのなら https://host/resource1/{detailId} も許容
WebAPIのエントリーポイント...
-
クラスの構成
-
プロパティを java.lang .* (基本型)としたDTO
-
Validationは型(文字列・数値)、必須判定(@NotBlank や@NonNull)に留める
-
ビジネスロジックを持たないシンプルなDTOとすることでクライアントのスタブとして早く公開できるようにする
-
やらないこと
-
ロジックによるデータ検証は Modelで行う
-
永続化された情報を用いたデータ検証は Application層で行う(RepositoryとModelにより検証)
-
RequestでGetter/Setter以外でやること
-
Modelへの変換(toModel)
-
リスクエスト元の構造が複雑でModelへの変換前に追加でValidationをしたい場合は、その検証ロジック
-
ResponseでGetter/Setter以外でやること
-
ModelからResponseへ変換する staticメソッド(createResourse(Model))
-
List構造のResponseへ変換するstaticメソッド(createResponses(List<Model>)
クラスの構成プロパティを java.lang .* (基本型)としたDTOValidationは型(文字列・数値)、必須判定(@NotBlank や@NonNull)に留めるビジネスロジックを持たないシンプルなDTOとすることでクライアントのスタブとして早く公開できるようにする...
-
Presentation層とInfrastructure層の境界
-
タスクの調整がレイヤーの主たる関心事
-
判断や編集を記述しない(ロジックはModelへ集約)
-
importする資産は本システムのパッケージ以外を参照しない
-
横断的関心事は【
dase
】で部品を作成して参照
-
lombokなどのシステム全体で参照するライブラリは利用可能
Presentation層とInfrastructure層の境界...
-
ModelとApplication層のクラスのみで実装する(Presentation層やinfrastructure層の呼び出しは禁止)
-
クラスは動詞単位で作成
-
クラス名の命名:(アクターは)AをBする を英語表記
-
例:SearchEntity、Apply(申請する:Aとなる対象が汎用的な場合は省略可)
-
ServiceからServiceを使用して良い
ModelとApplication層のクラスのみで実装する(Presentation層やinfrastructure層の呼び出しは禁止)...
-
参照系サービス(クエリー)は戻り値の型の単位で複数メソッドを実装して良い
-
事前条件がある場合はクラスを分ける
-
事前条件がある場合、どの検索のものかクラス単位で判別できるようにしたいため
参照系サービス(クエリー)は戻り値の型の単位で複数メソッドを実装して良い事前条件がある場合はクラスを分ける
事前条件がある場合、どの検索のものかクラス単位で判別できるようにしたいため
-
更新系サービス(コマンド)は1アクション1クラス
-
ユースケース記述のように 事前条件、フロー、例外フロー、事後条件 を1クラスにまとめて記述する
-
トランザクション境界
更新系サービス(コマンド)は1アクション1クラスユースケース記述のように 事前条件、フロー、例外フロー、事後条件 を1クラスにまとめて記述するトランザクション境界
-
リソースへの操作を抽象化したインターフェース
-
実際の永続情報の取得および永続化は 本インターフェースの実装(Infrastracture層)で行う
-
RepositoryをDIして利用して良いのは Serviceクラスのみ
リソースへの操作を抽象化したインターフェース実際の永続情報の取得および永続化は 本インターフェースの実装(Infrastracture層)で行うRepositoryをDIして利用して良いのは Serviceクラスのみ
-
リソースを扱うクラス
-
クラス名:ModelRepository(例:EmployeeRepository)
-
戻り値:RootModel やModel
-
リソースへのCRUDが主な役割
-
Model ≒ Resource
-
クラスは集約ルート単位を基本とするが、現実的な落とし所を適宜プロジェクトで決定する
-
厳しい:全ての操作は集約ルートのみ
-
緩い:子リソースの操作用にRepositoryを作成する、もしくは集約ルートのRepositoryに部分操作のメソッドを準備する
-
重複データ検証といったリソースへの問い合わせ参照も本カテゴリーで扱う(その場合、戻り値の型はModelでは無いケースも許容)
リソースを扱うクラスクラス名:ModelRepository(例:EmployeeRepository)戻り値:RootModel やModelリソースへのCRUDが主な役割Model ≒ Resourceクラスは集約ルート単位を基本とするが、現実的な落とし所を適宜プロジェクトで決定する...
-
コンポーネントを扱うクラス
-
クラス名:ComponentNameQuery(例:TemporaryWorkerQuery)
-
戻り値:Component(基本型による構造体に近いクラス)
-
参照(クエリー)のみ
-
Component:クライアントで扱いやすいコンポーネント単位
-
コンポーネント型のクラスを引数とした更新系は禁止
-
DBへの更新はServiceからリソース操作となるRepositoryで行う
コンポーネントを扱うクラスクラス名:ComponentNameQuery(例:TemporaryWorkerQuery)...
-
副作用を扱うクラス
-
クラス名:SideEffectNameCommand(例:OrderDataTransferCommand)
-
戻り値:同期の場合は処理結果、非同期の場合はvoid
-
副作用のトリガー(コマンド)
-
バッチの実行など非同期処理の実行
-
イベントの実行など外部システムへの通知
-
ドメインイベントの実行
副作用を扱うクラスクラス名:SideEffectNameCommand(例:OrderDataTransferCommand)...
-
外部ライブラリの利用を抽象化したインターフェース
-
例:ModelをPOIを用いてExcelに変換する
-
外部ライブラリへの直接的な依存を減らすことでライブラリの更新や置き換えの影響を限定的にする
-
DIして利用して良いのは Serviceクラスのみ
-
Serviceからlibraryを使ってModelへデータ変換をする。移行の処理はModelの操作を通じて編集・判断を行う
-
DTOは可能な限り作らず、Modelを戻り値として返却する
外部ライブラリの利用を抽象化したインターフェース例:ModelをPOIを用いてExcelに変換する外部ライブラリへの直接的な依存を減らすことでライブラリの更新や置き換えの影響を限定的にするDIして利用して良いのは ServiceクラスのみServiceからlibraryを使ってModelへデータ変換をする。移行の処理はModelの操作を通じて編集・判断を行う...
-
クラス名は規定なし(詳細は Infrastructureを参照)
-
利用ライブラリ毎にサブパッケージを作成する
-
副作用のある機能の実装は禁止
-
Repositoryパッケージの使用は禁止
クラス名は規定なし(詳細は Infrastructureを参照)利用ライブラリ毎にサブパッケージを作成する副作用のある機能の実装は禁止...
-
ビジネスロジックの実現が主たる関心事
-
POJOで実装してライブラリを含めて外部ライブラリの依存を持たない
-
システム全体として依存することを許容したものを除く(例:lombok、Bean Validation(などの検証ライブラリ)、Jackson)
-
副作用のある実装は禁止
-
データ入出力から完全独立させる
-
RepositoryはDIだけでなく、引数として使用するのも禁止
-
Modelでは Repositoryの結果を用いてロジックを組み立てる
ビジネスロジックの実現が主たる関心事POJOで実装してライブラリを含めて外部ライブラリの依存を持たない...
-
Atomic DesignのAtom/Molecule に相当する Context内で横断して使用するドメインオブジェクト
-
Context内のModelの基本型となるクラス(料金、名称、ID かつ 業務ロジックを省いた汎化したクラス)
-
ModelとしてModelとして作成し、より責務を集約した部品として独立させたほうが良いと思われる場合にpartに切り出して良い
Atomic DesignのAtom/Molecule に相当する Context内で横断して使用するドメインオブジェクトContext内のModelの基本型となるクラス(料金、名称、ID かつ 業務ロジックを省いた汎化したクラス)ModelとしてModelとして作成し、より責務を集約した部品として独立させたほうが良いと思われる場合にpartに切り出して良い
-
状態をもったクラスとして実装する
-
ビジネスロジックを実装したドメインオブジェクト
-
Modelを介してInfrastractureへ情報を伝えて処理(更新)を行う
状態をもったクラスとして実装するビジネスロジックを実装したドメインオブジェクトModelを介してInfrastractureへ情報を伝えて処理(更新)を行う
-
Modelおよび それらを組み合わせたクラス
-
計算・判断・編集のロジックをオブジェクトに集約する
-
型・桁・有効値などのValidationを実装する
-
同集約内におけるmodel複数modelを用いた判断や編集は、それらを包含したmodel(最上位は集約ルートのドメインオブジェクト)に実装する
-
ただしModelの中の1つの判断や編集とするのではなく、ビジネスにおけるコアとなるロジックの場合は Rule といて独立したオブジェクトにする
Modelおよび それらを組み合わせたクラス計算・判断・編集のロジックをオブジェクトに集約する型・桁・有効値などのValidationを実装する同集約内におけるmodel複数modelを用いた判断や編集は、それらを包含したmodel(最上位は集約ルートのドメインオブジェクト)に実装する...
-
Context内の基本型となるドメインオブジェクト
Context内の基本型となるドメインオブジェクト
集約単位でドメインオブジェクトを まとめる
-
情報参照の戻り値となる型の単位で作成する
-
プロパティを java.lang .* (基本型)としたDTO
-
Presentation のResponseや 永続化層の戻り値DTOとして、そのまま使用しても良い
情報参照の戻り値となる型の単位で作成するプロパティを java.lang .* (基本型)としたDTOPresentation のResponseや 永続化層の戻り値DTOとして、そのまま使用しても良い
-
状態を持たない関数として実装する
-
複数Modelを組み合わせて表現されるビジネスルールを扱う
-
複数のModelを扱うにあたって、どちらのModelにロジックを配置するのか悩ましいときの解決方法
-
ビジネスのコアであり更新頻度が高いロジックとして独立させておきたい場合にも
状態を持たない関数として実装する複数Modelを組み合わせて表現されるビジネスルールを扱う複数のModelを扱うにあたって、どちらのModelにロジックを配置するのか悩ましいときの解決方法ビジネスのコアであり更新頻度が高いロジックとして独立させておきたい場合にも
-
Modelおよび それらを組み合わせた関数
-
状態は持たない
Modelおよび それらを組み合わせた関数状態は持たない
-
データ永続化など技術的に解決すべきことが主な関心事
-
DIPを用いることでModelをPOJOで実装できるようにする
-
パッケージ名は技術要素を表す用語
-
!! Infrastructure層のクラスを直接使用するのは禁止
-
!! 以下の例示に限らず、技術要素に応じたパッケージを適宜追加(説明も絶対的なものではなく指針を示すに留める)
データ永続化など技術的に解決すべきことが主な関心事DIPを用いることでModelをPOJOで実装できるようにするパッケージ名は技術要素を表す用語!! Infrastructure層のクラスを直接使用するのは禁止!! 以下の例示に限らず、技術要素に応じたパッケージを適宜追加(説明も絶対的なものではなく指針を示すに留める)
-
DBアクセスへの操作を行う
-
クラス名は XxxDataStore のように技術要素を示すクラス名にする
-
例:UserRepository -> UserDataStore
-
複数のORMを使うときには、ORMライブラリ名毎のパッケージを作成します
-
例:DataStoreMyBatis、JpaDataStore
DBアクセスへの操作を行うクラス名は XxxDataStore のように技術要素を示すクラス名にする...
-
!! MyBatisの場合
-
Repository / Component 単位でフォルダを作成
-
Repositoryの実装に加えて、Mapperインターフェースや XMLファイルをペアで作成するため
!! MyBatisの場合Repository / Component 単位でフォルダを作成...
-
!! MyBatisの場合
-
資産名
-
Category名:user
-
実装名(RepositoryをImplしたクラス):UserDataStore
-
Mapperインターフェース名:UserMapper
-
MapperXML名:UserMapper.xml
!! MyBatisの場合資産名...
外部WebAPIを実行する(略)
非同期イベントを実行する(略)
ファイルシステムへの操作を行う(略)
-
POI によるデータ変換を行う
-
Model <-> Excel 変換を行う
-
(略)
POI によるデータ変換を行うModel <-> Excel 変換を行う(略)
-
バッチ処理を行うエントリーポイントとなるクラス
-
Serviceと異なり手続き的な実装になることは許容
-
バッチ実行のための全てのクラスを本パッケージに格納する
-
XxxBatch以外のクラスも本パッケージに作成する
バッチ処理を行うエントリーポイントとなるクラスServiceと異なり手続き的な実装になることは許容バッチ実行のための全てのクラスを本パッケージに格納するXxxBatch以外のクラスも本パッケージに作成する
-
バッチ処理を行う
-
DI対象資産はServiceと同じ
-
起動タイミングなどが 通常のServiceと異なることが多いため、Serviceとは別のパッケージとする
バッチ処理を行うDI対象資産はServiceと同じ起動タイミングなどが 通常のServiceと異なることが多いため、Serviceとは別のパッケージとする
src
package
Class
-
クラス格納パッケージの上位にカテゴリーとなるパッケージがあった方が見通しが良くなる場合は適宜追加する
クラス格納パッケージの上位にカテゴリーとなるパッケージがあった方が見通しが良くなる場合は適宜追加する
Viewer does not support full SVG 1.1