I would like add my two cents on this topic from software engineering viewpoint.

Before comment on the proposal, I want to state some opinionated principles 
about error handling.

  1. Each component should only catch an exception if and only if the component 
is responisble to handle the exception.
  2. If a component encounter an exception that it is not responsible to 
handle, the component should propagate up the exception **completely**. 
Complete means no information lost.



These principles applies to multi-language multi-serivce system. For example, 
in a micro-services environment, a service A written in Nim make an HTTP call 
to service B written in Java, and service B encounter an exception that it is 
not responsible to, then service B should return a json response (or whatever 
format) that contain all necessary info (e.g. error code, error message...) 
that service A can reconstruct the error completely in Nim. And if serivce A 
also not responsible to that exception, this process will continue.

Go back to the proposal, some comments:

  1. The proposal say that "... ErrorCode that covers everybody's use case..." 
IMO, this is unrealistic. For example, a money transaction 
`Transaction(sender:AccountId, receiver:AccountId, amount:Currency)` and a 
procedure `process(t: Transaction)` that process the transaction. The process 
can fail if the sender do not have enough balance; or if the account of 
sender/receiver is freezed; or if the sender has already exceed daily 
transaction limit; or etc. From what I see in the proposed ErrorCode list, 
generic `Failure` is best for the above three. It is not `PermissionDenied` nor 
`BadOperation`. In my experience, the unhappy paths are increasing over time, 
and they must be distinguishable. A generic fixed set of status codes is not 
practical. HTTP status code is long-known to be ambiguous. HTTP status code is 
more for observability for third-party tools, rather than error handling within 
a system.
  2. It seems to me the proposal try to avoid "error translation". My 
understanding of error translation is that a component catch the error X and 
then re-wrap the error as Y. My point of view (as following the principle 
above) is that if that translation is part of the responsibility of the 
component, then go ahead; if not, then no translation should be conducted and 
the error should be propagated up completely. This depends on application 
logics, and 'translation of error' should not be considered as evil.
  3. IMO, current Nim's error hierarchy is working fine. Co-existing two 
mechanisms/style of error handling will reduced readability and style 
consistence.
  4. IMO, the cost of throwing exception is neglectable. Any single IO 
operation takes way longer than exception propagation. And the extra 
information associated with error are not to be dropped (as proposed to put 
into thread local storage). 


Reply via email to