Many to many relationship in ddd - domain-driven-design

Is Many to many relationship should always avoided in ddd.
Suppose, I have two entities Publisher and SocialAccount.
1 publisher can register itself to 1 or many socialaccount.
For eg - : Joh is registering himself to twitter, FB.
1 SocialAccount can be associated with many publishers.
But according to business rule, Publisher should register itself to SocialAccount(s), but SocialAccount cannot register publisher, I mean there is no method.
How do i convert this many to many into one to many
Do in Publisher class.
List<SocialAccount> SocialAccounts.
and same in SocialAccount class. or do i use query to get how many publisher are register to one account.

You should do something like
List<int> SocialAccountIds { get { ... } }
... in your Publisher.
PS. I prefer to use
List<IdRef<SocialAccount>> SocialAccounts { get { ... } }
Where IdRef is basically a type-safe wrapper around int.

Related

Aggregate as a service

Assume scenario where the service requires some global configuration to handle some request.
For example when user wants to do something it requires some global configuration to check whether the user is permited todo so.
I realize that in axon i can have command handlers that could handle commands without specified target aggregate so the handling part isn't a problem.
Problem is where i would like to have persistent storage on top of that and some invariants when trying to change the configuration. The whole idea of the configuration is that it should be consistent like aggregate in axon.
ConfigService {
#Inject
configRepository;
#Inject
eventGateway;
#CommandHandler
handle(changeConfig){
let current = configRepository.loadCurrent;
//some checks
//persist here?
eventGateway.send(confgChanged)
}
#EventHandler
on(configChanged){
//or persist here?
configRepository.saveCurrent(configChanged.data)
}
}
If I do persistance on the command handler I think I shouldn't use event handler because it would save it twice. But then when i somehow lose the config repository data i can rebuild it based on the events.
Im not sure what im missing here in the understanding of the DDD concepts, to put it simply i would like to know where to put command handler for something that is neither an aggregate nor entity.
Maybe i should create command handler that calls the Config service instead making config service the command handler.
Are you using Axon without event sourcing here?
In Axon framework it is generally good practice only to change the state of an aggregate with events. If you are going to mix state or configuration loaded from a repository with state from the event store, how will you be able to guarantee that when you replay the same events, the resulting state will be the same? The next time the aggregate is loaded, there may be different state in your configRepository, resulting in a different state and different behavior of your aggregate.
Why is this bad? Well, those same events may have been handled by eventprocessors, they may have filled query tables, they may have sent messages to other systems or done other work based on the state the system had at the time. You will have a disagreement between your query database and your aggregate.
A concrete example: Imagine your aggregate processed a command to switch an email service on. The aggregate did this by applying an EmailServiceEnabledEvent and changing its own state to 'boolean emailEnabled = true'. After a while, the aggregate gets unloaded from memory. Now you change that configurationRepository to disable switching the email service on. When the aggregate is loaded again, events from the event store are applied, but this time it loads the configuration from your repository that says it shouldn't switch the email service on. The 'boolean emailEnabled' state is left false. You send a disable email service command to the aggregate, but the command handler in the aggregate thinks the email is already disabled, and doesn't apply an EmailServiceDisabledEvent. The email service is left on.
In short: I would recommend using commands to change the configuration of your aggregate.
It seems to me that you your global configuration is either a specification or a set of rules like in a rules engine.
Unlike the patterns described in GOF book, in DDD, some building blocks/patterns are more generic and can apply to different types of object that you have.
For example an Entity is something that has a life-cycle and has an identity. The stages in the life-cycle usually are: created, persisted, reconstructed from storage, modified and then it's life cycle ends by being deleted, archived, completed etc.
A Value Object is something that doesn't have identity, (most of the time) is immutable, two instances can be compared by the equality of their properties. Value Object represent important concepts in our domains like: Money in system that deal with accounting, banking etc., Vector3 and Matrix3 in systems that do mathematical calculations and simulations like modeling systems (3dsMax, Maya), video games etc. They contain important behavior.
So everything that you need to track and has identity can be an Entity.
You can have a Specification that is an entity, a Rule that is an entity, an Event can also be an entity if it has a unique ID assigned to it. In this case you can treat them just like any another entity. You can form aggregates, have repositories and services and use EventSourcing if necessary.
On the other hand a Specification, a Rule, an Event or a Command can also be Value Objects.
Specifications and Rules can also be Domain Services.
One important thing here is also the Bounded Context. The system that updates these rules is probably in a different Bounded context than the system that applies there rules. It's also possible that this isn't the case.
Here's an example.
Let's have a system, where a Customer can buy stuff. This sytem will also have Discounts on Orders that have specific Rules.
Let's say we have rule that says that: if a Customer has made an Order with more than 5 LineItems he get's a discount. If that Order has a total price of some amount (say 1000$) he gets discount.
The percentage of the discounts can be changed by the Sales team. The Sales system has OrderDicountPolicy aggregates that it can modify. On the other hand the Ordering system only reads OrderDicountPolicy aggregates and won't be able to modify them as this is the responsibility of the Sales team.
The Sales system and the Ordering system can be part of two separate Bounded Contexts: Sales and Orders. The Orders Bounded Context depends on Sales Bounded Context.
Note: I'll skip the most implementation details and add only the relevant things to shorten and simplify this example. If it's intent is not clear, I'll edit and add more details. UUID, DiscountPercentage and Money are value objects that I'll skip.
public interface OrderDiscountPolicy {
public UUID getID();
public DiscountPercentage getDiscountPercentage();
public void changeDiscountPercentage(DiscountPercentage percentage);
public bool canApplyDiscount(Order order);
}
public class LineItemsCountOrderDiscountPolicy implements OrderDiscountPolicy {
public int getLineItemsCount() { }
public void changeLineItemsCount(int count) { }
public bool canApplyDiscount(Order order) {
return order.getLineItemsCount() > this.getLineItemsCount();
}
// other stuff from interface implementation
}
public class PriceThresholdOrderDiscountPolicy implements OrderDiscountPolicy {
public Money getPriceThreshold() { }
public void changePriceThreshold(Money threshold) { }
public bool canApplyDiscount(Order order) {
return order.getTotalPriceWithoutDiscount() > this.getPriceThreshold();
}
// other stuff from interface implementation
}
public class LineItem {
public UUID getOrderID() { }
public UUID getProductID() { }
public Quantity getQuantity { }
public Money getProductPrice() { }
public Money getTotalPrice() {
return getProductPrice().multiply(getQuantity());
}
}
public enum OrderStatus { Pending, Placed, Approced, Rejected, Shipped, Finalized }
public class Order {
private UUID mID;
private OrderStatus mStatus;
private List<LineItem> mLineItems;
private DscountPercentage mDiscountPercentage;
public UUID getID() { }
public OrderStatus getStatus() { }
public DscountPercentage getDiscountPercentage() { };
public Money getTotalPriceWithoutDiscount() {
// return sum of all line items
}
public Money getTotalPrice() {
// return sum of all line items + discount percentage
}
public void changeStatus(OrderStatus newStatus) { }
public List<LineItem> getLineItems() {
return Collections.unmodifiableList(mLineItems);
}
public LineItem addLineItem(UUID productID, Quantity quantity, Money price) {
LineItem item = new LineItem(this.getID(), productID, quantity, price);
mLineItems.add(item);
return item;
}
public void applyDiscount(DiscountPercentage discountPercentage) {
mDiscountPercentage = discountPercentage;
}
}
public class PlaceOrderCommandHandler {
public void handle(PlaceOrderCommand cmd) {
Order order = mOrderRepository.getByID(cmd.getOrderID());
List<OrderDiscountPolicy> discountPolicies =
mOrderDiscountPolicyRepository.getAll();
for (OrderDiscountPolicy policy : discountPolicies) {
if (policy.canApplyDiscount(order)) {
order.applyDiscount(policy.getDiscountPercentage());
}
}
order.changeStatus(OrderStatus.Placed);
mOrderRepository.save(order);
}
}
public class ChangeOrderDiscountPolicyPercentageHandler {
public void handle(ChangeOrderDiscountPolicyPercentage cmd) {
OrderDiscountPolicy policy =
mOrderDiscountRepository.getByID(cmd.getPolicyID());
policy.changePercentage(cmd.getDiscountPercentage());
mOrderDiscountRepository.save(policy);
}
}
You can use EventSourcing if you think that it's appropriate for some aggregates. The DDD book has a chapter on global rules and specifications.
Let's take a look what whould we do in the case of a distributed application for example using microservices.
Let's say we have 2 services: OrdersService and OrdersDiscountService.
There are couple of ways to implement this operation. We can use:
Choreography with Events
Orchestration with explicit Saga or a Process Manager
Here's how we can do it if we use Choreography with Events.
CreateOrderCommand -> OrdersService -> OrderCreatedEvent
OrderCreatedEvent -> OrdersDiscountService -> OrderDiscountAvailableEvent or OrderDiscountNotAvailableEvent
OrderDiscountAvailableEvent or OrderDiscountNotAvailableEvent -> OrdersService -> OrderPlacedEvent
In this example to place the order OrdersService will wait for OrderDiscountNotAvailableEvent or OrderDiscountNotAvailableEvent so it can apply a discount before changing the status of the order to OrderPlaced.
We can also use an explicit Saga to do Orchestration between services.
This Saga will containt the sequence of steps for the process so it can execute it.
PlaceOrderCommand -> Saga
Saga asks OrdersDiscountService to see if a discount is available for that Order.
If discount is available, Saga calls OrdersService to apply a discount
Saga calls OrdersService to set the status of the Order to OrderPlaced
Note: Steps 3 and 4 can be combined
This raises the question: *"How OrdersDiscountService get's all the necessary information for the Order to calculate discounts?"*
This can either be achieved by adding all of the information of the order in the Event that this service will receive or by having OrdersDiscountService call OrdersService to get the information.
Here's a Great video from Martin Folwer on Event Driven Architectures that discusses these approaches.
The advantage of Orchestration with a Saga is that the exact process is explicitly defined in the Saga and can be found, understood and debugged.
Having implicit processes like in the case of the Choreography with Events can be harder to understand, debug and maintain.
The downside of having Sagas is that we do define more things.
Personally, I tend to go for the explicit Saga especially for complex processes, but most of the systems I work and see use both approaches.
Here are some additional resources:
https://blog.couchbase.com/saga-pattern-implement-business-transactions-using-microservices-part/
https://blog.couchbase.com/saga-pattern-implement-business-transactions-using-microservices-part-2/
https://microservices.io/patterns/data/saga.html
The LMAX Architecture is very interesting read. It's not distributed system, but is event driven and records both incomming events/commands and outgoint events. It's an interesting way to capture everything that happend in a system or a service.

