Difference between command handlers and aggregate methods in functional DDD - domain-driven-design

Following a functional programming paradigm, I have a CQRS architecture with event sourcing as the main persistence mechanism.
Currently my aggregates consist of
a set of command handlers (behavior)
a reducer to fold events to the current aggregate state (data)
A command handler does
fetch the event stream for a given aggregateId
folds the current aggregate state
applies some business logic based on the current state
persist any events created in step 3
Example of a command handler
type CommandHandler = (
state: AggregateState,
command: Command
) => E.Either<Err.Err, DomainEvent[] | void>;
Basically steps 1, 2 and 4 are abstracted away in a generic function:
// pseudo-code
const wrapCommandHanler = (handler: CommandHandler) => {
return wrapped = (command: Command) => {
const events = fetchEvents();
const state = applyReducer(events);
const newEvents = handler(state, command);
persistEvents(newEvents);
}
}
So my command handlers are quite lean and focused and only contain the business logic.
I read about DDD, but the given examples were following a OOP paradigm. In these examples the command handler would call an aggregate method where the aggregate is a class that contains state and domain logic.
But in my case the aggregate state and behavior is separated and my command handlers ARE the aggregate behavior. So my command handlers contain the domain logic.
My question(s):
Is this approach "correct" / valid DDD or am I shooting myself in the foot with this? If not, what is the main purpose of separating an aggregate function and a command handler?

You'll probably want to review Jérémie Chassaing's recent work on Decider
My question(s): Is this approach "correct" / valid DDD or am I shooting myself in the foot with this?
It's fine - there's no particular reason that you need your functional design to align with "Java best practices" circa 2003.
If not, what is the main purpose of separating an aggregate function and a command handler?
Primarily to create a clear boundary between the abstractions of the problem domain (ex: "Cargo Shipping") and the "plumbing" - the application logic that knows about I/O, messaging, databases and transactions, HTTP, and so on.
Among other things, that means you can take the aggregate "module" (so to speak) and move it to other contexts, without disturbing the relationships of the different domain functions.
That said, there's nothing magic going on - you could refactor your "functional" design and create a slightly different design the gives you similar benefits to what you get from "aggregates".

When doing pure functional DDD, the commands (I'm deliberately not using "object") correspond to the methods of an aggregate (if using types, you can say that the type corresponds to the interface and each instance to an invocation; the ultimate handler function corresponds to the body of the method).
Technically, if event sourcing, it's the pas de deux of the command and event handler which define the aggregate, though the command handler probably carries more of the load.
These two definitions of an aggregate in Scala are effectively the same thing. For the OO-style, I'm using a more "durable state" approach and the FP-style is event-sourced (OO-style event-sourced (aggregate methods return a Seq[Event] and you have some means of defining event handlers) and FP-style durable-state (no EventHandler and the command handler returns a State) are both possible, but IME feel unnatural). Both are equivalently unit-testable (event-sourced arguably moreso, especially for property-based testing):
// Note that Map here is an immutable Map (i.e. a value object)
// Domain has been simplified: assume that Item includes price and there are no discounts etc.
// OO and "durable state"-style persistence... application basically loads a cart from persistence, maps external commands into method calls, saves cart
class ShoppingCart(val itemCounts: Map[Item, Int], val checkedOut: Boolean = false) {
def addItem(item: Item, qty: Int): Unit =
// Collapsing the failed validations into a single do-nothing case
if (!checkedOut && qty > 0) {
itemCounts.get(item) match {
case Some(count) =>
itemCounts = itemCounts.updated(item, count + qty)
case None =>
itemCounts = itemCounts + (item -> qty)
}
}
def adjustQtyOfItem(item: Item, newQty: Int): Unit =
if (!checkedOut && itemCounts.contains(item)) {
newQty match {
case neg if neg < 0 =>
// do nothing
()
case pos if pos > 0 =>
itemCounts = itemCounts.updated(item, newQty)
case 0 =>
itemCounts = itemCounts - item
}
}
def removeAllOfItem(item: Item): Unit =
adjustQtyOfItem(item, 0)
def checkOut(): Unit =
if (!checkedOut) {
checkedOut = true
}
}
// FP and event-sourced persistence
object ShoppingCart {
case class State(itemCounts: Map[Item, Int], checkedOut: Boolean)
sealed trait Command
case class AddItem(item: Item, qty: Int) extends Command
case class AdjustQtyOfItem(item: Item, newQty: Int) extends Command
case object CheckOut extends Command
val RemoveAllOfItem: Item => Command = AdjustQtyOfItem(_, 0)
sealed trait Event
case class ItemsAdded(item: Item, qty: Int) extends Event
case class ItemsRemoved(item: Item, qtyRemoved: Int) extends Event
case class AllOfItemRemoved(item: Item) extends Event
case object CheckedOut extends Event
val CommandHandler: (State, Command) => Seq[Event] = handleCommand(_, _)
val EventHandler: (State, Event) => State = handleEvent(_, _)
val InitialState = State(Map.empty, false)
private def handleCommand(state: State, cmd: Command): Seq[Event] =
if (!state.checkedOut) {
cmd match {
case AddItem(item, qty) if qty > 0 => Seq(ItemAdded(item, qty))
case AdjustQtyOfItem(item, newQty) if state.itemCounts.contains(item) && newQty >= 0 =>
val currentQty = state.itemCounts(item)
if (newQty > currentQty) {
handleCommand(state, AddItem(item, newQty - currentQty))
} else if (newQty == 0) {
Seq(AllOfItemRemoved(item))
} else {
Seq(ItemsRemoved(item, currentQty - newQty))
}
case CheckOut => Seq(CheckedOut)
case _ => Seq.empty
}
} else Seq.empty
private def handleEvent(state: State, evt: Event): State =
evt match {
case ItemsAdded(item, qty) =>
state.get(item)
.map { prevQty =>
state.copy(itemCounts = state.itemCounts.updated(item, prevQty + qty))
}
.getOrElse {
state.copy(itemCounts = state.itemCounts + (item, qty))
}
case ItemsRemoved(item, qtyRemoved) =>
state.get(item)
.map { prevQty =>
state.copy(itemCounts = state.itemCounts.updated(item, prevQty - qtyRemoved))
}
.getOrElse(state)
case AllOfItemRemoved(item) =>
state.copy(itemCounts = state.itemCounts - item)
case CheckedOut =>
state.copy(checkedOut = true)
}
}
Part of the confusion probably stems from "command handler" having a specific meaning in the application layer (where it's something from outside) and a slightly different meaning in the context of an event-sourced aggregate (the application layer command handler in an event-sourced application is basically just an anti-corruption layer translating external commands into commands against the aggregate (for instance the commands against the aggregate probably shouldn't contain an ID for the aggregate: the aggregate knows its ID)).

