Protecting Entity Invariants

In the previous post Command Validation, we validated a RemoveItemsFromInventory command. All wasn’t fine yet, because we found a scenario where this command validation alone isn’t enough. If we have one item in stock, two users both want to remove one item and their RemoveItemsFromInventory command is validated against the read model with CurrentCount == 1. Both commands will validate, but clearly only one should succeed. Validation alone is not sufficient here.

The invariant “cannot have less than 0 items in stock” should be protected by the InventoryItem domain entity. Let’s put that in the form of a specification:

Given an InventoryItem with events
InventoryItemCreated and 2 ItemsCheckedInToInventory
when
we Remove 3 units
then we expect
an InvalidOperationException: "only 2 items in stock, cannot remove 3 items"

How to put this in code?

Read more...

Command Validation

In Extending Greg Young’s Simplest Possible Thing I thought up a couple of functional requirements. The first functional requirements were:

  • As a user, I should get a warning when I try to remove or add a negative number of items. #2
  • As a user, I should get a warning when I try to remove more items than are currently in stock. #2
  • As a user I should not be able to remove more items from inventory than are currently in stock. #1

(I’ve added Github issue numbers so you can easily check the changes on Github)

Read more...

Extending Greg Young’s Simplest Possible Thing

As part of my process learning CQRS, I thought it would be interesting to extend one of the existing examples with some new behavior. I decided to start with The Simplest Possible Thing, an example application by Greg Young. Simple it is - if you accept Lines of Code as a metric for simplicity: the total solutions has about 900 non-blank lines (includes braces and comments). It doesn’t do much either; it allows users to:

  • create inventory items
  • rename inventory items
  • check in a number of items
  • remove a number of items

Primary goal for me was to “get better acquainted with the CQRS way of doing things”. I tried to make that goal a bit smarter, by making up a couple of new requirements (both functional and non-functional) and implementing them.

Read more...