Ayende @ Rahien

My name is Oren Eini
Founder of Hibernating Rhinos LTD and RavenDB.
You can reach me by phone or email:


+972 52-548-6969

, @ Q c

Posts: 6,124 | Comments: 45,481

filter by tags archive

What is wrong with this API? Answer

time to read 1 min | 107 words

Originally posted at 11/11/2010

The reason that I don’t like this API is that I think it provides a piss poor usability:


In short, it doesn’t provide me with any reasonable way to tell the user why I rejected a message.

Here is the proper way of doing this:


MessageVeto also contains a reason string, which provide a much better experience all around.



I thought veto is about rejecting something without having to tell why. But maybe I didn't agonize long enough on this line of code...

Miguel Lira

At first glance I had the same assumption Rafal did - I thought the bool could have simply been a void. Then I figured you'd prefer more context if it actually performed a returnable action on the message.

Coincidently, your answer implies the type returned is an enum. How are you planning to provide a reason string? via some implied annotation?


It can also be a class with static properties like:

public class MessageVeto


public static Allowed




        return new MessageVeto(allowed: true, "Some message");



private MessageVeto(bool allowed, string message)






Jason Young

Returning something that can indicate the reason is indeed better. I thought most of the problems / solutions listed in the comments in the last post were good as well.


Funny thing,

plenty of people tried to find a must of having everything strong-typed. Strong-typing is cool, but considering that there is sth wrong when using a primitive type for some result, I don't buy it:P

Kelly Summerlin

I like the enum/class with a static property over the boolean value because it is more extensible. Today there may only be two values yes/no, true/false. With the enum you allow for the possibility of additional values without having to change the clients -- unless you really need to .

Jeff C

So, to NOT veto a message, you return a MessageVeto? That's kind of confusing, as well.


I don't get it now.

Brian Chavez

I agree with Jeff,

MessageVeto.Allowed makes absolutely no sense.

Just the fact you have "Veto.Allowed" read on the same line to express some kind of action... is like saying "this.TempFeels = Hot.Cold".

"Oxymoron: A figure of speech in which incongruous or contradictory terms appear side by side." Indeed.

Brian Chavez

I think it's better to go with actual your intention is:



Seems better to me.???

Brian Chavez

I also like:





Or something more generic:



That's neat. Naming is cool.

Luke Schafer

How about something like

//MessageAllowed with an internal constructor



MessageVeto : MessageAllowed {

public MessageAllowed Veto  { 

    get {

        return new MessageAllowed(MessageAllowedOptions.No, "Veto");




Rob Kent

I just think it would be better to use a positive method and a verb that is more common than veto, like:

public virtual MessageAllowed AllowMessage(IncomingMessage msg)


return MessageAllowed.Yes;


Jonas Stawski
This reasoning is always true with almost every API call that returns a boolean or some sort of notification to the user. Take into consideration an API call that updates some information for an entity. Usually we return true or false for specifying whether the action was successful or not, but we don't know why it wasn't successful. Was it because the record was not found, because of a DB error, because of a network error? 
So I always try to return some type of ReturnValue
<bool that returns whether it was successful plus any other type of information to let the caller take action on what to do next if it fails.

Thanks to implicit constructors you can refactor the API without any breaking changes at callsites. I had a certain case recently with a constraints callback.

Max Schilling

Hey Ayende,

Instead of creating new "result" objects each time I need a method to return a reason, I use the following Result object that I keep in my common library.

It creates a generalized way of solving the problem you are addressing.

I have a blog post written about it here: http://maxoncode.com/ though it is pretty straightforward.

I also use it to encapsulate any exceptions. I know it is somewhat non-standard, but for general shared code I don't necessarily know how the calling code wants to do exception handling, so if something goes awry, I'd just set the Result.Value to false, and populate the Result.Exception property, return the result and let the calling code decide whether it needs to throw or not. If nothing else it makes unit testing the method much cleaner.

public class Result : Result <object,>



public class Result <t : Result <t,>



/// <summary
/// Wraps an object to allow a function to return additional data about its execution to the caller


/// <typeparamThe type of Item. This is the "return type" for the result object.

/// <typeparamThe type of ResultCode. This is an optional spot for an enumeration of possible ResultCodes.

public class Result <t1,>


public Result()


    Message = String.Empty;


public bool Value { get; set; }

public T1 Item { get; set; }

public T2 ResultCode { get; set; }

public string Message { get; set; }

public Exception Exception { get; set; }


Comment preview

Comments have been closed on this topic.


  1. RavenDB 3.5 whirl wind tour: I’ll find who is taking my I/O bandwidth and they SHALL pay - 15 hours from now
  2. The design of RavenDB 4.0: Physically segregating collections - about one day from now
  3. RavenDB 3.5 Whirlwind tour: I need to be free to explore my data - 3 days from now
  4. RavenDB 3.5 whirl wind tour: I'll have the 3+1 goodies to go, please - 6 days from now
  5. The design of RavenDB 4.0: Voron has a one track mind - 7 days from now

And 12 more posts are pending...

There are posts all the way to May 30, 2016


  1. RavenDB 3.5 whirl wind tour (14):
    02 May 2016 - You want all the data, you can’t handle all the data
  2. The design of RavenDB 4.0 (13):
    03 May 2016 - Making Lucene reliable
  3. Tasks for the new comer (2):
    15 Apr 2016 - Quartz.NET with RavenDB
  4. Code through the looking glass (5):
    18 Mar 2016 - And a linear search to rule them
  5. Find the bug (8):
    29 Feb 2016 - When you can't rely on your own identity
View all series


Main feed Feed Stats
Comments feed   Comments Feed Stats