Why should we avoid returning error codes?

Asked

Viewed 4,254 times

100

It is common to say that one should avoid returning error codes in a function when some operation fails. It is not hard to see that error codes are confusing (is it a valid value or an error?) and do not provide relevant information.

The recommendation is to use exceptions instead of error codes. Why are exceptions better than error code returns? There are cases where this solution is worse?

The title obviously does not imply that one statement or another is correct. The doubt is this.

  • 1

    I’d rather return a exception. Use a try catch and in the catch deal with that exception, showing a message to the user, saving the error in a log in the database or text file. I believe it is a great practice to use try catch.

  • 1

    And how do you think that answers the question objectively and adds something useful besides informing you what you like?

  • Truth........

  • Being honest in the company where I work the application are in Delphi with Firebird and has no error treatments. Thanks to this the faults are usually easy to identify, so the resolution saves time.

  • @Daniloaraujo I appreciate the comment, but can be more specific?

  • if I understand correctly. the guy asks a question and he answers himself ???? WTF ???

  • On the contrary, the "fashion" today is to return errors instead of releasing exceptions, some modern languages even have the exception mechanism.

  • @epx as I replied Go, Rust and others are languages that have adopted it, but you can’t call it fashion. first because the adoption was done with conscience and not because others were doing it, and that is the fashion definition. These languages break the fashion, the custom, the current ethyl. And this wrong definition that people use to be something popular is also not fashion.

Show 3 more comments

4 answers

87


This is another of the myths that were created because people memorize sentences and do not understand the motivators.

It is true that returning error codes is not usually a very good idea. But if well done, if the proper semantics for the problem is the error code, there is no problem in doing it. Languages live encouraging this. Top experts, including language creators who have the concept of exceptions recommend the use of error codes. They don’t do it so explicitly, so the other programmers don’t get it. Let’s look at some cases.

Some say they have some problems using error codes. I will show below that this is invention in most cases. Or else the person does not know how to create the mechanism properly. I will show that there is usefulness for exceptions, but there was a time they started abusing them and that the modern way of programming is to use error codes, when they are suitable.

The fact that one does not know how to do it correctly is that it has made people think that this form is not correct. The first attempts were done badly, then they look for a solution to another problem instead of solving this problem. Exceptions are also used in the wrong way all the time, either to create them or to capture them. There is no magic mechanism that solves the problem of the person not knowing to program.

Every place where an exception fits, fits another mechanism simpler and made so that gives the same guarantees of the exception, or even better. What can happen is not to be the most convenient, that’s all. So I give all the options here, even the exception.

Return of null

Although I don’t like its indiscriminate use, null is present in most languages. The null usually acts as a reference for nothing and in some languages even as an unexpected value in the type domain. That is, the null is used to indicate that there is no valid value. You define that a function/method should return a type and it returns another type, in dynamic typing languages, or returns an invalid state of the type, in static typing languages.

The null is an error code. It doesn’t look like it, but it is. It’s confusing because you can get things with different semantics. But it has relevant information. He says there is no valid state. And that’s all you need to know.

Even the biggest bidders at the end of the null (i am not relevant in the world of computing, but it is one of the things I most desire in a language) admit that in many cases a way to get a similar solution is needed, probably by types nullable, option or maybe optionally used on top of the main types.

You cannot ignore this error. You cannot use the object without deciding what to do with a null. Some people say you cannot ignore exceptions. Yes, all the time people ignore it, but I won’t go into detail about it. When ignoring the exception is a runtime programming error, just like the use mechanism of null.

Checking if it is null is equal to or less verbose than treating an exception.

One way or another, returning an error code in this way is considered acceptable. I’m not the one saying, "everyone" uses this.

Null Object

This is a case that can be used as well, but it has a greater tendency to give some problem since he confuses himself with a valid object. This is an alternative that I would never use. Or almost, there may always be some situation that is appropriate.

Usually this is the opposite of using the object as an error indicator, it is creating confusion with valid and invalid object.

I’m not saying that this pattern is necessarily bad. I’m just saying it’s not meant to indicate disability.

