DDD use event or service? - c#

Hi im new to ddd design and is trying to develop my first application using this pattern working in C#
In my application i have an aggregate Contract that have child entity assets, when an asset is added or settled i should perform an accounting operation in another aggregate Accounts and ensure it in business logic.
Should i create a domain service that ensures that each operation in contract assets will raise an account operation, and call this service in application layer sending a collection of account entity. Or should I inject repository to this service load the account list and save the changes in account and operations list.
Or even make the methods in asset entity raise an event that enforce account changes. If this is the right approach, the event handle should be in the domain or application? If in the domain should the handler in the account entity perform the changes through respository injected?
Im a bit confused

generally this kind of problems can be elegantly solved using events, and focusing on one aggregate per transaction.
Let's say your use case is to add an Asset to a Contract.
You will have an application service with a ContractRepository that will retrieve the Contract, and a method addAsset will be called on that Contract.
When you add an asset to your Contract aggregate, this aggregate will record a domain event, like AssetAdded, with all relevant information about that action. Then your application service will persist the updated Contract in the database and then it will publish the event to an asynchronous bus. In this moment you can send a response.
Some subscriber, inside your application, will be notified about that event and will do stuff. In this case you could have an UpdateAccountOnAssetAdded that internally will do the rest of the job.
This article will help you understand how everything is organized inside this kind of architecture.
Good luck!

Let’s take the last question first. Events are for things that can be done asynchronously and in this case async won’t work. Any time an aggregate is saved it should satisfy all business rules so you have to deal with asset and the account at the same time.
Services should be used sparingly. They operate on more than one AR where none has an enforced relationship with the others. In your case, Contract owns all the other entities involved so all work should be done inside a method on Contract. If that requires a repository, then inject it into the Contract.

Related

Non-task-based interfaces and DDD

What should we do in case when we have UI that's not task based with tasks corresponding to our entity methods which, in turn, correspond to ubiquitous language?
For example, lets say we have a domain model for WorkItem that has properties: StartDate, DueDate, AssignedToEmployeeId, WorkItemType, Title, Description, CreatedbyEmployeeId.
Now, some things can change with the WorkItem and broken down, it boils to methods like:
WorkItem.ReassignToAnotherEmployee(string employeeId)
WorkItem.Postpone(DateTime newDateTime)
WorkItem.ExtendDueDate(DateTime newDueDate)
WorkItem.Describe(string description)
But on our UI side there is just one form with fields corresponding to our properties and a single Save button. So, CRUD UI. Obviously, that leads to have a single CRUD REST API endpoint like PUT domain.com/workitems/{id}.
Question is: how to handle requests that come to this endpoint from the domain model perspective?
OPTION 1
Have CRUD like method WorkItem.Update(...)? (this, obviously, defeats the whole purpose of ubiquitous language and DDD)
OPTION 2
Application service that is called by endpoint controller have method WorkItemsService.Update(...) but within that service we call each one of the domain models methods that correspond to ubiquitous language? something like:
public class WorkItemService {
...
public Update(params) {
WorkItem item = _workItemRepository.get(params.workItemId);
//i am leaving out check for which properties actually changed
//as its not crucial for this example
item.ReassignToAnotherEmployee(params.employeeId);
item.Postpone(params.newDateTime);
item.ExtendDueDate(params.newDueDate);
item.Describe(params.description);
_workItemRepository.save(item);
}
}
Or maybe some third option?
Is there some rule of thumb here?
[UPDATE]
To be clear, question can be rephrased in a way: Should CRUD-like WorkItem.Update() ever become a part of our model even if our domain experts express it in a way we want to be able update a WorkItem or should we always avoid it and go for what does "update" actually mean for the business?
Is your domain/sub-domain inherently CRUD?
"if our domain experts express it in a way we want to be able update a
WorkItem"
If your sub-domain aligns well with CRUD you shouldn't try to force a domain model. CRUD is not an anti-pattern and can actually be the perfect fit for certain sub-domains. CRUD becomes problematic when business experts are expressing rich business processes that are wrongly translated to CRUD UIs & backends by developers, leading to code/UL misalignment.
Note that business processes can also be expensive to discover & model explicitly. Sometimes (e.g. lack of resources) it may be acceptable to let those live in the heads of domain experts. They will drive a simple CRUD UI from paper-based processes as opposed to having the system guide them. CRUD may be perfectly fine here since although processes are complex, we aren't trying to model them in the system which remains simple.
I can't tell whether or not your domain is inherently CRUD, but I just wanted to point out that if it is, then embrace it and go for simpler business logic patterns (Active Record, Transaction Script, etc.). If you find yourself constantly wanting to map every bit of data with a single method call then you may be in a CRUD domain.
Isolate corruption
If you settle that a domain model will benefit your model, then you should stop corruption from spreading through the system as early as you can. This is done with an anti-corruption layer which in your case would be responsible for interpreting CRUD calls and transforming them into more meaningful business processes.
The anti-corruption layer should sit between the parts of the system you want to protect and the legacy/misbehaving/etc part. That would be option #2. In this case the anti-corruption code will most likely have to compare the current state with the new state to try and figure out what changes were done and how to correlate these to more explicit business processes.
Like you said, option 1 is pretty much against the ruleset. Additional offering a generic update is no good to the clients of your domain enitity.
I would go with a 2ish option: having an Application level service but reflecting the UL to it. Your controller would need to call a meaningful application service method with a meaningful parameter/command that changes the state of a Domain model.
I always try to think from the view of a client of my Service/Domain Model Code. As this client i want to know exactly what i call. Having a CRUD like Update is counter intiuitiv and doesn't help you to follow the UL and is more confusing to the clients. They would need to know the code behind that update method to know what they are changing.
To your Update: no don't include a generic update (atleast not with the name Update) always reflect business rules/processes. A client of your code would never know what i does.
In terms if this is a specific business process that gets triggered from a specific controller api endpoint you can call it that way. Let's say your Update is actually the business process DoAWorkItemReassignAndPostponeDueToEmployeeWentOnVacation() then you could bulk this operation but don't go with the generic Update. Always reflect UL.

