2,816 karma · joined April 16, 2014
Yes, this is the essential nature of real-time chat. The channel already serves as the demarcation of topic.
What you're describing is a forum, a totally different modality.
> Direct replies to the messages help but they still exist in that linear main chat stream, so there’s still a lot of clutter that everyone has to navigate through.
This isn't clutter, it's literally the point of the tool.
Never really a good idea, and never necessary.
> create a single channel owned by the reader
Channels cannot be effectively owned by their reader(s), the contortions you have to bend the code into to make that work never really make sense. That's just a constraint of the type, but it's hardly a problem -- it makes the thing easier to model. So this isn't really an option on the table.
> a Merge function
Yes! The answer. And goroutine per channel is kind of the point of using them! Nothing inefficient about it.
> a function that takes two channels . . .
Now there's some inefficiency! ;) No reason to do this, given Merge.
--
> None of these options are particularly intuitive.
The merge option seems perfectly intuitive to me, assuming you understand channels have to be owned by a singular writer.
Wild!
The rule is that channels are owned by a single goroutine, who's uniquely responsible for sending on them, and closing them. That's basically it. Do that and everything works fine, in my experience.
Yes, with predictable results.
> it can be closed
Yes, by the owner/sender, who then understands it as invalid. The effect of receiving on a closed channel is well-defined and predictable.
> and there's different behavior of [recv/send] whether it's in a select or not
I don't think that's true? What do you mean?
> And you often end up with multiple channels as well
Sure! That's part of their power.
> Reviewing code with channels is often more confusing than code that uses mutexes
I totally agree that goroutines and channels are often over-used by new Go programmers. If what you're trying to do is simply protect concurrent access to some shared state, a mutex is the far better choice.
This is definitionally correct (shrug)
> Dilettante programmers certainly do not know [that] Go slices, strings, and interface values are unsafely non-atomic.
Yes. They do. As soon as a Go programmer learns that there is such a thing as concurrency and "thread safety" they learn that nothing in Go is "thread safe" by default.
> Go is not memory-safe.
"Memory-safe" is not a precisely defined concept. Go is memory safe by some definitions, not by others.
They absolutely do.
https://software.intel.com/content/www/us/en/develop/blogs/b...
Violating the memory model gets you undefined behavior.
> However, this does not rebuke my original argument, which assumes that most devs are not in the know. They do not know about slices being unsafe, nor do they know about happens-before
I just don't agree. Go programmers know that nothing is safe for concurrent access unless explicitly noted otherwise. They don't have any confusion about slices requiring synchronization.
Concurrent programming isn't trivial but neither is it impossible. And data races are critical bugs that can be subtle, but are straightforward to identify, and straightforward to fix.
The original claim was that "Go has lots of weird edge cases, like sharing a slice across threads can lead to memory corruption." But that's not the whole picture, you have to violate the memory model, too. And that's not interesting, because if you violate the memory model, literally any consequence is fair game.
Maybe your point is (a) it's easy to violate the memory model, and/or (b) bugs that violate the memory model have surprising consequences? I don't agree with (a); the situation can always be improved, but it's easy to spot and fix data races, and Go provides plenty of tooling for that purpose. And I guess I agree with (b) in the basic sense, but that's just a truism, for the reasons stated above.
Source?
If I want to see a friend in the middle of the day, I do it. If I want to take a 3 hour lunch, I do it. When someone 8 time zones away answers a question I asked earlier at my 1AM, and I’m awake and see it, I’m excited to learn the new whatever thing, and may take an hour (or three!) to chat with them about it.
Everything I do in life I have opted into and enjoy. I gain nothing by firewalling some parts of it from other parts.
I have tried every modality of managing work and personal life and this one is by far —- by far —- the best one for me. The notion that there is a work laptop and a personal laptop and naer the twain shall meet is a complete anachronism. It’s fine if that separation helps other people but it actively hurts me.
This article was embarrassing, and makes Redis Labs look childish and inept. Whatever process resulted in this blog post should be axed immediately, and this author should not be writing anything public facing.
But these are subjective claims! Not everyone thinks the same way!
Um. Alright.
Well, with the requisite glue code that would inform each user's Prometheus instance how to scrape the service instances -- yes, more or less.
> is not at all clear to me how doing a purer version of Prometheus would make any of our users happier.
If the only things you care about when you build systems are "works" and "direct impact on customers" then there's not really a point to this conversation. The things I'm speaking about, the architectural soundness of a distributed system, are largely orthogonal to those metrics, at least to the first derivative.
OK, I understand this is your position. I don't share it, nor do the authors of the language. So I guess it's not a truism.
Patently false.
> Also, one of said frameworks I was referring to generates mocks for your app and wraps errors so you automatically get stack traces in errors that are being passed around. Something already solved in Java and C# and practically any language with exceptions.
You're speaking as if generating mocks and adding stack traces to errors are... features? They're not! Generating mocks almost totally defeats the purpose of using them, and stack traces have no business being attached to errors in the general case.
Sometimes I truly don't understand the context that my peers are working in. Totally incoherent...
I'm observing that you've used pull-based, horizontally-scaled tools to build a push-based, vertically-scaled telemetry infrastructure. It can be made to work, sure, but the solution is an impedance mismatch to the problem.
I'm well aware of them. (There are several more, too, which see at least as much use as these two, unfortunately.) They also reflect a misunderstanding of the language. Wire less so than FX. (I'm also aware Wire is written by Googlers, no need to point that out.)
> Prior to DI frameworks we used global variables, often initialized in a package's init() method.
I don't understand how these things are related. DI frameworks aren't necessary for Go-idiomatic dependency injection, and global variables were never an appropriate way to manage dependencies.
> Generally you have a few layers: gRPC/HTTP/Kafka handler, business logic, and database or external service access.
Yes!
> Layers are unit tested individually against mocks of the layers below.
Yes!
> Because you're going to inject a mock, you can't depend on a concrete type, so you depend on an interface.
Yes!
> Often when you're developing you want to know what the concrete implementation of a lower layer does, so it's useful to have "go-to-definition" see through the interface declaration to its implementations.
...no?
There are basically two situations where you use an interface in this way. One, most often, in an application where the "production" code uses one implementation, which you know a priori and therefore have no need to go spelunking. Or, two, in a library where you by definition cannot know what implementation your users will provide to you. In the first case, your mock would model the implementation, which I guess is trivial. In the second case, your mock would reflect your expectations of the interface's implementations, explicitly without knowledge of any implementation.
OK, but Prometheus can do all of this just fine?
> Because it works incredibly well, it's easy to operate, and handles multi tenancy for us.
Again, Prometheus itself ticks all of these boxes, too, if you're not trying to force it to be something it's not.
Sounds like they were trying to force the language to be something it's not. DI frameworks (I think what you mean) are basically incoherent in Go, dependency injection is naturally modeled with interfaces. In fact any inversion-of-control style "framework" is a mismatch to the language, it (intentionally) lacks the features that frameworks rely on to deliver benefits that outweigh their costs.
> The way interfaces are handled in golang makes it very annoying to try to find out which types implement said interface.
The desire to do this reflects a misunderstanding of interfaces.