Error hiding
Encyclopedia
Error hiding is an anti-pattern
in computer programming
. The programmer hides error messages by overriding them with exception handling
. As a result of this the root error message is hidden from the user (hence 'error hiding') and so they will not be told what the actual error is. Error hiding is a bane of support engineers' jobs as it often delays the resolution of the problem by hiding information needed to identify what is going wrong.
A common argument for error hiding is the desire to hide complexity from the user. Frequently best practice is to raise an exception to the user to hide a complex error message but to save the full error message to an error log which a support engineer can access to resolve the problem.
Example:
try
ImportFile(filename);
except
// an exception with almost no information
raise Exception.Create('import failed');
end;
This code fragment attempts to open a file and read it into memory. If it fails (for whatever reason) the user only gets a message telling them that the import failed, not why or indeed which file failed to import.
// better approach
try
ImportFile(filename);
except
on E:Exception do
begin
// build an informative message
E.Message := 'Import of file <'+filename+'> failed.'+#13#10 +
E.Message;
// re-raise the exception
raise;
end;
end;
In this example the user at least gets a message that tells them which file failed to import; this gives them a start at diagnosing the problem. A more complete solution would include additional information on why the import failed (e.g. "File does not exist", "File appears to be damaged", "Do not have permission to access this file", etc... ) and write the information to a log file, possibly (for very complex or enterprise level applications) also generating extra 'trace' files containing detailed records of the state of the application when the error occurred.
Sometimes error hiding is a valid activity, for example accessing the contents of a file that does not exist in Java
version 1.3 or older would result in an
Another justification for Error Hiding is to avoid component crashing in case of failure. Despite the error, the component continues its job. The user (and the testers) never see the crash, even if some anomalies can be discovered, as the results are not those expected.
This is accomplished either with a try/catch with an empty catch clause, or by executing code depending on the returning error status:
Example of try/catch error hiding (C++ code):
As it is this code is extremely difficult to debug (and is even more, in case of nested "empty try/catch" Error Hiding code), and any anomaly is extremely difficult to trace to its origin, increasing maintenance costs, only to keep up an appearance of robustness.
Example of error returning error hiding (VBScript code):
The consequence is that when some error happens, it is hidden by the code (because it's error prone or simply verbose to add an Else clause) until someone notices something is amiss.
A devious consequence is that when some similar code is written, but without the If/End If clauses, and is executed after the first code, the second code will fail, but no one will know the failure happened before and was hidden.
Thus one can provoke the appearance of a bug months after the bug was first introduced (but hidden and thus, never discovered).
. This type of exception forces the programmer to handle the exception even if the programmer has no means to effectively do so. The problem becomes more egregious in large or complex systems. For example, a programmer implementing function A may require the service of another component B. Component B may then in turn delegate to component C to fulfill that request. If component C encounters a failure during that service it may indicate this by throwing a checked exception to component B. Component B after recovering from the error but unable to fulfill the request from Function A may indicate this by re-throwing the error from C. Function A, having no recourse to handle an error from component C has three options:
A novice programmer may choose the third option and hide the error (also referred to as exception swallowing). The consequence of swallowing the exception is that the system may be put into an unstable state but its users (both human and machine) will remain unaware that a critical failure has occurred. These type of errors when finally discovered are sometimes near impossible to debug because when it does manifests as a noticeable error it is sometimes much later in the process from where the error actually occurred.
Given a large multi-layered application with a high amount of inter-object communication checked exceptions may end up being passed through multiple layers before finally reaching a point where they can be properly handled and reported the end user. In addition to being subject to potential hiding issues at each layer, domain models also become polluted with excessive coupling.
Anti-pattern
In software engineering, an anti-pattern is a pattern that may be commonly used but is ineffective and/or counterproductive in practice.The term was coined in 1995 by Andrew Koenig,...
in computer programming
Computer programming
Computer programming is the process of designing, writing, testing, debugging, and maintaining the source code of computer programs. This source code is written in one or more programming languages. The purpose of programming is to create a program that performs specific operations or exhibits a...
. The programmer hides error messages by overriding them with exception handling
Exception handling
Exception handling is a programming language construct or computer hardware mechanism designed to handle the occurrence of exceptions, special conditions that change the normal flow of program execution....
. As a result of this the root error message is hidden from the user (hence 'error hiding') and so they will not be told what the actual error is. Error hiding is a bane of support engineers' jobs as it often delays the resolution of the problem by hiding information needed to identify what is going wrong.
A common argument for error hiding is the desire to hide complexity from the user. Frequently best practice is to raise an exception to the user to hide a complex error message but to save the full error message to an error log which a support engineer can access to resolve the problem.
Example:
try
ImportFile(filename);
except
// an exception with almost no information
raise Exception.Create('import failed');
end;
This code fragment attempts to open a file and read it into memory. If it fails (for whatever reason) the user only gets a message telling them that the import failed, not why or indeed which file failed to import.
// better approach
try
ImportFile(filename);
except
on E:Exception do
begin
// build an informative message
E.Message := 'Import of file <'+filename+'> failed.'+#13#10 +
E.Message;
// re-raise the exception
raise;
end;
end;
In this example the user at least gets a message that tells them which file failed to import; this gives them a start at diagnosing the problem. A more complete solution would include additional information on why the import failed (e.g. "File does not exist", "File appears to be damaged", "Do not have permission to access this file", etc... ) and write the information to a log file, possibly (for very complex or enterprise level applications) also generating extra 'trace' files containing detailed records of the state of the application when the error occurred.
Sometimes error hiding is a valid activity, for example accessing the contents of a file that does not exist in Java
Java (programming language)
Java is a programming language originally developed by James Gosling at Sun Microsystems and released in 1995 as a core component of Sun Microsystems' Java platform. The language derives much of its syntax from C and C++ but has a simpler object model and fewer low-level facilities...
version 1.3 or older would result in an
IOException
message without any reference to the missing file. In this case is would be sensible to hide the error and raise an exception based on what the application was trying to do at the time, giving what extra information can be obtained.Another justification for Error Hiding is to avoid component crashing in case of failure. Despite the error, the component continues its job. The user (and the testers) never see the crash, even if some anomalies can be discovered, as the results are not those expected.
This is accomplished either with a try/catch with an empty catch clause, or by executing code depending on the returning error status:
Example of try/catch error hiding (C++ code):
As it is this code is extremely difficult to debug (and is even more, in case of nested "empty try/catch" Error Hiding code), and any anomaly is extremely difficult to trace to its origin, increasing maintenance costs, only to keep up an appearance of robustness.
Example of error returning error hiding (VBScript code):
The consequence is that when some error happens, it is hidden by the code (because it's error prone or simply verbose to add an Else clause) until someone notices something is amiss.
A devious consequence is that when some similar code is written, but without the If/End If clauses, and is executed after the first code, the second code will fail, but no one will know the failure happened before and was hidden.
Thus one can provoke the appearance of a bug months after the bug was first introduced (but hidden and thus, never discovered).
Manifestations in languages that support checked exceptions
Error hiding is one of the more common anti-patterns to encounter in languages that support the paradigm of checked exceptions including JavaJava (programming language)
Java is a programming language originally developed by James Gosling at Sun Microsystems and released in 1995 as a core component of Sun Microsystems' Java platform. The language derives much of its syntax from C and C++ but has a simpler object model and fewer low-level facilities...
. This type of exception forces the programmer to handle the exception even if the programmer has no means to effectively do so. The problem becomes more egregious in large or complex systems. For example, a programmer implementing function A may require the service of another component B. Component B may then in turn delegate to component C to fulfill that request. If component C encounters a failure during that service it may indicate this by throwing a checked exception to component B. Component B after recovering from the error but unable to fulfill the request from Function A may indicate this by re-throwing the error from C. Function A, having no recourse to handle an error from component C has three options:
- Re-throw the exception
- Catch the exception, log it and re-throw it
- Catch the exception but do nothing meaningful with it.
A novice programmer may choose the third option and hide the error (also referred to as exception swallowing). The consequence of swallowing the exception is that the system may be put into an unstable state but its users (both human and machine) will remain unaware that a critical failure has occurred. These type of errors when finally discovered are sometimes near impossible to debug because when it does manifests as a noticeable error it is sometimes much later in the process from where the error actually occurred.
Given a large multi-layered application with a high amount of inter-object communication checked exceptions may end up being passed through multiple layers before finally reaching a point where they can be properly handled and reported the end user. In addition to being subject to potential hiding issues at each layer, domain models also become polluted with excessive coupling.