Suppose I have a method that must return an object (say from a database layer) and takes as input some info about the requested object.
In the normal case, the method should return the object. But what happens if the precondition of the methods are not fulfilled by the caller; how should I (the code writer of the method) inform the caller?
Take for example the case that I should return information about the user from a db, and I take as input the username and the password. In the normal case I should return the User object. But what if the username and password are null, if they mismatch, if the password is too short... how should I inform the caller what is exactly the problem?
Normally I would have thrown an exception, but here - When to throw an exception? was suggested that it is a bad idea.
Should I put an errorDetail field in the User, or make a method checkInputData or getErrorStatus...
It sounds perfectly reasonable to throw an exception in this case. The method, which should be doing one thing and only one thing, is simply trying to fetch a user record from the database. If a precondition fails, give up. If the database errors out, give up. If no user is found, give up. Let the calling code deal with the consequences.
An exception is a perfectly acceptable exit path for a method.
In the case of the precondition, it's not the method's responsibility to fix that. It's the calling code's responsibility. So throw an ArgumentException of some kind and let the calling code deal with it.
In the case of a database error, either catch it and throw a custom exception (something like an InfrastructureFailed exception) for the application to handle accordingly. Basically the application needs to tell the user that there are technical difficulties and to please try again later.
In the case of no user being found, that sounds like a failed login. Throw some kind of SecurityException and let the calling application handle it by notifying the user that the login has failed. (Don't be more specific. For example, don't tell the user that the username was fine but the password was bad. That's giving a malicious user more information than you want them to have. Just say that the login failed, nothing more.)
You also mention a case of a password being too short. I imagine that's something that should be validated before it gets to this point. In this case, that falls up under input checking for the method. So the preconditions fail and the method never even tries to get to the database. But "password is too short" probably isn't a good error to tell a user at a login prompt. Rather, that's for when they try to create the password.
One thing you shouldn't do is return null or an empty user object or anything like that. This puts the onus on the calling code to check if there was an error. Exceptions are a perfectly valid way of notifying calling code of an error. A "magic object" being returned is just like any other "magic string" in code, but worse because it leaks out of the method and into other code.
Now, this isn't always a complete rule, of course. It depends on the structure of the application. For example, if this is a web service or some other kind of request/response system then you might want to have a standard response object which would indicate failure. That assumes some application context around the method, though. And in that case you probably should still be dealing with multiple methods. The inner one (a domain logic method) would throw the exception, the outer one (an application UX-aware method) would catch the exception and craft an appropriate non-null response to the UI.
How you handle the exception is up to the logical structure of your application. But throwing and catching exceptions (keep in mind that "catching" is not the same thing as meaningfully "handling") is perfectly acceptable behavior.
Does it make sense to return some kind of sentinel value? If so, consider using that. Otherwise, why not throw an exception?
I would return an object that contains both a user (null in the case of an error), a success flag (false in the case of an error) and a list of strings as validation messages (on error, a list of reasons why it failed).
Adding an errorDetail field on the user object doesn't make sense since that is not really a property of the user object. It's just part of this return data from the method. This path leads to objects with muddles properties that are only used by certain methods.
Related
Consider the following service (transactional by default). A player must always have one account. A player without at least one corresponding account is an error state.
class playerService {
def createPlayer() {
Player p new Player(name: "Stephen King")
if (!p.save()) {
return [code: -1, errors:p.errors]
}
Account a = new Account(type: "cash")
if (!a.save()) {
// rollback p !
return [code: -2, errors:a.errors]
}
// commit only now!
return [code: 0, player:p]
}
}
I have seen this pattern by experienced grails developers, and when I tell them that if creation of the account of the player fails for any reason, it wont rollback the player, and will leave the DB in an invalid state, they look at me like I am mad because grails handles rolling back the player because services are transactional right?
So then, being a SQL guy, I look for a way to call rollback in grails. There isn't one. According to various posts, there are only 2 ways to force grails to rollback in a service:
throw an unchecked exception. You know what this is right?
don't use service methods or transactional annotations, use this construct:
.
DomainObject.withTransaction {status ->
//stuff
if (someError) {
status.setRollbackOnly()
}
}
1. throw an unchecked exception
1.1 So we must throw runtime exceptions to rollback. This is ok for me (I like exceptions), but this wont gel with the grails developers we have who view exceptions as a throwback to Java and is uncool. It also means we have to change the whole way the app currently uses its service layer.
1.2 If an exception is thrown, you lose the p.errors - you lose the validation detail.
1.3 Our new grails devs don't know the difference between an unchecked and an checked exception, and don't know how to tell the difference. This is really dangerous.
1.4. use .save(failOnError: true)
I am a big fan of using this, but its not appropriate everywhere. Sometimes you need to check the reason before going further, not throw an exception. Are the exceptions it can generate always checked, always unchecked, or either? I.e. will failOnError AWLAYS rollback, no matter what the cause? No one I have asked knows the answer to this, which is disturbing, they are using blind faith to avoid corrupted/inconsistent DBs.
1.5 What happens if a controller calls service A, which calls Service B, then service C. Service A must catch any exception and return a nicely formatted return value to the controller. If Service C throws an exception, which is caught by Service A, will service Bs transactions be rolled back? This is critical to know to be able to construct a working application.
UPDATE 1:
Having done some tests, it appears that any runtime exception, even if thrown and caught in some unrelated child calls, will cause everything in the parent to rollback. However, it is not easy to know in the parent session that this rollback has happened - you need to make sure that if you catch any exception, you either rethrow, or pass some notice back to the caller to show that it has failed in such a way that everything else will be rolled back.
2. withTransaction
2.1 This seems a bazaar construct. How do I call this, and what do I pass in for the "status" parameter? What is "setRollbackOnly" exactly. Why is it not just called "rollback". What is the "Only" part? It is tied to a domain object, when your method may want to do update several different domain objects.
2.2 Where are you supposed to put this code? In with the DomainObject class? In the source folder (i.e. not in a service or controller?)? Directly in the controller? (we don't want to duplicate business logic in the controllers)
3. Ideal situation.
3.1 The general case is we want every thing we do in a service method to roll back if anything in that service method cant be saved for any reason, or throws any exception for any reason (checked or unchecked).
3.2 Ideally I would like service methods to "always rollback, unless I explicitly call commit", which is the safest strategy , but this is not possible I believe.
The question is how do I achieve the ideal situation?
Will calling save(failOnError:true) ALWAYS rollback everything, no matter what the reason for failing? This is not perfect, as it is not easy for the caller to know which domain object save caused the issue.
Or do people define lots of exception classes which subclass runtimeException, then explicit catch each of them in the controller to create the appropriate response? This is the old Java way, and our groovy devs pooh pooh this approach due to the amount of boiler plate code we will have to write.
What methods do people use to achieve this?
I wouldn't call myself an expert, and this question is over a year old, but I can answer some of these questions, if only for future searchers. I'm just now refactoring some controllers to use services in order to take advantage of transactions.
I have seen this pattern by experienced grails developers, and when I tell them that if creation of the account of the player fails for any reason, it wont rollback the player, and will leave the DB in an invalid state, they look at me like I am mad because grails handles rolling back the player because services are transactional right?
I'm not seeing in the documentation where it explicitly states that returning from a service method does not rollback the transaction, but I can't imagine that this would be a very sane behavior. Still, testing is an easy way to prove yourself.
1.2 If an exception is thrown, you lose the p.errors - you lose the validation detail.
Since you're the one throwing the exception, you can throw the errors along with it. For instance:
// in service
if (!email.save()) {
throw new ValidationException("Couldn't save email ${params.id}", email.errors)
}
When you catch the exception, you reload the instance (because throwing an exception clears the session), put the errors back into the instance, and then pass that to the view as usual:
// in controller
} catch (ValidationException e) {
def email = Email.read(id)
email.errors = e.errors
render view: "edit", model: [emailInstance: email]
}
This is discussed under the heading "Validation Errors and Rollback", down the page from http://grails.github.io/grails-doc/2.4.4/guide/single.html#transactionsRollbackAndTheSession.
1.4. use .save(failOnError: true) I am a big fan of using this, but its not appropriate everywhere. Sometimes you need to check the reason before going further, not throw an exception. Are the exceptions it can generate always checked, always unchecked, or either? I.e. will failOnError AWLAYS rollback, no matter what the cause? No one I have asked knows the answer to this, which is disturbing, they are using blind faith to avoid corrupted/inconsistent DBs.
failOnError will cause save() to throw a ValidationException, so yes, if you're in a transaction and aren't checking that exception, the transaction will be rolled back.
Generally speaking, it seems to be un-"Grailsy" to use failOnError a lot, probably for the reasons you listed (e.g., lack of control). Instead, you check whether save() failed (if (!save()) ...), and take action based on that.
withTransaction
I'm not sure the point of this, because SpringSource really encourages the use of services for everything. I personally don't like it, either.
If you want to make a particular service non-transactional, and then make one method of it transactional, you can just annotate that one method with #Transactional (unless your developers also dislike annotations because they're too "Java" ;) ).
Note! As soon as you mark a single method with #Transactional, the overall service will become non-transactional.
3.1 The general case is we want every thing we do in a service method to roll back if anything in that service method cant be saved for any reason, or throws any exception for any reason (checked or unchecked).
I feel like checked exceptions are generally considered not "Groovy" (which also makes them not Grails-y). Not sure about the reason for that.
However, it looks like you can tell your service to rollback on your checked exceptions, by listing them in the rollbackFor option to #Transactional.
Or do people define lots of exception classes which subclass runtimeException, then explicit catch each of them in the controller to create the appropriate response? This is the old Java way, and our groovy devs pooh pooh this approach due to the amount of boiler plate code we will have to write.
The nice thing about Groovy is that you can write your boiler plate once and then call it repeatedly. A pattern I've seen a lot, and am currently using, is something like this:
private void validate(Long id, Closure closure) {
try {
closure()
} catch (ValidationException e) {
def email = Email.read(id)
email.errors = e.errors
render view: "edit", model: [emailInstance: email]
} catch (OtherException e) {
def email = Email.read(id)
flash.error = "${e.message}: ${e.reasons}"
render view: "show", model: [emailInstance: email]
} catch (Throwable t) {
flash.error = "Unexpected error $t: ${t.message}"
redirect action: "list"
}
}
And then call it in each controller action like so:
def update(Long id, Long version) {
withInstance(id, version) { Email emailInstance ->
validate(emailInstance.id) {
emailService.update(emailInstance, params)
flash.message = "Email $id updated at ${new Date()}."
redirect action: "show", id: emailInstance.id
}
}
}
(withInstance is another similar method that DRYs up the check for existence and optimistic locking.)
This approach has downsides. You get the same set of redirects in every action; you probably want to write one set of methods for each controller; and it seems kind of silly to pass a closure into a method and expect the method to know what exceptions the closure will throw. But hey, programming's all about tradeoffs, right?
Anyway, hope that is at least interesting.
If you have a service such as:
In a Grails 2 app, the recommended way would be to use transactionStatus.setRollbackOnly().
import grails.transaction.Transactional
Class RoleService {
#Transactional
Role save(String authority) {
Role roleInstance = new Role(authority: authority)
if ( !roleInstance.save() ) {
// log errors here
transactionStatus.setRollbackOnly()
}
roleInstance
}
}
See: https://github.com/grails/grails-core/issues/9212
I was reading the documentation for cfthrow and came accross this
When to use the cfthrow tag
Use the cfthrow tag when your application can identify and handle
application-specific errors. One typical use for the cfthrow tag is in
implementing custom data validation. The cfthrow tag is also useful
for throwing errors from a custom tag page to the calling page.
For example, on a form action page or custom tag used to set a
password, the application can determine whether the password entered
is a minimum length, or contains both letters and number, and throw an
error with a message that indicates the password rule that was broken.
The cfcatch block handles the error and tells the user how to correct
the problem.
Have I been doing it wrong all this time or is this just a terrible use-case?
I was taught that exceptions shouldn't be used to handle regular application flow but for stuff that is somewhat out of your control. For example, a file being locked when you go to write to it.
A user breaking a password rule doesn't quite sound like something that's out of your control.
That is a poor example not a poor use case. I personally would pass in the parameters to a validation function and return a result that contained a pass or fail and a collection of failure messages to display to the user.
How I use exceptions is as follows.
Within functions. Let's say that you have a function that you are getting some data from the database and you are then constructing a structure from it. If the query returned has no values you have several options:-
You could return an empty structure and let the calling code deduce the problem from the fact the structure is empty. This is not ideal because then the application has to have complicated logic to address the missing data.
You could return a more complex datatype where one property is whether the process went ok and the actual data. Again this is not optimal as you have to then make this access the property on every call when the majority of the time you have data and again your application is dealing with this issue.
Or you could raise a custom exception with cfthrow indicating that there is no record that matches. This then means that you can choose to ignore the prospect of this error happening and let it bubble up to the onError handler or you could surround it in a try catch statement and deal with it there and then. This keeps your API clean and sensible.
Wrapping external errors let's say that you connect to an external API using cfhttp over https. Now this requires installing the certificate in your keystore otherwise it throws an error. If this certificate gets updated then it will start erroring again. In this instance I would wrap the call in a try catch and should this be the error I would wrap that in my own custom exception with a message detailing that we need to update the cert in the keystore so that any developer debugging it knows what to do to fix it without having to work it out. If it is not that particular error then I would cfrethrow it so that it bubbles up and is dealt with by whatever exception handling logic is above the call.
These are just a few examples, but there are more. To summarise I would say that throwing exceptions is a way of communicating up through the tiers of an application when something has occurred that is not the hoped for behaviour while keeping your API/Application logic clean and understandable.
It's really up to your discretion. It's extremely common in many languages to use exceptions for everything, including input validation.
Importantly, exceptions have nothing to do with something being in your control or not. For example, suppose that you have a fairly long and complicated module that uploads a file. There are many fail points in something like that: the file could be too big, the file could be the wrong format, etc. Without exceptions your only option is a lot of if/then checks and some kind of status return at the very end. With exceptions, all you have to do is use a set of cfthrows:
<cfthrow type="FileUpload.TooBig" message="The file size was #FileSize#, but the maximum size allowed is #MaxFileSize#">
<cfthrow type="FileUpload.WrongType" message="The file type was #FilType#, but the accepted types are #AcceptedTypeList#">
Then, whatever is calling the file upload function can catch either with <cfcatch type="FileUpload"> or catch a specific one (e.g. <cfcatch type="FileUpload.WrongType">).
Also, technically a user breaking a password is out of your control, in the sense that the user has determined the value for the password. That said, I loathe password rules as invariably they make it harder, not easier, to maintain security.
We use ELMAH for our ASP.NET web app and I am stumped as to some of the exceptions we get. Some of these are:
System.FormatException: Invalid length for a Base-64 char array.
System.Web.HttpException: Unable to validate data.
System.Security.Cryptography.CryptographicException: Padding is invalid and cannot be removed.
I simply have no idea why they occur, but the end user apparently does not see them, so I want to ignore them and supress the emails. If I do this, I want to make sure that System.FormatException only uses Invalid length for a Base-64 char array. for its message text and not also some other message. If it did and I ignored it, I might be missing out on other exceptions that are thrown under System.FormatException. If that is the case, I'd have to check for the message text. That's not a problem, but I really don't like hardcoding strings in my app.
Update:
I tried this code:
try
{
throw new System.FormatException();
}
catch (Exception e)
{
Console.WriteLine(e.Message);
}
Console.Read();
And its message text is:
One of the identified items was in an invalid format.
This tells that the answerer is right and that exceptions should be ignored based on both exception and message text.
The exception's Message property is not useful to help you diagnose bugs in your code or problems with the user's configuration. This is also why you don't know why they occur. You must put more information in your email, particularly the exception's StackTrace property is crucial to help you find out exactly where the exception occurred. If an exception has an InnerException then you always need to know that one as well since it is typically the core reason another exception got triggered.
Simply use the exception's ToString() method to generate a better diagnostic to put in your email message.
I found questions here Should a retrieval method return 'null' or throw an exception when it can't produce the return value? and Should functions return null or an empty object?, but I think my case is quite different.
I'm writing an application that consists of a webservice and a client. The webservice is responsible to access data, and return data to the client. I design my app like this:
//webservice
try
{
DataTable data = GetSomeData(parameter);
return data
}
catch (OopsException ex)
{
//write some log here
return null;
}
//client:
DataTable data = CallGetSomeData(parameter);
if(data == null)
{
MessageBox.Show("Oops Exception!");
return;
}
Well, there is a rule of not returning null. I don't think that I should just rethrow an exception and let the client catch SoapException. What's your comment? Is there better approach to solve this problem?
Thank you.
In your case, an exception has already been thrown and handled in some manner in your web service.
Returning null there is a good idea because the client code can know that something errored out in your web service.
In the case of the client, I think the way you have it is good. I don't think there is a reason to throw another exception (even though you aren't in the web service anymore).
I say this, because, technically, nothing has caused an error in your client code. You are just getting bad data from the web service. This is just a matter of handling potentially bad input from an outside source.
Personally, as a rule of thumb, I shy away from throwing exceptions when I get bad data since the client code can't control that.
Just make sure you handle the data == null condition in such a way that it doesn't crash your client code.
In general i try to design my webservices in such way that they return a flag of some sort that indicates whether there was a technical/functional error or not.
additionally i try to return a complex object for result not just a string, so that i can return things like:
result->Code = "MAINTENANCE"
result->MaintenanceTill = "2010-10-29 14:00:00"
so for a webservice that should get me a list of dataEntities i will return something like:
<result>
<result>
<Code>OK</Code>
</result>
<functionalResult>
<dataList>
<dataEntity>A</dataEntity>
</dataList>
</functionalResult>
</result>
so every failure that can occur behind my webservice is hidden in a error result.
the only exceptions that developers must care about while calling my webservice are the exceptions or errors that can occur before the webservice.
All the WebServices that I've used return objects, not simple data types. These objects usually contain a bool value named Success that lets you test very quickly whether or not to trust the data returned. In either event, I think any errors thrown should be untrappable (i.e. unintentional) and therefore signify a problem with the service itself.
I think there may be a few factors to consider when making a decision:
what is the idiomatic way to do this in the language your using (if it wasn't a webservice)
how good your soap/webservice library is (does it propogate exceptions or no)
what's the easiest thing for the client to do
I tend to make the client do the easiest, idiomatic thing, within the limitations of the library. If the client lib doesn't take care of auto restoring serialized exceptions I would probably wrap it with a lib that did so I could do the following.
Client:
try:
# Restore Serialized object, rethrow if exception
return CallGetSomeData(parameter);
except Timeout, e:
MessageBox.Show("timed out")
except Exception, e:
MessageBox.Show("Unknown error")
exit(1)
WebService:
try:
return GetSomeData(parameter) # Serialized
except Exception, e:
return e # Serialized
Your first problem is "a rule of not returning null". I would strongly suggest reconsidering that.
Returning a SoapException is a possibility, but like hacktick already mentioned, it would be better to return a complex object with a status flag {Success,Fail} with every response from the web service.
I think it all boils down to the question whether or not your client can use any info as to why no data was returned.
For example - if no data was returned because the (say sql) server that is called in GetSomeData was down, and the client can actually do something with that information (e.g. display an appropriate message) - you don't want to hide that information - throwing an error is more informative.
Another example - if parameter is null, and that causes an exception.. (although you probably should have taken care of that earlier in the code.. But you get the idea) - should have throw an appropriate (informative) exception.
If the client doesn't care at all why he didn't get any data back, you may return null, he'll ignore the error text anyhow and he's code will look the same..
If your client and service are running on different machines or different processes, it will be impossible to throw an error from the service and catch it on the client. If you insist on using exceptions, the best you can hope for is some proxy on the client to detect the error condition (either null or some other convention) and re-throw a new exception.
The general practice in handling exception is, when the sequence of flow is expected in the normal circumstance where as the sequence could not be completed due to non-availability of resources or expected input.
In your case, you still need to decide how do you want your client side code to react for null or exception.
How about passing in a delegate to be invoked when anything bad happens? The delegate could throw an exception if that's what the outside could would like, or let the function return null (if the outside code will check for that), or possibly take some other action. Depending upon the information passed to the delegate, it may be able to deal with problem conditions in such a way as to allow processing to continue (e.g. the delegate might set a 'retry' flag the first few times it's called, in case flaky network connections are expected). It may also be possible for a delegate to log information that wouldn't exist by the time an exception could get caught.
PS--It's probably best to pass a custom class to the problem-detected delegate. Doing that will allow for future versions of the method to provide additional information to the delegate, without breaking any implementations that expect the simpler information.
Exceptions are recommended in the same process space. Across processes, it is only through information that a success/failure is evaluated.
Since you are the client to your webservice, you can log the exception at the service layer and return null to the client, yet the client should still know if the CallGetSomeData returned null because a) data is not available, or b) there is a database exception as the table is locked. Hence its always good to know what has caused the error for easier reporting at client side. You should have a error code and description as part of your message.
If you are not consuming your webservice then you should definetly throw exception for the same reasons mentioned above, client should know what has happened and its upto them to decide to what to do with that.
When I design a class I often have trouble deciding if I should throw an exception or have 2 func with the 2nd returning an err value. In the case of 2 functions how should I name the exception and non exception method?
For example if I wrote a class that decompresses a stream and the stream had errors or incomplete I would throw an exception. However what if the app is trying to recover data from the stream and excepts an error? It would want a return value instead? So how should I name the 2nd function?
Or should I not have both an exception method and a nonexception method?
Or should I not have both an exception method and a nonexception method?
That. Unless you really have time to burn maintaining two separate but mostly-identical methods.
If you really need to allow for clients that won't consider errors exceptional, then just indicate them with a return value and be done with it... Otherwise, just write the exception-throwing version and let the odd error-eating client handle the exception.
It depends on the language, but...
In my opinion, two versions of each potentially failing method imposes too high a cognitive burden on the API user, and too high a burden on the API maintainer. My personal preference is for exceptions, since that's fewer parameters to remember the order of.
I believe that you should try to use exceptions even if you're not going to exit program in some cases. You just need to create a specific exception type for your errors. And catch only them when you need to do some spefic logic. All other exceptions will go to upper level of your code.
For example you've created function which throws exception on any error. And you don't want to exit program if user specified incorrect file name. Here is how it can look:
## this is top level try/catch block
try {
## your main code is here
...
## somewhere deep in your code
try {
## we trying to open file specified by user
}
catch (FileNotFoundException) {
## we are not going to exit on this error
## let's just show a user an error message
## and try to ask different file to open
}
} catch (Exception) {
## catch all exceptions here
## the best thing we can do here is save exception to log and quit }
}
We just need to create hierarchy of exceptions (if your language allows it):
Exception <-- MoreSpecificException
This approach is used in Java
Exceptions should normally be used for exceptional conditions, whatever they may be. Being unable to decompress a file is probably an exceptional condition (unless, for example, you're writing a program to scan for badly compressed files). Bad data may or may not be exceptional.
If you've got a class decompressing a stream, then what it should do is decompress the stream, and not try to interpret its contents. Another class should use the first class to get decompressed input, and do the interpretation. That gives you separation of functionality, and good cohesion. Avoid classes where you're tempted to put an "And" in their names: "DecompressAndParseInput" is a bad class name.
Given two classes, there's no particular reason why you have to use the same error-reporting
method for both. The decompressor could throw, and the parser could return an error code.
I would only throw an exception on the decompression function if the results were not usable. If they were usable, return the results and then the function that reads those results can throw an exception instead. IE
try
{
results = decompress(file); // only throws exceptions on non-usable files
} catch (FileNotFoundException) {
// file was not usable, can't recover anything, insert nuclear error handling here
}
try
{
read(results);
} catch (ErrorThatIsRecoverableException) {
partialRead(results);
}
so read() is the function you call on normal data, partialRead is the function that handles trying to recover screwed-up-but-still-usable data. And of course, you don't necessarily need exceptions or separate functions at all- you could do the error handling all within the read() function.