I'm writing a user input library to easily manage the dynamic creation of forms for asking users for data.
I wanted to make the end developer have to 'think' about the bare minimum, so I went with having them throw exceptions instead of returning 'true' or 'false' and remembering to handle the return value etc.
In reality, it's worked out really well. Throwing exceptions has also given me a side benefit of being able to automatically record user errors in a log, all for 'free' as the creation of the exception causes the logging to be done.
Having said all of that, I was wondering if this is really 'against best practices'? Should I have kept exceptions only for times when I didn't even expect user input error, or is it OK to say "the data from the user has a problem... that's an exception"?
Any thoughts?
Exceptions are for exceptional cases.
Bad user input is an expected case, and (in my opinion) you should always be trying to validate and massage it into the correct format before showing a non-exceptional error message.
symfony's form framework validators throw exceptions.
Personally, I think that's fine, and better as it forces the developer to handle the error from the input, which is obviously important.
I agree with Gareth on this one. Bad user input is an expected condition.
Consider this instead (this is a usual strategy in Java): create an Errors class. Pass an object of this type to your validators. The validators can leave the object untouched or they can add to it one or more error messages and their associated field. After you pass this through all the validators, inspect the Errors object to see if it's empty, if not, read it and show the form again together with the errors.
In my personal opinion, it has to do with where you are going to handle the error. If it's sufficiently up the code tree, an Exeption would be wise. If you're just catching it 3 lines below it's a waste of resources (it does contain the complete backtrace), and 'inline' error handling would be fine, for which you can easily add (the same) logging capability.
Related
Okay, its a very lame question for many but I hope I will have overwhelming response :)
When I throw an Exception in PHP I can add a code to the message.
I catch an exception and handle it according to its type (Like InvalidArgumentException or OutOfBoundException). I log the message or display it or do whatever is suitable.
I can add also append a previous exception to trace a path to the origin of the error.
BUT one thing I have never used or never thought of: how useful is code?
For example:
throw new Exception("db Error", $code, $previousException);
What do I do with $code?
The message is for display to the user, while the code is for use by your program. So for example, in your "database error" example, you might make up a set of codes like
Can't connect
Error during query
Empty result
Error closing connection
and then use the appropriate code. Then when other parts of your code saw they exception, they would know what happened and could possibly deal with it intelligently.
How $code is interpreted is dependent on the exception type. For example, if you have an Exception subclass that represents a MySQL database error, then the $code could be the native MySQL error code. In the case of a low-level IO error, this could be a value from <errno.h>.
Basically, $code should contain whatever you need to programmatically handle an exception. Most exceptions are meant to be handled somewhere. If all of your exceptions are simply displayed as errors, then $code is only useful if you need to include an error code from a library like the MySQL client library.
I've seen implementations (CakePHP) where the $code is used as HTTP status code.
I've implemented that concept with a subset of exceptions. So all exceptions extending from HttpException which are thrown respond with HTTP errors
In object oriented languages, the type of the exception conveys what type of error it is. However, if for example you have two things that can generate the same exception type, the error code could be used to give more detail.
The error code is a widely used feature in non-object oriented language to convey what type of error it is.
I personally use the code to get a compressed error message, that user can send to the support. For example, let's say the user tries to authenticate, and he fails, my code throws an AuthenticateException with the message: Failed to authenticate, and a specific code referring to the real issue behind the failure. The user will only see the authentication message, and the code, thus not knowing what the real reason of the failed authentication was. He is then advised, that if needed, contact the support team with the code.
Based on the exception code, our support colleagues can easily pin-point what was the real reason for the failed authentication (invalid password, inexistent user-name, account was suspended, etc.) and may help the user accordingly.
Lots of good answers so far, but I'm surprised none have hit upon the core of what an error code really is.
You need an error code for the same reason you need an id column in a database table. It's a unique identifier for the exact error that happened.
The name of the Exception type is not the same. For example:
There could be multiple variations or causes of an exception with the same type. The error code might give you more information if you look it up than just the type of error.
When you manually throw an error in code, there's a lot of positives to being able to pass a custom error code with it. You might want to identify the exact error or place in the code it happened without creating a new type for every exception in your code example.
When you need to check an error object for what error happened, doing a simple if ($error->code === 201) is a lot easier than checking the type or comparing error message strings. If you don't want to use 201 in your code because it doesn't convey the error, it's also really easy to assign it to a constant.
If you want to log information about an error in a database, having a unique identifier is a lot easier to work with in a database. And then when you pull it out of the database to work with it in code (no longer in an Exception object), it's again easier to identify the error by an error code and work with it that way. If you store something like a class name in the database, what if someone puts it in the database with camelCase as opposed to PascalCase, or they remember the exact name wrong, or they have a typo, etc. Even if you use an enum, what if you need to interface with a different database that might have used a different format?
If you give an error code to a user in your application, and he goes to a page with a list of errors, it's a lot easier for him to find the exact error with an error code than to look through text descriptions of the error. It's also easier for them to find it in a search engine.
Basically having a global error code makes it easy to store, reference, pass, compare, change formats without losing information, share code and data with others, create custom errors, etc. Most things that apply to storing data in a database with a unique id also applies to storing an error with an error code.
I want to use two different kind of exceptions in my project:
Fatal exceptions. If something goes unexpectedly wrong, like a mysql query fails, I want to throw this kind of exception, without necessarily having to catch it. This exception means that I need to take some action, like logging a message, then showing an error, using CodeIgniter's show_error() function. The script should exit without continuing.
Error exception. If a user does something not allowed, such as enters letters into a numbers field or accesses a page he doesn't have permissions for, this exception should be thrown and caught.
I want to use both kinds of exceptions throughout the project. Number 2 is clear enough, but how do I go about doing exception 1? It would be great to not have to have two catch blocks for every try block, as the 1st type is global and should always be the same: log message, show error, exit. And lastly, in codeigniter, where would be the correct place to extend the Exception class?
Thanks.
Fatal Exceptions
The link posted by Sunil above is great for globally handling Fatal Exceptions. You want to be very careful about throwing these exceptions, and be sure that to the end user, the site doesn't look scary and broken - humoring the user is always a good idea.
Error Exceptions
I think you would be better off not treating errors like text in a numeric field as exceptions, because they do not disrupt the normal flow of the program's instructions.
If a user enters an alpha into a numeric field and submits the form, your application should expect that a user may provide junk data, and you repeat the input process, which is the normal flow.
Here is how I handle scenario 2 in code igniter:
Extend CI_Log with /application/libraries/MY_Log
Add MY_Log::$logs to store messages in array if log level permits
The template hook gets the logs MY_Log::get_logs() then passes them on to the view that displays the appropriate message boxes for the log levels
I also implement a custom log level called error_log. This is for anything that I want to send to the log file without showing the user.
Okay, its a very lame question for many but I hope I will have overwhelming response :)
When I throw an Exception in PHP I can add a code to the message.
I catch an exception and handle it according to its type (Like InvalidArgumentException or OutOfBoundException). I log the message or display it or do whatever is suitable.
I can add also append a previous exception to trace a path to the origin of the error.
BUT one thing I have never used or never thought of: how useful is code?
For example:
throw new Exception("db Error", $code, $previousException);
What do I do with $code?
The message is for display to the user, while the code is for use by your program. So for example, in your "database error" example, you might make up a set of codes like
Can't connect
Error during query
Empty result
Error closing connection
and then use the appropriate code. Then when other parts of your code saw they exception, they would know what happened and could possibly deal with it intelligently.
How $code is interpreted is dependent on the exception type. For example, if you have an Exception subclass that represents a MySQL database error, then the $code could be the native MySQL error code. In the case of a low-level IO error, this could be a value from <errno.h>.
Basically, $code should contain whatever you need to programmatically handle an exception. Most exceptions are meant to be handled somewhere. If all of your exceptions are simply displayed as errors, then $code is only useful if you need to include an error code from a library like the MySQL client library.
I've seen implementations (CakePHP) where the $code is used as HTTP status code.
I've implemented that concept with a subset of exceptions. So all exceptions extending from HttpException which are thrown respond with HTTP errors
In object oriented languages, the type of the exception conveys what type of error it is. However, if for example you have two things that can generate the same exception type, the error code could be used to give more detail.
The error code is a widely used feature in non-object oriented language to convey what type of error it is.
I personally use the code to get a compressed error message, that user can send to the support. For example, let's say the user tries to authenticate, and he fails, my code throws an AuthenticateException with the message: Failed to authenticate, and a specific code referring to the real issue behind the failure. The user will only see the authentication message, and the code, thus not knowing what the real reason of the failed authentication was. He is then advised, that if needed, contact the support team with the code.
Based on the exception code, our support colleagues can easily pin-point what was the real reason for the failed authentication (invalid password, inexistent user-name, account was suspended, etc.) and may help the user accordingly.
Lots of good answers so far, but I'm surprised none have hit upon the core of what an error code really is.
You need an error code for the same reason you need an id column in a database table. It's a unique identifier for the exact error that happened.
The name of the Exception type is not the same. For example:
There could be multiple variations or causes of an exception with the same type. The error code might give you more information if you look it up than just the type of error.
When you manually throw an error in code, there's a lot of positives to being able to pass a custom error code with it. You might want to identify the exact error or place in the code it happened without creating a new type for every exception in your code example.
When you need to check an error object for what error happened, doing a simple if ($error->code === 201) is a lot easier than checking the type or comparing error message strings. If you don't want to use 201 in your code because it doesn't convey the error, it's also really easy to assign it to a constant.
If you want to log information about an error in a database, having a unique identifier is a lot easier to work with in a database. And then when you pull it out of the database to work with it in code (no longer in an Exception object), it's again easier to identify the error by an error code and work with it that way. If you store something like a class name in the database, what if someone puts it in the database with camelCase as opposed to PascalCase, or they remember the exact name wrong, or they have a typo, etc. Even if you use an enum, what if you need to interface with a different database that might have used a different format?
If you give an error code to a user in your application, and he goes to a page with a list of errors, it's a lot easier for him to find the exact error with an error code than to look through text descriptions of the error. It's also easier for them to find it in a search engine.
Basically having a global error code makes it easy to store, reference, pass, compare, change formats without losing information, share code and data with others, create custom errors, etc. Most things that apply to storing data in a database with a unique id also applies to storing an error with an error code.
I'm working on the back-end of my website and I'm wondering how far I should be going to test for errors and throwing exceptions accordingly? Testing in the sense of improper usage of methods and functions. Not errors under correct usage.
My biggest concern is code bloat and uglying it up with a bunch of if/elses, type checks, and other such tests.
Should you go so far as to consider every possible way someone could use an object, catch all the improper uses, and throw exceptions to make it clear to the developer using it what they've done wrong?
Or is it a better approach to let the code break naturally (obviously catching and checking for things that would be a big deal, but not for every contingency), and depend on anyone using the code to read the available documentation and use it accordingly?
Are there any general best practices or guidelines to follow when handling such issues? I'm working in PHP, is there anything specific to PHP, although this issue is generally language wide?
Thanks for any help on the matter.
At least, your application should not "break" : when an error is detected (be it because you detected a problem could happen and avoided it, or because a problem did happen), you should display some nice error message, and, eventually, log the technical informations of the error.
About bloating the code : I would not put too much tests and all that in my code : it would end up in something hard to understand and maintain -- which is important !
What I generally try to do is :
Test for errors in the user-supplied data
Using a specific class, for instance, so those checks are not in the middle of the code that deals with database and business rules.
Those tests are relatively precise, in order to generate useful error messages for the user
For instance : "You should not input more than 20 characters"
Or "there is already a user with that e-mail address"
Basically, the important thing here is the user.
When user-supplied data seems OK, I work with it.
And there, if some error happens, it'll most likely be a technical error
Which should be logged
And only a "oops, an error occured" should be displayed to the user.
Which means that, here, tests are not as precise : we only need to know if it works or not -- not necessarily in great details.
Of course, in the end, you should ensure that the data in the DB is correct, and that you don't save only half of the data.
A common way of dealing with technical errors is using exceptions ; here is a very basic idea :
try {
// Begin transaction to the DB
// Some code that might fail and throw an Exception
// Some other code that might fail and throw an Exception
// Code here will not be executed if an Exception has been thrown
// Commit DB transaction
} catch (Exception $e) {
// Rollback transaction (cancels the queries that were sent to the DB)
// Log technical informations to a file
// Display a nice message
}
The great thing is that it allows one to place all error-handling code in a single place, and put less testing code in the middle of the important stuff ; i.e. "let it fail, we'll deal with the problems later"
I usually just go as far as making sure method input parameters and/or public members are filled and of the proper type (string, int, etc...). Other than that I just let it break naturally. (If people aren't going to bother reading the documentation, they kind of deserve to have things break a little.)
As I see it, you don't bloat your code with error-checks, who's only purpose would be to support the laziness of your co-workers/clients/random-developers.
I was wondering what the excepted standard is for handling errors in the Model.
Currently I have 'setError' and 'getError' methods that's in use by all my Models.
This means I'm only concerned with whether a call to a method in my Model is true or false. If it's false then I would use $this->model->getError() in my Controller.
Additionally I'm contemplating setting up a separate file that contains all my errors. One file per model, also wanted to have thoughts on this.
A simpler solution would be to use exceptions.
When an error occurs that would be something you display to a user, throw a special kind of an exception - perhaps named UserError. The exception should contain the text of the error message when you throw it. These kinds of errors are features which provide users with useful information (i.e. they attempted to delete something that did not exist - which can happen when they have multiple browsers open, etc.)
e.g.:
throw new UserError("That object no longer exists.");
When an error occurs that you want to hide from the user, throw a different kind of exception, perhaps named InternalError. You would want to log this and allow the program to continue, so the specific error is hidden from the user. If it prevents something from happening, you might want to throw up a generic error message. These would be bugs and you want to fix them as soon as possible.
e.g.:
throw new InternalError("Failed to connect to remote service");
All of the error messages can be stored (hard-coded) in the source where the exception is thrown. This is not necessarily a bad design practice - if you use a tool like gettext, you can easily translate all of these messages.
I've been using log4j and log4cxx and logging to a syslogd. Kiwi is a simple Win32 syslogger that will track your log messages and save them to a file. Log4j / Log4cxx have configuration files that you can use to setup all your log levels or log message destinations (you can log to multiple places).
It takes so little effort to setup and use, and it works like a charm.
I haven't tried out log4php myself.
Exceptions are good when you no longer want your program to continue executing. Catch exceptions at a high level where you can accept the fall-out of failed executions.
Review the NerdDinner tutorial on how to create validation routines before making a final decision:
http://nerddinnerbook.s3.amazonaws.com/Part3.htm
The Validation part is about 2/3 of the way down the page.