Error handling problem. Error codes vs Exceptions.

188 views
Skip to first unread message

Илья Фофанов

unread,
Aug 3, 2013, 12:55:24 PM8/3/13
to clean-code...@googlegroups.com
Out team is at the cusp of a new project.
One of the components at the boundary of the system is the component which interacts with a printer through an external COM component (referenced as a usual dll).

The COM component returns integer codes if there were an error whilst command execution.
Lets consider a concrete code.

      public class OperationException:Exception {
        public int ErrorCode { get; private set; }
        public string ErrorDescription { get; private set; }

        public OperationException(int errorCode, string errorDescription) {
            ErrorCode = errorCode;
            ErrorDescription = errorDescription;
        }
    }

    //The exception throwing way
    public class Provider1:IFrProvider {
        private readonly IDrvFR48 driver;

        public string GetSerialNumber() {
            //must read status before get SerialNumber
            int resultCode = driver.ReadEcrStatus();
            if (resultCode != 0) {
                throw new OperationException(resultCode, driver.ErrorDescription);
            }
            return driver.SerialNumber;
        }
    }

    //The way of out parameters returning.
    public class Provider2 : IFrProvider
    {
        private readonly IDrvFR48 driver;     

        public string GetSerialNumber(out Result result) {
            //must read status before get SerialNumber
            int resultCode = driver.ReadEcrStatus();          
            if (resultCode != 0) {
                result = new Result(resultCode, driver.ErrorDescription);
                return null;
            }
            result = new Result(0, null);
            return driver.SerialNumber;
        }
    }

    //The way of LastResult property setting.
    public class Provider3 : IFrProvider
    {
        private readonly IDrvFR48 driver;

        public Result LastResult {
            get {
                return new Result(driver.ErrorCode, driver.ErrorDescription);
            }
        }  
   
        public string GetSerialNumber() {
            //must read status before get SerialNumber
            if (driver.GetECRStatus() == 0)
                return driver.SerialNumber;
            return null;
        }
    }

    public class Result {
        public int ResultCode { get; private set; }
        public string Description { get; private set; }

        public Result(int resultCode, string description) {
            ResultCode = resultCode;
            Description = description;
        }
    }

    public class Caller {
        public void CallProvider1() {
            var provider = new Provider1();
            try {
                string serialNumber = provider.GetSerialNumber();
                //success flow
            }
            catch (OperationException e) {
                if (e.ErrorCode == 123) {
                    //handling logic
                }
            }
        }

        public void CallProvider2() {
            var provider = new Provider2();

            Result result;
            string serialNumber = provider.GetSerialNumber(out result);
            if (result.ResultCode == 123) {
                //error handling  
            }
            //success flow
        }

        public void CallProvider3()
        {
            var provider = new Provider3();

            string serialNumber = provider.GetSerialNumber();
            if (provider.LastResult.ResultCode == 123) {               
                //handling              
            }
            //success flow               
        }
    }


So we have three ways of error handling. The most specific thing in all this stuff is that each operation can fail, because it depends on a device.

Our teamlead insist on using out parameters, because of unhandled exceptions propagation fear. The other reason, connected with the fear, is that we will have to cover all calls by try\catch blocks to stop to be afraid, but such a code will be pretty ugly.

What pros and cons do you see and what could you advice?

Uncle Bob

unread,
Aug 5, 2013, 8:23:48 AM8/5/13
to clean-code...@googlegroups.com
Use exceptions.  They are much cleaner then all the other options.  And write tests for each caller showing that each caller can handle the exception when thrown.  

The fear about uncaught exceptions is misplaced.  Forgetting to catch an exception is much better than forgetting the if statement to check a result.  The former fails visibly, and the latter fails silently. 

The fear of messy code near the try/catch blocks is also misplaced.  Use the 'extract till you drop' rule, and make sure that any function with a try/catch block has _only_ the try/catch block in it; with the try block being a single function call.

Finally, write tests for all your exception throws, and all your exception catches.  Error processing is part of the legitimate behavior of your system and testing it is very important.
Reply all
Reply to author
Forward
0 new messages