Domain Layer

A sphere of knowledge (ontology), influence, or activity. The subject area to which the user applies a program is the domain of the software.

—Wikipedia [1]

Business logic of your application should be place in domain layer with limited outside dependencies and based on simple plain python objects.

Entity

An object that is not defined by its attributes, but rather by a thread of continuity and its identity.

Example: Most airlines distinguish each seat uniquely on every flight. Each seat is an entity in this context. However, Southwest Airlines, EasyJet and Ryanair do not distinguish between every seat; all seats are the same. In this context, a seat is actually a value object.

—Wikipedia [2]

class acd.domain.Entity(**attributes: typing.Any) → None

Base class for application domain entities.

Example:
>>> class Example(Entity, id_attributes=('num', )):
...     num: int
...     text: str
>>> entity = Example(num=1, text='some data')
>>> entity.num
1
>>> entity.text
'some data'
entity_id

Unique id for entity build from selected attributes.

Example:
>>> class Example(Entity, id_attributes=('num', )):
...     num: int
>>> Example(num=1).entity_id
(1,)

Value Object

An object that contains attributes but has no conceptual identity. They should be treated as immutable.

Example: When people exchange business cards, they generally do not distinguish between each unique card; they only are concerned about the information printed on the card. In this context, business cards are value objects.

—Wikipedia [2]

class acd.domain.ValueObject(**attributes: typing.Any) → None

Base class for value objects based on annotation.

Domain Service

When an operation does not conceptually belong to any object. Following the natural contours of the problem, you can implement these operations in services.

—Wikipedia [2]

class acd.domain.DomainService

Base class for logic services in domain module.

  • Every service should inherit from this interface so we can track dependencies.
  • All dependencies should be passed in constructor and service should do one thing implemented in __call__ method.
Example:
>>> from typing import Callable
>>> class AdderService(DomainService):
...     def __init__(self, adder: Callable[[int, int], int]) -> None:
...         self._adder = adder
...
...     def __call__(self, first: int, second: int) -> int:
...       return self._adder(first, second)
...
>>> add = AdderService(int.__add__)
>>> add(1, 3)
4

Domain Event

A domain object that defines an event (something that happens). A domain event is an event that domain experts care about.

—Wikipedia [2]

class acd.domain.DomainEvent(**attributes: typing.Any) → None

Base class for domain events.

[1]DDD Concepts Wikipedia
[2](1, 2, 3, 4) Building Blocks Wikipedia