Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

How to implement business rules? #15

Open
MZybura opened this issue Dec 3, 2015 · 10 comments
Open

How to implement business rules? #15

MZybura opened this issue Dec 3, 2015 · 10 comments

Comments

@MZybura
Copy link

MZybura commented Dec 3, 2015

I'm wondering how to implement business rule depends on entity current state. For example: "You can change the name of the InventoryItem only if new name is longer".

@Narvalex
Copy link

Narvalex commented Dec 4, 2015

@MZybura, a simple approach: In a rehydration method (those that updates sate by playing all past events) just assign the name of the item from a past event to a field of the aggregate, and then, when handling a command just compare the new name to the field. That's it

@Narvalex
Copy link

Narvalex commented Dec 4, 2015

And of course, if a validation fails don't throw an exception. Just publish an event like "CouldNotUpdateInventoryItemName"

@MZybura
Copy link
Author

MZybura commented Dec 14, 2015

Do you mean in "Apply" method? So I'm not sure how it should work. My understanding is that InventoryCommandHandler invokes "InventoryItem.ChangeName" method with new name as parameter. Do you suggest that "ChangeName" method should not be change, "InventoryItemRenamed" event published and business logic implemented in "Apply" method? How to get current state of the object to compare new name with current name?

@Narvalex
Copy link

Narvalex commented Feb 4, 2016

Its all about left folding (a high order function, similar to aggregate in C# Linq) from previous events. It is a core concept of event sourcing. You left fold, or apply from an initial state all events that happened to the aggregate, starting from the beginning.
When you applied all previous events, you then have the current state. Then you can process a command to publish a new event.

For instance:

  1. State0: No Name
  2. Incoming Command: "CreateNewItem { name: foo }" => nothing to validate.
  3. Apply: "NewItem { name: foo }" => State1: Item named Foo
  4. Incoming Command: "RenameItem { name: foo2 }" => Check from current state (state1) if name is diferent.
  5. Apply: "ItemRenamed { newName: foo2 }" => Steate2: Item renamed from foo to foo2

@perty
Copy link

perty commented Feb 4, 2016

But can't you get race conditions then? If two threads change the name, looking at the name "foo", only one of them is right. Do you have some kind of optimistic locking?

@gregoryyoung
Copy link
Owner

There is optimistic locking built into this example see expected version

On Thu, Feb 4, 2016 at 11:51 AM, Per Lundholm notifications@github.com
wrote:

But can't you get race conditions then? If two threads change the name,
looking at the name "foo", only one of them is right. Do you have some kind
of optimistic locking?


Reply to this email directly or view it on GitHub
#15 (comment).

Studying for the Turing test

@Narvalex
Copy link

Narvalex commented Feb 4, 2016

It is right here

@perty
Copy link

perty commented Feb 4, 2016

Thanks! :)

@exoer
Copy link

exoer commented Apr 29, 2021

I'm wondering how to implement business rule depends on entity current state. For example: "You can change the name of the InventoryItem only if new name is longer".

Another example ... a business rule to prevent removal of a given number of items from stock if there is enough left. To implement that, the entity/aggregateRoot could have a count property, or a way to get the counts from the change events.

@amguilmet
Copy link

amguilmet commented Dec 31, 2022

business rule to prevent removal of a given number of items from stock if there is enough left.

I kind of did that... just did sort of the opposite by instead of adding a Min Qty to the Remove, I added a MaxQty to the Check In instead 🤷‍♂️

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

6 participants