Skip to content

Instantly share code, notes, and snippets.

Created September 7, 2022 23:11
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
Star You must be signed in to star a gist
Save kevinmichaelchen/6afae8ecf0bfb28248877c39abaf0ced to your computer and use it in GitHub Desktop.
go interfaces and proverbs

πŸ‘‹πŸΌ here's what I'm thinking regarding my earlier comments about interfaces (inspired by here and mainly here).

This is a really subtle point that I'm still trying to wrap my head around and understand the tradeoffs πŸ˜†

I think at small scale it makes no difference whichever approach we take.

I definitely think we want and need interfaces (for mocking, multiple implementations, etc).

But it's just the where that is the focus here.

Say we've got the following directory structure:

β”œβ”€β”€ redis
β”‚  └── redis.go
β”œβ”€β”€ supply
β”‚  β”œβ”€β”€ supply.go
β”‚  └── supply_test.go
β”œβ”€β”€ demand
β”‚  β”œβ”€β”€ demand.go
β”‚  └── demand_test.go

Say our Redis client can do a lot of different things:

// redis.go
type Cache interface {
  GetName() string
  Put(ctx context.Context, key string, value string) error
  Get(ctx context.Context, key string) (value string, err error)
  Remove(ctx context.Context, key string) (err error)
  ContainsKey(ctx context.Context, key string) (containsKey bool)

And say the supply and demand packages both use the client, but only a subset of the client's functionality. And those subsets of functionality might not be overlapping.

This is where defining interfaces on the client-/consumer-side has the benefit of smallness and keeps more with the proverb: "The bigger the interface, the weaker the abstraction."

// supply.go

// a small interface - means we won't 
// have to mock as much in the unit test
type RedisCache interface {

func NewService(rc RedisCache) *Service {
  return &Service{
    RedisCache: rc,

type Service struct {
  RedisCache RedisCache

func (s *Service) BusinessLogic() {

In main.go we can inject the implementation itself:

func main() {
  rc := redis.NewCache()
  supplyService := supply.NewService(rc)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment