Live data from Hacker News

The 4-chan Go programmer

dolthub.com

141–150 of 177 posts

Re: The 4-chan Go programmer

#141
post #7

As a scientist that ends up working closely with actual professional software engineers... lots of the stuff they do looks like this do me, and I can't for the life of me make sense of why you'd do it. I have seen a single line of code passed through 4 "interface functions" before it is called that call each other sequentially, and are of course in separate files in separate folders. It makes reading the code to figu…

The author says as much and more at the end of the article.

Re: The 4-chan Go programmer

#142

Earlier quoted context omitted.

This is actually really bad practice and a very “over eager junior engineer” way of writing software. You’re not off base at all that it seems excessive and confusing. It’s the kind of thing that seems technically complex and maybe even “elegant” (in isolation, when you first write the “interesting” code) at first but becomes a technical nightmare when used in real software that has to grow around and with it. You’re…

Back at uni, we had a 200-level ‘software engineering’ unit, largely introducing everyone to a variety of ‘patterns’. Reading the Gang of Four book, blah blah blah. You get the idea. Our final assignment for this unit was to build a piece of software, following some provided specification, and to write some supplementary document justifying the patterns that we used. A mature-aged student that had a little bit of ind…

Nice with such teachers :-) What's a 200 level unit? It means it's "very advanced"?

Re: The 4-chan Go programmer

#143
post #42

Earlier quoted context omitted.

This is actually really bad practice and a very “over eager junior engineer” way of writing software. You’re not off base at all that it seems excessive and confusing. It’s the kind of thing that seems technically complex and maybe even “elegant” (in isolation, when you first write the “interesting” code) at first but becomes a technical nightmare when used in real software that has to grow around and with it. You’re…

when I was learning Go, I read a guide that told you to fire off a goroutine to walk a tree and send the values back to the main goroutine via a channel. I think about that "just an example" guide a lot when I see bad channel code. For me the biggest red flag is somebody using a channel as part of an exported library function signature, either as a param or a return value. Almost never the right call.

> when I was learning Go, I read a guide that told you to fire off a goroutine to walk a tree and send the values back to the main goroutine via a channel.

Okay, I gotta ask - what exactly is wrong with this approach? Unless you're starting only a single goroutine[1], this seems to me like a reasonable approach.

Think about recursively finding all files in a directory that match a particular filter, and then performing some action on the matches. It's better to start a goroutine that sends each match to the caller via a channel so that as each file is found the caller can process them while the searcher is still finding more matches.

The alternatives are:

1. No async searching, the tree-walker simply collects all the results into a list, and returns the one big list when it is done, at which point the caller will start processing the list.

2. Depending on which language you are using, maybe have actual coroutines, so that the caller can re-call the callee continuously until it gets no result, while the callee can call `yield(result)` for each result.

Both of those seem like poor choices in Go.

[1] And even then, there are some cases where you'd actually want the tree-walking to be asynchronous, so starting a single goroutine so you can do other stuff while talking the tree is a reasonable approach.

Re: The 4-chan Go programmer

#144
post #128
post #42

Earlier quoted context omitted.

when I was learning Go, I read a guide that told you to fire off a goroutine to walk a tree and send the values back to the main goroutine via a channel. I think about that "just an example" guide a lot when I see bad channel code. For me the biggest red flag is somebody using a channel as part of an exported library function signature, either as a param or a return value. Almost never the right call.

The only time I've seen it work with channels in the API is when it's something you'd realistically want to be async (say, some sort of heavy computation, network request, etc). The kind of thing that would probably already be a future/promise/etc in other languages. And it doesn't really color the function because you can trivially make it sync again.

> The kind of thing that would probably already be a future/promise/etc in other languages.

Or a coroutine (caller calls `yield(item)` for each match, and `return` when done).

Re: The 4-chan Go programmer

#145
post #45

Earlier quoted context omitted.

imagine enforcing invariants as part of the design of a software system

I’m just saying enforce invariants at construction time / type-designing instead of with the validity checks

This wasn't that kind of validation - it was "is this token allowed to do this thing?" Like "validate your parking" kind of scenario.

(And yes, it should probably have been "CheckAuthorisation")

Re: The 4-chan Go programmer

#146
post #88

Earlier quoted context omitted.

That’s some pretty Go code, I like it. Just out of interest, why have a channel for subscribe/unsubscribe? Did you want to avoid a mutex on the subscriber map?

Not the OP but yeah, that’s usually the reason I reach for a channel in this case. A mutex or wait group is just begging for a deadlock to rise up when you least expect.