DDD: Create one aggregate root within another AR

Suppose that I have 2 aggregate roots (AR) in my domain and invoking some method on the 1st requires access to an instance of the 2nd. In DDD how and where should retrieval and creation of the 2nd AR happen?
Here's a contrived example TravelerEntity that needs access to a SuitcaseEntity. I'm looking for an answer that doesn't pollute the domain layer with infrastructure code.
public class TravelerEntity {
// null if traveler has no suitcase yet.
private String suitcaseId = ...;
...
// Returns an empty suitcase ready for packing. Caller
public SuitcaseEntity startTrip(SuitcaseRepository repo) {
SuitcaseEntity suitcase;
if (suitcaseId == null) {
suitcase = new SuitcaseFactory().create();
suitcase = repo.save(suitcase);
suitcaseId = suitcase.getId();
} else {
suitcase = repo.findOne(suitcaseId);
}
suitcase.emptyContents();
return suitcase;
}
}
An application layer service handling the start trip request would get the appropriate SuitcaseRepository implementation via DI, get the TravelerEntity via a TravelerRepository implementation and call its startTrip() method.
The only alternative I thought of was to move SuitcaseEntity management to a domain service, but I don't want to create the suitcase before starting the trip, and I don't want to end up with an anemic TravelerEntity.
I'm a little uncertain about one AR creating and saving another AR. Is this OK since the repo and factory encapsulate specifics about the 2nd AR? Is there a danger I'm missing? Is there a better alternative?
I'm new enough to DDD to question my thinking on this. And the other questions I found about ARs seem to focus on identifying them properly, not on managing their lifecycles in relation to one another.
Ideally TravelerEntity wouldn't manipulate a SuitcaseRepository because it shouldn't know about an external thing where suitcases are stored, only about its own internals. Instead, it could new up a SuitCase and add it to its internal [list of] suitcases. If you wanted that to work with ORMs without specifically adding the suitcase to the repository though, you'd have to store the whole suitcase object in TravelerEntity.suitcaseList and not just its ID, which conflicts with the "store references to other AR's as IDs" best practice.
Moreover, TravelerEntity.startTrip() returning a suitcase seems a bit artificial and unexplicit and you'll be in trouble if you need to return other entities created by startTrip(). So a good solution could be to have TravelerEntity emit a SuitcaseAdded event with the suitcase data in it once it has added the suitcase to its list. An application service could subscribe to the event, add the suitcase to SuitcaseRepository and commit the transaction, effectively saving both the new suitcase and the modified traveler to the database.
Alternatively, you could place startTrip() in a Domain Service instead of an Entity. There it might be more legit to use SuitcaseRepository since a domain service is allowed know about multiple domain entities and the overall domain process going on.
First of all persistence is not domain's job so i would get rid of all the repositories from the domain models and create a service that would use them.
Second of all you should rethink your design. Why a StartTrip method of a Traveller should return a SuitCase?
A Traveller either has or hasn't a suitcase. Once you have retrieved the Traveller you should already have their SuitCases too.
public class StartTripService {
public void StartTrip(int travellerId) {
var traveller = travellerRepo.Get(travellerId);
traveller.StartTrip();
}
}

