6 ms·
My frustration, possibly perhaps how I'm coding, is wrapping every instruction on an error wrapper and then I've got twenty if not an error do the next thing.
by pizzafeelsright 3y ago
My frustration, possibly perhaps how I'm coding, is wrapping every instruction on an error wrapper and then I've got twenty if not an error do the next thing.
I code solo, so I'm not sure how others do it.
The alternative is to have twenty methods?
I build a data structure, modify its state in a dozen ways and then return it to the caller.
- marcus_holmes 3y agoI like Go's error handling. Yes, I know that puts me in a special category of coder. Reasons: - It's simple and easy to understand. There's no hidden complexity, no magic, no gotchas. Nothing is going to surprise me about it. - It's a very readable cadence. Do the thing, check the error, do the thing, check the error, do the thing, check the error. Once you get used to the error checks it's extremely readable. - Despite all the extra characters the actual mental load of the error checks is tiny. Yes it's more typing, but the hard bit about code is thinking not typing, and it doesn't make more thinking. - If I have to do something special with the error, it's easy. There's no incentive to handle this error just like the rest, or ignore it and let the exception handler catch it. If this error needs (for example) extra logging then I can just put it in there for this error check, no hassle. - It's pretty much standard across all Go code. If I have to deal with someone else's code, I can expect the same cadence, the same simplicity, the same readable pattern of error checks. One of the great things about Go is that it is opinionated about stuff like this.
- lmm 3y ago> - Despite all the extra characters the actual mental load of the error checks is tiny. Yes it's more typing, but the hard bit about code is thinking not typing, and it doesn't make more thinking. The hard part is understanding the existing code. The more cluttered and verbose the code is, the harder that is. Go's boilerplate if err != nil return err, nil becomes something that your eyes just skim over - which is fine right up until you have some code that's doing something similar but not the same, and don't even notice.
- marcus_holmes 3y agoI find that the differences leap out at me. Even just a `err == nil` instead of `err!= nil` is noticeable. I do have to spend a second reading the action if it's not just `return result, fmt.Errorf("failed to do the thing: %w", err)` but that's good, I think. And all of this is way easier than trying to trace up through the stack to the nearest exception handler and work out what it will do with the error edit: also, verbosity doesn't make code harder to understand, imho. If anything the other way around. Packing 5 statements into a single line is massively harder to read than separating those same 5 statements into 20 lines with error handlers.
- lmm 3y ago> And all of this is way easier than trying to trace up through the stack to the nearest exception handler and work out what it will do with the error You still have to do that part though? Like, this function returns err, so the caller returns err, so the caller of that returns err, ... - you've still got to walk up the stack to the point where the error is actually dealt with. > edit: also, verbosity doesn't make code harder to understand, imho. If anything the other way around. Packing 5 statements into a single line is massively harder to read than separating those same 5 statements into 20 lines with error handlers. Very much not my experience. There's a huge understandability hit when a function doesn't fit on a single screen and you have to scroll, so vertical space is really precious.
- marcus_holmes 3y ago> you've still got to walk up the stack to the point where the error is actually dealt with. This is why we wrap errors. The error message gives a pretty good indication of what the stack was doing when it went wrong. I had a junior dev work with me on some JS. I was writing it in functional style because it made sense at the time. He was really struggling, so I refactored it to old-school imperative and he understood it and was able to work with it. It might have been an issue with the way he was taught JS, but I think it's more that tightly-packed concise code is actually harder to parse. Not least because you have to understand the whole thing to work out wtf it's doing. Whereas with one-statement-per-line you can scan down to the lines you're interested in and focus on those.
- threeseed 3y agoThe problem is that it's so incredibly inflexible and dated. Many effectful actions e.g. reading from a file system can have a range of different errors each of which you want to handle differently e.g. out of disk space versus lack of permissions. It's great that you're treating errors as values. But you need pattern matching and other techniques as they make your code more: (a) readable, (b) safer, (c) simpler and (d) less verbose. The hilarious thing is that eventually Go is going to get these because there is nothing but upside. And then at that point you're going to wonder how you ever survived without it.
- Kamq 3y ago> But you need pattern matching and other techniques... The go way to do this would be: switch { case errors.Is(err, outOfDiskSpaceError): // handle out of disk space error case errors.Is(err, lackOfPermissionsError): // handle lack of permissions ... default: // do the equivalent of the `_` case in a scala match statement or `t` in a lisp cond } Which is roughly as readable as scala/rust's match statements. Moreso if someone tried to get cute in scala and bind both the object as a whole and parts of it at the same time ( something like `case x @ Type(_, _, y, _)` ) or when people get real cute with the unapply method. I mean, I like scala. It's fun. But I would never say it's more readable than go. I've been left to support things that happen when a team of average intelligence devs get a hold of it. You're also really comparing an MIT and New Jersey style solution here, and judging them both on MIT merits. And I don't think that's exactly a fair argument.
- blueberry87 3y agoTrying to compare a switch statement to proper pattern matching is like comparing a rock to a rocket.
- di4na 3y agoI am unashamedly stealing this one, it is both apt and making me smile. Kudos
- 3y ago
- dd82 3y ago- Simple and lots of duplicated code. Golang took DRY overuse and turned it on its head to be dupliate everthing everywhere - Its duplicated everywhere which means I need to mentally figure whether I need to figure out this path or ignore. Mental load of typing is small, load of reading is not Golang has alot of good things about it. This is not one of them and is a wart on the language that is tolerated because the genesis of the language is to be an entirely inverted approach to verbosity than Java. Its not something to be praised.
- marcus_holmes 3y agoThe mental load of reading a lot of simple code is less than reading a small amount of complex code, I find. It's easy to look at a 50-line function with one statement every 5 lines and find the bit I'm interested in, because it's easier to screen out the bits I'm not interested in. Rather than unentangling a 5-line function that has 10 statements in it, because I have to work out what all of it does in order to understand it and I can't focus in on the bit I'm interested in.
- et1337 3y agoThe problem with lots of simple code is now there’s 5,000 slightly different ways of doing the same thing. You end up trying to wrangle it with a mess of code generation and linters.
- marcus_holmes 3y agoYeah, this is something I think feels like a bigger problem than it actually is. If I change the way I'm handling something, it is a lot of typing. But it's just typing. No big deal.
- setr 3y agoThe usual issue isn’t the typing, but the fact that you need to make sure you identified and updated every site correctly. DRY isn’t about reducing LoC
- kaba0 3y ago> It's simple and easy to understand. There's no hidden complexity, no magic, no gotchas. Nothing is going to surprise me about it There absolutely are gotchas, exactly because they are not sum types. There are functions where both “slots” are used as return types, when an error occurred. > It's a very readable cadence. Do the thing, check the error, do the thing Arguably, you can’t reasonably handle most errors in-place, you just don’t have enough context for that. Also, you want to make your business logic right — all those verbose, often incorrect/naive error handles will just make it harder to read your own logic. Also, very easy to accidentally swallow an error - exceptions/sum types are much better in this regard, you can’t not care about them.
- kaba0 3y agoUse a sane language instead.
- Cthulhu_ 3y agoThe alternative is to... not have errors I suppose. It does sound like the function you're describing is your core business logic, e.g. load from db, transform data, send somewhere else, etc, each of which CAN go wrong. One thing you can do is go to the Go slack space at https://invite.slack.golangbridge.org/ https://invite.slack.golangbridge.org/ and ask for a review in the #reviews channel; 20 error checks is a lot.