Boolean and multiple returns

If a function returns more than one value separately, one being the error code and the other the effective value that the function/method should return, it seems to be acceptable as well.

  • This is possible in languages that actually allow the return of multiple values (Python or C# 7, for example);
  • or in languages that allow referenced parameters that can be used to receive extra function/method values (almost all languages, some with limitations or weird way of doing);
  • or all other languages that allow to return a data structure composed of various types, a tuple, for example. There are also languages that allow similar effect with Union Types that is just an optimization.

Usually the error return is done with a boolean type. Because only what you need to know is whether there was an error or not. If there was no error the program knows that it can use the other value in some way, otherwise the value should be ignored.

With the multiple return, the problem of the relevant value being confused with the error code is eliminated and the only important information about the error code that the program needs is whether it has an error or not. You don’t need anything else. The error code return solution is good.

We can see in the example of Tryparse() do . NET a solution like this. The creation of this method occurred after much reflection. It is a better solution to return an error code than to throw an exception.

There are modern languages that are preferring this solution for most cases. It comes to mind now Rust (example) and Go (example).

Return of enumerations

This is a variation of the previous form. It would also be done through multiple returns.

I don’t see many examples of it, but for consistency there is no reason not to use it. If you consider that a boolean is an enumeration that has members true and false, return an enumeration only gives more granular information. And it is often necessary only to know superficially what the error occurred, that is, to know what the error is, but nothing but a simple indicative of this. Exception is too heavy.

Return of a code as part of the expected domain

This is not one of the best ways to return an error code but if you expect something to go wrong, a function does not get the result that the program expects, but needs to communicate it, an exception can be an exaggeration. In addition to the performance problem in a non-exclusive situation, there is a likely increase in code size to handle the exception. In addition the exception will be creating an abnormal flow for a data only invalid.

If it is part of the expected domain it does not create a lot of error tables. Some people don’t understand this, perhaps because they’ve read it generically somewhere and don’t understand the workings of the mechanism.

Example

A good example are the functions/methods that seek the position/index of a string inside of another (IndexOf()). They usually return a value between 0 and the size of the string minus one. But if you find nothing, the return is -1. This is an error code returned. The documentation tells you how to handle this situation and you should take appropriate action in your code as part of the normal flow. It would be crazy to make an exception for something expected.

It is possible to argue that then it should check first whether the string exists within the other and only if it exists should it seek to know what position it is in, so it would be ensured that the return is positive and if this were not possible, it would be a programming error. It’s a valid argument. But it’s probably not worth the effort. And it wouldn’t be performative. It would have to sweep the string twice. And depending on the way the string is implemented, there may be problem of running condition in competing environments.

Abuse

Of course, that can be abused. One of the problems of using it is that in some ill thought out case, one day a negative number may pass as a valid return value.

Another abuse is to return -1 to an error, -2 to another, and so on. But there are situations where this is still better than throwing exceptions. Remember that an exception should only be made in exceptional cases, when something happens that is not expected. Exception is not synonymous with error, invalidity.

Good documentation is essential in such cases.

In search of sacred perfection

Forget the programming will be perfect. After decades of experience, Apis still need to be deprecated because something has not been predicted before and programmers forget to do all their homework. There is no silver bullet that will solve this. Think long before making a decision, but be sure to use a solution because someone said it is bad. You’ll probably just be changing trouble.

Return objects with error information

It is another variation that should be used with multiple returns. But it has mechanism that can be used even better, as has been said before

An exception is costly, it should only be launched when it really is the best solution to that problem. Worse, it is hardly predictable. An exception is a flow control. But it is a control of abnormal flow. It’s hard to be sure you’re treating all the exceptions you should in the right places.

Some cases make more sense return a class that looks like an exception but is just an error code full of additional information that may be necessary for the program to know what to do. There is no confusion and there is rich information of what is the error.

I don’t see this happening, but it should. Probably there is little use because they use the same tool for everything.

Result or derivatives

With it the error and the correct happens to be one thing, but without causing confusion.

It uses an object that encapsulates the correct object and the error object. In some cases it is a union, which saves memory. There are cases where the error object is a simple null. In this way to access the object that is the result it is mandatory to unchain it from the optional object. Abstract example:

union Result<T, E> {
    Ok(T),
    Error(E),
}

A fictitious function could create it:

Result<string, string> Read(string name) {
    string resultado = "";
    if (File.Open(name)) {
        foreach (linha in handler.ReadLine()) {
            resultado += linha;
        }
    } else {
        return Error("O arquivo nem foi aberto");
    }
    return Ok(resultado);
}

There to access the object:

var = textoLido = Read("arquivo.txt");
match textoLido {
    Error(msg) => print("Deu problema:" + msg);
    Ok(texto) => print(texto);
}

Obviously this is not the case to provide the exact implementation, but you can notice that you cannot use textoLido directly, has to treat obligatorily, before using it. You can do this in most languages with more or less convenience.

Of course the programmer may treat wrong, but except no thanks is. Only finds out when it runs and does not work, so the compiler already picks up the problem.

Launch exceptions with built-in error code

Here already changes a little. Obviously there is no confusion because there is no return in case of an error occurrence. The exception is thrown and not returned. It is different from the return of multiple values because there is no return. A function/method that should return something, even returns, after all it is not even finished, it is interrupted by the exception. It is abnormal flow. Also where this exception will be treated can vary quite a lot. The calling function has no obligation to handle the error. Even in languages with checked exceptions effective treatment may be delegated to other methods.

No one who advocates the use of exceptions can say that there is a lack of relevant information in a well-made exception. What may be questioned is whether there should be error codes within the exception.

The more purist will say that instead of having several error codes within an exception, there should be several specialized exceptions. But it’s all about semantics. If the exception is more general, if the important treatment is it and not the codes, ie if the program should capture the exception a little more general even, why capture a more specialized? Just to make the program bigger? To have to put tens or hundreds of catchs to do the same thing in most of them? I think an example explains better.

Example

The question How to get the specific type of error returned by the Entityframework? motivated this post. There we see user6026’s response to Sqlexception has error codes. Looking at the documentation even scares with the amount of possible error codes.

No one can say that relevant information is missing. One cannot argue that the error code has no meaning. Error number is only one of the available information.

If the semantics of the exception is to notify an SQL error, then that’s what it does. If the SQL error has something more specific, it is possible to treat it more specifically. Even throw another exception only in relevant cases as is the case with DbUpdateException.

This is a solution that must have been very well thought out. It certainly wasn’t made by inexperienced programmers. I have my doubts if she’s that good, but it seems to be valid.

Global system of errors

In this mechanism within the functions that can generate an error a global variable is marked, often through a function/method wrapper, with the error information. Any code can access this variable, probably by wrapper, and verify the existence and details of the error.

It can be useful in very specific situations. I had to list it, but he’s bad.

The main problem is that it demands global state.

Error reporting is not done by the API directly. But this is a problem that the exception has as well. Of course, the compiler can deal better with creating new exceptions than with new global error codes. Too much decoupling can be problematic as well.

What it can be used, and it has newer languages that they’re doing, is breaking the application and calling a global treatment when the error is programming or environment. Why throw exception to something that cannot be circumvented?. Exception has its own purpose and does not include this kind of thing. One language thought it was elegant to use exception for all kinds of mistakes, others liked it, copied it, but now many people, who are not stubborn, already accept that it was a mistake to use exception for everything.

When the exception is better

First, understand that exception is nothing simple. It is an unconditional deviation that will take you to a totally undetermined location. This is crazy. A lot can go wrong. You have to follow a lot of rules to work. And practice shows that few programmers know how to use the right way. So why use something complex if you have something simpler?

Some modern languages are even avoiding or limiting the use of exceptions. There are some good reasons to use it and many reasons to avoid it. Exceptions are viral and poorly orthogonal. The design Language is incredibly complicated because of them. These languages have preferred to use an error code return system or some similar way, or stop the execution abruptly giving the chance of a custom output, and leave the exception clearly for exceptional cases.

In Best way to deal with Exceptions i show some cases how an exception should exist and be treated in C#. It is a good basis to think about what is exceptional case or not.

Programming errors are no exceptions

If you consider that general environment failures and programming errors should not be dealt with by the program itself, you should probably have some different form than the exception of indicating an unrecoverable program failure. This would probably prevent abuse of catch that we see every day in programs. There should be a centralized place to address these failures. In them, what we can do is log in the failure and present it to the user in a customized way. Ok, if the language does not have a special way to represent these flaws, then casting an exception is appropriate. Capturing her and trying to save the program, it’s not.

No, you cannot recover a division error by zero. Any solution in this sense will be crazy. If you know how to solve it, then don’t let the exception occur. An exception should not replace a program’s normal flow control. An exception of division by zero is a programming error saying that the programmer forgot to check a situation before splitting.

I will not deal here with cases of poorly made Apis that make exceptions when they should clearly return error codes. In the answer linked above talks about it.

Legitimate exceptions

I am not against the use of exceptions in certain external operations, which depend on resources that the application has no control over. An access to a file is a good example. Note that I said error code and do not check before if an operation will be possible.

if (File.Exists("arq.txt") {
    handler = File.Open("arq.txt");
    foreach(linha in handler.ReadLine()) {
        print linha;
    }
} else {
    print "Não foi possível executar a operação";
}
if (handler != null) {
    handler.Close();
}

The above example (written in generic language) is problematic. It may have a race condition. It relies on true information that can become false between the check and the next file opening operation. This should never be done. But it has how to do the same without risk:

if (File.Open("arq.txt", @handler)) {
    foreach(linha in handler.ReadLine()) {
        print linha;
    }
} else {
    print "Não foi possível executar a operação";
}
if (handler != null) {
    handler.Close();
}

In such case you try to open the file and the reading will only occur if the opening is successful. An error code return (the @handler which is passed by reference) works very well. But there is a problem. Reading can also fail. Let’s improve:

if (File.Open("arq.txt", @handler)) {
    foreach(linha in handler.ReadLine()) {
        if (linha != null) {
            print linha;
        }
    }
} else {
    print "Não foi possível executar a operação";
}
handler.Close();

This API is not very coherent, but I used this form to show different ways of error code return. In this case there is an attempt to read a line, if it fails, the line is null. It is an error code and works well. I made a change in the example by removing the if whereas the close() just wouldn’t do anything instead of fail if there’s nothing to close.

Of course the API could be something like bool deuCerto = handler.ReadLine(linha); but I don’t know if it would be an advantage. Maybe a FileErrorCode erro = handler.ReadLine(linha); was better. In this case the FileErrorCode is an enumeration to give more information about the error. But it could be a (not exceptional) class with more detailed information about the error, essentially the same information you would have in the case of an exception.

This works very well in many cases. There may be problems in others. In C it has always been so and there have never been big problems. This is not why there are problems in C, unless programmers relapse.

Anyway there may be several situations of failure in access to this or other files in the same task and you do not want to fill your function/method of ifs to verify the success of each operation. It is likely that you want to have a generic treatment for all access failures in all files involved. This is a case where letting the error happen and catching an exception can be a good choice. Of course the API should launch the exception.

But since it’s not a good idea to have two Apis doing the same thing or have two ways to handle the error in the same API, it would be confusing, the API picks the one that fits all the cases and you have no choice. You must use the exception.

Interestingly, this is a case where having a lot of information about the exception doesn’t help at all. But there may be other situations that this information is useful.

Using exceptions the example could stay, simply like this:

try {
    handler = File.Open("arq.txt")) {
    foreach(linha in handler.ReadLine()) {
        print linha;
    }
} catch (IOException e) {
    print "Não foi possível executar a operação";
} finnaly {
    handler.Close();
}

I put in the Github for future reference.

The only head start What I see in this case is separating error treatment from normal logic. Of course, if a language has exceptions this becomes practically mandatory. It is the only way to ensure file closure. The existence of exceptions requires the use of exceptions.

Criticism and alternative

Some languages allow you to manipulate these various failure situations differently. In addition to Rust and Go already cited, I can remember D with his scope.

Exceptions are good to treat abnormalities. An exception is a flow control as is the if but it should only be used for abnormal flow, when you need to subvert the normal flow and it is rare to need it when there is no programming error.

The exception mechanism is unstructured by nature. And it should only be used when you have a unstructured error handling situation.

  • When you can avoid error effectively, avoid, don’t let an exception occur.
  • If you have a clear and predictable situation of everything that can result in error, if the error is something normal, possible, expected, but invalid, and not something exceptional, treat the error and not an exception.
  • If an exception is appropriate and cannot be treated in a minimally specialized manner, do not treat it locally. Leave for a general treatment, which can be up to the standard set by framework.

Exception is not panacea. The difficulty of dealing with errors does not occur by using error codes. But there are cases that it is useful to shorten code. You have to write code to handle errors can make the algorithm long, complex or confusing. Are cases where you do not want or can not handle errors, at least in an individualized way, exception can be useful.

Exception could be better

There’s a proposed exception implementation in C++ which goes in the most suitable way, and can suit various best scenarios. I do not know if it is ideal and much less will come true, but clearly it is a better way and solves several problems of the exception.

Completion

When it comes to creating an API or a simple function, returning error codes is not such a big deal. Use them when they make more sense. Use in the way that best suits the language you are using and the specific situation. Use exceptions sparingly. Use them when your engine or your semantics make more sense to the problem. Use them when the problem is programming.

Abuse of exceptions

Here I will not go into detail about the abuse in capturing existing exceptions. I criticize this in several posts. Search between my answers and others from the site.

When it is not certain what to do with more specialized exceptions it is possible to capture an exception from a higher level in the hierarchy. With error codes this is not possible. They have no hierarchy. In thesis. Maybe it is possible to create one, but I will not enter it here.

Possibility to ignore the error

Some argue that error codes can be ignored. Exceptions too, and unfortunately it’s common to see codes that capture them just to swallow them. Bad programmer will produce bad code, no matter what you do to prohibit it. If you do not test correctly you may have problems with the code no matter the error handling mechanism.

In addition, it is possible to use language which requires the processing of error codes. Or make a static analysis tool that checks whether the error codes are being handled.

Culture

Of course some languages force more the culture of one mechanism over the other, but I know of none that does not accept in their standard libraries the return of error codes in some situations.

Exception considered Harmful

Exceptions are the goto of our time. And worse, no one recognizes this. At least there are more reasons to use exceptions than to use goto. Exception is a goto at its worst.

Joel Spolky’s article on the subject.

Nomenclature

I know some people will say that some of the error codes I quoted are not actually error codes. Okay. Call them what you like but don’t trade them for exceptions when there’s no exceptional situation.

References:

  • My question is: do you mean that you should not use error routines ?. I almost do not use in my software, but basically this is it?

  • 1

    @Harrypotter I don’t know what you call error routines. What I said is that there are no problems in returning error codes. I showed that this happens all the time in Apis. I said you should avoid exceptions to the maximum. But avoid is not stop using.

  • 1

    Also depends on the language right? PHP for example is a ghetto of so many different and deregulated error types. it is interesting to convert everything to Exceptions. I even created a mechanism that automatically handles Exceptions in a way that they hardly break the flow as they normally do.

  • 1

    @Brunoaugusto Yes, I even en passant I talk that depends. My knowledge of PHP is pre 5.x and yet I’ve never done anything serious with it, so I don’t know how all this is working. I know that PHP is the champion of disorganization and discrepancy. I don’t know if what you did is good or not, since I don’t know how it works. Sounds like something interesting.

  • In summary, all errors make exceptions, including Controllers if something goes wrong. However, we Controllers, conceptually a single type of exception must (ria) be introduced because the Dispatcher, responsible for the exchange of Front Controller and the Action Controllers, turns that particular Exception into a template variable. Hence the flow does not break as it automatically turns to the previous page without a manual redirection.

  • It is that avoid or not everything depends and I do not see this as an important factor. It is very based on opinion and a text like this demonstrates only opinion.

  • In dynamic languages (where returns have no type set) it is easy to return false instead of the expected return (int or string, for example). But in static languages, it is not unreadable for the code to return a data structure instead of the expected value directly?

  • 1

    @Andrey, yes, the ideal is that the language allows things to be returned separately and not in a data structure. But there is an advantage. You cannot use the value directly. One of the criticisms that is made to the return of error code is that it can be forgotten. This way, you may not even treat it properly (exceptions can also) but you will have to do it consciously. The return would be a structure, but you would immediately separate out what is error and what is the result and then just need to deal with the result, a string for example, no longer deals with the structure

  • 1

    @But it is a mistake to think that it is easier to deal with this in dynamic languages. As you said, it is easy to return, but it can still be handled. And actually, it doesn’t require error management, so it can be worse in them. You must have read the answer about dynamic X static languages, there I say that in practice dynamic languages always return structures, the programmer does not have to deal with them, the compiler does it for him, but it’s there. Sure, I understand it’s easier, but not better.

  • 1

    @Bigown Li yes, because I was the one who asked the question. Only with so many giant answers it is difficult to remember everything always. hahaha The question of structures I had already forgotten. =)

Show 5 more comments

22

Such a recommendation has very strong reasons. I will illustrate some...

Avoiding assumptions

When developing the API of financial calculations, it was assumed that some routines would return only positive numbers in case of success, so it was decided to use negative values to denote error.

After a period of development, it was found that actually negative numbers are valid.

The API will need to be changed completely and all calls (which may be spread across several projects) will need to be revised.

The problem here is not to have to change, but to use an "error object" (negative number) that belongs to the same class as a "success object". This makes changes have more impact.

Defensive programming

PHP is known to contain functions that return different data types according to the function result. Fetching a character in a text can return the position or false, for example.

This solves our first problem, but generates another, namely, passes the responsibility to each call to verify the value returned.

This is why there are always many bugs related to using == or != instead of === or ===, since PHP considers true comparisons as false == 0, for example.

Some people may argue that it is the fault of the programmer not to be careful or read the documentation properly. Well, but bugs don’t always blame some programmer?

Defensive programming means programming always seeking to minimize the possibility of introducing involuntary bugs. Error codes often cause this kind of confusion.

Standardization in error handling

Another problem in returning error codes starts when we start having tables and more tables of possible errors.

In procedural-prone languages, it is common to have Apis that need to define routines specifically to get a description of the errors, check whether the error type, etc.

Soon, each API ends up using a different method of error handling and the burden of checking each returned value is who makes the call, which increases the learning curve and also the probability of programmers making mistakes.

Exceptions are more "simple and secure", in the sense that execution is stopped and the programmer can generically capture errors from several Apis, specializing the treatment when necessary.

Avoiding hidden mistakes

Consider the statement:

Showing an exception to the user is always better than an incorrect result.

In some labor camps, you can’t afford to make a mistake. Imagine a financial system incorrectly calculating interest because the routine that should never return zero returned a zero as error code. Believe me, I’ve seen several times something like this happen.

Because of these things, experienced programmers in some industries would much rather have an exception interrupting execution and generating a generic error than having the possibility of a result that might be detrimental, fine or any possible negative consequence for the business in question.

About the null

Null returns are considered bad for the same reasons mentioned above.

For example, return null requires, but does not require, the programmer to treat the return.

So if I assumption that the routine will not return null and do not do the proper treatment, I am introducing a potential bug in the code, because any future change can introduce changes that make my assumption incorrect. This is a kind of encapsulation break, because who invokes routine presupposes something about it.

The correct then would always be to check the return, but the code would be very verbose.

Alternatives

Empty object

Some situations, such as routines that return arrays, lists, or other collections, should simply return an empty collection if no elements are found.

I’ve seen codes that launch NenhumItemEncontradoException or returning null and this only causes more problems as mentioned above.

In Java:

return Collections.emptyList();

For other cases, there are some people who argue against and in favor of the standard Null Object, which basically consists of creating an object to represent a null return, thus avoiding NullPointerException.

Personally, I don’t like this one design, given the other alternatives below.

Optional return

In routines that return an object, but that at certain times the object may not be present, one can use a wrapper which may or may not contain the object.

In Java:

Optional<Cliente> getCliente(long id) {
    return Optional.ofNullable(daoCliente.findClienteById(id));
}

What is the advantage? For you to access the client object that may or may not be inside the Optinal, it is necessary to test the presence of the object, otherwise an exception is thrown.

In other words, you force whoever calls the method to do some sort of treatment, which makes your API more defensive to errors.

Exclusive return

If you need or want an exceptional object returned, the "safe" way is to return a compound object, which obliges the caller to check the return.

One of the ways is something widely used in functional programming is a class or entity Either. There is no such concept in the Java 8 API, but you implement your version or use a library as Run.

Example in Java:

Either<PlanoDeFuga, PlanoB> getPlanoDeFuga() { ... }

Or else:

Either<ResultadoOperacao, ProblemasProcessamento> processarOperacaoFinanceiraComplexa() { ... }

Considerations

Note that the first term of my reply is recommending. All these are recommendations from people who have developed certain practices after many years of experience.

Unfortunately, there is a lot of distortion and an attempt to apply all this as if it were law, which does not work.

At the same time, it is important to try to understand what lies behind rules or practices. Even if you do not agree or apply, you will still be aware of the risk for which it was created.

In this case, the main risks are: mix the different types of returns (affects languages with weak typing) and expect that the treatment of a possible error value returned is always done in the correct way without, however, having assurance that this will occur.

  • @Filipemoraes Yes, one of the same came out. Thank you for warning.

13

Personally I prefer to return error codes (or true/false) rather than throw exceptions for security reasons, as someone might forget to treat an exception.

In projects where I worked where Apis were developed (usually Dlls written in C) for use by multiple systems or by multiple programming languages (Java, Delphi and C#) it was standard to return "0" as "ok", a negative number for operating system errors (example: file opening error) and a positive number for "business logic" errors (example: unregistered account).

In this type of project each API function had an error code/description table for consultation by programmers and for system documentation. In addition, we sought to standardize the error codes: if "425" was the code used for "unregistered account" in a function, all others that would return this error would use the same code.

Already in functions used inside systems I prefer to return true/false as return and a variable of type "out" with the error message (which will be empty if returned "true" - no error).

0

Why should we avoid returning error codes?

The question is old, but the dilemma is present! The extension of the article proves the vast knowledge of the author, something praiseworthy, even more when he decides to share. Thank you Maniero!!!

Before answering, some fundamental aspects need to be considered:

  1. Who should decide on this?
  2. How to implement the decision?
  3. Consider the sacred triad Q/C/T to answer the above (Quality, Cust, Time)
  4. Who will get the mistakes after all?

That said, we must remove the biased part of the question "...avoid error codes...", because there is no way to avoid them. We need to devote a lot of planning time deciding how to deal with them, regardless of the means/methods to be used, as this will vary depending on the language, basically.

For question 1: So, who should decide: software architect, business analyst, systems analysis, in this order or combined. Ultimately, by default of the above, the developer.

2: Of course, the developer, but backed by a predefined, clear and flexible standard, duly provided in the flow/use case/other documents that are used to specify the solution development. Even be part of the test plan.

3: To consider the aforementioned triad, we know that the variables Q/C/T change according to the phase in which the project is, but it must be considered from the first phase, survey requirements! And in some cases, deciding on it late is the worst choice.

4: Finally, deciding "how to do" and "what to show" will depend on the nature of the application. For, reporting an error to a user is much more expensive than communicating error between applications. Take as an example treat error messages for desktop applications, with end user dealing with exceptions and in the case of micro web services exchanging messages among themselves, in these cases the "who will receive the errors" already pre-defines the treatment method (frendly, typified, Rest, Httpstatus, etc).

In conclusion, there is no answer or direction to be pointed in a 'prior' way, so we must understand the variables to decide how to deal with errors, whether they are predictable or not.

Browser other questions tagged

You are not signed in. Login or sign up in order to post.