Skip to content

Instantly share code, notes, and snippets.

@Yengas
Last active August 23, 2023 21:05
Show Gist options
  • Save Yengas/26400312a330576dbada8f9e8caf0d8f to your computer and use it in GitHub Desktop.
Save Yengas/26400312a330576dbada8f9e8caf0d8f to your computer and use it in GitHub Desktop.
Examples in Implementing Domain Driven Design

Chapter 1 - Getting Started with DDD

BacklogItem is modeled two different ways. First one is the anemic model where we only have getters and setters on the BacklogItem. Making it pretty much the "domain" version of the database model we have in our minds.

The second one is a richer BacklogItem that has logic to uncommit / commit to a new sprint. E.g. All of the logics related to "committing to a sprint" are put into the BacklogItem's #commitTo. Creating high cohesion. BacklogItem emits an event after comitting to the sprint. This way other actors in the same/different bounded context can be notified of the changes.

Private/Protected methods + different #uncommitFrom are highlighted to show how they are helpful to implement #commitTo and other usecases.

Chapter 2 - Domains, Subdomains, and Bounded Contexts

"When a user is browsing the Catalog, Customer means one thing, but when a user is placing an Order, it means something else." Each domain expert things of something else.

Database schema should ideally live in the bounded context. BacklogItem may have Value Objects on it that may get persisted to the database.

Bounded Context may be divided to architectural reponsibilities using modules such as;

com.mycompany.optimalpurchasing.presentation
com.mycompany.optimalpurchasing.application
com.mycompany.optimalpurchasing.domain.model
com.mycompany.optimalpurchasing.infrastructure

Forum Entity designed in somewhat DDD way is shown. Collabration Context is introduced. Forum can start a discussion. Acting as a Factory for the Discussion Entity. However the user is checked to see if it has a StartDiscussion permission. Here two things are highlighted.

  • User entity is used and the "authorName" is derived using .person().name().asFormattedName(). Instead Author Value Object can be introduced and this formatting can be done when constructing that Value Object.
  • User entity has no place in the Collabration Context, Context Mapping can be applied to create Author instead.

This way code is cleaner and the permission strategy can be changed without affecting Collabration Context much. Identity and Access Context is introduced.

Chapter 3 - Context Maps

Identity and Access Context has an Open Host Service and a Publish Language. Collabration Context is connected to it using a Anti Corruption Layer. In this scenario the Collabration Context is the downstream and the Identity and Access Context is the Upstream. Remember shit flows downstream!

Upstream models have influence on the downstream where as downstream dependencies may or may not affect the Upstreams change plans / SLA requirements. This is subject to the relationship between these Contexts(Conformist, Partnership etc.).

In this chapter we see three different ways of mapping contexts.

  • Mapping between Collabration Context (Downstream) and Identity and Access Context (Upstream). Here the requirement is to get User and Role information from the Identity Context to check and see if the user has necessary authorization to moderate discussions. The Collabration Context should not know anything about Users and Roles. It only knows about Moderator value objects.
    • An implementation of UserRoleAdapter is created to make get requests to the User entity in the Identity Context. This can be an endpoint like "/tenants/:tenantId/users/:username/inRole/:role". When coding this adapter you can create classes with only the attributes that you are interested in to do the Contet Mapping / Value Object translation.
    • CollaboratorTranslator#toCollaborator is created to translate the User entity in Identity Context to the Moderator value object in the Collabration Context. This Translator can be used by the UserRoleAdapter.
    • CollaboratorService uses the UserRoleAdapter to check if the user is a moderator. The UserRoleAdapter can be an interface. This way the CollaboratorService in Collabration Context won't have a reference to the implementation of it. The implementation can live in a separate module as an adapter.
  • Mapping between Agile Project Management Context (Downstream) and Identity and Access Context (Upstream). Here the requirement is similar to previous scenario. We need to check if the users in our system are a Product Manager or a developer or someone else? Differently from the scenario, to keep the Agile Context autonomous and decoupled from the Identity Context. We setup a periodic sync of the Identity Context in our Agile Context, after translating the User and Role entities to what they will be in the Agile Context.
    • An implementation of MemberAdapter is created to retrieve users from the Identity Context. This adapter behaves like the previous example's UserRoleAdapter. And makes a get request to the Identity Context, then translates the User and Roles to "Member" in the Agile Context. Using a MemberTranslator#toMember.
    • MemberService uses the MemberAdapter to update Member entities in the Agile Context. A method called syncronizeMembers is put on the MemberService that triggers the process of going to the Identity Context to getting changes in that context that we have not processed, and updating the Member Entities accordingly.
  • Mapping between Agile Project Management Context (Downstream) and Identity and Access Context (Upstream). Here the requirement is to create a Product in the Agile Context. And make sure we have a Discussion for it in an async way.
    • We need to model Discussion availability on the Product in a verbose way. When creating the product we may have selected "No Discussion" option. Or the Discussion may not be ready yet. We should be able to distinguish between these situations.
    • DiscussionAvailability enum can be created to model these different states.
    • A ValueObject called Discussion in the Agile Context may be created. That holds the DiscussionAvailability status and a DiscussionDescriptor that may be empty, according to our state.
    • CollaborationAdapter, DiscussionTranslator, DiscussionService are created. And the DiscussionService may attachDiscussion to the Product after receiving an event, perodiocally etc.

Chapter 4 - Architecture

Always choose architecture according to the business requirements, not by technical dogma. SaasOvation teams successful history is given as an example.

  • They started with a Layered Architecture because the initial product was a Desktop application with a central database.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment