In the pre 4.4 version of abp.io when implementing IssueTracking Implementing Domain Driven Design using DDD principles, a custom user profile AppUser was used to add custom properties. I would like to have some custom collections associated with that custom user profile as well as some navigation properties and simple properties. Also I would like to have some inheritance hierarchy between some children and their base: custom user profile.
Now that version 4.4 and 5 are out (with .net 6) I was wondering if AppUser is still allowed to extend IdentityUser class. It was convenient to introduce navigation properties, simple properties and to add some collections of related entities.
I wanted to know how to establish 1 to many, 1 to 1 and many to 1 relationships with Custom
User class (for example in a Real Estate app I might have person (user) who might be a seller, buyer and agent and Person might have its separate relationships with other entities and seller, buyer, agent that inherit from Person (or have 1 to 1 relationship with Person) might have their own relationships.
Of course I would like to be able to manage these relationship in a User registration and edit forms so I can select or search for related entities.
Can anyone point me to some examples on how to do all of this in DDD abp.io 4.4+ way.
I would like to see this user profile extensibility explained in one topic instad of being spread thoughout documentation. It only covers the case of SSN adding a simple property.
We need more complex cases.
Thanks
Rad
Related
I'm facing an case with my new microservice application.
I have an Entity as users (An single table, but different roles).
consider i have roles as manager and reader, And one more entity as
Book.
Where the manager can assign Books to readers, And i have Microservices as usermS, bookmS.
When i want to get all the readers of Book-A, the API will go in to bookmS, but the user details are still with the usermS.
And also combined searches.
I'm more worried about the paginations and search for the readers, if the readers for a Book keeps increasing. Expected to get roles in future.
My ddd vision of your problem:
You have 2 bounded contexts, each one a microservice, and you have to integrate both of them translating concepts:
Identity and access management (IAM). Here you have the concepts of users and roles.
Library: Here you have the concepts of managers and readers, which are roles in IAM.
Regarding searches and information about readers, in the IAM bounded context you have the login name and the password for example, but IAM doesn't know about other details of a reader.
UPDATE: About duplication of data
In your comment https://stackoverflow.com/posts/comments/101968503?noredirect=1 , you mean duplicated data across different entities inside the same BC don't you? For example, having an email in Reader and Manager entities? You could do an abstract base entity with the common data, and both entities inherit from it. This is the approach in Vaughn Vernon's book.
The duplication of data just exists across different BCs if you go for an async integration. But there's no denormalization, each BC has its own database, and each database is normalizated.
Library BC (downstream) and IAM BC (upstream) are enventually consistent. Library BC will listen to IAM BC events, and will update its database. This means a delay that it is supposed you can live with. Regarding email, I wouldn't allow to modify it, since it is the login for the user, but that's just my opinion.
If you don't want to duplicate data across BCs, or you cannot live with the update delay in the downstream BC, you could go for a sync integration. So that everytime the Library BC needs data from the IAM BC, it calls an http rest api that IAM BC offers, and waits for the response.
Lets first break down your problem:
start with the easy one:
When i want to get all the readers of Book-A, the API will go in to bookmS, but the user details are still with the usermS.
your doubt here is how to show the user details from the bookms?
there are two options :
When some user becomes a reader of your book save user name and email type of details in the reader object in bookms so that you could shown them , also listen to event of user detail change from userms so that you could update the readers.
good part here is that there is no dependency between userms and bookms.
bad part here is that you may need to update multiple reader entity when a user detail changes, small optimizations here is just update in the read model.
get data first from bookms and then from userms .
good part : no event listening , always consistent data.
bad part: high dependency between bookms and userms and And also combined searches.
i would have gone with the first approach assuming user dosen't change the basic details on which you need to show data very frquently.
SECOND QUESTION:
How to break the system using DDD?
In this the first answer written given right direction to it. i just want to add a bit more.
You should consider manager and reader as entity in bookms and not as roles.
Reason from DDD and in general:
In General: A user could be managing a book and as well a reader .
DDD: Manager and Reader are notions which bookms (which actually should be named libraryms ) are part of the domain entity.
So your solutions would be:
userms :
user: person which has access to library and can apply for being a manager or a reader. there could be two roles - student , admin .
libraryms:
Manager Entity - users which are allowed to subscribe a book to readers.
ReaderEntity - any user which has taken a book subscriptions
BookEntity - represents a book registered in the library
BookSubscriptionEntity - its your choice, you could use the BookEntity but i would prefer this.
Now by separating the role as admin and manager as entity you achieved two things.
One is now a admin could be a reader as well and a student can be a manager as well.Also library microservice works according to DDD , easy to understand and some api like assign book to reader dosent need to check anyhthing from userms
I am feeling stuck in my MPA ABP app development between three principles that I believe are DDD ones :
Application service has not to be tied to a controller. I mean a controller doesn't have to use always only one application service. Because application service conception has not presentation in mind.
DTO has to fit the view needs to minimize HTTP data transfer. So sometimes we have to design one DTO class per entity/concept and per view.
Application services get and return always DTO's.
Now I have a view which follows the Master-Detail principle: select one entity in the Master part from an entity list loads entity details in the Details part by Ajax call. But the entity selection in Master part is made by Ajax-synchronized cascade of dropdown lists: ParentEntities > Entities.
What choice respects better DDD ?
Put GetAllParent(), GetAllEntities(parentId) and GetEntity(id) all in MyViewApplicationService, then my application service can return optimized DTO's for my view needs, but violates DDD principle,
Put each of theses three methods in different application services, isolated more "domain" in mind, but DTO's are domain-oriented, somewhat generic. So DTO's are not optimized.
Let the controller the responsability to map into a DTO that fits view needs, but it should not do that.
Application service has not to be tied to a controller. I mean a controller doesn't have to use always only one application service.
Because application service conception has not presentation in mind.
Application services are not tied to the client type, but to the client needings. They return the data that client needs, so in that sense application services has the client (presentation) in mind.
Application services get and return always DTO's.
Not always. There are alternatives to DTOs, as Vaughn Vernon says in his book Implementing DDD (page 512):
Mediator
Domain Payload Object
State Representations
Use Case optimal repository queries (closed to CQRS)
Data Transformers
What choice respects better DDD ?
Put GetAllParent(), GetAllEntities(parentId) and GetEntity(id) all in MyViewApplicationService, then my application service can return
optimized DTO's for my view needs, but violates DDD principle,
You shouldn't name the application service refering the client technology (MyView), but according to the functionality it offers.
Put each of theses three methods in different application services, isolated more "domain" in mind, but DTO's are
domain-oriented, somewhat generic. So DTO's are not optimized.
It doesn't matter if you put the 3 methods in just one service or you have one service for each method. The controller should call them anyway.
Let the controller the responsability to map into a DTO that fits view needs, but it should not do that.
If you mean the application service returns domain objects and the controller translates them to DTOs, then no, you shouldn't do that as you are exposing the domain to clients.
I understand your problem I think, let's start at the beginning:
...Put GetAllParent(), GetAllEntities(parentId) and GetEntity(id) all in MyViewApplicationService...
Which of those words would a business person understand? Are any of those words part of the ubiquitous language?
They are of course all purely technical, therefore should be detail and should not influence the architecture. Basically they would be in the wrong place, they should not be visible at all.
...but DTO's are domain-oriented, somewhat generic. So DTO's are not optimized...
DTOs should not be part of anything remotely object-oriented. However, you did not say you want object-orientation so let's not dwell on that.
Still, if your object is supposed to be domain-oriented, then how come it's unfit (not optimized) for the application that is written specifically for that domain?
I think the problem is that your "object" is actually modeling something different than the domain. It's likely modeling the database table or its records.
I mean, if you are showing a profile for a product, then your "object" should be ProductProfile, not the generic Product. Or ProductDetails, or ProductHeroImage, and so on. Those things are of the domain and likely mentioned in the requirements document too.
Let the controller the responsability to map into a DTO that fits view needs, but it should not do that.
Why should it not do that? If the purpose of your feature is to show some data to the user, then why is that not considered a "business function". I mean it should be literally the other way around. The "view" is the business function you want, and the database/repository/controller/service or whatever is "just" technology that should be just a detail and not visible in the architecture.
Disclaimer: I must admit these views are not what most projects do under DDD, but maybe you find some sense in it to question those projects more in the future.:)
Not quite sure how to approach this problem regarding DDD.
Say you have 2 domains:
A Product domain which is responsible for creating new and managing existing Products which a person has created. Product Aggregate Root
A Store domain which is responsible for assigning all created Products to a given Store to be sold, and other stuff. But the Store can also create new Products which will be assigned to themselves but also available for other Stores so that they can assign the Product to themselves. Store Aggregate Root
A Product can exist without belonging to a Store. A Store can exist without having any Products in it whatsoever (doesn't make sense I know, but this is just a simple example of a complex solution I'm working on atm.)
So when a Person comes along into the system, they can start at either end. They can start by creating new Products or they can start by adding a new Store.
Here is where it gets complicated, when they create a new Store, they are given the option to add existing Products or they can create a new Product and add it to the Store.
How do you deal with this use case. is the does the Store have a behavior to CreateNewProduct where it's responsible to setting up the new Product and then adding it to the Store. Or do you simply create a new Product outside the Store Domain as part of the Product domain, and tell the Store to AddProduct / AddExistingProduct?
UPDATE: Would something like this be appropriate as a Domain Service
public class StoreProductService {
public Store CreateNewStoreProduct (Store store, string sku, string name, etc){
Product newProduct = ProductFactory.CreateNewProduct(sku, name, etc);
store.AddProduct(newProduct);
return store;
}
}
You need the two domains to communicate with each other. You can communicate using various methods but one common way is to use a REST API. In your Store domain, you need something that communicates or knows how to communicate with the API. I have generally implemented these as a service that wraps api calls. The service will be able to understand your domain Ubiquitous language and will translate that into API commands. You can use domain events to possibly listen for when the product has been created and then you can associate the store with the product or you can implement some kind of polling mechanism.
An example was requested, so here goes:
Call from UI (probably from a controller)
StoreService.CreateStore(storeName: String, newProduct : StoreProduct)
You could pass in primitives to represent the newproduct. This allows you to create a new product without the need for a new class for it. You subsequently don't need a shared infrastructure class or converter between your domain and UI layers.
StoreService
public StoreService
{
public StoreService(ProductApiClient productApiClient...)...
public void CreateStore(string StoreName, StoreProduct prod...)
{
var newStore = StoreFactory.Create(storeName);
//below might be better as an asynch call but for simplicity
//keeping it all synchronous
var newProd = productApiClient.CreateProduct(prod);
//check if product was created successfully, if so
newStore.Add(newProd);
//save
StoreRepo.Create(newStore);
//check if store was created successfully
}
The main points to take from here:
Create your aggregate entity using a factory (at this state it has not being persisted).
You need a repo to serialize and persist your new store to your data store.
productApiClient will translate between your domain model and a request to the productApi. It knows how to generate an Api request (if REST for example) given domain entities.
ProductApiClient will return a domain entity from the Api Response.
You add a new product to a store using the store entity.
You persist your store using the repo
You may choose to pick a more asynchronous approach if the call to the api is time consuming.
This example illustrates the power of DDD and the separation of concerns. Depending on the size of your project and your requirements, this might be overly tedious so fit it to your needs, skills and requirements.
This business problem is very common. You surely can find some of examples about eCommerce systems with DDD.
Typical situation is that you have not finished developing your UL. If you discuss the Store (I won't mark it as code since I am talking about UL terms, not classes) with your domain experts, you can find out that Store only cares about Product Availability, not the Product itself.
Typically, your Product that belongs to a Product Catalogue, has little to do with the availability. It might have general description, manufacturer details, country of origin, picture, package size and weight and so on.
Product Availability, however, has, well, the availability, i.e. count of available product items. It might have some extra details, for example a count of reserved items, expected to arrive items and so on.
The fact is that often both of these concepts, despite they are rather different, are referred by domain experts as "Product". This is a typical example of two separate Bounded Contexts.
As soon as you have two different things that are called Product in two different Bounded Contexts (and physical places), you will need to keep them in sync. This is usually done by publishing domain events outside of the Bounded Contexts and updating the other side by subscribing to these events there and doing internal domain command handling inside the Bounded Context.
I am developing a Java EE business management application using the following technologies:
JSF
JPA
GlassFish 4
Derby 10.10.1.1
As a start, I created the following objects:
Person (JPA Entity)
Name
Address
Email
etc.
PersonManager (Stateless EJB)
createPerson
deletePerson
updatePerson
findPersonById
I then created the following xhtml pages with backing beans.
PersonCreater
PersonViewer
PersonUpdater
Using JSF and JPA, I found it easy to create the xhtml with backing bean to support creating, viewing and updating my person object.
Using the Java EE Security #RolesAllowed annotation, it was easy to limit access to the PersonManager methods to specific roles, and using the web.xml security-constraint element it was easy to limit JSF page access to specific roles.
I am now to the point where I want to add sensitive information such as social security number to my Person entity, but I only want specific roles to be able to create, read and update the sensitive information. Is there a standard way to add sensitive information to an entity and then control access?
My fundamental problem is with the PersonManager's getPersonById method. Currently, this method looks like the following:
#RolesAllowed("Reader")
public Person findPersonById(long id) {
return em.find(Person.class, id);
}
If I add the social security number property to the Person entity, the method will return the social security number with the returned Person to all users with role Reader. Of course, I want everyone to be able to read most of the data associated with my Person object, but I don't want everyone to be able to read the Person's social security number.
I could add logic to the gerPersonById method to remove sensitive information from the Person object based on the current role using the EJBContext's getCallerPrincipal and isCallerInRole methods. Is this a good way to limit access to the social security property?
I thought about putting all the sensitive information in another entity called PersonSensitive and then creating a OneToOne relationship between Person and PersonSensitive. However, this leads me back to the problem of how do I limit access to specific entity fields based on the current role. I tried using #RolesAllowed on the Person entity but this did not work.
I might be able to use some type of inheritance scheme where the sensitive data belongs to a descendant of Person and only specific roles can access the descendant's manager methods. However, this leads me to creating sets of JSF pages where each set is designated for use by a specific role. Maybe this is the best way to move forward but it seems like it will require much extra work.
Despite having studied Domain Driven Design for a long time now there are still some basics that I simply figure out.
It seems that every time I try to design a rich domain layer, I still need a lot of Domain Services or a thick Application Layer, and I end up with a bunch of near-anemic domain entities with no real logic in them, apart from "GetTotalAmount" and the like. The key issue is that entities aren't aware of external stuff, and it's bad practice to inject anything into entities.
Let me give some examples:
1. A user signs up for a service. The user is persisted in the database, a file is generated and saved (needed for the user account), and a confirmation email is sent.
The example with the confirmation email has been discussed heavily in other threads, but with no real conclusion. Some suggest putting the logic in an application service that gets an EmailService and FileService injected from the infrastructure layer. But then I would have business logic outside of the domain, right? Others suggest creating a domain service that gets the infrastructure services injected - but in that case I would need to have the interfaces of the infrastructure services inside the domain layer (IEmailService and IFileService) which doesn't look too good either (because the domain layer cannot reference the infrastructure layer). And others suggest implementing Udi Dahan's Domain Events and then having the EmailService and FileService subscribe to those events. But that seems like a very loose implementation - and what happens if the services fail? Please let me know what you think is the right solution here.
2. A song is purchased from a digital music store. The shopping cart is emptied. The purchase is persisted. The payment service is called. An email confirmation is sent.
Ok, this might be related to the first example. The question here is, who is responsible for orchestrating this transaction? Of course I could put everything in the MVC controller with injected services. But if I want real DDD all business logic should be in the domain. But which entity should have the "Purchase" method? Song.Purchase()? Order.Purchase()? OrderProcessor.Purchase() (domain service)? ShoppingCartService.Purchase() (application service?)
This is a case where I think it's very hard to use real business logic inside the domain entities. If it's not good practice to inject anything into the entities, how can they ever do other stuff than checking its own (and its aggregate's) state?
I hope these examples are clear enough to show the issues I'm dealing with.
Dimitry's answer points out some good things to look for. Often/easily you find yourself in your scenario, with a data shoveling from db up to GUI through different layers.
I have been inspired by Jimmy Nilsson's simple advice "Value objects, Value objects and more Value objects". Often people tend to focus to much on Nouns and model them as entity. Naturally you often having trouble in finding DDD behavior. Verbs are easier to associate with behavior. A good thing is to make these Verbs appear in your domain as Value objects.
Some guidance I use for my self when trying to develop the domain (must say that it takes time to construct a rich domain, often several refactoring iterations...) :
Minimize properties (get/set)
Use value objects as much as you can
Expose as little you can. Make you domain aggregates methods intuitive.
Don't forget that your Domain can be rich by doing Validation. It's only your domain that knows how to conduct a purchase, and what's required.
Your domain should also be responsible for validation when your entities make a transition from one state two another state (work flow validations).
I'll give you some examples:
Here is a article I wrote on my blog regarding your issue about anemic Domain http://magnusbackeus.wordpress.com/2011/05/31/preventing-anemic-domain-model-where-is-my-model-behaviour/
I can also really recommend Jimmy Bogard's blog article about entity validations and using Validator pattern together with extension methods. It gives you the freedom to validate infrastructural things without making your domain dirty:
http://lostechies.com/jimmybogard/2007/10/24/entity-validation-with-visitors-and-extension-methods/
I use Udi's Domain Events with great success. You can also make them asynchronous if you believe your service can fail. You also wrap it in a transaction (using NServiceBus framework).
In your first example (just brainstorming now to get our minds thinking more of value objects).
Your MusicService.AddSubscriber(User newUser) application service get a call from a presenter/controller/WCF with a new User.
The service already got IUserRepository and IMusicServiceRepository injected into ctor.
The music service "Spotify" is loaded through IMusicServiceRepository
entity musicService.SignUp(MusicServiceSubscriber newSubsriber) method takes a Value object MusicServiceSubscriber.
This Value object must take User and other mandatory objects in ctor
(value objects are immutable). Here you can also place logic/behavior like handle subscriptionId's etc.
What SignUp method also does, it fires a Domain Event NewSubscriberAddedToMusicService.
It get caught by EventHandler HandleNewSubscriberAddedToMusicServiceEvent which got IFileService and IEmailService injected into it's ctor. This handler's implementation is located in Application Service layer BUT the event is controlled by Domain and MusicService.SignUp. This means the Domain is in control. Eventhandler creates file and sends email.
You can persist the user through eventhandler OR make the MusicService.AddSubscriber(...) method to this. Both will do this through IUserRepository but It's a matter of taste and perhaps how it will reflect the actual domain.
Finally... I hope you grasp something of the above... anyhow. Most important is to start adding "Verbs" methods to entitys and making the collaborate. You can also have object in your domain that are not persisted, they are only there for mediate between several domain entities and can host algorithms etc.
A user signs up for a service. The user is persisted in the
database, a file is generated and saved (needed for the user account),
and a confirmation email is sent.
You can apply Dependency Inversion Principle here. Define a domain interface like this:
void ICanSendConfirmationEmail(EmailAddress address, ...)
or
void ICanNotifyUserOfSuccessfulRegistration(EmailAddress address, ...)
Interface can be used by other domain classes. Implement this interface in infrastructure layer, using real SMTP classes. Inject this implementation on application startup. This way you stated business intent in domain code and your domain logic does not have direct reference to SMTP infrastructure. The key here is the name of the interface, it should be based on Ubiquitous Language.
A song is purchased from a digital music store. The shopping cart
is emptied. The purchase is persisted. The payment service is called.
An email confirmation is sent. Ok, this might be related to the first example. The question here is, who is responsible for orchestrating this transaction?
Use OOP best practices to assign responsibilities (GRASP and SOLID). Unit testing and refactoring will give you a design feedback. Orchestration itself can be part of thin Application Layer. From DDD Layered Architecture:
Application Layer: Defines the jobs the software is supposed to do and directs the
expressive domain objects to work out problems. The tasks this layer
is responsible for are meaningful to the business or necessary for
interaction with the application layers of other systems.
This layer is kept thin. It does not contain business rules or
knowledge, but only coordinates tasks and delegates work to
collaborations of domain objects in the next layer down. It does not
have state reflecting the business situation, but it can have state
that reflects the progress of a task for the user or the program.
Big part of you requests are related to object oriented design and responsibility assignment, you can think of GRASP Patterns and This, you can benefit from object oriented design books, recommend the following
Applying UML and Patterns