My experience has been channels are a really good way to make highly concurrent code readable for people who hate concurrency (ymmv).
They aren't as efficient, but using them as a semaphore (i.e. only signaling) can facilitate fairly-efficient, easier-to-read shared memory. But I'm kind of proving the whole...
> You can very carefully design around it only channels
...part of your post.