vkhorikov / dddinaction Goto Github PK
View Code? Open in Web Editor NEWSource code for the DDD in Practice Pluralsight course
Home Page: https://www.pluralsight.com/courses/domain-driven-design-in-practice
Source code for the DDD in Practice Pluralsight course
Home Page: https://www.pluralsight.com/courses/domain-driven-design-in-practice
I am sure it is not the requirement that objects that are not equal have different hash codes. It is just by accident, though very probable, that this test passes. There are more different objects that different hash codes.
P.S. Thanks for your great course.
Hello,
I saw your code but I think repository is not a repository because you implement it as generic type. So it means each derived type will have Get/Save methods. When Save method is divided into Insert and Update and Remove method will be added there is class which implements CRUD operation above table. When you have class for CRUD operation it is more Table Gateway pattern than Repository pattern.
There is some differences between TableGtw and Repository pattern. Important thing in DDD (domain model more exactly) is that domain model works with entities aggregates. It means I have entity Invoice and it have many Items. Domain model works with root entity which is Invoice. Important is that nobody can change Invoice Item directly but Item are encapsulated inside Invoice entity and each change can be done by Invoice entity only - not from outside Invoice entity.
It means Invoice entity should be loaded with Items together. So Repository pattern can provide access to whole aggregate for Invoice entity. Instead of TableGtw pattern provides access to one table in database which means one entity - Invoice is loaded by InvoiceTableGtw and Items are loaded by InvoiceItemTableGtw. Exception could be value object which can be stored in same table as entity.
Repository pattern can provide some logic to check if entity is consistent and valid. It means it can check if price on Invoice entity is equal sum of price on items.
Repository is created only for root entities, not for entities inside aggregate.
Repository is not responsible for saving data to data store, it has not Save method.
I think it is very important to think in aggregates and each entity/value object is encapsulate inside aggregate and can be accessed and changed only by root entity - not directly outside of aggregate. It is difference to Table Module business pattern or Transaction Script.
There is difference between domain model and domain driven design (DDD) which is confused often. DDD is whole methodology how to distil bounded contexts, how to establish communication between contexts and other systems, what is core/support/generic domain, ... Domain model is more implementation technique which can take more complex business by model. Model can by created by Model Driven Design methodology but when we use DDD we create model for each context instead of whole system in case of Model Drive Design.
I saw some projects where people said we use DDD because we have entities, repositories and we have many apis. Ok and what are your bounded context? No, we don't have bounded context we have more apis and it is DDD. You don't have value objects. Each object has identity - primary key in database. Ok, but it is not business identity. Your entity has not any behavior it is POCO object - it is not domain model, it can be anemic domain model or another business pattern but not rich domain model. Each entity is 1:1 with database table and it is loaded by generic repository. Generic repository is TableGtw pattern. You don't have any domain service. We have services. Ok, but it is in application layer and these services hold use cases but domain service hold business case.
In DDD can be used any business pattern (domain model, transaction script or table module). DDD doesn't say which pattern or technology should be used. Each context can be implemented by different approach. DDD doesn't say nothing about code.
The tests using ShouldThrow should be changed to the syntax below if you use a later version of FluentAssertions. I'm using 5.10.2
` public void Substract_more_then_exists()
{
Money money1 = new Money(0,1,0,0,0,0);
Money money2 = new Money(1,0,0,0,0,0);
Action action = () =>
{
Money money = money1 - money2;
};
action.Should().Throw<InvalidOperationException>();
}`
https://github.com/vkhorikov/CSharpFunctionalExtensions/blob/98dc557a017c00fb66c4cfb19a5aee6c3b8abc03/CSharpFunctionalExtensions/ValueObject/ValueObject.cs#L143 this violates https://rules.sonarsource.com/csharp/RSPEC-3875. I am not sure whether I agree with SonarQube, but could you give your view?
Hello, first ever issue I've raised on github. Hope I am doing right. This is more of a note than anything. One has to ensure you are downgraded to nHibernate 4.x to compile this. There are changes in nHibernate5.x that prevent compilation. Thank you
In order to compile;
This line -> aggregateRoot.ClearDomainEvents();
Needs to be changed to -> aggregateRoot.ClearEvents();
Note: I see in later versions of Khorikov's DDD classes there are a few method name changes and filename changes. for example -> IHandler.cs is renamed to IDomainEventHandler.
Hi @vkhorikov,
Is there a reason you didn't address business rules in the domain and UI validation?
Thanks,
Karl
Hey Vlad,
I am trying to learn DDD and your courses have helped me a lot. So, as far as I understand, an aggregate is a cluster of related objects that forms a boundary inside which transactional consistency is enforced. So, when fetching an aggregate using a repository from the database you should only fetch the data related to the entities (and value objects) contained in that aggregate. In the case of snack machine bounded context, there are two aggregates (snack machine and snack). However, you only created and used a single repository and disabled lazy loading (since you were creating a new session each time) when fetching the snacks for the slots/snack piles. So I have the following questions:
Why did we do that? Shouldn't we create a separate snackRepository instead and have only the snackIds in the snack-piles? Then maybe use a snackRepository to fetch all the snacks by their IDs in our application services?
Even if we used lazy loading, aren't we violating the rule about transactional consistency when loading the data of a different aggregate? What if we referenced multiple aggregates?
Note: I have read your article: https://enterprisecraftsmanship.com/posts/link-to-an-aggregate-reference-or-id/ and the comments.
Amazing course! As I am a java developer I tried to "translate" it in java (as a REST API using spring boot and hibernate). Here is the link to my repo in case you want to check it out: https://github.com/kosletr/DDD-In-Practice-In-Java
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.