Skip to main content

🧱 DDD for python

モジュラモノリス + ドメイン駆動設計のカーネル。業務語彙をひとつも持たないことを設計制約にしている。

アーキテクチャ契約の検査は clean-architecture が担う。 このリポジトリは「import できるカーネル」だけを配る。

入っているもの

提供するもの
合成 AppModule / CompositeModule — モジュールの宣言点と合成ルート
集約 DomainEvent / DomainEventPublisher / DomainEventSubscriber / DomainRegistry
ユースケース UnitOfWork / ApplicationServiceLifeCycle / @transactional
outbox StoredEvent / EventStore / EventContextProvider
inbox ConsumedNotification / ConsumedNotificationStore / MessageSubscriber
発行 Notification / NotificationPublisher / PublishedNotificationTracker
アダプタ InMem*(テスト用) / SQLAlchemyUnitOfWork(extras: sqlalchemy
適合テスト ddd4py.common.testing.verify_* — 自分のアダプタ実装が契約を満たすか検証する

導入

uv add ddd4py
uv add "ddd4py[sqlalchemy]"   # SQLAlchemy アダプタも使う場合

配布名は ddd4py、import 名は ddd4py.<module> になる。今あるモジュールは ddd4py.common (業務語彙を持たないカーネル本体)だけで、ddd4py 直下には __version__ しか置かない。 common 以外のモジュールを足しても import 名が衝突しないための空間の取り方。

from ddd4py.common import DomainEvent, UnitOfWork, transactional
from ddd4py.common.port.adapter.persistence.inmem import InMemEventStore

トランザクションと配送の保証

@transactional の内側で publish されたドメインイベントは、集約の更新と同一トランザクションで outbox(StoredEvent)に追記される。ネストした境界は最外に join し、内側で失敗すれば最外まで巻き戻る (部分 commit を許さない)。

受信側は MessageSubscriber._dispatch が listener ごとにトランザクションを開始し、 consumed marker の INSERT(claim-before-process)と listener の副作用を単一トランザクションで commit する (Idempotent Consumer / transactional inbox)。at-least-once の重複は marker の unique 制約が先勝ち 1 つに絞る。

実行文脈というただ 1 つの拡張点

カーネルは「いま誰のリクエストを処理しているか」を知らない。知っているのは、outbox にそれを刻印する ことと、受信時にそれを確立することだけ。

from ddd4py.common import EventContext, EventContextProvider

class TenantContextProvider(EventContextProvider):
    def current(self) -> EventContext:
        tenant = CurrentTenant.get()
        return EventContext(partition_key=tenant.id, payload=tenant.to_dict())

    @contextmanager
    def bind(self, context: EventContext) -> Iterator[None]:
        with CurrentTenant.of(context.payload).bind():
            yield

単一テナントなら NullEventContextProvider のままでよい。

案件ごとの差し替え

CompositeModule は並べた順に DI を登録し、後ろに置いたモジュールが前の束縛を差し替える。 案件固有の実装は継承や上書きではなく、後ろにモジュールを足すことで注入する。

CompositeModule([Core(), Authority(), Tenant(), AcmeOverrides()])

適合テスト

自分のアダプタ実装が契約を満たすかを、利用側の CI で検証する。

from ddd4py.common.testing import verify_consumed_notification_store

def test_postgresql_consumed_notification_store(store):
    verify_consumed_notification_store(store)

開発

task init          # 依存インストール
task test          # テスト
task style:check   # ruff / mypy
task style:check:arch   # clean-architecture による自分自身への契約検査

リリース

PyPI への公開は GitHub Release をトリガーに、Trusted Publishing (OIDC) で自動実行される。 API トークンはリポジトリに置かない。

# 1. pyproject.toml の version を上げて main へマージする
# 2. その version と同じタグで Release を作る (v プレフィックス付き)
gh release create v0.1.0 --generate-notes

タグと pyproject.toml の version が食い違うとワークフローは公開前に落ちる。 __version__pyproject.toml から読むため、バージョンを書き換える箇所は pyproject.toml の 1 行だけ。

ライセンス

MIT

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

ddd4py-0.2.1.tar.gz (60.4 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

ddd4py-0.2.1-py3-none-any.whl (43.8 kB view details)

Uploaded Python 3

File details

Details for the file ddd4py-0.2.1.tar.gz.

File metadata

  • Download URL: ddd4py-0.2.1.tar.gz
  • Upload date:
  • Size: 60.4 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/7.0.0 CPython/3.13.14

File hashes

Hashes for ddd4py-0.2.1.tar.gz
Algorithm Hash digest
SHA256 bbae5234142f0197ded867edac189ffabde920f1c28bfb1e82706eff394634e2
MD5 fd41338de972d7ee600b32fc33c2186a
BLAKE2b-256 1d1695857604bc911c833124c70cb1eabdf3b3c58855d7b2b67a222ac80d5f2b

See more details on using hashes here.

Provenance

The following attestation bundles were made for ddd4py-0.2.1.tar.gz:

Publisher: publish.yml on theindiehacker/ddd4py

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file ddd4py-0.2.1-py3-none-any.whl.

File metadata

  • Download URL: ddd4py-0.2.1-py3-none-any.whl
  • Upload date:
  • Size: 43.8 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/7.0.0 CPython/3.13.14

File hashes

Hashes for ddd4py-0.2.1-py3-none-any.whl
Algorithm Hash digest
SHA256 4640b54a3e64a8d79ccaf5aa375a7c545ac978caf5d35ad6d0b33795e8521fa5
MD5 76da52bcb865279b3c039a57061f7f4e
BLAKE2b-256 5c4f0b1dbfe8f04b6cbc3b3ac0fb0dfd89c145786d5465ef312d2be6ca584a4c

See more details on using hashes here.

Provenance

The following attestation bundles were made for ddd4py-0.2.1-py3-none-any.whl:

Publisher: publish.yml on theindiehacker/ddd4py

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Release history Release notifications | RSS feed

This release

0.2.1 This release

2 files

0.2.0

2 files

0.1.0

2 files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page