The 4-chan Go programmer
Go programmers are debating the merits and pitfalls of deeply nested channel patterns like `chan chan` and even `chan chan chan chan int`, prompted by a tongue‑in‑cheek blog post that parodies “three-star pointer” C code. Many see channels-of-channels as a valid tool for things like async replies, pub‑sub, or thread pools, but argue they are often misused, overcomplicate code, and signal premature abstraction—especially when simpler function calls, mutexes, or iterators would do. The exchange broadens into a critique of over‑engineered architectures, misplaced design‑pattern zeal, and the challenge of teaching good taste in abstraction and concurrency.
Use of chan chan and higher-order channel patterns
- Several commenters note that “channel of channel” is a normal Go pattern:
- Sending a reply channel with a request (RPC/actor style).
- Implementing promise/future-like semantics.
- Pub/sub systems and thread pools where workers send back a result channel.
- Dynamic dispatch and asynchronous tree/FS walks.
- Typically this is
chan struct{… reply chan T …}rather than a literalchan chan. - Most report never needing more than two levels;
chan chan chanis seen as vanishingly rare or unnecessary. - Some argue the blog’s example is parody-level complexity; others say multiple layers of channels are analogous to chained pointers and can be fine if properly abstracted.
Over-engineering, indirection, and interfaces
- Many complain about code where a simple operation passes through multiple “interface” functions or wrapper layers, often in different files.
- This is attributed to:
- Premature abstraction (“just in case we change it later”).
- Pattern cargo-culting from Java/C# “interface everything” culture.
- Frameworks/Clean Architecture/SOLID taken to extremes, yielding “ravioli code” or Law-of-Demeter chains.
- Others defend indirection when:
- It supports testing, reuse, or company-wide architectural consistency.
- Backwards-compatible public APIs need stable abstractions.
- Consensus: abstraction should be justified by actual needs; simplicity and readability are strong virtues.
Concurrency design and channel vs mutex/waitgroup
- Some view misuse of channels as a hallmark of over-eager or inexperienced Go developers:
- Using channels where a direct call, mutex, or waitgroup would be simpler.
- Exposing channels in public APIs without clear benefit.
- Others prefer channels to shared-memory primitives, citing clearer invariants and Go’s “share memory by communicating” guidance.
- Multiple people stress that:
- Channels can deadlock too and invite complex actor-style designs that are hard to debug.
- A good heuristic is to ask whether concurrency truly pays for its added complexity.
Design patterns, education, and “taste”
- Commenters describe education heavy on patterns (GoF, Clean Architecture) applied to toy problems, encouraging over-abstraction.
- Stories are shared where deliberately avoiding patterns produced simpler, better solutions, even in academic settings.
- Several emphasize “taste” in abstraction:
- It develops only with experience and by suffering through both under- and over-designed systems.
- Teams should tolerate stylistic differences as long as code remains clear and correct.
4chan pun and off-topic tangent
- Some readers initially expect a connection to the 4chan site; others point out the title is just a wordplay on
chan chan chan chan. - There’s a brief digression into an unrelated internet personality with the same phonetic name, generally characterized as disturbing and irrelevant to Go or the article.