『実践ドメイン駆動設計』を読んでWiki風のアプリケーションを作ってみた

最近『実践ドメイン駆動設計』を読んだので、DDD のより深い理解のために小さめのアプリケーション(Wikiのような)を作ってみました。

github.com

特徴

  • Wiki風のWebアプリケーション(Python + Flask + インメモリのモック)
  • DDD + CQRS + イベントソーシングで実装
    • 記事の作成コンテキストと参照コンテキストを分離
    • Markdown記事の作成でイベントが発行され、それにもとづき参照用HTMLページが生成

インストール

下記のようなコマンドをターミナルなどで実行します。

$ git clone https://github.com/signdoubt/ddd-wiki-example.git
$ cd ddd-wiki-example
$ pip install -e .

起動

下記コマンドで起動します。

$ mywiki

起動後 http://localhost:5000/ にアクセスしてWiki風アプリケーションを利用できます。

ユーザ認証・認可

ユーザ認証・認可のモジュールはモック実装となっています。ポリシーは下記です。

  • admin でログインするとMarkdownで記事の作成・参照が可能
    • モック実装のため、ユーザ名さえあっていればログイン可能
  • Bob でログインすると記事を参照可能
  • 未ログイン状態では作成・参照でエラー

処理の流れ

処理の流れは下記のようになっています。

https://raw.githubusercontent.com/signdoubt/ddd-wiki-example/images/interactions.svg?sanitize=true

  1. EditorMarkdownで記事を作成すると Article.Issued イベントが発行される
  2. Article.Issued イベントにもとづき ArticleConverter が HTMLの記事を作成する
  3. Viewer はHTMLの記事を参照できるようになる

構成

パッケージ構成は下記です。

mywiki.application     # アプリケーション層
mywiki.domain.model    # ドメインモデル
mywiki.infrastructure  # インフラ層
mywiki.presentation    # プレゼンテーション層

application パッケージ

  • edit.py

    • Markdown記事の編集まわりのアプリケーションサービスを配置
    • ドメイン層のモジュールを連結(アクセス制御の有効化など含む)
  • view.py

    • HTML記事の参照をおこなうためのアプリケーションサービスを配置
    • ドメイン層のモジュールを連結(アクセス制御の有効化など含む)

domain.model パッケージ

下記のように edit / view / userのコンテキストに分かれています。

edit

記事(Markdown)の編集まわりのコンテキストです。 記事の編集をあらわすのにステートソーシングではなくイベントソーシングを使っています (Article オブジェクトの値を直接変更せずに、 Article に対する変更をイベントとして保持)。

view

記事(HTML)の参照まわりのコンテキストです。 editコンテキストで発行されたドメインイベント( Article.Issued / Article.Discarded など)をサブスクライブして参照用HTMLページを作成します。

user

ユーザ認証、認可まわりのコンテキストです。

  • 認証
    • 認証サービスに応じた認証用データを入力する
      • パスワード認証ならアカウント名+パスワード
  • 認可
    • URIの形式でパーミッションを指定
    • たとえば view://localhost/customers/resellers で表されるパーミッションの意味は:
      • 「viewコンテキストで customers/resellers カテゴリ配下の記事へアクセスできる」ことを意味する

各ユーザがパーミッション(ポリシーの定義)にもとづいて実際にどのようにアクセス制御するか(ポリシーの施行)はそれぞれのコンテキストで実装します。

  • 例えば、viewコンテキストでは mywiki/domain/model/view/security.py でどの権限に対して何ができるかを制御

infrastructure パッケージ

各種モック実装や、Flaskセッションに依存した実装をここに配置しています。

その他

mywiki コマンドを実行すると mywiki/__main__.pymain() メソッドが実行されます。 __main__.py ではDI(各種モックとの連携)をおこない、Flaskアプリケーションとして起動しています。