title: Decoupling Redis PubSub in Go
body: <p>Let's say I want to decouple github.com/go-redis/redis/v8 from my app, for the usual reasons.</p>
  <p>What I have until now is this:</p>
  <pre><code>import (
      &quot;context&quot;
  
      &quot;github.com/go-redis/redis/v8&quot;
  )
  
  type Pubsub interface {
      Publish(ctx context.Context, topic string, message interface{}) *redis.IntCmd
      Subscribe(ctx context.Context, topics ...string) *redis.PubSub
  }
  
  type PubsubClient struct {
      Client Pubsub
  }
  
  func (psClient *PubsubClient) Publish(ctx context.Context, topic string,
      message interface{}) error {
  
      err := psClient.Client.Publish(ctx, topic, message).Err()
      if err != nil {
          return err
      }
  
      return nil
  }
  
  func (psClient *PubsubClient) Subscribe(ctx context.Context,
      topics ...string) &lt;-chan *redis.Message {
  
      redisPubsub := psClient.Client.Subscribe(ctx, topics...)
      return redisPubsub.Channel()
  }
  </code></pre>
  <p>How do I avoid exposing *redis.Message to the users of PubsubClient?</p>
  <p>I'm a newbie in Go, so I thought using the following approach:</p>
  <pre><code>type ThirdPartyType struct{}
  func ThirdPartyFunc() ThirdPartyType{
      return ThirdPartyType{}
  }
  
  type MyType ThirdPartyType
  type MyAbstractStuff interface {
      ThirdPartyFunc() ThirdPartyType
  }
  type MyConcreteStuff struct{
      Client MyAbstractStuff
  }
  func (mcs *MyConcreteStuff) MyFunc() MyType {
      tpt := mcs.Client.ThirdPartyFunc()
      return MyType(tpt)
  }
  </code></pre>
  <p>So I moved forward and did this:</p>
  <pre><code>type PubsubMsgChan &lt;-chan *redis.Message
  
  func (psClient *PubsubClient) Subscribe(ctx context.Context,
      topics ...string) PubsubMsgChan {
  
      redisPubsub := psClient.Client.Subscribe(ctx, topics...)
      return PubsubMsgChan(redisPubsub.Channel())
  }
  </code></pre>
  <p>But this doesn't seem right. If I was a user of this code, I would understand it better if there was a &lt;-chan in my Subscribe() return type signature, so the user wouldn't have to dig in to find out that PubsubMsgChan is a read-only channel.</p>
  <p>Considering <code>redisPubsub.Channel()</code> returns <code>&lt;-chan *redis.Message</code>, how can I keep the &lt;-chan in my method signature and at the same time hide *redis.Message?</p>
  <p>For starters, is my approach to decoupling in Go actually valid/good/workable?</p>