Monday, March 15, 2010

A note on exceptions...

I've worked in a plethora of different work environments related to software engineering and it seems like everyone tends to have their own practices for diff things. Exceptions and exception handling is no exception.


Exceptions are designed to handle exceptional behavior


What does that mean? Exceptional behavior is behavior that is not the normal. Eg, say part of your applications functionality connects to a website, downloads a file, disconnects and then process the file. What should happen when halfway through the download, the webserver is reset, or the connection is severed in some other manner?

Consider the following...


string html = string.Empty;
            
                HttpWebRequest request = (HttpWebRequest)WebRequest.Create("http://www.google.com/");
                HttpWebResponse response = (HttpWebResponse) request.GetResponse();
                Stream receiveStream = response.GetResponseStream();
                StreamReader readStream = new StreamReader(receiveStream, Encoding.UTF8);
                html = readStream.ReadToEnd();
                response.Close();
                readStream.Close();
     
            return html;

Depending on the expected functionality at a higher level, you need to decide how to handle it. If you want a failure here to result into a failure failure... dont bother catching... leave it as is. If you'd like to do something with the exception (like perhaps log), catch it, perform extra functionality, or perform extra functionality and then rethrow. If for example you wanted a failed get to result in a log entry, and setting the downloaded file to empty you might do something like.

string html = string.Empty;
            try
            {
                HttpWebRequest request = (HttpWebRequest)WebRequest.Create("http://www.google.com/");
                HttpWebResponse response = (HttpWebResponse) request.GetResponse();
                Stream receiveStream = response.GetResponseStream();
                StreamReader readStream = new StreamReader(receiveStream, Encoding.UTF8);
                html = readStream.ReadToEnd();
                response.Close();
                readStream.Close();
            }catch(Exception e)
            {
                //
            }finally
            {
                //
            }
            //this may very well be empty if the url is bad, or has changed.
            return html;


In the catch statement you could have caught the dirty error, and replaced with an exception that exposed less, or was more friendly. It could have been a subclassed exception with yet even more information that the built in exceptions.

Say you wanted to just log and throw...

string html = string.Empty;
            try
            {
                HttpWebRequest request = (HttpWebRequest)WebRequest.Create("http://www.google.com/");
                HttpWebResponse response = (HttpWebResponse) request.GetResponse();
                Stream receiveStream = response.GetResponseStream();
                StreamReader readStream = new StreamReader(receiveStream, Encoding.UTF8);
                html = readStream.ReadToEnd();
                response.Close();
                readStream.Close();
            }catch(Exception e)
            {
                //
                throw;
            }
            //this may very well be empty if the url is bad, or has changed.
            return html;

Exceptions aren't for validation!


I've actually seen, and worked on many projects that actually used exceptions as validation components... which is improper use of Exceptions and in at least .net, aren't exactly the lightest objects to generate.

if(name.Length >10)
               throw new InvalidLengthException("Name must be at least 3 characters long");

As you might guess, validation isn't exactly exceptional behavior. Generating a new exception here may save you have processing any further, and bubbling up validation failures... however its a decent tax in a high usage application. Generating an exception, also generates a stack trace among other things... and uses reflection for some of it.

You don't need to sit there and question usage of every last little thing in code, while in a relatively low usage application you'd probably never notice the overhead of throwing exceptions for validation, a little precaution here could definitely help down the road when you start seeing problems. Simpler design USUALLY ends up with cleaner, easier to maintain code.

An additional note on disposables


In the event something does happen, you use finally to clean up resources.. but where it makes sense, a using statement will ensure the resources get cleaned up before moving on. This works out very well for things like drawing and database connections... so:

try{
              using(SqlConnection conn = new SqlConnection(connectionString))
              using(SqlCommand command = new SqlCommand(query,conn))
              {
                 conn.Open();
                 command.ExecuteNonQuery();
                 conn.Close();
              }
          }catch(Exception e)
           {
              //do something
           }


In the event you caught the exception, the using statement would ensure items that implement IDisposable are disposed properly. Not really specific to exceptions, but helpful to prevent memory leaks, as well as just make things like disconnecting connections pretty common sense.


Thats all for now.