mercredi 8 juillet 2020

Dependency injection in Golang - idiomatic way of interface implementation

Take a look at this snippet assuming that Fetcher instance comes from external package:

type DefaultHandler struct{
    Fetcher Fetcher
}

type Fetcher interface {
    FetchData(ID int) ([]byte, error)
} 

func (h * DefaultHandler) GetData() {
    data, _ := h.Fetcher.FetchData(1)
}

Fetcher interface here is abstract enough to be replaced with another data provider or to be mocked.

But what if the data from Fetcher is of exact type, more sophisticated than []byte(some struct with number of fields):

type DefaultHandler struct{
    Fetcher Fetcher
}

type Fetcher interface {
    FetchUser(ID int) (externalpackage.User, error)
} 

func (h * DefaultHandler) GetData() {
    user, _ := h.Fetcher.FetchUser(1)
}

Fetcher interface here kinda looses its abstraction because depends on exact package and doesn't make much of sense.

The attempt to fix the issue will be introducing intermediate local type like model.User and adapter that will transform externalpackage.User into model.User. Does it look GOish at all? What will be the idiomatic way to implement that?

For now I ended up with Fetcher interface that is a pointer to instance of externalpackage.Client(which has all necessary functions like FetchUser()), just describing dependency and sacrificing normal testing/abstraction/decoupling:


type DefaultHandler struct{
    Fetcher *externalpackage.Client
}

func (h * DefaultHandler) GetData() {
    user, _ := h.Fetcher.FetchUser(1)
}

Aucun commentaire:

Enregistrer un commentaire