Advantages of config injection

Given that config injection is an expanded form of constructor and method injections, the advantages of the other methods also apply here. In this section, we will discuss only the additional benefits that are specific to this method.

It's excellent for decoupling from a config packageWhen we have a config package that loads from a single place, such as a file, then this package tends to become a dependency for many of the other packages in the system. When considering the Single responsibility principle section from Chapter 2SOLID Design Principles for Go, we recognize that the more users a package or object has, the more resistant and/or difficult it is to change.

With config injection, we are also defining our requirements in a local interface and leveraging Go's implicit interfaces and the dependency inversion principle (DIP) to keep the packages decoupled.

These steps also make it significantly easier to test our structs. Consider the following code:

func TestInjectedConfig(t *testing.T) {
// load test config
cfg, err := config.LoadFromFile(testConfigLocation)
require.NoError(t, err)

// build and use object
obj := NewMyObject(cfg)
result, resultErr := obj.Do()

// validate
assert.NotNil(t, result)
assert.NoError(t, resultErr)
}

Now, see the same code with config injection:

func TestConfigInjection(t *testing.T) {
// build test config
cfg := &TestConfig{}

// build and use object
obj := NewMyObject(cfg)
result, resultErr := obj.Do()

// validate
assert.NotNil(t, result)
assert.NoError(t, resultErr)
}

// Simple implementation of the Config interface
type TestConfig struct {
logger *logging.Logger
stats *stats.Collector
}

func (t *TestConfig) Logger() *logging.Logger {
return t.logger
}

func (t *TestConfig) Stats() *stats.Collector {
return t.stats
}

Yes, the amount of code is greater. However, we no longer have to manage test configuration files, which can often be a pain. Our tests are entirely self-contained and should have no concurrency problems, as they might with a global config object.

It eases the burden of injecting common concerns—In the previous example, we are using config injection to inject the logging and instrumentation objects. Common concerns such as this are an excellent use for config injection as they are frequently needed but are not informative regarding the purpose of the function itself. They can be considered environmental dependencies. Due to their shared nature, another approach would be to turn them into global singletons instead of injecting them. Personally, I prefer to inject them as this gives me the opportunity to validate their usage. This in itself might feel weird, but in many cases, we build system monitoring and alerts from the existence or lack of instrumentation data, thereby making instrumentation part of the features or contract of our code and something we might want to protect from regression with tests.

It improves usability by reducing parameters—Similar to the previous advantage, applying config injection can enhance the usability of methods, particularly constructors, but reduce the number of parameters. Consider the following constructor:

func NewLongConstructor(logger Logger, stats Instrumentation, limiter RateLimiter, cache Cache, url string, credentials string) *MyStruct {
return &MyStruct{
// code removed
}
}

Now. take a look at the same constructor with config injection:

func NewByConfigConstructor(cfg MyConfig, url string, credentials string) *MyStruct {
return &MyStruct{
// code removed
}
}

With the environmental dependencies removed from the constructor definition, we are left with significantly fewer parameters. Even more than that, the only parameters that remain are those that are specific to the purpose, hence making the method simpler to understand and use.

Dependency creation can be deferred until use—Have you ever tried to inject a dependency, only to find that it didn't exist or wasn't ready yet? Have you ever had a dependency that was so expensive to start or run that you wanted to create it only when it was absolutely necessary?

With config injection, dependency creation, and access only need to be resolved at the point of usage and not during injection.

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

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