Hacker News new | ask | show | jobs
by dkarl 1514 days ago
I disagree. These two bits of code cater to different ways of reading. The first caters to a happy-path reading, where the reader has the choice to yadda-yadda the error handling or mentally expand it. The second foregrounds the error handling on an equal footing with the other logic.

I like your example, because this is exactly what happened in the application code I had to work with. In an application with complicated business logic, it isn't just one line of code turning into ten like you have here. It's ten lines of business logic turning into forty or fifty, where each operation is separated from the next by multiple lines of error-handling boilerplate.

The trade-off is that in Go code you can see every error path. This is a good trade-off for systems where absolute reliability and rigorous error handling are critical.

In an exception-oriented language the error paths are often invisible. This is a good trade-off for complicated business logic where error handling usually means aborting with an appropriate exception. Think about processing a record or a request where you have to validate the request, look up a few related objects in a datastore, check some business rules, do an authorization check for the requesting user, calculate the result of the request, store the result in a datastore, and produce a response. Each step can be written in a couple of lines of code that are hopefully pretty understandable if you have good names, like this:

    validate_request(request)
    user = fetch_user(request.for_user_id)
    authorize_user(user, Privileges.CanFoo)
    dingles = fetch_dingles_by_dongle_group(request.dongle_group_id)
    unfooable_dingles = dingles.filter(not_fooable)
    if (!unfooable_dingles.is_empty()) {
        throw BadRequestException("This dongle group contains unfooable dingles")
    }
    fooment = calculate_total_fooment(dingles)
    fooment_store.save(fooment)
    return DongleGroupFooed(request.dongle_group_id)
From one point of view, this code is nice. You can read these lines of code quickly and see what the basic request handling logic is. It reads like a story.

From another point of view, this code is terrible. A lot of different things can go wrong here, and only one of them is visible. What happens if the user can't be found? What happens if the user isn't authorized? What happens if the dongle group id can't be found? If the wrong exception is thrown, the wrong result will be reported for this request. You have to navigate to other functions to check that. If that makes it bad code for you, then you'd probably rather be writing Go. In Go, these eleven lines would turn into thirty to fifty lines of code. The handling of each error would be visible, at the cost of the happy path being harder to follow.

1 comments

You're absolutely spot-on with this analysis. And it is a core assertion of Go that non-explicit error handling produces less reliable programs. It's a value judgment and it's a subjective assessment.