Self-documenting Service interfaces

I’m mocking up a quick example project for a presentation about Fitnesse and when I had to draw up some quick business services I was once again reminded of how much I hate Exceptions.

Let me explain: Exceptions are a pain to create and to handle… often you end up throwing some kind of generic BusinessException and stuffing a String in there or at the most making a subclass for the business method. Making a different Exception for each thing that can go wrong is not only tiresome to write, it also makes using the interface a pain because of the try {} catch structure needed.

So… here’s what I came up with :)

We start out really simple, with a Result enum:

public enum Result {
 
    /** The operation succeeded **/
    SUCCESS,
 
    /**
    * The operation failed because a rule was not followed.
    * E.g. the user didn't fill in a field, the name exists,
    * etc.
    */
    FAILURE,
 
   /**
    * The operation failed for an unexpected reason.
    * It's usually better to throw an exception in that
    * case.
    */
    ERROR
}

Nothing special so far. The second class mostly functions as a Generic wrapper for the Result:

   /**
   * Result of an operation
   **/
    public class OperationResult<P, F> {
        /** Value if succesful **/
        private P value;
 
        /** Reason for failure **/
        private F reason;
 
        /** Result: SUCCESS, FAIL, ERROR **/
        private Result result;
 
        public OperationResult( Result result ) {
            this.result = result;
        }
 
        public OperationResult( Result result, P value, F reason ) {
            this(result);
            this.value = value;
            this.reason = reason;
        }
 
        public void setReason(F reason) { 
            this.reason = reason;
        }
 
        public void setResult(Result result) {
            this.result = result;
        }
 
        public void setValue( P value ) {
            this.value = value;
        }
 
        public F getReasonForFailure() {
            return reason;
        }
 
        public P getValue() {
            return value;
        }
 
        public Result getResult() {
            return result;
        }
 
        public boolean isSuccess() {
            return this.result == Result.SUCCESS;
        }
 
        public boolean isError() {
            return this.result == Result.ERROR;
        }
 
        public boolean isFailure() {
            return this.result == Result.FAILURE;
        }
}

OK, now comes the “clever” bit:

This allows me to write my business interface as follows:

 public interface UserService {
 
   /**
    * All the failures that can occur while creating a new User
   */
    public static enum UserCreationFailure {
        EMAIL_NOT_UNIQUE, /** The username already exists in the system **/ 
       EMAIL_INVALID, /** The provided e-mail was not a valid mail address **/
       INVALID_PASSWORD; /** The password should was not valid **/
    }
 
/**
* Adds a new user to the system.
*
* The new user is returned. If the user could not
* be created, the reason is returned.
*
* @param emailAddress
* @param realName
* @param password
*
* @return on success the created user, or the reason of the failure.
*/
OperationResult<User, UserCreationFailure>
createNewUser(String emailAddress,
String realName, String password );
 
}

The interface documents exactly what can go wrong. If the operation succeeds you get the value, else you get the reason for failure:

 
OperationResult<User, UserService.UserCreationFailure> result = this.userService.createNewUser(
emailAddress, name, password);
 
User newUser = null;
 
if ( result.isSuccess() ) {
    newUser = result.getValue();
} else {
    UserService.UserCreationFailure reasonForFailure =   
        result.getReasonForFailure();
        //Do something with the reason
}

You could choose to handle the different failures in a switch statement, or simply use the enum constant as a key to a localization map. The options are endless :)

5 comments on “Self-documenting Service interfaces

  1. Herman Suijs on said:

    Looks really nice and descriptive. Small omission is the missing setter for value. You could even add a constructor with value which sets result automatically to success. A constructor with reason and result is also possible.

    I can see advantages.

    Nice.

    • NightWhistler on said:

      Thanks for the feedback… I added the missing setter and some better construction options.

      I actually tried your suggestion first, but I couldn’t make the generics work for making a seperate success and failure constructor. I also considered static factory methods and a private 3-argument constructor.

      In both cases you’d still need to provide a dummy object of the second type to actually bind the type-parameter. Only solutions to that riddle are very welcome :)

      What I have been wondering later on is how to make this work with Spring declarative transaction management, since a FailureResult wouldn’t automatically trigger a rollback()

  2. Pingback: Full-blooded domain models « Nightwhistler.net

  3. rc helicopters on said:

    Glad to visit this blog, keep it going.

  4. Chris Mousset on said:

    Nice article.

    I used it in the past for a business validator service. Such a service is supposed to return results thus enabling the client to display all feedback. Or none in case all business validation is met.

Leave a Reply

  • Google ads