Best way to coordinate atomic transactions between different business services in .NET Core / EF Core 2.1?

Let's say you have a UsersService, a TenantsService, and a TenantUserRolesService.
Each of these services has a "create" method to create their entity and has the same DbContext dependency injected, except for UsersService which has the Identity UserManager class injected.
Your goal is to provide an API endpoint that lets a new tenant register which creates a User, a Tenant, and a TenantUserRole entity. TenantUserRole is created last and is an associative entity with foreign keys to the newly created User, the newly created Tenant, and the "Owner" Role.
What's the best way to create an atomic transaction between these 3 services, so that if a single create fails, everything is rolled back and the DB is not in a broken state where there are tenants with no users or users with no tenants, etc.
I have looked at: https://learn.microsoft.com/en-us/ef/core/saving/transactions, but I can't figure out if there is a way to use those methods between different service classes.
The only way I can think of is to take an imperative approach and manually check the result of each create, and if there is an error then use the same entity service to delete the recently created entity.
I'm hoping there is someone who is a bit more knowledgeable on the subject that can point me in the right direction.
Thanks
Assuming you are building RESTFul services, please bear in mind that REST services by definition are stateless, and they should not participate in a transactional boundary that spans more than one service.
Your services look like nanoservices. Your data is highly correlated so the way you've broken down your services feels very artificial. What if your application needs to display a list of all Tenants? Have you considered the performance implications and complexity of implementing HATEOUS?
My first suggestion would be to remodel your services. User Roles, User and arguably Tenant the way you've defined it should be in a single API. They're all related to a user and you've also indicated they all share the same dbContext. If this is not possible, the way architects solve the problem that you're trying to solve is through a concept of Eventual Consistency, i.e. synchronize the User, Tenant and User Role stores through some kind of background synchronization process.
Please do not be tempted to wrap your call to 3 APIs around a single transaction. Not only is this completely anti-REST, but chances are you don't need 3 APIs if they're all sharing the same database.
If your transaction extend across service boundaries that is so called Transactional integration antipattern.
One way to coupe with that issue is to use external orchestration service (for example Camunda). It's responsibility would be to handle business flow and do some compensation actions on failure.
It wouldn't be totally "transactional" - ACID properties would be achieved by compensations.
You can create that service by yourself. It's responsibility would be to manage that specific workflow.

DDD Child object references

