Suppose I need to register user in my system.
Buisness rules are:
It looks like I need Service for it.
Probably something like that:
public interface RegistrationService {
bool Register(String email, String name);
}
And it's fine until I have to return failure reason to user. How to deal with it?
I can see few options (but I don't like any of them):
Implement a kind of result object:
public interface RegistrationService { RegistrationResult Register(String email, String name); } public interface RegistrationService { bool Succes(); Error[] Errors(); User NewUser(); }
It's fine, and even could be useful for example for REST api. But isn't it too cumbersome(especially considering that blank name probably should be checked at factory)?
Throw exceptions
public interface RegistrationService { void Register(String email, String name) throws RegistrationError; }
It looks a bit more accurate. But exception are expensive. Using them like this is looks like bad idea.
let's start with point 3: DB constraints get their job done. Yes, the exception/error message is messy, I agree about that. But ask yourself: What is more messy: a terrible error message shown to 1 user or 2 user accounts with the same email adress that can corrupt your system? The DB constraint should be your last safety net. Your service needs to check if a user account with this email already exists. But what happens if in another thread somebody creates a user account with this email in the microsecond between your check and the creation of the new user account? You'll be happy about the DB constraint. Yes, you could find a better solution, but that would require you to have a singleton service that serializes all account creation and makes sure that no two threads can create a user account at the same time.
Point 2: Exceptions are for exceptional situations. The situation that somebody wants to create a user account with an already used email is an exceptional situation. Don't be worried about costly operations in situations where somebody wants to do something dirty.
Point 1: I don't like this. But that's just my opinion. There are situations where a Result Object of this kind makes sense, but I try to Keep it to a Minimum.