Domain Design Question - domain-driven-design

I am working on an application where I can have Teacher, Student etc role. Some of the functionality is similar so I also have a base class User. User contains AddRole method and other stuff.
Now, I want that when the Teacher object is created the "Teacher" role is automatically assigned to the object. I am doing this inside the constructor but I think it is ugly. Here is the code:
public class Teacher : User
{
public Teacher()
{
AddRole(new Role() { RoleName = "Teacher"});
}
}
There is no Teacher table in the database. Everything is User based. Teacher is just a Role and have different functionality then a Student.
How would I go about this?

How about
//C++ look alike pseudocode
public class User{
String role;
User (role_){role = role_;}
String getRole(){return role;}
}
public class Teacher : User
{
public Teacher():User("Teacher")
{
}
}

How does it work in your domain model? Whatever works for your domain model should be in your code.

It's actually quite common to have a Role table that has a 1-to-m or m-to-m relationship with the User table.
The implementation depends highly on how your roles are going to be used. Do they have functions associated with them? Or are they just labels? Are your roles fixed or dynamic? Depending on how they're used and defined, interfaces or inheritance might work for your roles, or actual Role objects might be better.

Related

Aggregate or entity without business attributes

Regarding below excerpt, concerning cqrs and ddd, from Patterns, Principles, and Practices of Domain-Driven Design by Nick Tune, Scott Millett
Does it mean that domain model on command side can omit most of business attributes ?
How would it look like for eg Customer Entity?
Could Customer entity omit FirstName, Surname etc?
If so, where would these business attributes be? Only in read model in CustomerEntity?
Or maybe apart from CustomerEntity containing all business attributes there would also be CustomerAggregate wrapping CustomerEntity with 1:1 relation, and command object would operate on CustomerAggregate? (seems strange to me).
What does it mean "Customer entity desn't make sense"?
The text you pointed means that you do not have to model a reusable Entity for your whole system or even for your whole bounded context (Do not model reusable real life things). Doing this is a bad design.
You have to model an Aggregate that performs an action. You feed the Aggregate with only, and just only, the data needed to perform that action and the aggregate response, the changes the domain suffered, is what you have to persist.
Why Entities and V.O.'s then?
To model consistency, encapsulation and decoupling is the basic part but these are implementation details. For DDD what matters is that are different roles (or concepts).
When feeding the aggregate (constructor, function call parameters, etc) the aggregate has to know if it is working with entities and/or with V.O. to build its response.
If the domain action means a change in an attribute of a entity (something with unique identification in your whole system) the response of the aggregate (once all rules and invariants has been checked) should include the new attribute value and the identification of that entity that allows persist the changes.
So, by default, every aggregate has its own entity with the unique identification and the attributes needed for the aggregate action.
One aggregate could have a Customer entity with ID and its Name.
Another aggregate could have a Customer entity with ID and its Karma points.
So every aggregate has its own inner Customer entity to work with. When you feed an aggregate you pass Customer data (i.e. ID and name or ID and Karma points) and the aggregate treats that info as a entity (It is a matter of implementation details if there is a struct, class, etc internally to the aggregate to represent the entity).
One important thing: If you just need to deal with entities ID's then treat it as a V.O. (CustomerIdentityVO) because the ID is immutable and, probably, in that action you just need to write this CustomerIdentityVO in some field in persistence, not change any Customer attribute.
This is the standard vision. Once you start to identify common structures relevant to several aggregates or one aggregate that can perform several actions with the same data fed you start to refactoring, reusing, etc. It just a matter of good OOP design and SOLID principles.
Please, note that I am trying to be higly above of implementation details. I know that you almost always will have unwanted artifacts that depends of programing paradigm type, chosen programing language, etc. but this approach helps a lot avoiding the worse artifact you could have.
Recommended readings:
http://blog.sapiensworks.com/post/2016/07/29/DDD-Entities-Value-Objects-Explained
http://blog.sapiensworks.com/post/2016/07/14/DDD-Aggregate-Decoded-1
http://blog.sapiensworks.com/post/2016/07/14/DDD-Aggregate-Decoded-2
https://blog.sapiensworks.com/post/2016/07/14/DDD-Aggregate-Decoded-3
and
https://blog.sapiensworks.com/post/2016/08/19/DDD-Application-Services-Explained
for a complete puzzle vision.
If you are using Event Sourcing then it's true that you can model aggregates without adding attributes that they don't need for implementing the business logic.
Here's an example:
class Customer {
public Guid ID { get; private set; }
public Customer(Guid id, firstName, lastName, ...) {
ID = id;
this.AddEvent(new CustomerCreatedEvent(id, firstName, ....);
}
public void ChangeName(firstName, lastName) {
this.AddEvent(new CustomerRenamedEvent(this.ID, firstName, lastName),
}
}
Custom only has ID attribute because it needs it to add it to every event that it generates. FirstName and LastName are omitted as they are not needed even when ChangeName method is called. It only records an event that this happened. If your logic requires the FirstName then you can add it. You can omit any properties that you don't need.
Your Repository in this case will save only the events and won't care about the values of the attributes of the Customer.
On the Read side you will probably need these properties as you will display them to your users.
If your aggregates are not event sourced, then you probably will need more attributes on your aggregate to implement it's logic and they will be saved to the database.
Here's an example:
class Customer {
public Guid ID { get; private set; }
public string FirstName { get; private set; }
public string LastName { get; private set; }
public void ChangeName(firstName, lastName) {
FirstName = firstName;
LastName = lastName;
}
}
In this case your Repository will need these properties as it will generate a query to update the database with the new values.
Not sure what "Customer entity doesn't make sense" means.

Can I create multiple identity tables in ASP.NET MVC?

In my project, Admin adds Instructors, then each Instructor adds his students. When they are added, they'll receive an email asks them to complete registration .
I have the following classes in my project :
1-Student class
Student: int id, int Registry number, int grade, string password, string email, string name
2-Instructor class:
Instructor: int id, string name , string email , string password
3-My database context:
public class InstructorContext:DbContext
{
public InstructorContext() : base("InstructorContext")
{
}
public DbSet<Instructor> Instructors { get; set; }
public DbSet<Student> Students { get; set; }}
When a user loges in , I must determine whether he is an Admin or Instructor or Student. Do I have to use role-based authentication? I already have 2 separate classes for different roles. Is it possible for both of them to inherit from IdentityUser?
No, you cannot have multiple user tables with Identity, at least not technically. All the other core components of Identity (roles, claims, logins, etc.) are setup with foreign keys to one user table.
For your scenario here, you should use inheritance. For example:
public class ApplicationUser : IdentityUser
public class Instructor : ApplicationUser
public class Student : ApplicationUser
By default, Entity Framework will create the one table for ApplicationUser and add a Discriminator column to it. This column will have one of three possible values: "ApplicationUser", "Instructor", and "Student". When EF reads from this table, it will use this column to instantiate the right class. This is what's known as single-table inheritance (STI) or alternatively as table-per-hierarchy (TPH). The main downside to this approach is that all of the properties for all of the classes must be represented on the same table. If you're creating a new Student for example, the columns for an Instructor would still be on the record, only with nulls or defaults for those values. This also means that you can't enforce a property on something like Instructor be required at the database level, as that would prevent saving ApplicationUser and Student instances which are unable to provide those values. In other words, all your properties on your derived classes must be nullable. However, you can always still enforce something like a property being required for the purpose of a form using view models.
If you really want to have separate tables, you can somewhat achieve that goal by changing the inheritance strategy to what's called table-per-type (TPT). What this will do is keep the table for ApplicationUser, but add two additional tables, one each for Instructor and Student. However, all the core properties, foreign keys, etc. will be on the table for ApplicationUser, since that is where those are defined. The tables for Instructor and Student would house only properties that are defined on those classes (if any) and a foreign key to the table for ApplicationUser. When querying, EF will then do joins to bring in the data from all of these tables and instantiate the appropriate classes with the appropriate data. Some purists like this approach better as keeps the data normalized in the database. However, it's necessarily heavier on the query side because of the joins.
One last word of caution, as this trips people up constantly dealing with inheritance with Identity. The UserManager class is a generic class (UserManager<TUser>). The default instance in AccountController, for example, is an instance of UserManager<ApplicationUser>. As a result, if you use that instance, all users returned from queries will be ApplicationUser instances, regardless of the value of the Discriminator column. To get Instructor instances, you would need to instantiate UserManager<Instructor> and use that for your Instructor-related queries.
This is especially true with creating users for the first time. Consider the following:
var user = new Instructor();
UserManager.Create(user);
You might expect that the user would be saved with a discriminator value of "Instructor", but it will actually be saved with "ApplicationUser". This is because, again, UserManager is an instance of UserManager<ApplicationUser> and your Instructor is being upcasted. Again, as long as you remember to use the appropriate type of UserManager<TUser> you'll be fine.

How to model inheritance on DDD?

I am currently trying out DDD and reading Evans book. I have arrived at a model that has an aggregate whose root is Student. Now I need to have (or be able to distinguish) a RegisteredStudent and an EnrolledStudent (inherits RegisteredStudent). I don't know how to handle inheritance in DDD.
Should the 2 inherited classes be inside the aggregate? If so, are they also considered aggregate roots since their identity is the same as the root (there are only added properties to them)? If not, how do I give access to them from other entities?
Or should I not be using inheritance? Why?
And also, what if you have an entity in an aggregate that isn't a root, but you need it to inherit an entity outside? How should you go about it?
What you need to ask yourself here is whether a RegisteredStudent and an EnrolledStudent are different concepts. Are they not both students, but just in a different state?
In general, you should favor composition over inheritance.
Here's an example of what I would do. (Note that it's just my example, I don't know the domain, so it's not a definitive solution).
You could have a Student class, which is your aggregate root and then a few different state classes: Registered and Enrolled. That way you don't need to expose these state classes on the student but you could just expose methods on the Student. A small example in C#:
class Student
{
State _currentState;
void Enroll()
{
if(!_currentState is Registered)
throw new InvalidOperationException("Cannot enroll student who is not registered");
this._currentState = new Enrolled();
}
void Register(string name)
{
this._currentState = new Registered(name);
}
}
class StudentState{}
class Enrolled : StudentState
{}
class Registered : StudentState
{
public Registered(string name)
{
Name = name;
}
public string Name {get; private set;}
}
This is a simple application of the State design pattern, you could externalize more parts of it and build a complete state-machine, but I'll leave that up to you. (Also it's typed directly in to the SO-editor, so there could be syntax errors)
EDIT after comments
Whether you need to expose a State-property or not depends on the context. In general I would recommend not to do that, because you're exposing the internals of the Student. It would be better to expose a method called CanEnroll for example. That way you can change the internal implementation of your state pattern without affecting any clients.
As for question 3, it's hard to say without a use case. However, here are some guidelines:
Favor composition over inheritance (again, I know).
You can have a reference from inside an aggregate to the outer world, you shouldn't have a reference the other way around though.

