Tricky java that should not be tricky, and how go is better :)
What is the problem with the following java method? (Medium’s code presentation sucks, so it’s a screenshot.) Here it is as a gist.

I’m still collecting samples, but so far myself and 2 coworkers failed to see the problem. One coworker did spot the problem, but we were in there looking for it. I saw the problem as soon as he pointed it out. Reviewing the git blame/history of the code, I found that the error was introduced by the original author of the method. All four of us are professional programmers, with many, many years of java experience.
The problem is (if you haven’t found it yet) that the throw new BatchJobFailureException()
never achieves its purpose, because the exception is immediately caught and logged by the catch (Exception e)
before we ever leave the method.
There are 2 root problems, as I see it:
- Exceptions are not always exceptional
try ... catch
style error handling is hard to reason about
The bug in the code is obvious, and easy to spot, in theory. But the reality is that this type of error handling is more challenging to deal with (3 out of 4 coders missed the problem) than go’s approach. The try ... catch
construct encourages dealing with errors later, or maybe never.
Go addresses both these issues by not having exceptions, nor any magical construct to handle exceptions. (Yes, there is panic
but it’s use is strongly discouraged, and it is literally exceptional.)
The source of the bug in this particular case is that the method really has 3 possible responses:
- the job is not yet complete (still working on it)
- the job is complete
- the job failed/was cancelled
Below is the logic from above translated, as directly as possible, to idiomatic go. Here is a gist.

The biggest change, in logic flow, is that checking for a communication failure is moved right next to the client.status()
call, rather than dangling at the end of the method.
There is a case where we fail to communicate, and that should be logged. But the return value for that is “not yet complete” (i.e. try again later).
This is a perfect example of how errors are sometimes not errors (failure to communicate is not a serious error), and sometimes non-errors are errors (successfully retrieving a status of a remote failure generates an error).
Personally, I take this as further evidence that go’s decision to treat errors as values, and not consider them exceptional, is key to building less buggy, and more robust software.
One of the very first thing that newcomers to go complain about is the lack of try ... catch
and all the explicit error checking that is required. But the bottom line is that go’s error handling style makes code simpler, and more maintainable.