I am developing an small application, just to practice DDD. Afaik. invariants are the umbrella term of validation related to domain. So for example if I want to have only ucfirst names, then that is an invariant and I need validation in the property setter to make sure that this invariant is protected and make only the setter public, not the property itself.
My current problem is that I need to have usernames, which are generated from firstname, lastname, birthDate and probably some random stuff, if these are not unique enough. As far as I understand having a unique username is a domain concern, because it is very important if you want to login, or just bind some data to an actual user. So having a database table with pk on the username and wait for violating constraint error is just not enough, I should put some code into the domain, which makes sure that the generated username will be unique. I guess the code goes into the repository or into the entity somehow. Can you show me an example how this would look like in a real app? The domain and the app service implementation what I am curious of.
I might not be right about this. Every entity has a unique identifier and has repository, so probably I should put the username generation into the repository, and that's all. I might need to rephrase this for example what if we don't have a unique identifier, just a property which should be unique?
I made a little code draft:
class CustomerService {
// ...
public createCustomerFromNameAndYear(name, year){
try {
transaction.begin();
username = generateUsername(name, year);
while (repo.findByUsername(username))
username = addSomeRandomChar(username, 1);
password = "";
password = addSomeRandomChar(password, 6);
customer = new Customer(username, password, name, year);
repo.save(customer);
transaction.commit();
dto = new CustomerDTO(customer.getUsername(), customer.getPassword());
return dto;
}
catch(exception) {
transaction.rollback();
throw new ExceptionWithCauses(CUSTOMER_CREATION_FAILED, exception.getMessage());
}
}
}
If I put this into the app service, it will ensure that the name is unique unless if concurrence happens, but sending an error message is okay in that rare case. I am not sure whether this is okay. It does not feel right if the invariants must be parts of the domain code.
Another possible solution to have a create method in the repo.
class CustomerService {
// ...
public createUserFromNameAndYear(name, year){
try {
transaction.begin();
customer = repo.create(name, year);
transaction.commit();
dto = new CustomerDTO(customer.getUsername(), customer.getPassword());
return dto;
}
catch(exception) {
transaction.rollback();
throw new ExceptionWithCauses(CUSTOMER_CREATION_FAILED, exception.getMessage());
}
}
}
class CustomerRepository implements iCustomerRepository {
// ...
public create(name, year){
username = generateUsername(name, year);
while (this.findByUsername(username))
username = addSomeRandomChar(username, 1);
password = "";
password = addSomeRandomChar(password, 6);
customer = new Customer(username, password, name, year);
this.save(customer);
return customer;
}
}
This might be better.
UsernameAllocation
that dealt with unique usernames. I had a requierement that the user must choose another username in case of conflicts.