Domain Driven Design: Repository per aggregate root?

I'm trying to figure out how to accomplish the following:
User can have many Websites
What I need to do before adding a new website to a user, is to take the website URL and pass it to a method which will check whether the Website already exist in the database (another User has the same website associated), or whether to create a new record. <= The reason for this is whether to create a new thumbnail or use an existing.
The problem is that the repository should be per aggregate root, which means I Cant do what I've Explained above? - I could first get ALL users in the database and then foreach look with if statement that checks where the user has a website record with same URL, but that would result in an endless and slow process.
Whatever repository approach you're using, you should be able to specify criteria in some fashion. Therefore, search for a user associated with the website in question - if the search returns no users, the website is not in use.
For example, you might add a method with the following signature (or you'd pass a query object as described in this article):
User GetUser(string hasUrl);
That method should generate SQL more or less like this:
select u.userId
from User u
join Website w
on w.UserId = u.UserId
where w.Url = #url
This should be nearly as efficient as querying the Website table directly; there's no need to load all the users and website records into memory. Let your relational database do the heavy lifting and let your repository implementation (or object-relational mapper) handle the translation.
I think there is a fundamental problem with your model. Websites are part of a User aggregate group if I understand correctly. Which means a website instance does not have global scope, it is meaningful only in the context of belonging to a user.
But now when a user wants to add a new website, you first want to check to see if the "website exists in the database" before you create a new one. Which means websites in fact do have a global scope. Otherwise anytime a user requested a new website, you would create a new website for that specific user with that website being meaningful in the scope of that user. Here you have websites which are shared and therefore meaningful in the scope of many users and therefore not part of the user aggregate.
Fix your model and you will fix your query difficulties.
One strategy is to implement a service that can verify the constraint.
public interface IWebsiteUniquenessValidator
{
bool IsWebsiteUnique(string websiteUrl);
}
You will then have to implement it, how you do that will depend on factors I don't know, but I suggest not worrying about going through the domain. Make it simple, it's just a query (* - I'll add to this at the bottom).
public class WebsiteUniquenessValidator : IWebsiteUniquenessValidator
{
//.....
}
Then, "inject" it into the method where it is needed. I say "inject" because we will provide it to the domain object from outside the domain, but .. we will do so with a method parameter rather than a constructor parameter (in order to avoid requiring our entities to be instantiated by our IoC container).
public class User
{
public void AddWebsite(string websiteUrl, IWebsiteUniquenessValidator uniquenessValidator)
{
if (!uniquenessValidator.IsWebsiteUnique(websiteUrl) {
throw new ValidationException(...);
}
//....
}
}
Whatever the consumer of your User and its Repository is - if that's a Service class or a CommandHandler - can provide that uniqueness validator dependency. This consumer should already by wired up through IoC, since it will be consuming the UserRepository:
public class UserService
{
private readonly IUserRepository _repo;
private readonly IWebsiteUniquenessValidator _validator;
public UserService(IUserRepository repo, IWebsiteUniquenessValidator validator)
{
_repo = repo;
_validator = validator;
}
public Result AddWebsiteToUser(Guid userId, string websiteUrl)
{
try {
var user = _repo.Get(userId);
user.AddWebsite(websiteUrl, _validator);
}
catch (AggregateNotFoundException ex) {
//....
}
catch (ValidationException ex) {
//....
}
}
}
*I mentioned making the validation simple and avoiding the Domain.
We build Domains to encapsulate the often complex behavior that is involved with modifying data.
What experience shows, is that the requirements around changing data are very different from those around querying data.
This seems like a pain point you are experiencing because you are trying to force a read to go through a write system.
It is possible to separate the reading of data from the Domain, from the write side, in order to alleviate these pain points.
CQRS is the name given to this technique. I'll just say that a whole bunch of lightbulbs went click once I viewed DDD in the context of CQRS. I highly recommend trying to understand the concepts of CQRS.

Domain Driven Design - Entities VO's and Class Hierarchy

The shorter version of the Question: "Is it ok to have a superclass, with 2 subclasses, one is an entity the other is a Value Object?"
To longer version:
T have a Team superclass. The Team has the Master, Helpers and a Code.
Then i have the DefaultTeam, subclass of Team, which is an entity with an unique **Code**** has its domain identity.
Then i have the **ExecutionTeam, its a subclass of Team and has an extra attribute OriginalTeam:
public abstract class Team{
public string Code{ get; protected set; }
public Worker Master{ get; protected set; }
public IList<Worker > Helpers { get; protected set; }
...
}
public class DefaultTeam: Team
{
}
public class ExecutionTeam : Team
{
public virtual string Code { get { return OriginalTeam.Code; } }
public virtual DefaultTeam OriginalTeam { get; private set; }
...
}
The ExecutionTeam, is the team that executes a Task.
When a Task needs to be executed, we choose a DefaultTeam to execute it.
But we can change the Helpers from the DefaultTeam (the master never changes).
That team that executes the task, is a variation of the DefaultTeam (OriginalTeam), but with the Helpers that were chosen just for that Task.
The ExecutionTeam will have the same code has the OriginalTeam. So the ExecutionTeam has no unique identity.
If there are 10 executions of tasks by the same DefaultTeam, there will be 10 ExecutionTeams with the same code (with the same OriginalTeam). So ExecutionTeam is cannot be an Entity.
But having an Entity and a Value Object sharing the same superclass (both being Teams), is a bit strange. Maybe this domain model has something wrong.
Need opinions.
Thanks
What is it that makes the DefaultTeam a Value Object rather than an Entity? Isn't a DefaultTeam also an entity?
That being said, here are some comments:
Why do you need a special class for DefaultTeam? Can't a DefaultTeam simply be an ExecutionTeam, with certain specified values?
A DefaultTeam should probably be an instance of a Team that is associated with an application domain. For example, you might have a particular team that is generally used to solve problems with Project XYZ.
Instead of listing "DefaultTeam" as a property of the ExecutionTeam, you should probably have a "PreviousTeam" as a property of both the Team and ExecutionTeam classes.
This will be more generalizable, in case the team gets changed yet again.
Since Task is an important part of the domain and is assigned to a Team, it should probably be a property of Team.
"Helpers" doesn't seem an appropriate name for the team members. Why not just name them "Members" or "TeamMembers"?
"Master" is probably un-PC unless you are working in Dilbert land or dealing with a database :) You might want to change this to "Supervisor" or "Manager".
"Code" is probably a bad name in the context of your application, as it may easily be confused with programming code. You might want to use "Id" or "TeamId" instead.
Sounds like ExecutionTeam might be better modeled as an interface ICanExecuteTasks. Would that work for you? It would eliminate the issue you are struggling with..
As to your short question, if the ExecutionTeam was indeed a derived class of Team, (inheriting from team and representing an "IsA" relatoonship, then the answer is No, they cannot be of different types because of course, every ExecutionTeam isA Team, thgere is only one thing, which is both a Team and an ExecutionTeam at the same time... It cannot be both an entity Type and a value type at the same time.
But the way you have designed the classes, as you have structured things, ExcecutionTeam is not a derived class, it is a property of the DefaultTeam. This implies that they have a "HasA" relationship. THis implies that they are different, co-existing objects, one of which can be an entity and one of which can be a value type. But my gut tells me this is not an accurate mirror of your real domain model...

Resources