S
Steve
I have read a couple articles online, read my Jesse Liberty book but I am
still confused as to just what the best practices are for using exceptions.
I keep changing how I'm working with them and it has now, after 15k lines of
code resulted in a royal mess!
It's my hope to ask some specific questions with scenario examples and that
some of you might offer a little guidance or general suggestions.
1) string GetCustomerFirmwarePath(string serialNumber) - This is a method
in a class library I have written and it is called from my UI "Presenter"
class' (In case you aren't familiar, Model View Presenter is very similar
to Model View Controller pattern). In the event that a customer can't be
located from the serialNumber parameter, is it a better choice to return
null and check for it or to throw an exception from
GetCustomerFirmwarePath()? Possibly even my own exception, IE:
"CustomerNotFoundException"? I have read that exceptions shouldn't be used
for logic, but I have been spending a lot of time with the Patterns and
Practices group's Composite Application Block and in one of the examples,
they use exceptions in this manner.
2) methodA calls MethodB which calls MethodC, MethodD and MethodE. IE:
PrinterInfo GetEmployeeDefaultPrinter(string employeeFullName)
calls EmployeeInfo GetEmployeeInfo(employeeFullName)
calls ComputerInfo GetEmployeeComputerInfo(EmployeeInfo info)
returns ComputerInfo.DefaultPrinter
So that is a massively stupid design, but I couldn't think of an example
that is easy to visualize (mine is very confusing and wouldn't be a good
example) Point is, if the call to GetEmployeeComputerInfo fails, there is
no clean way to return that error back from GetEmployeeDefaultPrinter() or
if the call to GetEmployeeInfo() fails, same thing. I can return null all
the back down the stack, but short of looking at the log (assuming I'm
logging) there is no clean way to determine where the problem was. This
example makes me think that throwing an "ComputerInfoNotFoundException"
might be a good idea, then I could could catch it in GetEmployeeInfo and
throw a "EmployeeInfoNotFound" exception with the
"ComputerInfoNotFoundException" as the inner exception. Does that makes
sense? Is it a good design? Seems like a lot of exceptions! But what
other clean way could you handle this? Please don't suggest anything like
overriding GetEmployeeComputerInfo(string employeeFullName) and avoiding the
whole call stack, it's just an example, my actual situation has a good
reason for breaking things apart like this.
3) How do you decide what exceptions to catch and which ones not to? I
have read that if I know I can handle it(IE: FileNotFound) then I can catch
it and act accordingly, but that would suggest that it's OK to let all
others bubble up... bubble up to where? Application.Run()? What guidelines
are there?
4) One last one. As I think I mentioned earlier, I'm using the Composite
Application Block. Using the CAB encourages breaking logic into separate
assemblies to be shared by other assemblies for code reuse, etc. There is a
concept of a "Service" which is a basically a singleton that will perform
tasks related to a Workitem. For example, I have a service called
"FirmwareService" and it is responsible for adding new versions of firmware
for our products to the database, retrieving older version, assigning a
particular version to specific customers, etc, etc. An example method is:
string GetCustomerFirmwarePath(Customer customer);
This function is similiar to GetEmployeeDefaultPrinter() in that it makes a
lot of other calls that could result in an error, either acceptable or
fatal. What I have tried to do in my design is avoid having code like this
scattered throughout my Presenters and other task code:
<code>
// Presenter method to get a customer's firmware path and display in the
view
// All manufactured products have a record of what customer they are for
and from that, what firmware should be loaded
ProductInfo productInfo =
_productionService.GetProductRecordFromSerialNum(serialNumber);
if(productInfo == null)
{
// show error
return false;
}
Customer customer = _firmwareService.GetCustomerFromProductInfo(productInfo
;
if(customer == null)
{
// show an error
return false;
}
string firmwarePath = _firmwareService.GetCustomerFirmwarePath(customer);
if(firmwarePath == null || firmwarePath.Length < 1)
{
// show an error
return false;
}
</code>
(that was not real code, so if there are errors, please excuse me)
What I DO want to have is something like this:
<code>
string firmwarePath =
_firmwareService.GetFirmwarePathFromSerialNum(serialNum);
if(firmwarePath == null || firmwarePath.Length < 1)
{
// show an error
return false;
}
</code>
This question is ending up to be a duplicate of #2, but I guess that is my
main question. Given the example above assuming that
GetFirmwarePathFromSerialNum() performs all the tasks in the example code
before it, how do gracefully return errors and handle the exceptions? For
example, if the Customer record was found but not the firmware path, I might
want to do something like allow the user to add firmware for the customer or
something... I dunno, I've written too much, I'll stop.
Hopefully someone will take notice of this very long email and respond with
some insights for me :0)
Thanks for reading,
Steve
still confused as to just what the best practices are for using exceptions.
I keep changing how I'm working with them and it has now, after 15k lines of
code resulted in a royal mess!
It's my hope to ask some specific questions with scenario examples and that
some of you might offer a little guidance or general suggestions.
1) string GetCustomerFirmwarePath(string serialNumber) - This is a method
in a class library I have written and it is called from my UI "Presenter"
class' (In case you aren't familiar, Model View Presenter is very similar
to Model View Controller pattern). In the event that a customer can't be
located from the serialNumber parameter, is it a better choice to return
null and check for it or to throw an exception from
GetCustomerFirmwarePath()? Possibly even my own exception, IE:
"CustomerNotFoundException"? I have read that exceptions shouldn't be used
for logic, but I have been spending a lot of time with the Patterns and
Practices group's Composite Application Block and in one of the examples,
they use exceptions in this manner.
2) methodA calls MethodB which calls MethodC, MethodD and MethodE. IE:
PrinterInfo GetEmployeeDefaultPrinter(string employeeFullName)
calls EmployeeInfo GetEmployeeInfo(employeeFullName)
calls ComputerInfo GetEmployeeComputerInfo(EmployeeInfo info)
returns ComputerInfo.DefaultPrinter
So that is a massively stupid design, but I couldn't think of an example
that is easy to visualize (mine is very confusing and wouldn't be a good
example) Point is, if the call to GetEmployeeComputerInfo fails, there is
no clean way to return that error back from GetEmployeeDefaultPrinter() or
if the call to GetEmployeeInfo() fails, same thing. I can return null all
the back down the stack, but short of looking at the log (assuming I'm
logging) there is no clean way to determine where the problem was. This
example makes me think that throwing an "ComputerInfoNotFoundException"
might be a good idea, then I could could catch it in GetEmployeeInfo and
throw a "EmployeeInfoNotFound" exception with the
"ComputerInfoNotFoundException" as the inner exception. Does that makes
sense? Is it a good design? Seems like a lot of exceptions! But what
other clean way could you handle this? Please don't suggest anything like
overriding GetEmployeeComputerInfo(string employeeFullName) and avoiding the
whole call stack, it's just an example, my actual situation has a good
reason for breaking things apart like this.
3) How do you decide what exceptions to catch and which ones not to? I
have read that if I know I can handle it(IE: FileNotFound) then I can catch
it and act accordingly, but that would suggest that it's OK to let all
others bubble up... bubble up to where? Application.Run()? What guidelines
are there?
4) One last one. As I think I mentioned earlier, I'm using the Composite
Application Block. Using the CAB encourages breaking logic into separate
assemblies to be shared by other assemblies for code reuse, etc. There is a
concept of a "Service" which is a basically a singleton that will perform
tasks related to a Workitem. For example, I have a service called
"FirmwareService" and it is responsible for adding new versions of firmware
for our products to the database, retrieving older version, assigning a
particular version to specific customers, etc, etc. An example method is:
string GetCustomerFirmwarePath(Customer customer);
This function is similiar to GetEmployeeDefaultPrinter() in that it makes a
lot of other calls that could result in an error, either acceptable or
fatal. What I have tried to do in my design is avoid having code like this
scattered throughout my Presenters and other task code:
<code>
// Presenter method to get a customer's firmware path and display in the
view
// All manufactured products have a record of what customer they are for
and from that, what firmware should be loaded
ProductInfo productInfo =
_productionService.GetProductRecordFromSerialNum(serialNumber);
if(productInfo == null)
{
// show error
return false;
}
Customer customer = _firmwareService.GetCustomerFromProductInfo(productInfo
;
if(customer == null)
{
// show an error
return false;
}
string firmwarePath = _firmwareService.GetCustomerFirmwarePath(customer);
if(firmwarePath == null || firmwarePath.Length < 1)
{
// show an error
return false;
}
</code>
(that was not real code, so if there are errors, please excuse me)
What I DO want to have is something like this:
<code>
string firmwarePath =
_firmwareService.GetFirmwarePathFromSerialNum(serialNum);
if(firmwarePath == null || firmwarePath.Length < 1)
{
// show an error
return false;
}
</code>
This question is ending up to be a duplicate of #2, but I guess that is my
main question. Given the example above assuming that
GetFirmwarePathFromSerialNum() performs all the tasks in the example code
before it, how do gracefully return errors and handle the exceptions? For
example, if the Customer record was found but not the firmware path, I might
want to do something like allow the user to add firmware for the customer or
something... I dunno, I've written too much, I'll stop.
Hopefully someone will take notice of this very long email and respond with
some insights for me :0)
Thanks for reading,
Steve