2,096 karma · joined September 12, 2012
[ my public key: https://keybase.io/natefinch; my proof: https://keybase.io/natefinch/sigs/zmM0s7UYyYw1F1gFUV2w0MZmAdRu5w1R0AMnw-7wWQg ]
Go's error handling isn't any more error prone that writing if statements for all the rest of your code. if err != nil is no different than if age < 18. Either one is a branch in the code. I can literally count on one hand the number of times in 6 years of full time go development that I've seen people miss writing the if err != nil.
Being explicit is good. Spreading out the logic is good. Cramming a lot of logic into one line is bad.... and that's the sole purpose of try.
Maybe there's another way to make error handling better in Go. I'm not averse to looking into that. But try wasn't it.
You're talking about writing if err != nil being tedious, but what about matching Results from Rust, isn't that tedious? What about writing proper catch blocks in java or C++ or python, isn't that tedious? It's all just logic.
I almost never see code that application developers write using it, and usually if someone is writing that code, it's wrong, and I help them figure out how to avoid it.
Usually you can avoid it by using closures or interfaces.
Rob Pike's example code is bad and I would not allow it through a code review. Why? It makes the code lie. It appears as though the writes cannot fail, but in fact they can, and later writes become no-ops. On top of that, it means that you lose the context of which write failed. Did you fail writing the header, the body, or the footer? You can't know anymore.
This is like
try {
doThing()
doThing2()
doThing3()
catch (Exception ex) {
// handle
}
You can't tell what failed. You can't tell what is possible to fail. The handler can't differentiate.I agree that code review for configuration changes is necessary. That same code review process can ensure that the comments in the config file are also correct.
Also, it can be really hard to find where exactly a configuration value is used. You may have to trace through a ton of code to find the place, and then you can't be sure that's the only place it's used.
Configuration comments are crucial, both for onboarding new users (explaining what the default is if you don't set a value, explaining what the configuration value actually controls, etc) and for experienced users to tell others why this esoteric configuration is set the way it is.
A configuration file is literally just a stack of magic numbers and strings. Why are we setting threadpool to 10 and not 1000? Why are we disabling X feature? What the heck does TPS_Report=true do?
You need comments.
The type system not being "strong" simply means that you put logic in functions and methods instead of magic parts of the type system.
And Go can absolutely make abstractions. The standard library is full of abstractions. Every Go package is an abstraction. Hell, every function is an abstraction.
That's like saying Dale Earnhardt could recommend driving a Gremlin... sure, it would get a lot of people to go for a test drive, and a lot of those people would then run away.
I fully admit I clinked on the link to the Go website purely because it was from a big name... the exact same thing I did for Hack and Swift and Rust. But I don't write code in Hack or Swift or Rust. I write code in Go.
Sure, I may have missed some really great language put out by an obscure name that never made it to Hacker News. But then again, evidently so did everyone else.
So why do I write code in Go? Because the language and the ecosystem around it are really good. Because I feel like I can understand any piece of code written in it without needing a PhD from Stanford. Because I feel like it pushes people towards simple, straightforward solutions.
Past that first click, the only thing Google means to me is a guaranteed check to pay the bills of all the great people working on the project.
Also see the aforementioned "the answer is to write a loop".
The biggest problem with inheritance is that it's a lot like monkey patching (except in production)... the rest of the base class's code expects method X to do ABC, and you've just swapped out the implementation to do LMNO ... and if that never bites you in the ass, you're luckier than most OO programmers I know.
It even uses different words for the same thing - sometimes remove, sometimes rm sometimes -d.
Common actions often require obscure command lines, like "make a new branch" which is git checkout -b instead of just "git branch".
The reason people don't use other git frontends is that a vast majority of the help topics already out there only reference git itself. So if you want help for rebase, for example, if you're using some frontend that re-kajiggers the command line, all that help is now useless, or even worse, potentially downright incorrect.
There's no operator overloading, macros, or monkey patching, so you don't have to know about the entire state of the universe to know what one little function will do. There's no destructors or finalizers that magically get called sometime in the future.
There's no exceptions, so you never have to worry that the control flow of your program is going to jump all over the place. There's multiple returns, so you almost never have null pointer exceptions, because you always just check the error before using the value returned.
And of course, channels and goroutines make modern multithreaded code very easy to reason about, because they're just functions and a little pipe primitive. They don't do a lot of fancy schmancy stuff, and that's good. It means it's very easy to tell what go Foo() will do.
There's probably more I can't think of right now.
Rust seems nice, but its multitude of different pointers and mutable versus non-mutable data really makes for complicated code.
I work on Juju. It's over 200k lines of code spanning several applications that coordinate across multiple machines. The number of times generics would have helped the codebase I can count on a single hand... and none of it is huge stuff, just some very minor parts of the code.
When I was going home, I stuffed my lighter jacket in my backpack with my laptop... and it looked exactly like that. In crowded areas, when I'm not going anywhere, I almost always take off my backpack and put it between my legs. It's the only way I can safely swivel my upper body to look around without knocking people over.
Don't jump to conclusions. It's a dude with a big black backpack. There's hundreds of thousands of those in Boston. I would be surprised if there weren't a picture of a guy with a big black backpack in that area. Lots of people work around there and lots of people don't get the day off... I didn't. I saw a ton of regulars on the Commuter Rail that morning that obviously also didn't get the day off.
I applaud the efforts of people to scan photos looking for the perpetrators... but saying they may have found the guys responsible is incendiary and dangerous.