Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

When is better to throw an exception and when is better to return some error log 'object'?

I was wondering how to decide between :

1) If to throw custom exceptions OR

2) return a kind of LOG object that has flags like 'CityNotFound,' 'ReferenceConstraintBroken' etc.

I have been reading the exceptions are expensive. If I just need to know specific details of a process result, to me it sounds more beneficial to have a custom 'process LOG object' that contains only the necessery information of a process.

So, if I come back to my question:

When is better to throw an exception and when is better to return some error log 'object' ?

like image 861
pencilCake Avatar asked Apr 18 '11 07:04

pencilCake


2 Answers

Throw an exception to provide more information (type of exception, message, etc.) for proper handling and to signify that:

  1. your code is being used inappropriately / illegally
    1. i.e. against contractual constraints that cannot be enforced during compile time
  2. an alternative to the primary flow has occurred
    1. i.e. you expected an operation to succeed but it failed, like obtaining a resource or connection

I would actually discourage returning "log objects" (i.e. returning an exception object rather than throwing one) as this

  1. results in unnecessary mashes of if statements to check the result AND handle a potential error
    1. all your methods would have to return of a "log object" (or have an out param) or else you cannot "bubble up" the error/exception for scoped handling, resulting in further limitations
  2. loses the helpfulness of try/catch/finally
  3. hurts readability of scope (operation attempt vs error handling vs clean up)

If you want to return "log objects", you should really use boolean returns with methods that makes sense (i.e. FindCity) or methods with an out boolean parameter (i.e. TryFindCity). This way, you don't need to specify flags, but just use the methods whose boolean return allows you to determine the would-be flag value.

EDIT

Per OP's comment, if there is a giant method with numerous possible validation errors, then the giant method should be refactored to call smaller methods that each throw the appropriate exception. The giant method can then simply re-throw each exception or just allow each exception to bubble up if it shouldn't be the one handling it.

If there are validation dependencies that prevent "proper separation", then simply throw a single ValidationException with the proper argument(s). An example of what this class could be is below:

public class ValidationException : Exception {
    private readonly object _Field;
    public object Field { get { return _Field; } }

    public ValidationException(string message) : base(message) { }

    public ValidationException(string message, object field)
        : this(message) {
        _Field = field;
    }
}

Then you can just throw one exception explaining the validation error.

like image 79
bitxwise Avatar answered Sep 21 '22 03:09

bitxwise


If you're concerned about the performance of exceptions, you could factor towards the "tester-doer" pattern, which can be used to avoid them in most cases (it also makes the code more readable than a try/catch in my opinion).

// Traditional try catch
try
{
    var record = myDb.myTable.Select(primaryKey);

    // do something with record...
}
catch (RecordNotFoundException)
{
    // The record not found in the database... what to do?
}

// Tester-doer pattern
if (myDb.myTable.RecordExists(primaryKey))
{
    var record = myDb.myTable.Select(primaryKey);

    // do something with record...
}
else
{
    // The record not found in the database... what to do?
}

Same result, no exceptions. The cost is you have to write the "RecordExists" function yourself, usually it would be as simple as doing something like return COUNT FROM myTable WHERE PrimaryKey=foo == 1

like image 27
MattDavey Avatar answered Sep 21 '22 03:09

MattDavey