I have an invoice object, which consists of items, and each item has a relation to service.
Following structure.
{
"invoiceId" : "dsr23343",
"items":{
"id":1,
"service":{
"serviceCode":"HTT"
}
}
}
One of my requirements is that the item should not have a relation to service which does not exist in our system.
From my understanding, domain objects should never enter in an invalid state.
So what I am doing is following:
var service = new Service("SomeService");
var item = new Item(service);
invoice.AddItem(item);
My question is, should i require AddItem function to receive Repository as second parameter, and throw exception if Service does not exist in database?
My question is, should i require AddItem function to receive Repository as second parameter, and throw exception if Service does not exist in database?
Short answer: sure, why not?
Longer answer...
If Service and Invoice are part of the same aggregate, then the repository is unnecessary -- just look at the state of the aggregate. So what follows assumes that there is a transaction boundary between the Invoice and the Service.
Using a Repository as the argument is a bit too much stuff -- Invoice doesn't need to load the Service, it just needs to know if the Service exists. So instead of putting a Repository in the method signature, you could use a DomainService that supports the "does this service exist?" query.
(The implementation of the DomainService probably does a lookup in the Repository -- we're not doing magic here, we're just isolating Invoice from implementation details it doesn't need to know about).
Using the more restrictive interface in the signature documents clearly what the integration contract is between these components.
That said, the requirement is very suspicious. If Service and Invoice are in different aggregates, then they potentially have different life cycles. What is supposed to happen when you try to load an invoice, that includes an item that references a service which no longer exists? Is that use case supposed to explode? if so, it's going to be hard to edit the invoice to fix the problem....
What if, while you are adding the item to the invoice, some other thread is deleting the service...?
Review Udi Dahan's essay: Race Conditions Don't Exist. Executive summary - if your model is sensitive to microsecond variations in timing, you probably aren't modelling your business.
You've got at least three other alternatives to protect this "invariant".
One is at the client level; if you don't let the client produce invalid service codes, then you aren't going to have this problem. Input validation belongs in the client component or in the application component, not so much the model. That is, it's the sort of thing that you might check when the application is constructing the ServiceCode from the DTO that traveled across the process boundary.
One is downstream of the model - if you can detect invoice items that reference service codes that are invalid, then you can broadcast an exception report, and use the contingency response process to manage the problem. Consistency issues that are rare, cheap to detect, easy to fix don't need tight validation in the domain model.
One is within the model itself - if creation of an invoice item is tightly coupled to the lifetime of a service, then maybe the item is created by the service, rather than by the invoice. For example
class Service {
reportUsage(Customer, TimePeriod)
}
Wouldn't be an unusual looking signature, and you can probably be confident that the Service raising a domain event is going to correctly report its own ServiceCode.

Linking together Repository pattern, caching and web-service

I'm try to understand Repository pattern to implement it in my app. And I'm stuck with it in a some way.
Here is a simplified algorithm of how the app is accessing to a data:
At first time the app has no data. It needs to connect to a web-service to get this data. So all the low-level logic of interaction with the web-service will be hiding behind the WebServiceRepository class. All the data passed from the web-service to the app will be cached.
Next time when the app will request the data this data will be searched in the cache before requesting them from the web-service. Cache represents itself as a database and XML files and will be accessed through the CacheRepository.
The cached data can be in three states: valid (can be shown to user), invalid (old data that can't be shown) and partly-valid (can be shown but must be updated as soon as possible).
a) If the cached data is valid then after we get them we can stop.
b) If the chached data is invalid or partly-valid we need to access WebServiceRepository. If the access to the web-service is ended with a success then requested data will be cached and then will be showed to user (I think this must be implemented as a second call to the CacheRepository).
c) So the entry point of the data access is the CacheRepository. Web-service will be called only if there is no fully valid cache.
I can't figure out where to place the logic of verifying the cache (valid/invalid/partly-valid)? Where to place the call of the WebServiceRepository? I think that this logic can't be placed in no one of Repositories, because of violation the Single Responsibility Principle (SRP) from SOLID.
Should I implement some sort of RepositoryService and put all the logic in it? Or maybe is there a way to link WebServiceRepository and WebServiceRepository?
What are patterns and approaches to implement that?
Another question is how to get partly-valid data from cache and then request the web-service in the one method's call? I think to use delegates and events. Is there other approaches?
Please, give an advice. Which is the correct way to link all the functionality listed above?
P.S. Maybe I described all a bit confusing. I can give some additional clarifications if needed.
P.P.S. Under CacheRepository (and under WebServiceRepository) I meant a set of repositories - CustomerCacheRepository, ProductCacheRepository and so on. Thanks #hacktick for the comment.
if your webservice gives you crud methods for different entities create a repository for every entityroot.
if there are customers create a CustomerRepository. if there are documents with attachments as childs create a DocumentRepository that returns documents with attachments as a property.
a repository is only responsible for a specific type of entity (ie. customers or documents). repositories are not used for "cross cutting concerns" such as caching. (ie. your example of an CacheRepository)
inject (ie. StuctureMap) a IDataCache instance for every repository.
a call to Repository.GetAll() returns all entities for the current repository. every entity is registered in the cache. note the id of that object in the cache.
a call to Repository.FindById() checks the cache first for the id. if the object is valid return it.
notifications about invalidation of an object is routed to the cache. you could implement client-side invalidation or push messages from the server to the client for example via messagequeues.
information about the status whether an object is currently valid or not should not be stored in the entity object itself but rather only in the cache.

