My takeaways from domain driven design

Start with creating a ubiquitous language which describes all terms used in the use cases and domain model. These terms must be used by the domain experts and must be used in the source code as well.

In big systems, don’t try to model one big domain model, but try to create a Bounded contexts for the problem you try to solve in you application and only create your domain model for that.

A domain model contain Value Objects, Entities and (root) Aggregates.

Value Objects are immutable and represent a measurement or quantity (e.g. 12 degrees Celsius for a temperature, of 15 days for a duration). These cannot be mutated and can contains methods on them (e.g. to add durations). Since they are immutable, they are easy to test and are thread safe.
Value Objects do not have an ID field, only value fields. They are typically also not stored in a separate database table, but in the same database table as the entity that contains these value objects.
When possible, use these Value Objects in your domain model.

Larger objects can be presented as Entities. Entities do have an ID field and two entities with the same ID are considered as the same entity.
Entities are mutable and may consist out of fields and Value Objects.

Aggregates contains one or more entities. The aggregrate makes sure that the invariants and validations of the entities stays valid. The aggregate may also contain logics about the model.

Domain Services are located in the same module as the domain model and also contain domain logics. They contain services that cannot be places within an aggregate of entity because e.g. they span multiple entities.

Outside of the domain model, it must not be possible for the services to access and modify an entity or value object directly. All acces goes through the aggregate root. That way is it possible to keep the model consistent.

Repositories are used to get aggregates from the persistent storage. Repositories only return either aggregate roots, or for specific needs some DTO’s. It is not possible to directly get or store entities.

When using the ports and adapters architecture, there are application services that convert the domain model to the model required for the external service/storage that is used.
Never is the domain model itself returned to the outside.