Can't channels deadlock too? Sending or receiving on a channel will block by default until the other side receives/sends the value if the channel is unbuffered, or it's buffered but the buffer is full. You have to write extra code to make it non-blocking; the pubsub example under discussion is blocking. I don't see how switching the discussed code to a mutex would make it any more blocking or deadlock prone.

I found a bug in production caused by the author not realizing a send on a channel can block.

Re: The 4-chan Go programmer

#147
post #79

Earlier quoted context omitted.

Most C# education will teach you to always make an interface for everything for some reason. Even in academia they’ll teach CS students to do this and well… it means there is an entire industry of people who think that over-engineering everything with needless abstractions is best practice. It is what it is though. At least it’s fairly contained within the C# community in my part of the world.

Isn't that "for some reason" in C# being it's the standard way of doing dependency injection and being able to unit test/mock objects? I've found it easier to work in C# codebases that just drank the Microsoft Kool-Aid with "Clean architecture" instead of Frankenstein-esque C# projects that decidedly could do it better or didn't care or know better. Abstraction/design patterns can be abused, but in C#, "too many inte…

I agree with you on this, my issue is mainly when they bring this thinking with them into other languages. I can easily avoid working with C# (I spent a decade working with it and I’d prefer to never work with it again), but it’s just such a pain in the ass to onboard developers coming from that world.

It may be the same for Java as GP mentioned it along with C#, but they tend to stay within their own little domain in my part of the world. By contrast C# is mostly used by mid-sized stagnant to failing companies which means C# developers job hop a lot. There is also a lot of them because mid-sized companies that end up failing love the shit out of C# for some reason and there are soooo many of those around here. Basically we have to un-learn almost everything a new hire knows about development or they’ve solely worked with C#.

Re: The 4-chan Go programmer

#148
A couple suggestions for improving the code:

* Currently sendChanChan() takes 2 params: a 4chan and a 3chan. I think it can be simplified by just taking a 3chan. The send on the 4chan can be done before calling sendChanChan().

* Why does the code have 2 levels of loops in receiveChanChanChan()? I think a single loop would be fine. Especially since there are 0 loops in the place where receiveChanChanChan() is called. So currently, a single goroutine performs N receives all the values from the 4chan, but we have N goroutines to receive values for each 3chan (so each goroutine will perform on average 1 receive). That's inconsistent.

Re: The 4-chan Go programmer

#149

Earlier quoted context omitted.

I saw some code in a job I was just starting where they had added several abstractions that I found...confusing. After taking an extra long time to understand what the code actually did, I realized that some junior engineer had been using some design pattern they didn't really understand, and that added zero actual value to the routine. After deleting all of that code and refactoring it to use completely different ab…

> I realized that some junior engineer had been using some design pattern they didn't really understand, and that added zero actual value to the routine. £3.50p says it was the Generic Repository pattern implemented over Entity Framework dbContext, right? -------- Speaking of design-patterns, I subscribe to the opinon that _Design-patterns are idioms to work-around missing features in your programmign language_, whic…

FP has design patterns too, just different ones, and they don't all have tidy names.

Also some GoF design patterns map pretty closely to FP equivalents... pattern-matching on ADTs + traverse/fold + ReaderT ends up looking a lot like the visitor pattern.

Re: The 4-chan Go programmer

#150
post #42

Earlier quoted context omitted.

when I was learning Go, I read a guide that told you to fire off a goroutine to walk a tree and send the values back to the main goroutine via a channel. I think about that "just an example" guide a lot when I see bad channel code. For me the biggest red flag is somebody using a channel as part of an exported library function signature, either as a param or a return value. Almost never the right call.

> when I was learning Go, I read a guide that told you to fire off a goroutine to walk a tree and send the values back to the main goroutine via a channel. Okay, I gotta ask - what exactly is wrong with this approach? Unless you're starting only a single goroutine[1], this seems to me like a reasonable approach. Think about recursively finding all files in a directory that match a particular filter, and then performi…

> what exactly is wrong with this approach?

Before Go had iterators, you either had callbacks or channels to decompose work.

If you have a lot of files on a local ssd, and you're doing nothing interesting with the tree entries, it's a lot of work for no payoff. You're better off just passing a callback function.

If you're walking an NFS directory hierarchy and the computation on each entry is substantial then there's value in it because you can run computations while waiting on the potentially slow network to return results.

In the case of the callback, it is a janky interface because you would need to partially apply the function you want to do the work or pass a method on a custom struct that holds state you're trying to accumulate.

Now that iterators are becoming a part of the language ecosystem, one can use an iterator to decompose the walking and the computation without the jank of a partially applied callback and without the overhead of a channel.

Post reply on HN