Simplified dependency creation

When we started in Chapter 4Introduction to the ACME Registration Service, our main() function looks rather simple, as shown in the following code:

func main() {
// bind stop channel to context
ctx := context.Background()

// start REST server
server := rest.New(config.App.Address)
server.Listen(ctx.Done())
}

After applying several DI methods to our code, by Chapter 9, Just-in-Time Dependency Injection, our main() function had become the following:

func main() {
// bind stop channel to context
ctx := context.Background()

// build the exchanger
exchanger := exchange.NewConverter(config.App)

// build model layer
getModel := get.NewGetter(config.App)
listModel := list.NewLister(config.App)
registerModel := register.NewRegisterer(config.App, exchanger)

// start REST server
server := rest.New(config.App, getModel, listModel, registerModel)
server.Listen(ctx.Done())
}

As you can see, it had become longer and more complicated. This is a common complaint regarding DI. So, in Chapter 10, Off-the-Shelf Injection, we reduced this cost by letting Wire do it for us. This brings us back to a nice concise main() function, as follows:

func main() {
// bind stop channel to context
ctx := context.Background()

// start REST server
server, err := initializeServer()
if err != nil {
os.Exit(-1)
}

server.Listen(ctx.Done())
}

Similarly, in Chapter 9, Just-in-Time Dependency Injection, we recognized the fact that there would only ever be one live implementation of the data layer, and the only time we would inject anything different was during testing. We, therefore, decided not to make the data layer a constructor parameter, but instead to use JIT injection, as shown in the following code:

// Getter will attempt to load a person.
type Getter struct {
cfg Config
data myLoader
}

// Do will perform the get
func (g *Getter) Do(ID int) (*data.Person, error) {
// load person from the data layer
person, err := g.getLoader().Load(context.TODO(), ID)
if err != nil {
if err == data.ErrNotFound {
return nil, errPersonNotFound
}
return nil, err
}

return person, err
}

// Use JIT DI to lessen the constructor parameters
func (g *Getter) getLoader() myLoader {
if g.data == nil {
g.data = data.NewDAO(g.cfg)
}

return g.data
}

As can be seen here, this gives us simplified, local dependency creation without detracting from the UX of our constructors and without losing our ability to mock the data layer during testing.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.223.170.223