Skip to content

devkabiir/diydigo

Repository files navigation

diydigo - a do-it-yourself dependency injection framework in GO

Go

A superior simplicity dependency injection framework in under 60 lines of code. You are encouraged to fork it, copy-paste it to your source code and modify it as you please based on your requirements.

For full documentation checkout this blog post, including how this was built from ground up, the rationale and alternatives.

This is released under MIT license.

Example of diydigo usage

Feature Complete

  • Allows strong isolation of concerns
  • Promotes decoupling of logic and modules from its variants
  • Facilitates unique registries for different use cases
  • Allows overriding dependencies in local scopes, eliminating global side effects
  • Use with any primitive, struct or function values to be registered as a dependency
  • Resolves dependencies until the root registry in the chain and fails gracefully.
  • Unit tests with full coverage
  • Basic gin server implementation for usage example

Usage

// Imagine your code needs access to certain configs at runtime
// You could hard-code it or pass it via a function
// But things quickly get messy if you need variants or need to check different behaviors during testing
func LoadConfig() string {return "Production" }
func LoadTestConfig() string {return "Development" }

// You could write it the traditional way with if-blocks

func BusinessLogic() {
    config := LoadConfig()
    if isTesting {
        config = LoadTestConfig()
    }

    // The business logic has nothing to do with whether this code is being run under test or production
    // The unnecessary 

    // TODO: use the config.
}

Using DI, allows for better decoupling and isolation.

func BusinessLogic(reg *diydigo.Registry) {
    config := reg.Resolve("config") 
    // TODO: use the config
    print(config)
}

Notice that the BusinessLogic is far simpler and does not care about how or what produces the config.

reg := diydigo.NewRegistry()
reg.Provide("Config", func() (any, error) { return LoadConfig(), nil })

BusinessLogic(reg) // prints Production

// All modules share the same registry:
config1, _ := reg.Resolve("Config") // Production

// Now override locally for tests, this creates a new registry:
newReg = reg.Override("Config", func() (any, error) { return LoadTestConfig(), nil })

BusinessLogic(newReg) // prints Development

// config1 still is production
config1, _ := reg.Resolve("Config") // Production
// config2 in any part of the app is now the test config!
config2, _ := newReg.Resolve("Config") // Development

About

Superior Dependency Injection under 60 lines of code

Topics

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages