Comments (3)
Please do not @ people who have not explicitly consented to it. Thanks.
Sorry @udidahan for this faux-pas. Same for twitter. Just wanted to ask you for your feedback on this regarding your suggestion in your mentioned article.
from php-ddd.
Please do not @ people who have not explicitly consented to it. Thanks.
from php-ddd.
(Copy/Pasted from https://gist.github.com/webdevilopers/687c8b34d68e97a8f93df5db09242406 )
Disclaimer: I'm no expert or authority, I might be "wrong" on every line below ;)
Thoughts regarding terminology/structure:
- "Policy" for me is something that is a reaction to an event ("Whenever X, then Y"), which might hold it's own aggregated state - I usually call specifications like this "Constraints", e.g.: "OverlappingEmploymentContractsConstraint" or simply name them according to the rule: "EmploymentsMayNotOverlap"
- It feels weird for me that a ReadModel is instantiating an aggregate - I would not expect a ReadModel to be more than data and queries.
Besides the instantiation of an EmploymentContract, the PersonReadModel seems to be 1) a factory for dependencies of the OverlappingEmploymentContractPolicy and 2) control-flow, checking the constraint
... Personally, I would probably do something like:
public function __invoke(SignEmploymentContract $command): void
{
$enteredContracts = $this->contractsDetailsRepository->ofPersonId($person->personId());
if(!OverlappingEmploymentContractPolicy::isSatisfiedBy($command->... , $enteredContracts))
{
throw new EmploymentPeriodOverlapsException();
}
$person = $this->personDetailsRepository->ofPersonId($command->personId()->toString());
$contract = EmploymentContract::sign($command->... , $person->... )
$this->contractCollection->save($contract);
EDIT: you could probably clean it up by injecting the "policy" as a dependency, which encapsulates the 'contractsDetailsRepository' (as long as you don't need it to be 'pure'):
public function __invoke(SignEmploymentContract $command): void
{
$constraintSatisfied = $this->newEmploymentContractMayNotOverlap->isSatisfiedBy($command);
if(!$constraintSatisfied)
{
throw new EmploymentPeriodOverlapsException();
}
$person = $this->personDetailsRepository->ofPersonId($command->personId()->toString());
$contract = EmploymentContract::sign($command->... , $person->... )
$this->contractCollection->save($contract);
Thoughts regarding consistency/invariants:
Be aware that all code in this gist so far does not guarantee that 2 contracts for the same person do not overlap periods.
It "only" guarantees it as long as that person does not sign up for 2 different contracts at the same time - It's probably only a window of a few milliseconds, and more a theoretical edge case than anything worth coding around.
Besides "how probably is it", I find another heuristic for whether the code should care, is the severity of the consequence of such invariant failing.
If there is a way to identify and compensate for a theoretical edge case without much blowback, and the race-condition would probably never happen, I would suggest not complicating things with saga/process-manager/policies.
Just be aware that you have a guard, not an absolute guarantee ;)
from php-ddd.
Related Issues (20)
- Repositories inside or outside Domain Services HOT 1
- Event Enriching and external changes to read-model data
- When, where and how to create Summary Events HOT 3
- Passing read models (value objects representing state) / domain service to aggregate methods HOT 6
- Unit testing value objects with internal datetime calculation HOT 14
- How to test application service command handlers dealing with read models? HOT 12
- Process Manager example with Symfony Messenger Command / Event Bus and ProophOS HOT 5
- Batch / Bulk operations handling multiple event-sourced aggregate roots HOT 3
- How to use factory methods on aggregates in CQRS - WRITE vs. READ model HOT 1
- How to keep read-models up-to-date when a name property was externally changed?
- How to upcast events with Prooph HOT 1
- Are CQRS commands part of the domain model? HOT 13
- Populate Projection with multiple tables HOT 2
- Where to call or pass a domain service? HOT 16
- How to implement the Equatable interface / Equals or SameValueAs method in value objects
- Domain Event Publisher for Doctrine Entities HOT 1
- Event Sourcing vs. Event-Driven Architecture (EDA)
- The repository pattern HOT 4
- Properties on Domain Events HOT 3
- PHP Command DTO with Symfony Constraints equivalent in Angular Forms HOT 1
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from php-ddd.