this is a real problem in go, very easy to have bugs when working with channels and the way it handles errors etc.
If you write comprehensive unit tests, it is not easy to have bugs in golang. Especially as things change over time. A library like this isn't going to protect you from having bugs.
TIL: HN doesn't like writing tests. The downvotes on this are hilarious. "Job security" ¯\_(ツ)_/¯.
Hard disagree on this. Large production apps that use channels have very subtle bugs that cause all kinds of annoying issues that only come up under load in prod. I have been using go for ten years and still pick it as my language of choice for most projects however I stay away from channels and especially any complex use of them unless it’s 100% required to scale the application. Even then you can most of the time come up with a better solution by re architecting that part of the application. For pet projects go crazy with them though.
What are you disagreeing with exactly, are you trying to argue against testing? Are you trying to argue that using a library protects you from bugs somehow?
You stay away from something you don't understand after 10 years of working with it? What kind of logic is that? Channels aren't magic.
Subtle bugs in what? Have you considered that maybe you have bugs because you aren't writing tests?
If you aren't unit testing that stuff, then how are you able to fix/change things and know it is resolved?
My experience is that I built a binary that had to run perfectly on 30,000+ servers across 7 data centers. It was full of concurrency. Without a litany of automated tests, there is no way that I would have trusted this to work... and it worked perfectly. The entire deployment cycle was fully automated. If it passed CI, I knew that it would work.
It wasn't easy, it took a lot of effort to build that level of testing. But it was also totally bug free in production, even over years of use and development.
You asserted that bugs are hard if you write unit tests. The parent stated that some issues only occur under production load and a unit test will not catch it. Nowhere was it implied that unit tests are useless.
Perhaps a less defensive posture might invite more discussion.
> The parent stated that some issues only occur under production load and a unit test will not catch it.
I can't think of a single production problem that can't be replicated with a unit test. If you're seeing a problem in production, you need to fix it. How do you fix it? You write a test that replicates the problem and then fix the code, which fixes the test.
> If you write comprehensive unit tests, it is not easy to have bugs in golang.
First you claimed before that unit tests will catch your subtle concurrency bugs before they happen, and that's just not often the case. They are subtle, might involve many systems and weird edge cases and often don't get caught BEFORE they happen. Of course anyone can write a test to replicate the problem after seeing it in production and spending hours/days debugging it.
More importantly, "Write comprehensive tests" is technically a strategy to avoid any bug ever. You can tell C programmers not to segfault by writing comprehensive tests but that doesn't negate the point that the language makes it easy to write segfaults. "Write more tests" is not a rebuttal to saying C makes some classes of errors easy to write. Writing comprehensive tests often takes a lot of time, is often not prioritized by companies, and is especially hard with distributed systems, concurrency, mocks and complex applications. If we just said "git gud noob" in the face of error prone and difficult abstractions, we might as well all be using assembly.
Why are you comparing golang to C?
Your replies here have been less than useless. I clicked on your profile and saw you were "founder and CEO" of some company.
I guarantee you I won't be using your product. Just something to consider.
Thank you for sharing your perspective. I genuinely appreciate honest feedback. My goal is always to add value to discussions, but it seems I’ve fallen short in this instance. If there’s a specific way I could clarify or improve my comments, I’d be grateful to hear it.
Regarding my company, I respect your decision, but I hope that if our paths cross again, I might have the opportunity to change your mind through actions that demonstrate the value we provide to our customers.
Then you have not worked on complicated systems.
Why would anyone even say this to someone? Totally rude.
Reading through the thread, I can tell you have depth of experience.
Perhaps bringing it down a notch could help you connect with others’ perspectives as well.
If people were actually sharing perspectives (like the guy above), that would be fantastic.
The original comment was about how concurrency expands / makes it easier for there to be errors in go (which avoids LOTs of other errors just with compile time / type safety stuff).
"very easy to have bugs when working with channels and the way it handles errors etc"
If you've done some programming you'll find this to be true. You have to think a LOT harder if doing concurrency, and you generally have to do a lot more tests.
Go - WITHOUT that much testing, is often surprisingly error free compared to more dynamic languages just out of the box both language side and how a lot of development happens. Python by contrast, you can have errors in dependencies, in deployment environment (even if code is fine), based on platform differences (tz data on windows), and plenty of runtime messes.
Channels are not as default safe / simple after compile as a lot of other go.
Try programming without channels in go and this may become clearer.
I think you're getting downvoted for the unsupported assertion that "If you write comprehensive unit tests, it is not easy to have bugs in golang." Probably because you made that assertion in the context of a discussion of channels, widely believed to have underlying concurrency semantics that are subtle and easy to misunderstand, making "write comprehensive unit tests" seem like a strategy that's apt to let real-world problems slip through (because a programmer's belief that their tests are "comprehensive" is likely to be mistaken).
Go makes it easier to write concurrent code, but it's a serious chore to iron out all of the kinks in more complex tasks. I've missed some weird stuff over the years.
I don't blame Go. It's an inherently difficult problem space. As a result, testing isn't a trivial job either. I wish it was.
It is not a chore, it is our job. This is what we do. We write code. Of course you've missed stuff, we all have. Tests help alleviate the missed stuff. Even better is that they protect us over time, especially when we want to refactor things or find bugs in production. How do you fix a production bug without breaking something else? You write tests so that you know your code works.
Again with the HN downvotes, hilarious. People really hate the truth.
I think what you're missing is that "you write tests so that you know your code works" doesn't actually work for some important classes of "works," security and concurrency (the subject of this HN discussion) being two prominent ones. That's because testing only shows that your code works for the cases you test. And, when it comes to security and concurrency, identifying the cases that matter is a hard enough problem that if you can figure out how to do it more reliably, that's publishable research.
Think about it: If you're writing code and don't realize that it can deadlock under certain conditions, how are you going to realize that you need to test for whether it deadlocks under those conditions? If you're writing code that interpolates one kind of string into another and don't realize that you may have created an XSS vulnerability, are you suddenly going to gain that insight when you're writing the tests?
You run your code in production, you see it is deadlocking and you fix it. How do you fix it? You write a test the reproduces the deadlock, you fix the code and your test passes. Just like any other testing.
I'm not arguing that you magically predict everything that's going to happen. But, without those tests and the culture of writing tests and writing your code to be testable, you're screwed when you do have bugs in production.
What you wrote was "you write tests so that you know your code works," but what you seem to have meant is "you write tests so that you when you get burned in production by problems that your tests didn't anticipate, you can write more tests at that time to make sure those newly discovered problems don't burn you again."
That's nice, but it's far from "knowing your code works". When code works, it doesn't burn you in production.
This nit pick is peak HN obstinacy.
How do you know your code is going to work in production before you got there? You wrote tests.
You're missing something important.
You know your code is going to work in production before you got there not because you wrote tests but because you thought about what it means for your code to work in production and then came up with a plan to generate the required confidence that it actually will work in production. And, for any nontrivial system, tests can only satisfy part of that plan.
The goal isn't to have well-tested code. The goal is to have code that you can easily be confident will work as intended. And testing is only good at establishing some kinds of that confidence. For the other kinds, such as confidence you're not going to launch a bunch of security disasters or concurrency landmines, you need to do something else: types, proofs, correctness by construction, model checking, and so on.
I wrote about this idea almost twenty years ago: https://blog.moertel.com/posts/2006-10-10-unit-testing-is-a-...
I elaborated in a later post: https://blog.moertel.com/posts/2012-04-15-test-like-youre-be...
That you seem to believe otherwise is probably why a lot of people are having trouble with your claim that that world doesn't need better concurrency abstractions, just more tests because "if you write comprehensive unit tests, it is not easy to have bugs in golang."
Not a single person has spoken up to say that they write a lot of tests AND they have a lot of bugs.
All the negativity (downvotes) has come from people who are trying to argue that writing tests doesn't solve the problem of bugs. The same people who don't write a lot of tests AND have a lot of bugs. ¯\_(ツ)_/¯
I write a lot of tests and I don't have bugs. I have decades of experience and millions of lines of code, with this simple fact. I know it is true, at least for me.
I don't know what else to bike shed here other than the constant downvoting by people who somehow don't believe my claim. The loss in karma doesn't bother me, I know I'm right on this and it appears as though the only people who disagree with me are the same people who don't write tests (and have a lot of bugs).
golang is a relatively simple language. It is why I like it so much. Occasionally there are somewhat difficult things to reason about, but if you write golang code that is easily testable (and this requires thought and planning), then my experience is that even the "harder" channel/goroutine code can always be tested in one way or another.
> I know I'm right on this and it appears as though the only people who disagree with me are the same people who don't write tests (and have a lot of bugs).
For the record, I write lots of tests, and don't have bugs. I even wrote a testing framework. Nobody is arguing that writing tests is dumb. The pushback is on your insistence that writing tests is all you need:
> All the negativity (downvotes) has come from people who are trying to argue that writing tests doesn't solve the problem of bugs.
Writing tests doesn't solve the problem of security bugs. Writing tests doesn't solve the problem of concurrency bugs. Writing tests to prove your code is bug free in those cases is expensive and error prone.
People who care about these things know to go beyond testing when testing isn't enough. That's why things like model checkers exist.
Nobody is arguing that tests are dumb. The argument is that if writing tests is all you're doing to get the bugs out of your code, you probably aren't very effective at preventing certain classes of problems.
For instance: Show me the tests you'd write to prove your software doesn't have XSS vulnerabilities.
> Show me the tests you'd write to prove your software doesn't have XSS vulnerabilities.
I'd have tests around the code that renders 3rd party user input and integration tests for the display of the data.
I've built some of the most heavily trafficked websites on the planet (porn), with user input (comments) and have never had an XSS issue.
Show me the tests.
If you can't show me the tests you'd use to prove you don't have XSS problems, it's hard to believe that your tests are effective at preventing XSS problems.
> I've built some of the most heavily trafficked websites on the planet (porn), with user input (comments) and have never had an XSS issue.
Right, because the gold standard for proof in the security field is "we never had [read: noticed] an issue."
It was code written in 2009 and private, not open source and I of course didn't take it with me when I left the company. I ran it for 4 years and we never had a single security incident. We took it very seriously. Partly because our code (in Java) was a rewrite from some really buggy PHP, that did in fact have a bunch of holes in it (and no testing).
You're also being absurd. We started this talking about golang testing and it has somehow gone off the rails to me having to prove things to you about XSS? Come on, what is with the hostility? Is this how you treated people while working at Google?
I'm only asking you to show me how you'd write tests to detect XSS (or concurrency) problems. In Go or the language of your choice. You've claimed that writing tests as all you need. I'm asking you to show how it's done. Just in general. No need to share actual code you've written in the past.
> It is not a chore, it is our job. This is what we do.
I'm not sure how to meaningfully distinguish the two here. I'm saying it takes extra effort, not denying that it's my job. It's non-trivial, that's all I'm trying to say.
> How do you fix a production bug without breaking something else? You write tests so that you know your code works.
Of course, you're right. Sometimes writing the tests can be harder than writing the code, though.
You’re getting downvoted because you’re essentially arguing that a language abstraction which is a known source of bugs can be solved simply by writing better code.
which misses the point of the OP.
They're also suggesting a method of testing which almost certainly doesn't offer sufficient assurance under most circumstances will uncover all possible bugs. When I've got concurrency in an application, I'll use unit tests here and there, but mostly I want assurance that the entire system behaves as expected. It's too much complexity to rely on unit tests.
Very true. As an author of a several multithreaded applications, I concur that unit testing thread interactions is hard and seldom exhaustive.
It is not exhaustive because you haven't taken the effort to do it. It isn't easy, you have to write you code in a way that can be tested. It takes planning and effort to do this, but it pays off with having applications that aren't full of bugs.
You sound like the people who argue that, despite decades of security vulnerabilities offering evidence otherwise, C is perfectly safe if you know what you’re doing and just put more effort into it.
Technically you may be right, but it’s not a helpful viewpoint. What the world needs are abstractions that are easier to understand and program correctly, not assertions that everyone else is doing it wrong and just needs to be smarter/work harder.
That's absurd, I'm not arguing anything of the sort.
If you want an analogy, I'm arguing that a condom helps prevent STD's and unwanted pregnancies. It isn't perfect, but at least it is better than not wearing a condom at all. Nobody loves wearing a condom, but we do it cause it is the right thing to do.
You can't prove away chlamydia or an unwanted pregnancy, but you can provably eliminate whole classes of logic errors by having more powerful type systems.
100%. Compilers for the win for sure. It was a big reason why I started to write Java code and move away from PHP. This lead me to co-found Java @ Apache.
It’s not exhaustive because complex multi-threaded software has a plethora of hidden edge cases, many of which actually fall outside the traditional remit of a unit test.
This is where other forms of software testing come into play. Such as integration tests.
wtf is a hidden edge case? Is that like flying a plane with blinders on? Come on...
You write tests to cover edge cases. If you miss one, you write more tests when you come across them. This isn't magic.
> If you miss one, you write more tests when you come across them.
…before such point you have hard to find bugs in your software.
And that’s the crux of everyone’s argument against your “just write better code” fallacy ;)
> This isn't magic.
No it’s not. That’s why people disagree with your assessment that unit tests can catch every type of bug.
If unit tests really were that magical then we wouldn’t need for other methods of tests.
I mean, do you even know what a unit test is? It’s meant to be self-contained but the problem with multithreaded code is that you can start to introduce side effects that happen outside that functions scope.
I’ve got exactly that issue right now calling OS APIs from cgo. Some of those APIs (particularly with SDL) are very thread sensitive and you cannot unit test for that because the problem lies outside that functions scope. So the only way to test for that is with e2e or integration tests instead.
I didn't say "just write better code", I said write more tests. Writing those tests will produce better code.
I also never said unit tests were the ONLY tests.
But you were ONLY talking about unit tests for catching concurrency bugs; bugs which often fall outside the scope of a unit being tested.
Nobody disagrees with your point about the importance of unit tests. But the way you present that point is more than a little naive (and that’s the polite way of putting it).
All this "complexity" can be unit tested, I've done it.
Trying to handwave and say that your code is too complex to be tested is very strange to me. Maybe take a step back and ask yourself why your code is too complicated to test. Maybe refactor it a bit to be less complicated or more easily testable.