Aggregate as a service - domain-driven-design

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.

Related

Implementing user-defined business rules with DDD

Let's say If I have an application which let's user create business rules to be applied on a domain entity. A rule can be a combination of a condition and multiple actions where if condition evaluates to true then corresponding actions are executed. This rule is created by users in free-form text format which is then converted to a proprietary format which rule engine can understand and execute.
E.g. For an employee management system, if there is business rule to check if an employee is working in current Role for more than an year and has performed better than expected then can be promoted to next role with a 10% salary increment. This business rule can be entered by users as below.
Condition: Employee.CurrentRoleLength > 1 && Employee.ExceededExpectations()
Action: Employee.PromoteToNextRole() | Employee.GiveSalaryIncrement(10)
Note that multiple Actions are delimited with a |. Also in order to execute this rule, application uses a separate rule engine class library to parse this condition and both actions to a proprietary format, say, ExecutableScript also defined in the rule engine class library.
Now in order to model this requirement using DDD; I have come up with following Domain objects.
Rule (Entity)
Condition (Value Object)
Action (Value Object)
where Rule is an Entity which contains a Condition Value Object and a list of Action Value Objects as below.
public class Rule : Entity
{
public Condition Condition { get; private set; }
public IList<Action> Actions { get; private set;}
public Rule(Condition condition, IList<Action> actions)
{
Condition = condition;
Actions = actions;
}
}
public sealed class Condition : ValueObject<Condition>
{
public string ConditionText { get; private set;}
public ExecutableScript ExecutableCondition{ get; private set;}
public Condition(string conditionText)
{
ConditionText = conditionText;
}
public Parse()
{
ExecutableCondition = // How to parse using external rule engine ??;
}
public Execute()
{
// How to execute using external rule engine ??;
}
}
public sealed class Action : ValueObject<Action>
{
public string ActionText{ get; private set;}
public ExecutableScript ExecutableAction{ get; private set;}
public Action(string actionText)
{
ActionText = actionText;
}
public Parse()
{
ExecutableAction = // How to parse using external rule engine ??;
}
public Execute()
{
// How to execute using external rule engine ??;
}
}
Based on above domain model, I have following questions.
How can I parse and execute Condition and Actions without having a dependency on external rule engine. I understand Domain layer should not have any dependency on outer layers and should be confined to it's own.
Even if I Parse Condition and Actions outside their domain objects, still their parsed ExceutableScript value need to be present within them which will still need dependency on external rule engine.
Is it just that DDD is not the right approach for this scenario and I am going into wrong direction.
Sorry for the long post. Any help would be highly appreciated.
Thanks.
Technical domains may benefit from DDD tactical patterns, but the cost of creating the right abstractions is usually higher than with other domains because it often requires to abstract away complex data structures.
A good way to start thinking about the required abstractions is to ask yourself what abstractions would be needed if you were to swap the underlying technologies.
Here you have a complex text-based expression from which an ExecutableScript is created by the rules engine.
If you think about it there three major elements here:
The text-based expression syntax which is proprietary.
The ExecutableScript which is proprietary; I will assume this is an Abstract Syntax Tree (AST) with an embedded interpreter.
The rule evaluation context which is probably proprietary.
If you were to swap the underlying technology to execute the rules then the expression syntax of the other rule engine may be different and it would certainly have an entirely different rule interpretation mechanism.
At this point we have identified what have to be abstracted, but not what would be the proper abstractions.
You could decide to implement your own expression syntax, your own parser, your own AST which would be a tree-based representation of the expression in memory and finally your own rule evaluation context. This set of abstractions would then be consumed by specific rule engines. For instance, your current rule engine would have to convert a domain.Expression AST to an ExecutableScript.
Something like this (I left out the evaluation context intentionally as you did not provide any information on it).
However, creating your set of abstractions could be costly, especially if you do not anticipate to swap your rule engine. If the syntax of your current rules engine suits your needs then you may use it as your abstraction for text-based expressions. You can do this because it doesn't require a proprietary data structure to represent text in memory; it's just a String. If you were to swap your rule engine in the future then you could still use the old engine to parse the expression and then rely on the generated AST to generate the new one for the other rule engine or you could go back to writing your own abstractions.
At this point, you may decide to simply hold that expression String in your domain and pass it to an Executor when it has to be evaluated. If you are concerned by the performance cost of re-generating the ExecutableScript each time then you should first make sure that is indeed an issue; premature optimization is not desirable.
If you find out that it is too much overhead then you could implement memoization in the infrastructure executor. The ExecutableScript could either be stored in memory or persisted to disk. You could potentially use a hash of the string-based expression to identify it (beware collisions), the entire string, an id assigned by the domain or any other strategy.
Last but not least. Keep in mind that if rule actions aren't processed by aggregates or if the rule predicate spans multiple aggregates then the data used to evaluate the expression may have been stale. I'm not expanding on this because I have no idea how you plan to generate the rule evaluation context and process actions, but I thought it was still worth mentioning because invariant enforcement is an important aspect of every domains.
If you determine that all rules may be eventually consistent or that decisions made on stale data are acceptable then I'd also consider creating an entirely separate bounded context for that, perhaps called "Rule Management & Execution".
EDIT:
Here's an example that shows how creating a rule may look like form the application service perspective, given that expressions are stored as Strings in the domain.
//Domain
public interface RuleValidator {
boolean isValid(Rule rule);
}
public class RuleFactory {
private RuleValidator validator;
//...
public Rule create(RuleId id, Condition condition, List<Action> actions) {
Rule rule = new Rule(id, condition, actions);
if (!validator.isValid(rule)) {
throw new InvalidRuleException();
}
return rule;
}
}
//App
public class RuleApplicationService {
private RuleFactory ruleFactory;
private RuleRepository ruleRepository;
//...
public void createRule(String id, String conditionExpression, List<String> actionExpressions) {
transaction {
List<Action> actions = createActionsFromExpressions(actionExpressions);
Rule rule = ruleFactory.create(new RuleId(id), new Condition(conditionExpression), actions);
ruleRepository.add(rule); //this may also create and persist an `ExecutableScript` object transparently in the infrastructure, associated with the rule id.
}
}
}
How can I parse and execute Condition and Actions without having a dependency on external rule engine. I understand Domain layer should not have any dependency on outer layers and should be confined to it's own.
This part is easy: dependency inversion. The domain defines a service provider interface that describes how it wants to talk to some external service. Typically, the domain will pass a copy of some of its internal state to the service, and get back an answer that it can then apply to itself.
So you might see something like this in your model
Supervisor.reviewSubordinates(EvaluationService es) {
for ( Employee e : this.subbordinates ) {
// Note: state is an immutable value type; you can't
// change the employee entity by mutating the state.
Employee.State currentState = e.currentState;
Actions<Employee.State> actions = es.evaluate(currentState);
for (Action<Employee.State> a : actions ) {
currentState = a.apply(currentState);
}
// replacing the state of the entity does change the
// entity, but notice that the model didn't delegate that.
e.currentState = currentState;
}
}

