Structuring go interfaces with subpackages

Issue

I am developing my first real go application and am trying to wrap my hand around my codefiles should be structured.

The main part of my code is going to be a number of types which all implement a common interface.


type Runner interface {
  Run() string
}

They are going to be in a package. As the number of the interface implementations is going to be very large I would like to split them (semantically) into a couple of subpackages.

runner/
  blue/
  red/

The Runner implementation need access to a couple of other interfaces that are defined elsewhere in my application (e.g., Cache and Secret). Those are currently defined & implemented in separate packages. My plan is to use a Config struct, which contains all those utility interfaces and pass it to the Runner implementations.

I am unsure how to best handle those subpackages and where to put the Config and interface declarations.
My intuitive approach would be to define both the Config struct and the Runner interface in the runner package and only return a []Runner collection from there, but this violates this recommendation.
Also, the number of imports required and the danger of running into circular references which are prohibited gives me the feeling, that my solution is going against best practices.

Are there any suggestions how to improve my code structure?
Would adding a common package which contains all my interface definitions and the Config struct be advisable?

Solution

I ended up creating a domain package containing the interface and Config definintions.

So in domain/domain.go I have

package domain


type Config struct {
    Cache
}

type Runner interface {
  Run() string
}

type Cache interface {
  // ...
}

The runners are structured in subpackages as mentioned above. I do not export the types but rather have a function in each package collecting all of them and returning it them as interfaces.

runner/blue/blue.go:

package blue

import "my/domain"

func All(config domain.Config) (list []domain.Runner) {
    list = append(list, fooRunner{Config: config})
    list = append(list, barRunner{Config: config})
    return
}

runner/runner.go:

package runner

import ( 
  "my/runner/blue"
  "my/runner/red"
  "my/runner/domain"
)

func All(config domain.Config) (list []domain.Runner) {
    list = append(list, blue.All(config)...)
    list = append(list, red.All(config)...)
    return
}

Answered By – mat

Answer Checked By – Terry (GoLangFix Volunteer)

Leave a Reply

Your email address will not be published.