TE
科技回声
首页24小时热榜最新最佳问答展示工作
GitHubTwitter
首页

科技回声

基于 Next.js 构建的科技新闻平台,提供全球科技新闻和讨论内容。

GitHubTwitter

首页

首页最新最佳问答展示工作

资源链接

HackerNews API原版 HackerNewsNext.js

© 2025 科技回声. 版权所有。

Better Error Handling

72 点作者 zdgeier23 天前

21 条评论

jackjeff23 天前
Checking for errors after every line (like in Go) is the worst. Used to do that in c&#x2F;c++ calling win32 APIs. Know what happened when sloppy developers come along? They don’t bother checking and you have really bizarre impossible to debug problems because things fail in mysterious ways. At least with an exception if you “forget” to catch it blows up in your face and it’ll be obvious<p>Sure monads are cool and I’d be tempted to use them. They make it impossible for forget to check for errors and if you don’t care you can panic.<p>But JS is not Rust. And the default is obviously to use exceptions.<p>You’ll have to rewrap every API under the moon. So for Monads in JS to make sense you need a lot of weird code that’s awkward to write with exceptions to justify the costs.<p>I’m not sure the example of doing a retry in the API is “enough” to justify the cost. Also in the example, I’m not sure you should retry. Retries can be dangerous especially if you pile them on top of other retries: <a href="https:&#x2F;&#x2F;devblogs.microsoft.com&#x2F;oldnewthing&#x2F;20051107-20&#x2F;?p=33433" rel="nofollow">https:&#x2F;&#x2F;devblogs.microsoft.com&#x2F;oldnewthing&#x2F;20051107-20&#x2F;?p=33...</a>
评论 #43752439 未加载
评论 #43754311 未加载
评论 #43752254 未加载
评论 #43749747 未加载
评论 #43749883 未加载
评论 #43762125 未加载
geocar23 天前
&gt; An interesting debate emerged about the necessity of checking every possible error:<p>&gt; In JS world this could be true, but for Rust (and statically typed compiled languages in general) this is actually not the case… GO pointers are the only exceptions to this. There are no nil check protection at compile level. But Rust, kotlin etc are solid.<p>Yes it actually is the case. You cannot check&#x2F;validate for every error, not even in rust. I recommend getting over it.<p>For a stupid-simple example: You can&#x27;t even check if disk is <i>going</i> to be full!<p>The disk <i>being</i> full is a real error you have to deal with, and it could happen at any line in your code through no fault of your own, and no it doesn&#x27;t always happen at write() but can also when you allocate pages for writing (e.g. SIGSEGV). You cannot really do anything about this with code- aborting or unwinding will only ever annoy users, but you <i>can</i> do something.<p>We live in a multitasking world, so our users can deal with out-of-disk and out-of-memory errors by deleting files, adding more storage, closing other (lower priority) processes, paging&#x2F;swapping, and so on. So you can wait: <i>maybe</i> alert the user&#x2F;operator that there is trouble but then <i>wait</i> for the trouble to clear.<p>Also: Dynamic-wind is a useful general-purpose programming technique awkward to emulate, and I personally dislike subclassing BackTrack from Error because of what can only be a lack of imagination.
评论 #43750051 未加载
评论 #43752097 未加载
评论 #43751769 未加载
评论 #43754002 未加载
zeroq23 天前
JS aside, I recently tried my very best to introduce proper logging and error handling to otherwise &quot;look ma, no handlebars&quot; codebase.<p>Call it a thought experiment. We start with a clean implementation that satisfies requirements. It makes a bold assumption that every star in the universe will align to help us achieve to goal.<p>Now we add logging and error handling.<p>Despite my best intentions and years of experience, starting with clean code, the outcome was a complete mess.<p>It brings back memories when in 2006 I was implementing deep linking for Wikia. I started with a &quot;true to the documention&quot; implemention which was roughly 10 lines of code. After handling all edge cases and browser incompatibilites I ended up with a whooping 400 lines.<p>Doing exactly the same as the original lines did, but cross compatible.
评论 #43748305 未加载
评论 #43751954 未加载
评论 #43748031 未加载
ivanjermakov23 天前
Errors as values approach suffers similar problem as async&#x2F;await - it&#x27;s leaky. Once the function is altered to possibly return an error, its signature changes and every caller needs to be updated (potentially all the way to the main(), if error is not handled before that).<p>This approach is great when:<p>* program requirements are clear<p>* correctness is more important than prototyping speed, because every error has to be handled<p>* no need for concise stack trace, which would require additional layer above simple tuples<p>* language itself has a great support for binding and mapping values, e.g. first class monads or a bind operator<p>Good job by the author on acknowledging that this error handling approach is not a solver bullet and has tradeoffs.
评论 #43747877 未加载
whatsakandr23 天前
Like most things in C++, I wish the default was `nothrow`, and you added throw for a function that throws. There&#x27;s so many functions that don&#x27;t throw, but aren&#x27;t marked `nothrow`.<p>In my experience I&#x27;ve used exceptions for things that really should never fail, and optional for things that are more likely to.
评论 #43755039 未加载
评论 #43748534 未加载
kikimora23 天前
Common Lisp has retries in addition to exceptions. Retry works almost the same way as exception except it allows exception handler to restart execution from the place it happened. I wish we have this in modern widespread languages.
pmontra23 天前
It&#x27;s strange that they didn&#x27;t write about the Erlang &#x2F;Elixir approach of<p>1. returning a tuple with an ok or fail value (so errors as values) plus<p>2. pattern matching on return values (which makes error values bearable) possibly using the with do end macro plus<p>3. failing on unmatched errors and trying again to execute the failed operation (fail fast) thanks to supervision trees.<p>Maybe that&#x27;s because the latter feature is not available nearly for free in most runtimes and because Erlang style pattern matching is also uncommon.<p>The approach requires a language that&#x27;s built on those concepts and not one in which they are added unnaturally as an afterthought (the approach becomes burdensome.)<p>Pattern matching: <a href="https:&#x2F;&#x2F;hexdocs.pm&#x2F;elixir&#x2F;pattern-matching.html" rel="nofollow">https:&#x2F;&#x2F;hexdocs.pm&#x2F;elixir&#x2F;pattern-matching.html</a><p>With: <a href="https:&#x2F;&#x2F;hexdocs.pm&#x2F;elixir&#x2F;1.18.1&#x2F;Kernel.SpecialForms.html#with&#x2F;1" rel="nofollow">https:&#x2F;&#x2F;hexdocs.pm&#x2F;elixir&#x2F;1.18.1&#x2F;Kernel.SpecialForms.html#wi...</a><p>Supervisors: <a href="https:&#x2F;&#x2F;hexdocs.pm&#x2F;elixir&#x2F;1.18.1&#x2F;supervisor-and-application.html" rel="nofollow">https:&#x2F;&#x2F;hexdocs.pm&#x2F;elixir&#x2F;1.18.1&#x2F;supervisor-and-application....</a>
eximius23 天前
The three things I wish were more standardized in the languages I use are<p>1. Stacktraces with fields&#x2F;context besides a string 2. Wrapping errors 3. Combining multiple errors
评论 #43749614 未加载
Animats23 天前
Most of these proposals miss the point. Errors need a useful taxonomy, based on what to do about them. The question is what do you do with an error after you caught it. A breakdown like this is needed:<p>- Program is broken. Probably need to abort program. Example: subscript out of range.<p>- Data from an external source is corrupted. Probably need to unwind transaction but program can continue. Example: bad UTF-8 string from input.<p>- Connection to external device or network reports a problem.<p>-- Retryable. Wait and try again a few times. Example: HTTP 5xx errors.<p>-- Non-retryable. Give up now. Example: HTTP 4xx errors.<p>Python 2 came close to that, but the hierarchy for Python 3 was worse. They tried; all errors are subclasses of a standard error hierarchy, but it doesn&#x27;t break down well into what&#x27;s retryable and what isn&#x27;t.<p>Rust never got this right, even with Anyhow.
评论 #43749038 未加载
评论 #43749198 未加载
评论 #43748745 未加载
评论 #43760389 未加载
Lord_Zero23 天前
This is called the &quot;result pattern&quot;. I would not call this a novel concept. In C# we use this: <a href="https:&#x2F;&#x2F;github.com&#x2F;ardalis&#x2F;Result">https:&#x2F;&#x2F;github.com&#x2F;ardalis&#x2F;Result</a>
评论 #43747754 未加载
akoboldfrying23 天前
Pretty sure this line: <a href="https:&#x2F;&#x2F;meowbark.dev&#x2F;Better-error-handling#:~:text=return%20Result.fromThrowable(a%20&#x2F;%20b%2C%20()%20%3D%3E%20new%20Error(%27Division%20by%20zero%27))" rel="nofollow">https:&#x2F;&#x2F;meowbark.dev&#x2F;Better-error-handling#:~:text=return%20...</a><p>will immediately throw if b == 0, because<p><pre><code> a &#x2F; b </code></pre> is evaluated immediately, so execution never makes it into fromThrowable(). Does it need to be<p><pre><code> () =&gt; a &#x2F; b </code></pre> instead?<p>Similarly, withRetry()&#x27;s argument needs to have type &quot;() =&gt; ResultAsync&lt;T, ApiError&gt;&quot; -- at present, it is passed a result, and if that result is a RateLimit error, it will just return <i>the same error again</i> 1s later.
ChrisMarshallNY23 天前
I’m of the opinion that the best error handling, is to not encounter the error, in the first place.<p>That means good UX, intuitive interfaces, good affordances, user guidance (often, without requiring them to read text), and simplicity.<p>When an error is encountered, then it needs to be reported to the user in as empathetic and useful manner as possible. It also needs to be as “bare bones” simple as can reasonably be managed.<p>Designing for low error rates, starts from requirements. Good error reporting requires a lot of [early] input from non-technical stakeholders.
评论 #43749606 未加载
RadiozRadioz23 天前
The caveat that this focuses on the JS ecosystem is important. JS error handling is notoriously terrible. Lots of the complaints here would be solved by native support for typed &amp; checked exceptions, the latter of which was not mentioned in the article. Support for those two would be a big improvement, and we could still use the Optional&#x2F;Result &quot;errors as values&quot; pattern in places where that is the more elegant approach.
herrington_d23 天前
the blog lacks the review of one critical player effect.ts <a href="https:&#x2F;&#x2F;effect.website&#x2F;docs&#x2F;error-management&#x2F;two-error-types&#x2F;" rel="nofollow">https:&#x2F;&#x2F;effect.website&#x2F;docs&#x2F;error-management&#x2F;two-error-types...</a>
pragmatic22 天前
Please, please don’t graft on error handling schemes like this.<p>It go, use go style, in js use try&#x2F;catch&#x2F;finally.<p>Some junior engineer is going to stumble upon this and create a mess &#x2F;bad week for the next poor soul who has to work with this.
sestep23 天前
Somewhat related, from March: <a href="https:&#x2F;&#x2F;news.ycombinator.com&#x2F;item?id=43297574">https:&#x2F;&#x2F;news.ycombinator.com&#x2F;item?id=43297574</a>
havkom23 天前
try catch - where you catch the right types of errors at the right level is hard to beat.<p>However, many make the mistake to handle any errors at the wrong level. This leads to really buggy and hard to reason about code and in some cases really bad data inconsistency issues.<p>A rule of thumb is to never catch a specific error which you are not in a good position to handle correctly at that precise level of code. Just let them pass through.
the_linux_lich21 天前
Hey, thanks for mentioning my library, go-go-try. I just released a new version with a simplified API surface, check it out!
medhir22 天前
not a solution for every single type of JS error, but reading through this I found myself wondering why not just use .then().catch() statements when making async calls.<p>Compared to try &#x2F; catch with await, falling back to promises at least makes the error handling explicit for each request — more along the lines of what Go does without having to introduce a new pattern.
domlebo7023 天前
Very balanced post thank you. Often these posts tout an approach, and never consider downsides.
teddyh23 天前
&gt; <i>Lack of Type System Integration</i><p>Well, IIUC, Java had (and still has) something called “checked exceptions”, but people have, by and large, elected to not use those kind of exceptions, since it makes the rest of the code balloon out with enormous lists of exceptions, each of which must be changed when some library at the bottom of the stack changes slightly.
评论 #43747425 未加载
评论 #43748324 未加载
评论 #43748746 未加载
评论 #43747127 未加载
评论 #43751893 未加载
评论 #43747198 未加载