Is this approach "correct" / valid DDD or am I shooting myself in the foot with this?
DDD is based on two principles :
You should model your business logic (BL) using OOP in a "domain layer"
The domain layer contains the BL, the whole BL and nothing but the BL
By putting your business logic in your reducers you have failed the DDD principles and have achieved an anemic domain model. Your domain is indeed so anemic that it is even not modeled using OOP. This is important because by doing so, you violate the single responsibility principle (SRP) by having your reducers having two responsibilities : translating a series of event into state and validating business rules.
If not, what is the main purpose of separating an aggregate function and a command handler?
With the query handlers, command handlers implement parts of the interface specification, and lies in the application layer. It receive information from the clients (commands) and does some low level validation (for instance, reject malformed messages or unauthenticated requests). The command handler then calls other layers for them to do their job: the infrastructure layer for event store access, reducers for event to aggregates translation, and the domain layer for business rules validation and integrity. The code in these handlers is application specific as another application in the same domain will inherently have different interface specification and different commands to handle.
Aggregates are responsible for business logic and business rules. It is an abstraction of the actual concepts you are trying to manipulate. Good domain modeling try to be as application ignorant as possible, in order to increase reusability. A domain model could be used for multiple applications that does similar business. Whether you implement a piece of software used by pharmacists when delivering medications, or another one used by medicine doctors to prescribe them, you can use the same domain layer modeling drug interactions. Using OOP in your domain layer allows to model very complex business logic using very simple code. By putting the business logic in a separate layer, you can have a small team of developers working closely with business experts of the matter, to model all the business logic, constraints and processes, relevant to a set of applications. You can even unit test your domain.
Please note that your approach is perfectly acceptable, and can be very efficient. Doing DDD for the purpose of doing DDD is not a good practice. Doing good DDD modeling is not an easy task and should be considered as a mean of reducing complexity of large domain models.

Related

Use JOOQ Multiset with custom RecordMapper - How to create Field<List<String>>?