Defining aggregate roots when invariants exist within a list

I'm doing a family day care app, and thought I'd try DDD/CQRS/ES for it, but I'm running into issues with designing the aggregates well. The domain can be described pretty simply:
A child gets enrolled
A child can arrive
A child can leave
The goal is to track the times of the visits, generate invoices, put notes (eg. what was had for lunch, injuries etc.) against the visits. These other actions will be, by far, the most common interaction with the system, as a visit starts once a day, but something interesting happens all the time.
The invariant I'm struggling with is:
A child cannot arrive if they are already here
As far as I can see, I have the following options
1. Single aggregate root Child
Create a single Child aggregate root, with the events ChildEnrolled, ChildArrived and ChildLeft
This seems simple, but since I want each other event to be associated with a visit, it means the visit would be an entity of the Child aggregate, and every time I want to add a note or anything, I have to source all the visits for that child, ever. Seems inefficient and fairly irrelevant - the child itself, and every other visit, simply isn't relevant to what the child is having for lunch.
2. Aggregate Roots for Child and Visit
Child would source just ChildEnrolled, and Visit would source ChildArrived and ChildLeft. In this case, I don't know how to maintain the invariant, besides having the Visit take in a service for just this purpose, which I've seen is discouraged.
Is there another way to enforce the invariant with this design?
3. It's a false invariant
I suppose this is possible, and I should protect against multiple people signing in the same child at the same time, or latency meaning the use hits the 'sign in' button a bunch of times. I don't think this is the answer.
4. I'm missing something obvious
This seems most likely - surely this isn't some special snowflake, how is this normally handled? I can barely find examples with multiple ARs, let alone ones with lists.
Aggregates
You're talking heavily about Visits and what happened during this Visit, so it seems like an important domain-concept of its own.
I think you would also have a DayCareCenter in which all cared Children are enrolled.
So I would go with this aggregate-roots:
DayCareCenter
Child
Visit
BTW: I see another invariant:
"A child cannot be at multiple day-care centers at the same time"
"Hits the 'sign in' button a bunch of times"
If every command has a unique id which is generated for every intentional attempt - not generated by every click (unintentional), you could buffer the last n received command ids and ignore duplicates.
Or maybe your messaging-infrastructure (service-bus) can handle that for you.
Creating a Visit
Since you're using multiple aggregates, you have to query some (reliable, consistent) store to find out if the invariants are satisfied.
(Or if collisions are rarely and "canceling" an invalid Visit manually is reasonable, an eventual-consistent read-model would work too...)
Since a Child can only have one current Visit, the Child stores just a little information (event) about the last started Visit.
Whenever a new Visit should be started, the "source of truth" (write-model) is queried for any preceeding Visit and checked whether the Visit was ended or not.
(Another option would be that a Visit could only be ended through the Child aggregate, storing again an "ending"-event in Child, but this feels not so good to me...but that's just a personal opinion)
The querying (validating) part could be done through a special service or by just passing in a repository to the method and directly querying there - I go with the 2nd option this time.
Here is some C#-ish brain-compiled pseudo-code to express how I think you could handle it:
public class DayCareCenterId
{
public string Value { get; set; }
}
public class DayCareCenter
{
public DayCareCenter(DayCareCenterId id, string name)
{
RaiseEvent(new DayCareCenterCreated(id, name));
}
private void Apply(DayCareCenterCreated #event)
{
//...
}
}
public class VisitId
{
public string Value { get; set; }
}
public class Visit
{
public Visit(VisitId id, ChildId childId, DateTime start)
{
RaiseEvent(new VisitCreated(id, childId, start));
}
private void Apply(VisitCreated #event)
{
//...
}
public void EndVisit()
{
RaiseEvent(new VisitEnded(id));
}
private void Apply(VisitEnded #event)
{
//...
}
}
public class ChildId
{
public string Value { get; set; }
}
public class Child
{
VisitId lastVisitId = null;
public Child(ChildId id, string name)
{
RaiseEvent(new ChildCreated(id, name));
}
private void Apply(ChildCreated #event)
{
//...
}
public Visit VisitsDayCareCenter(DayCareCenterId centerId, IEventStore eventStore)
{
// check if child is stille visiting somewhere
if (lastVisitId != null)
{
// query write-side (is more reliable than eventual consistent read-model)
// ...but if you like pass in the read-model-repository for querying
if (eventStore.OpenEventStream(lastVisitId.Value)
.Events()
.Any(x => x is VisitEnded) == false)
throw new BusinessException("There is already an ongoning visit!");
}
// no pending visit
var visitId = VisitId.Generate();
var visit = new Visit(visitId, this.id, DateTime.UtcNow);
RaiseEvent(ChildVisitedDayCenter(id, centerId, visitId));
return visit;
}
private void Apply(ChildVisitedDayCenter #event)
{
lastVisitId = #event.VisitId;
}
}
public class CommandHandler : Handles<ChildVisitsDayCareCenter>
{
// http://csharptest.net/1279/introducing-the-lurchtable-as-a-c-version-of-linkedhashmap/
private static readonly LurchTable<string, int> lastKnownCommandIds = new LurchTable<string, bool>(LurchTableOrder.Access, 1024);
public CommandHandler(IWriteSideRepository writeSideRepository, IEventStore eventStore)
{
this.writeSideRepository = writeSideRepository;
this.eventStore = eventStore;
}
public void Handle(ChildVisitsDayCareCenter command)
{
#region example command douplicates detection
if (lastKnownCommandIds.ContainsKey(command.CommandId))
return; // already handled
lastKnownCommandIds[command.CommandId] = true;
#endregion
// OK, now actual logic
Child child = writeSideRepository.GetByAggregateId<Child>(command.AggregateId);
// ... validate day-care-center-id ...
// query write-side or read-side for that
// create a visit via the factory-method
var visit = child.VisitsDayCareCenter(command.DayCareCenterId, eventStore);
writeSideRepository.Save(visit);
writeSideRepository.Save(child);
}
}
Remarks:
RaiseEvent(...) calls Apply(...) instantly behind the scene
writeSideRepository.Save(...) actually saves the events
LurchTable is used as a fixed-sized MRU-list of command-ids
Instead of passing the whole event-store, you could make a service for it if you if benefits you
Disclaimer:
I'm no renowned expert. This is just how I would approach it.
Some patterns could be harmed during this answer. ;)
It sounds like the "here" in your invariant "A child cannot arrive if they are already here" might be an idea for an aggregate. Maybe Location or DayCareCenter. From there, it seems trivial to ensure that the Child cannot arrive twice, unless they have previously left.
Of course, then this aggregate would be pretty long-lived. You may then consider an aggregate for a BusinessDay or something similar to limit the raw count of child arrivals and departures.
Just an idea. Not necessarily the way to solve this.
I would try to base the design on reality and study how they solve the problem without software.
My guess is they use a notebook or printed list and start every day with a new sheet, writing today's date and then taking notes for each child regarding arrival, lunch etc. The case with kids staying the night shouldn't be a problem - checking in day 1 and checking out day 2.
The aggregate root should focus on the process (in your case daily/nightly per-child caring) and not the participating data objects (visit, child, parent, etc.).
I'm missing something obvious
This one; though I would quibble with whether or not it is obvious.
"Child" probably should not be thought of as an aggregate in your domain model. It's an entity that exists outside your model. Put another way, your model is not the "book of record" for this entity.
The invariant I'm struggling with is:
A child cannot arrive if they are already here
Right. That's a struggle, because your model doesn't control when children arrive and leave. It's tracking when those things happen in some other domain (the real world). So your model shouldn't be rejecting those events.
Greg Young:
The big mental leap in this kind of system is to realize that
you are not the book of record. In the warehouse example the
*warehouse* is the book of record. The job of the computer
system is to produce exception reports and estimates of what
is in the warehouse
Think about it: the bus arrives. You unload the children, scan their bar codes, and stick them in the play room. At the end of the day, you reverse the process -- scanning their codes as you load them onto the bus. When the scanner tries to check out a child who never checked in, the child doesn't disappear.
Your best fit, since you cannot prevent this "invariant violation", is to detect it.
One way to track this would be an event driven state machine. The key search term to use is "process manager", but in older discussions you will see the term "saga" (mis)used.
Rough sketch: your event handler is listening to these child events. It uses the id of the child (which is still an entity, just not an aggregate), to look up the correct process instance, and notifies it of the event. The process instance compares the event to its own state, generates new events to describe the changes to its own state, and emits them (the process manager instance can be re-hydrated from its own history).
So when the process manager knows that the child is checked in at location X, and receives an event claiming the child is checked in at location Y, it records a QuantumChildDetected event to track the contingency.
A more sophisticated process manager would also be acting on ChildEnrolled events, so that your staff knows to put those children into quarantine instead of into the playroom.
Working back to your original problem: you need to think about whether Visits are aggregates that exist within your domain model, or logs of things that happen in the real world.

Decorating Repositories with AutoFac

Hi I have a maybe a common problem that I think not entirely can be solved by Autofac or any IoC container. It can be a design problem that I need some fresh input on.
I have the classic MVC web solution with EF 6. Its been implemented in a true DDD style with Anti-corruption layer, three bounded contexts, cross-cutting concerns movers out to infrastructure projects. It has been a real pleasure to see all pieces fall in to place in good way. We also added Commands to CUD operations into Domain.
Now here is the problem. Customer want a change log that tracks every entities property and when updates are done we need to save into change log values before and after update. We have implemented that successful in a ILoggerService that wraps a Microsoft test utility that we uses to detect changes. But I, my role is Software Architect, took the decision to Decorate our generic repositories with a ChangeTrackerRepository that have a dependency on ILoggerService. This works fine. The Decorator track methods Add(…) and Modify(…) in our IRepository<TEntity>.
The problem is that we have Repositories that have custom repositories that have custom queries like this:
public class CounterPartRepository : Repository<CounterPart>, ICounterPartRepository
{
public CounterPartRepository(ManagementDbContext unitOfWork)
: base(unitOfWork)
{}
public CounterPart GetAggregate(Guid id)
{
return GetSet().CompleteAggregate().SingleOrDefault(s => s.Id == id);
}
public void DeleteCounterPartAddress(CounterPartAddress address)
{
RemoveChild(address);
}
public void DeleteCounterPartContact(CounterPartContact contact)
{
RemoveChild(contact);
}
}
We have simple repositories that just closes the generic repository and get proper EF Bounded context injected into it (Unit Of Work pattern):
public class AccrualPeriodTypeRepository : Repository<AccrualPeriodType>, IAccrualPeriodTypeRepository
{
public AccrualPeriodTypeRepository(ManagementDbContext unitOfWork)
: base(unitOfWork)
{
}
}
The problem is that when decorating AccrualPeriodTypeRepository with AutoFac through generic Decorator we can easily inject that repo into CommandHandler actor like this
public AddAccrualPeriodCommandHandler(IRepository<AccrualPeriod> accrualRepository)
This works fine.
But How do we also decorate CounterPartRepository???
I have gone through several solutions in my head and they all end up with a dead-end.
1) Manually decorate every custom repository generate to many custom decorators that it will be near unmaintainable.
2) Decorate the closed Repository Repository with extended custom queries. This smells bad. Should be part of that repository?
3) If we consider 2… maybe Skip our Services and only rely on IRepository for operating on our Aggregate Roots and IQueryHandler (see article https://cuttingedge.it/blogs/steven/pivot/entry.php?id=92)
I need some fresh input to a common problem I think, when it comes to decorating your repositories when you have custom closed repositories and simple repositories also closed but both inherit from same Repository
Have you consider decorating command handlers instead of decorating repositories?
Repos are too low level, and it is not their responsibility to know what should be logged and how.
What about the following:
1) You have your command handlers in a way:
public class DeleteCounterPartAddressHandler : IHandle<DeleteCounterPartAddressCommand>
{
//this might be set by a DI container, or passed to a constructor
public ICounterPartRepository Repository { get; set; }
public void Handle(DeleteCounterPartAddressCommand command)
{
var counterpart = repository.GetPropertyById(command.CounterPartId);
// in DDD you always want to read and aggregate
// and save an aggregate as a whole
property.DeleteAdress(command.AddressId);
repository.Save(counterpart)
}
}
2) Now you can simply use Chain Of Responsibility pattern to "decorate" your handlers with logging, transactions, whatever:
public class LoggingHandler<T> : IHandler<T> {
private readonly IHandler<T> _innerHandler;
public LoggingHandler(IHandler<T> innerHandler) {
_innerHandler = innerHandler;
}
public void Handle(T command)
{
//Obviously you do it properly, but you get the idea
_log.Info("Before");
_innerHandler.Handle(command);
_log.Info("After");
}
}
Now you have just one piece of code responsible for logging and you can compose it with any command handler, so if you ever want to log a particular command then you just "wrap" it with the logging handler, and it is still your IHandle<T> so the rest of the system is not impacted.
And you can do it with other concerns too (threading, queueing, transactions, multiplexing, routing, etc.) without messing around and plumbing this stuff here and there.
Concerns are very well separated this way.
It is also much better (to me) because you log on a real operation (business) level, rather than on low-level repository.
Hope it helps.
P.S. In DDD you really want your repositories to only expose aggregate-level methods because Aggregates suppose to take care of their invariants (and nothing else, no services, no repositories), and because Aggregate represents transaction boundary.
Really, it is up to the Repository how to get the Aggregate from persisted storage and how to persist it back, outside it should look like you ask someone for an object and it gives you an object you can call behaviors on.
So normally you would only get an aggregate from the repository, call its behavior(s) and then save it back. Which really means that your repositories would mostly have GetById and Save methods, not some internals like "UpdateThatPartOfAnAggregate".

Connecting the dots with DDD

I have read Evans, Nilsson and McCarthy, amongst others, and understand the concepts and reasoning behind a domain driven design; however, I'm finding it difficult to put all of these together in a real-world application. The lack of complete examples has left me scratching my head. I've found a lot of frameworks and simple examples but nothing so far that really demonstrates how to build a real business application following a DDD.
Using the typical order management system as an example, take the case of order cancellation. In my design I can see an OrderCancellationService with a CancelOrder method which accepts the order # and a reason as parameters. It then has to perform the following 'steps':
Verify that the current user has the necessary permission to cancel an Order
Retrieve the Order entity with the specified order # from the OrderRepository
Verify that the Order may be canceled (should the service interrogate the state of the Order to evaluate the rules or should the Order have a CanCancel property that encapsulates the rules?)
Update the state of the Order entity by calling Order.Cancel(reason)
Persist the updated Order to the data store
Contact the CreditCardService to revert any credit card charges that have already been processed
Add an audit entry for the operation
Of course, all of this should happen in a transaction and none of the operations should be allowed to occur independently. What I mean is, I must revert the credit card transaction if I cancel the order, I cannot cancel and not perform this step. This, imo, suggests better encapsulation but I don't want to have a dependency on the CreditCardService in my domain object (Order), so it seems like this is the responsibility of the domain service.
I am looking for someone to show me code examples how this could/should be "assembled". The thought-process behind the code would be helpful in getting me to connect all of the dots for myself. Thx!
Your domain service may look like this. Note that we want to keep as much logic as possible in the entities, keeping the domain service thin. Also note that there is no direct dependency on credit card or auditor implementation (DIP). We only depend on interfaces that are defined in our domain code. The implementation can later be injected in the application layer. Application layer would also be responsible for finding Order by number and, more importantly, for wrapping 'Cancel' call in a transaction (rolling back on exceptions).
class OrderCancellationService {
private readonly ICreditCardGateway _creditCardGateway;
private readonly IAuditor _auditor;
public OrderCancellationService(
ICreditCardGateway creditCardGateway,
IAuditor auditor) {
if (creditCardGateway == null) {
throw new ArgumentNullException("creditCardGateway");
}
if (auditor == null) {
throw new ArgumentNullException("auditor");
}
_creditCardGateway = creditCardGateway;
_auditor = auditor;
}
public void Cancel(Order order) {
if (order == null) {
throw new ArgumentNullException("order");
}
// get current user through Ambient Context:
// http://blogs.msdn.com/b/ploeh/archive/2007/07/23/ambientcontext.aspx
if (!CurrentUser.CanCancelOrders()) {
throw new InvalidOperationException(
"Not enough permissions to cancel order. Use 'CanCancelOrders' to check.");
}
// try to keep as much domain logic in entities as possible
if(!order.CanBeCancelled()) {
throw new ArgumentException(
"Order can not be cancelled. Use 'CanBeCancelled' to check.");
}
order.Cancel();
// this can throw GatewayException that would be caught by the
// 'Cancel' caller and rollback the transaction
_creditCardGateway.RevertChargesFor(order);
_auditor.AuditCancellationFor(order);
}
}
A slightly different take on it:
//UI
public class OrderController
{
private readonly IApplicationService _applicationService;
[HttpPost]
public ActionResult CancelOrder(CancelOrderViewModel viewModel)
{
_applicationService.CancelOrder(new CancelOrderCommand
{
OrderId = viewModel.OrderId,
UserChangedTheirMind = viewModel.UserChangedTheirMind,
UserFoundItemCheaperElsewhere = viewModel.UserFoundItemCheaperElsewhere
});
return RedirectToAction("CancelledSucessfully");
}
}
//App Service
public class ApplicationService : IApplicationService
{
private readonly IOrderRepository _orderRepository;
private readonly IPaymentGateway _paymentGateway;
//provided by DI
public ApplicationService(IOrderRepository orderRepository, IPaymentGateway paymentGateway)
{
_orderRepository = orderRepository;
_paymentGateway = paymentGateway;
}
[RequiredPermission(PermissionNames.CancelOrder)]
public void CancelOrder(CancelOrderCommand command)
{
using (IUnitOfWork unitOfWork = UnitOfWorkFactory.Create())
{
Order order = _orderRepository.GetById(command.OrderId);
if (!order.CanBeCancelled())
throw new InvalidOperationException("The order cannot be cancelled");
if (command.UserChangedTheirMind)
order.Cancel(CancellationReason.UserChangeTheirMind);
if (command.UserFoundItemCheaperElsewhere)
order.Cancel(CancellationReason.UserFoundItemCheaperElsewhere);
_orderRepository.Save(order);
_paymentGateway.RevertCharges(order.PaymentAuthorisationCode, order.Amount);
}
}
}
Notes:
In general I only see the need for a domain service when a command/use case involves the state change of more than one aggregate. For example, if I needed to invoke methods on the Customer aggregate as well as Order, then I'd create the domain service OrderCancellationService that invoked the methods on both aggregates.
The application layer orchestrates between infrastructure (payment gateways) and the domain. Like domain objects, domain services should only be concerned with domain logic, and ignorant of infrastructure such as payment gateways; even if you've abstracted it using your own adapter.
With regards to permissions, I would use aspect oriented programming to extract this away from the logic itself. As you see in my example, I've added an attribute to the CancelOrder method. You can use an intercepter on that method to see if the current user (which I would set on Thread.CurrentPrincipal) has that permission.
With regards to auditing, you simply said 'audit for the operation'. If you just mean auditing in general, (i.e. for all app service calls), again I would use interceptors on the method, logging the user, which method was called, and with what parameters. If however you meant auditing specifically for the cancellation of orders/payments then do something similar to Dmitry's example.

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 { ... });

Resources