I have an immutable User
entity:
public class User {
final LocalDate lastPasswordChangeDate;
// final id, name, email, etc.
}
I need to add a method that will return information if the user's password must be changed i.d. it has not been changed for more than the passwordValidIntervalInDays
system setting.
The current approach:
public class UserPasswordService {
private SettingsRepository settingsRepository;
@Inject
public UserPasswordService(SettingsRepository settingsRepository) {
this.settingsRepository = settingsRepository;
}
public boolean passwordMustBeChanged(User user) {
return user.lastPasswordChangeDate.plusDays(
settingsRepository.get().passwordValidIntervalInDays
).isBefore(LocalDate.now());
}
}
The question is how to make the above code more object oriented and avoid the anemic domain model antipattern? Should the passwordMustBeChanged
method be moved to User
if so how to access SettingsRepository
, should it be injected into User
's constructor, or should a Settings
instance be provided to the ctor, or should the passwordMustBeChanged
method require a Settings
instance to be provided?
The code of Settings
and SettingsRepository
is not important, but for completness, here it is:
public class Settings {
int passwordValidIntervalInDays;
public Settings(int passwordValidIntervalInDays) {
this.passwordValidIntervalInDays = passwordValidIntervalInDays;
}
}
public class SettingsRepository {
public Settings get() {
// load the settings from the persistent storage
return new Settings(10);
}
}
The problem is that both User and Course are Entity Framework proxy objects. This means that when we hit navigation properties on either User or Course it can cause a huge hit to the database because those objects are not IQueryable so it iterates through them normally.
The anemic domain model is described as a programming anti-pattern where the domain objects contain little or no business logic like validations, calculations, rules, and so forth.
A Rich Domain Model is the technical part when applying DDD, it envolves the building blocks like Entity, Value Objects and Aggregate Root. The goal is to build a ubiquitous language between developers and stakeholders using the a vocabulary that describes the business rules.
For a system-wide password expiration policy your approach is not that bad, as long as your UserPasswordService
is a domain service, not an application service. Embedding the password expiration policy within User would be a violation of the SRP IMHO, which is not much better.
You could also consider something like (where the factory was initialized with the correct settings):
PasswordExpirationPolicy policy = passwordExpirationPolicyFactory().createDefault();
boolean mustChangePassword = user.passwordMustBeChanged(policy);
//class User
public boolean passwordMustBeChanged(PasswordExpirationPolicy policy) {
return policy.hasExpired(currentDate, this.lastPasswordChangeDate);
}
If eventually the policy can be specified for individual users then you can simply store policy objects on User
.
You could also make use of the ISP with you current design and implement a PasswordExpirationPolicy
interface on your UserPasswordService
service. That will give you the flexibility of refactoring into real policy objects later on without having to change how the User
interacts with the policy.
If you had a Password
value object you may also make things slightly more cohesive, by having something like (the password creation date would be embedded in the password VO):
//class User
public boolean passwordMustBeChanged(PasswordExpirationPolicy policy) {
return this.password.hasExpired(policy);
}
just to throw out another possible solution would be to implement a long-running process that could do the expiration check and send a command to a PasswordExpiredHandler that could mark the user with having an expired password.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With