Suppose I have two tables USER_GROUP and USER_GROUP_DATASOURCE. I have a classic relation where one userGroup can have multiple dataSources and one DataSource simply is a String.
Due to some reasons, I have a custom RecordMapper creating a Java UserGroup POJO. (Mainly compatibility with the other code in the codebase, always being explicit on whats happening). This mapper sometimes creates simply POJOs containing data only from the USER_GROUP table, sometimes also the left joined dataSources.
Currently, I am trying to write the Multiset query along with the custom record mapper. My query thus far looks like this:
List<UserGroup> = ctx
.select(
asterisk(),
multiset(select(USER_GROUP_DATASOURCE.DATASOURCE_ID)
.from(USER_GROUP_DATASOURCE)
.where(USER_GROUP.ID.eq(USER_GROUP_DATASOURCE.USER_GROUP_ID))
).as("datasources").convertFrom(r -> r.map(Record1::value1))
)
.from(USER_GROUP)
.where(condition)
.fetch(new UserGroupMapper()))
Now my question is: How to create the UserGroupMapper? I am stuck right here:
public class UserGroupMapper implements RecordMapper<Record, UserGroup> {
#Override
public UserGroup map(Record rec) {
UserGroup grp = new UserGroup(rec.getValue(USER_GROUP.ID),
rec.getValue(USER_GROUP.NAME),
rec.getValue(USER_GROUP.DESCRIPTION)
javaParseTags(USER_GROUP.TAGS)
);
// Convention: if we have an additional field "datasources", we assume it to be a list of dataSources to be filled in
if (rec.indexOf("datasources") >= 0) {
// How to make `rec.getValue` return my List<String>????
List<String> dataSources = ?????
grp.dataSources.addAll(dataSources);
}
}
My guess is to have something like List<String> dataSources = rec.getValue(..) where I pass in a Field<List<String>> but I have no clue how I could create such Field<List<String>> with something like DSL.field().
How to get a type safe reference to your field from your RecordMapper
There are mostly two ways to do this:
Keep a reference to your multiset() field definition somewhere, and reuse that. Keep in mind that every jOOQ query is a dynamic SQL query, so you can use this feature of jOOQ to assign arbitrary query fragments to local variables (or return them from methods), in order to improve code reuse
You can just raw type cast the value, and not care about type safety. It's always an option, evne if not the cleanest one.
How to improve your query
Unless you're re-using that RecordMapper several times for different types of queries, why not do use Java's type inference instead? The main reason why you're not getting type information in your output is because of your asterisk() usage. But what if you did this instead:
List<UserGroup> = ctx
.select(
USER_GROUP, // Instead of asterisk()
multiset(
select(USER_GROUP_DATASOURCE.DATASOURCE_ID)
.from(USER_GROUP_DATASOURCE)
.where(USER_GROUP.ID.eq(USER_GROUP_DATASOURCE.USER_GROUP_ID))
).as("datasources").convertFrom(r -> r.map(Record1::value1))
)
.from(USER_GROUP)
.where(condition)
.fetch(r -> {
UserGroupRecord ug = r.value1();
List<String> list = r.value2(); // Type information available now
// ...
})
There are other ways than the above, which is using jOOQ 3.17+'s support for Table as SelectField. E.g. in jOOQ 3.16+, you can use row(USER_GROUP.fields()).
The important part is that you avoid the asterisk() expression, which removes type safety. You could even convert the USER_GROUP to your UserGroup type using USER_GROUP.convertFrom(r -> ...) when you project it:
List<UserGroup> = ctx
.select(
USER_GROUP.convertFrom(r -> ...),
// ...

How to diagram continuous user event maps in GUI?

I'm trying to create a diagrams of user interactions. In many cases I have to take some arguments like: mousePosition.x or touchDown.duration etc, and pass it through some f(x) function to render different UI using these arguments as interface properties.
Let's take an example of basic slider interface. [-----o-----]
I want to diagram a simple behavior of manipulating slider's knob. My logic is as follows:
pre condition: mousePosition.x = knobPosition.x; knobPosition.x = n
event: mosuseDown
event: mouseMove.x
if knobPosition.xMin < mousePosition.x < knobPosition.xMax
render: knobPosition.x = mousePosition.x
if ( mousePosition.x > knobPosition.xMax )
render: knobPosition.x = knobPosition.xMax
if ( mousePosition.x < knobPosition.xMin )
render: knobPosition.x = knobPosition.xMin
My first thought was to diagram this behavior through State Machine, although it becomes messy for more complex examples. Maybe there is some modeling language that was design to model these kind of behaviors?
Your logic is a kind of decision tree. This can best be modeled using an activity diagram. Each if-statement is a decision symbol in the diagram.

Map three different functions to Observable in Node.js

I am new to Rxjs. I want to follow best practices if possible.
I am trying to perform three distinct functions on the same data that is returned in an observable. Following the 'streams of data' concept, I keep on thinking I need to split this Observable into three streams and carry on.
Here is my code, so I can stop talking abstractly:
// NotEmptyResponse splits the stream in 2 to account based on whether I get an empty observable back.
let base_subscription = RxNode.fromStream(siteStream).partition(NotEmptyResponse);
// Success Stream to perform further actions upon.
let successStream = base_subscription[0];
// The Empty stream for error reporting
let failureStream = base_subscription[1];
//Code works up until this point. I don't know how to split to 3 different streams.
successStream.filter(isSite)
.map(grabData)// Async action that returns data
/*** Perform 3 separate actions upon data that .map(grabData) returned **/
.subscribe();
How can I split this data stream into three, and map each instance of the data to a different function?
In fact partition() operator internally just calls filter() operator twice. First to create an Observable from values matching the predicate and then for values not matching the predicate.
So you can do the exact same thing with filter() operator:
let obs1 = base_subscription.filter(val => predicate1);
let obs2 = base_subscription.filter(val => predicate2);
let obs3 = base_subscription.filter(val => predicate3);
Now you have three Observables, each of them emitting only some specific values. Then you can carry on with your existing code:
obs2.filter(isSite)
.map(grabData)
.subscribe();
Just be aware that calling subscribe() triggers the generating values from the source Observable. This doesn't have to be always like this depending on what Observable you use. See “Hot” and “Cold” Observables in the documentation. Operator connect() might be useful for you depending on your usecase.

DDD: How do structure or resolve more complex behaviour in a domain entity?

Assume the classic Order/OrderLine scenario.
public class Order {
...
public void AddOrderLine(OrderLine ol) {
this.OrderLines.Add(ol);
UpdateTaxes();
}
private void UpdateTaxes() {
//Traverse the order lines
//Collect the VAT amounts etc
//Update totals
var newTaxes = Orderlines.SelectMany(ol => ol.GetTaxes());
Taxes.Clear();
Taxes.Add(newTaxes);
}
}
Now, we figure that we need to handle taxes better, with different ways for customers in various countries etc, where some require VAT to be collected and others not.
In short, the tax rules will depend on the customer's location, items purchased etc. How would we do this? Should we put a lot of code into UpdateTaxes? Could we use tax calculator factory and reference it in UpdateTaxes?
private void UpdateTaxes() {
var taxRules = TaxRulesFactory.Get(this);
var taxes = taxRuleCalc.Apply(this);
Taxes.Clear();
Taxes.Add(taxes);
}
Considering your broader question regarding complex behaviour in ARs the preferred way to handle this would be to use double-dispatch. Bear in mind that complex behaviour certainly can be included in the AR if that behaviour is cohesive.
However, for functionality that varies to the degree of tax or even discount calculation, where one would implement various strategies, you could opt for the double dispatch:
public class Order
{
public void ApplyTax(ITaxService taxService)
{
_totalTax = taxService.Calculate(TotalCost());
}
public void ApplyDiscount(IDiscountService discountService)
{
_discount = discountService.GetDiscount(_orderLines.Count, TotalCost());
}
public Money TotalCost()
{
// return sum of Cost() of order lines
}
}
These services also should not be injected into the AR but rather passed into the relevant method.
May be you could extract UpdateTaxes into a separate class which would be responsible for tax calculation against a particular order. And itself would chose an appropriate strategy (a separate strategy class) depending on customer, order, etc. I feel that tax calculation is a separate responsibility here.
You might also have a think about whether the concept of Tax and the concept of Orders need to be located within the same bounded context. It perhaps seems logical or at least implicit that when you're in the process of creating an Order you will want to know Tax due, but does this necessarily apply in your domain?
I'm not saying it does or it doesn't, by the way -- I'm simply saying think about it for your particular domain. Very often when the model seems awkward to represent it's because it mixes concerns that don't belong together.

Creating a group of test objects with AutoMapper

I'm trying to create a repository of data that I can use for testing purposes for an emerging car production and design company.
Beginning Automapper Question:
In this project, I have 2 classes that share the same properties for the most part. I don't need the Id, so I am ignoring that.
My existing code looks like this:
Mapper.CreateMap<RaceCar, ProductionCar>()
.Ignore(d => d.fId) //ignore the ID
.ForMember(d=> d.ShowRoomName,
o=> o.MapFrom(s => s.FactoryName) //different property names but same thing really
//combine into my new test car
var testCarObject = Mapper.Map<RaceCar, ProductionCar>()
My main requirements are:
1) I need to create 100 of these test car objects
2) and that for every ProductionCar I use, it needs to have a corresponding RaceCar which are matched up by the name(ShowRoomName & FactoryName)
So is there a way of sticking this in some type of loop or array so that I can create the needed 100?
Also, is there a way to ensure that each new test car has the combined FactoryCar and RaceCar?
Thanks!
Use AutoMapper with AutoFixture:
var fixture = new Fixture();
var items = Enumerable.Range(1, 100)
.Select(i => fixture.Create<RaceCar>())
.Select(car => new { RaceCar = car, ProductionCar = Mapper.Map<RaceCar, ProductionCar>(car))
.ToList();
items.Profit()

Resources