Error Handling is very important component of a software system. Operational logging, defects tracking and effecient debugging is only possible if error handling is given greate attention in the design phase. Some usescases like security events and audits are based heavily on error-handling and additionaly efficient logging.
There are a few error handling strategies that i have experienced so far and today will talk about them.
Common & Centralised Error Response Structure
Both Common & Centralised are 2 different things here so let me 1st talk about Common Error Response Structure.
- Define a common pattern/structure for error responses that will be used as a contarct between backend and frontend codebases.
- Backend devs must be advised to strictly follow that error response structure when throwing errors/exceptions.
- Frontend devs must expect the same structure for incoming error objects.
Coming back to Centralised Error Response Structure.
Now, we know that Reusibilty is a big factor for efficient software systems. There is a famous quote by Douglas Crockford (a javascript pioneer):
"Code reuse is the Holy Grail of Software Engineering".
Advanced applications are taking the inspiration from that(maybe 🤷‍♂️) & these days Error Messages are not hardcoded in the code. Instead of that:
- Create a centralised file/DB-table/document
(file recommended)
. Fill that centralised file with pre-defined error responses. - These pre-defined error responses must be used by backend devs when throwing error/exception across the whole codebase.
This approach has many benefits:
- One error response could be used for multiple errors in application so no repetitive code.
- Any change in an error response is needed only in one place and that change will propagate through the code itself.
- It's easier to maintain a single centralised error response location/file than using hard-coded error message strings for each error.
Once Centralised and Common Error Response Structure is defined for the system. Next step is to decide the Error-Handling strategy for your codebase that how your code will throw an error while conforming to the Error Response Structure.
1. Generic Error Class
In this approach, one generic error class extended from base Error class available in the language is written for catching errors irrespective of the error type. This error class is used in every part of the code to throw exceptions/errors.
A predefined error response (imported from Centralised Error Response file) will be passed to this generic class each time an exception is thrown.
each time an exception is thrown.
-
Pros:
- No repetitive code to handle multiple error types.
- A single point of concern to manage all errors/exceptions in the system.
- No hassle required to drill down the error types at multiple code layers and make error handling complex.
- Simple and straight-forward way to track the error location and type from error response.
-
Cons:
- Readability is an issue as only a single class name is being used for every error type.
- No identification of the code layer or module that generated the error so extra debugging effort is required from developers.
- Cumbersome for nested errors as error flow will become complex because all errors have one type/class.
2. Child Error Classes
In this approach, we create multiple child classes extended from base Error class. Each child class is supposed to handle errors for a particular error type like UnAuthorizedError, UserNotFoundError. We can customise these child error classes to send the desired error response from the centralised error responses file.
-
Pros:
- Better understanding of error types.
- Can customise child error class for any relevant application component name/term.
- In case of nested errors, error flow is easy to comprehend.
-
Cons:
- Repetitive code with a slight change for http code possibly.
- Huge number of child error classes will make the architecture a mess.
3. Error Handling Middleware
This is the most optimised approach for error handling. Here, an error handling middleware is registered to the application which accepts all errors from each part of the codebase and custom actions can be performed on errors in the middleware like response transformation/ notification emails/ recognise error types etc.
-
Pros:
- Distinguish error type and take actions for error based on its type.
- Transform error response to common structure decided and send it to the client.
- No duplicated code for multiple error types.
- Code structure becomes clean because no more error handling modules are to be maintained.
- Single point to manage your system error handling strategy.
-
Cons:
- Have to update middleware for every new error type identified in the system.
- A deliberate effort is required to identify existent system error types and make them functional for client responses.
Logging
Logging is an important component of architecture not only for tracking errors but also for audits and operational purposes. Try to implement or use a 3rd party logger with basic logging featuers like:
- Seamless transports for exporting logs to file system/DB etc.
- Sensitive information masked off.
- Customizable log strings for console.
Top comments (0)