DDD - Invalidating expirable

Currently diving into DDD and i've read most of the big blue book of Eric Evans. Quite interesting so far :)
I've been modeling some aggregates where they hold a collection of entities which expire. I've come up with a generic approach of expressing that:
public class Expirable<T>
{
public T Value { get; protected set; }
public DateTime ValidTill { get; protected set; }
public Expirable(T value, DateTime validTill)
{
Value = value;
ValidTill = validTill;
}
}
I am curious what the best way is to invalidate an Expirable (nullify or omit it when working in a set). So far I've been thinking to do that in the Repository constructor since that's the place where you access the aggregates from and acts as a 'collection'.
I am curious if someone has come up with a solution to tackle this and I would be glad to hear it :) Other approaches are also very welcome.
UPDATE 10-1-2013:
This is not DDD with the CQRS/ES approach from Greg Young. But the approach Evans had, since I just started with the book and the first app. Like Greg Young said, if you have to make good tables, you have to make a few first ;)
There are probably multiple ways to approach this, but I, personally, would solve this using the Specification pattern. Assuming object expiration is a business rule that belongs in the domain, I would have a specification in addition to the class you have written. Here is an example:
public class NotExpiredSpecification
{
public bool IsSatisfiedBy(Expirable<T> expirableValue)
{
//Return true if not expired; otherwise, false.
}
}
Then, when your repositories are returning a list of aggregates or when performing any business actions on a set, this can be utilized to restrict the set to un-expired values which will make your code expressive and keep the business logic within the domain.
To learn more about the Specification pattern, see this paper.
I've added a method to my abstract repository InvalidateExpirable. An example would be the UserRepository where I remove in active user sessions like this: InvalidateExpirable(x => x.Sessions, (user, expiredSession) => user.RemoveSession(expiredSession));.
The signature of InvalidateExpirable looks like this: protected void InvalidateExpirable<TExpirableValue>(Expression<Func<T, IEnumerable<Expirable<TExpirableValue>>>> selector, Action<T, Expirable<TExpirableValue>> remover). The method itself uses reflection to extract the selected property from the selector parameter. That property name is glued in a generic HQL query which will traverse over the set calling the remove lambda. user.RemoveSession will remove the session from the aggregate. This way the I keep the aggregate responsible for it's own data. Also in RemoveSession an domain event is raised for future cases.
See: https://gist.github.com/4484261 for an example
Works quite well sofar, I have to see how it works further down in the application though.
Have been reading up on DDD with CQRS/ES (Greg Young approach) and found a great example on the MSDN site about CQRS/ES: http://msdn.microsoft.com/en-us/library/jj554200.aspx
In this example they use the command message queue to queue a Expire message in the future, which will call the Aggregate at the specified time removing/deactivate the expirable construct from the aggregate.