Services and Repositories in DDD (C#)

How do Services and Repositories relate to each other in DDD? I mean, I've been reading up on DDD for the past 2 days and everywhere I go, there's always a Service layer and there's always a Repository layer. How do these differentiate or compliment each other?
From what I've read, isn't the Repository the layer responsible for delegating interactions between the application and the data?
So, what's the need for the Service layer if it has to implement the Repository to interact with the data anyway even though the Repository probably already implements the methods needed to do so?
I'd appreciate some enlightenment on the subject.
P.S. Don't know if this will help any, but I'm working with an ASP.NET MVC 2 application in which I'm trying to implement the Repository pattern. I just finished implementing the Dependency Injection pattern (for the first time ever)...
UPDATE
Okay, with so many answers, I think I understand what the difference is. So, to review (correct me if I'm wrong):
A Repository layer interacts only with a single object out of the database or the ORM, IEmployeeRepository -> Employee.
A Service layer encapsulates more complex functionality on objects returned from Repositories, either one or multiple.
So, then I have a sub question. Is it considered bad practice to create abstract objects to be sent to my views? For example an AEmployee (A for abstract because to me I means interface) which contains properties from Employee and X or X?
Actually, one more subquestion. If a Service layer can be considered "tuned" for an application does it need to be implemented with an interface?
The Service will use a Repository to retrieve an Entity and then call methods on it (the Entity) to perform the Command/task.
True, a repository works with data (ie. SQL, Webservice etc.) but that's the only job. CRUD operations, nothing more. There is no place for stored procedure based busines logic.
The service (or business logic layer) provides the functionality. How to fullfill a business request (ie. calculate salary), what you have to do.
Oh, and this is a really nice DDD book:
http://www.infoq.com/minibooks/domain-driven-design-quickly
As a concrete example a Shopping Cart application might have the following services:
ShoppingCartService - manages a cart of items with add/remove/update support etc.
OrderService - take a cart, converts it to an order and handles the payment process etc.
each of these services needs to talk a "data source" for CRUD operations. This is where the Repository pattern comes in handy as it abstracts the loading and saving of data to and from the data source be it a database, web service or even in-memory cache.
When you want to create a quick prototype of your application without having to deal with database setup, schema, stored procedures, permissions, etc. you can create a cache or fake repository in a matter of minutes.
For the example above your prototype might start off with the following:
FakeCustomerRepository
FakeAddressRepository
FakeCartRepository
FakeCartLineItemRepository
FakeOrderRepository
FakeOrderLineItemRepository
once your prototype is ready to evolve to the next level you can implement these against a real database:
SQLCustomerRepository
SQLAddressRepository
SQLCartRepository
SQLCartLineItemRepository
SQLOrderRepository
SQLOrderLineItemRepository
From what I can remember, the repository is the final class before the data. The service class can act on data retrieved from the repository. The repository is really just meant to get data to somebody else to do the work. The service layer can provide things such as business logic that all data must pass through. It could also provide for a translation between the application logic and the data layer. But again, this is just what I can remember.
There's no golden standard that defines a service or a repository. In my applications a repository is (as you say) an interface into a database. A service has full access to a repository - but the service exposes a subset of functionality to its consumers.
Think of the repository as more low level. The repository has to expose many ways of accessing the underlying database. A service might combine calls to a repository with other code that only makes sense at a code level (i.e. not in the database), such as access to other state in the application, or validation/business logic that can't easily be applied in a database.

Categories

Resources