1

To cut a long story short...

I want my clients (client as in "service consumer", e.g. REST) to get status information about what the business layer did or failed to do. Just returning a null object or just null is not exactly very descriptive. Anything might have happened.

Damn it - I made such a nice UML sequence diagram to illustrate the problem but StackOverflow won't let me post it due to insufficient reputation points :'(

The problem is probably the oldest in the world. However I didn't find a satisfying answer to it. I could settle for the solution described here How Do You Communicate Service Layer Messages/Errors to Higher Layers Using MVP? but it doesn't make me jump through loops. Throwing exceptions all over the place doesn't sound like a good thing to do. Exceptions are expensive after all. Also I'd need to create an Exception for quite a lot of "this might happen" scenarios.

****So the question is... do you design "Generic Return Values" or throw Exceptions?****
Unfortunately I didn't find an answer to that so far... this is where you come into play :)

I'd go ahead and put a status code, a message and the actual requested information of type T in it. Let's assume this generic return value is "ServiceResult".

Considerations I made:

  • Ok so my business layer methods all return ServiceResult objects. Good.
  • That is very easy to work with - providing that all your business layer magic happens in the one public method you call. Well - it doesn't. Not typically.
  • So you would either have to make the ServiceResult accessible to all private methods as well or pass it around as a parameter. You don't want to pass it around a 100 times... trust me.
  • That's when you decide to add a ServiceResult property to your "controling" business class. But wait.. you don't add generic properties in c#. Because it's not a supported feature.
  • What is next? Using "object" as a property instead? Hardly... you don't want to cast all the time and you wouldn't know what to cast to in the first place because T could be anything. And you private method (3 levels down from the public method you initially called) simply doesn't know the type - of course you could make that a property of your class as well. It's still bad design I guess..
  • Assuming you solved that problem you'd need to check the ServiceResult.Status every time before the next method is invoked if the ServiceResult isn't already in a "faulted" state and further processing is useless. Of course you could put all that magic in a Run(Func func) method but if you are at this point... at the latest... you start considering using Exceptions again :)

Basically that's why I think people just throw exceptions and catch them at the highest level (within your business logic - not in the controller).

Is there a design patterns to this problem which I am not aware of?

Community
  • 1
  • 1
lapsus
  • 2,915
  • 2
  • 32
  • 61

1 Answers1

3

Throwing exceptions all over the place doesn't sound like a good thing to do.

Of course not. Throw exceptions when something exceptional have happened. For instance: If you call the method Repository.UpdateUser(var user) you expect a user object and that it got an Id specified (how else could you update it).

If not you should throw exceptions since the method contract was not followed. By throwing exceptions you also force the developers to take meassures to prevent the exceptions. For instance by making sure that the user object is valid.

Exceptions are expensive after all.

Not that expensive. It's probably a lot more expensive to debug an application which do not do proper sanity checks, than buying new hardware to make up for the exception performance hit. (See? That does sound absurd since it's not really likely that exceptions will affect your overall performance that much).

Also I'd need to create an Exception for quite a lot of "this might happen" scenarios.

No. You need to make sure that you handle those "this might happen" scenarios before calling methods which can not handle those situations.

So the question is... do you design "Generic Return Values" or throw Exceptions?

Generic return values are in most cases worthless. A lazy dev ignoring the return value may introduce a dormant bug which will surface later and result in several hours of debugging.

Instead design methods to either expect errors or that throws exceptions. Compare int.TryParse and int.Parse. The first one tells you that it can fail (since it's trying) while the other one expects the value to be an integer (and hence throw an exception since it can not complete as promised if it isn't).

jgauffin
  • 99,844
  • 45
  • 235
  • 372
  • 1
    It's not only about a lazy programmer that forgets to check a return value, but using return values all over the place makes code hard to read and hard to maintain. It will dramatically increase the cost of maintaining the code. – Steven Feb 19 '13 at 16:17
  • +1 Good comment. I'll say that it's both. The application is harder to maintain (which I took for granted that everyone knows, but something that I should have pointed out anyway) but either way there will always be places where the return value is not handled. May be that the dev is lazy or simply did not understand that he has to handle it. – jgauffin Feb 19 '13 at 17:27
  • The *only* place where I'd actually evaluate the return value would be on the client side. As a necessity of not providing an error message which I would have to translate and make it fit for various clients. If the client doesn't look at the return value it's his fault. It's only meant as an aid for API consumers to make their code more resilient. If someone chooses to not use the returnvalues it's not my concern really. The question is **how** to *gather* all possible codes before returning to the client. – lapsus Feb 19 '13 at 18:29
  • `The question is how to gather all possible codes before returning to the client` No it's not. Re-read your own question. – jgauffin Feb 19 '13 at 19:12
  • Also: If you are using some sort if IPC communication you might want to state that since not many IPC libraries/frameworks is not very good at transferring exception information to the client. – jgauffin Feb 19 '13 at 19:13
  • Ok probably I should have made clear what a "client" is. I was refering to service clients where the service might be a REST service. So I thought about catching my exceptions at the business logic entry/and exit point and convert it into a ServiceResult object (which is a lot easier to transfer/serialize and more importantly easier understood by the client) – lapsus Feb 19 '13 at 20:01