Ncqrs: How to raise an Event without having an Aggregate Root

Given I have two Bounded Contexts:
Fleet Mgt - simple CRUD-based supporting sub-domain
Sales - which is my CQRS-based Core Domain
When a CRUD operation occurs in the fleet management, an event reflecting the operation should be published:
AircraftCreated
AircraftUpdated
AircraftDeleted
etc.
These events are required a) to update various index tables that are needed in the Sales domain and b) to provide a unified audit log.
Question: Is there an easy way to store and publish these events (to the InProcessEventBus, I'm not using NSB here) without going through an AggregateRoot, which I wouldn't need in a simple CRUD context.
If you want to publish the event about something, this something probably is an aggregate root, because it is an externally identified object about a bundle of interest, otherwise why would you want to keep track of them?
Keeping that in mind, you don't need index tables (I understand these are for querying) in the sales BC. You need the GUIDs of the Aircraft and only lookups/joins on the read side.
For auditing I would just add a generic audit event via reflection in the repositories/unit of work.
According to Pieter, the main contributor of Ncqrs, there is no way to do this out of the box.
In this scenario I don't want to go through the whole ceremony of creating and executing a command, then loading an aggregate root from the event store just to have it emit the event.
The behavior is simple CRUD, implemented using the simplest possible solution, which in this specific case is forms-over-data using Entity Framework. The only thing I need is an event being published once a transaction occurred.
My solution looks like this:
// Abstract base class that provides a Unit Of Work
public abstract class EventPublisherMappedByConvention
: AggregateRootMappedByConvention
{
public void Raise(ISourcedEvent e)
{
var context = NcqrsEnvironment.Get<IUnitOfWorkFactory>()
.CreateUnitOfWork(e.EventIdentifier);
ApplyEvent(e);
context.Accept();
}
}
// Concrete implementation for my specific domain
// Note: The events only reflect the CRUD that's happened.
// The methods themselves can stay empty, state has been persisted through
// other means anyway.
public class FleetManagementEventSource : EventPublisherMappedByConvention
{
protected void OnAircraftTypeCreated(AircraftTypeCreated e) { }
protected void OnAircraftTypeUpdated(AircraftTypeUpdated e) { }
// ...
}
// This can be called from anywhere in my application, once the
// EF-based transaction has succeeded:
new FleetManagementEventSource().Raise(new AircraftTypeUpdated { ... });

DDD: keep a link to an entity inside an aggregate root, for reporting only

I'm refactoring a project using DDD, but am concerned about not making too many Entities their own Aggregate Root.
I have a Store, which has a list of ProductOptions and a list of Products. A ProductOption can be used by several Products. These entities seem to fit the Store aggregate pretty well.
Then I have an Order, which transiently uses a Product to build its OrderLines:
class Order {
// ...
public function addOrderLine(Product $product, $quantity) {
$orderLine = new OrderLine($product, $quantity);
$this->orderLines->add($orderLine);
}
}
class OrderLine {
// ...
public function __construct(Product $product, $quantity) {
$this->productName = $product->getName();
$this->basePrice = $product->getPrice();
$this->quantity = $quantity;
}
}
Looks like for now, DDD rules as respected. But I'd like to add a requirement, that might break the rules of the aggregate: the Store owner will sometimes need to check statistics about the Orders which included a particular Product.
That means that basically, we would need to keep a reference to the Product in the OrderLine, but this would never be used by any method inside the entity. We would only use this information for reporting purposes, when querying the database; thus it would not be possible to "break" anything inside the Store aggregate because of this internal reference:
class OrderLine {
// ...
public function __construct(Product $product, $quantity) {
$this->productName = $product->getName();
$this->basePrice = $product->getPrice();
$this->quantity = $quantity;
// store this information, but don't use it in any method
$this->product = $product;
}
}
Does this simple requirement dictates that Product becomes an aggregate root? That would also cascade to the ProductOption becoming an aggregate root, as Product has a reference to it, thus resulting in two aggregates which have no meaning outside a Store, and will not need any Repository; looks weird to me.
Any comment is welcome!
Even though it is for 'reporting only' there is still a business / domain meaning there. I think that your design is good. Although I would not handle the new requirement by storing OrderLine -> Product reference. I would do something similar to what you already doing with product name and price. You just need to store some sort of product identifier (SKU?) in the order line. This identifier/SKU can later be used in a query. SKU can be a combination of Store and Product natural keys:
class Sku {
private String _storeNumber;
private String _someProductIdUniqueWithinStore;
}
class OrderLine {
private Money _price;
private int _quantity;
private String _productName;
private Sku _productSku;
}
This way you don't violate any aggregate rules and the product and stores can be safely deleted without affecting existing or archived orders. And you can still have your 'Orders with ProductX from StoreY'.
Update: Regarding your concern about foreign key. In my opinion foreign key is just a mechanism that enforces long-living Domain relationships at the database level. Since you don't have a domain relationship you don't need the enforcement mechanism as well.
In this case you need the information for reporting which has nothing to do with the aggregate root.
So the most suitable place for it would be a service (could be a domain service if it is related to business or better to application service like querying service which query the required data and return them as DTOs customizable for presentation or consumer.
I suggest you create a statistics services which query the required data using read only repositories (or preferable Finders) which returns DTOs instead of corrupting the domain with query models.
Check this

Resources