Graph: Dependency and Lifecycle Management
Dependency injection is a technique to "magically" satisfy dependencies within an application, reducing the mental overhead for programmer and ensuring the dependencies remain loosely coupled.
This module for Go provides one implementation of such magic, with the following aims:
- Provide dependency injection for
struct
fields; - Explicit lifecycle management for an application;
- Mapping between an
interface
and its' concrete implementation through module imports; - Passing of state between dependencies in different phases of the lifecycle;
- A framework for developing tools and unit tests.
The Graph module provides a programming pattern which aims to target the best features of Go (channels, goroutines and composition for example) to simplify complex application development.
Installing & Using
To use Graph just import the definitions to create a Unit, an instance which can
be used in dependency injection. Mark any Unit with an anonymous graph.Unit
field.
For example, mymodule.MyInterface
can be injected into an application shell tool:
package main
import (
graph "github.com/djthorpe/graph"
tool "github.com/djthorpe/graph/pkg/tool"
"mymodule"
)
type App struct {
graph.Unit
mymodule.MyInterface
}
func main() {
tool.Shelltool(context.WithCancel(/* ... */),"myapp",os.Args[1:],new(App))
}
The magic here is that the MyInterface
dependency is satisifed without further
code, and according to the lifecycle can resolve its' own dependencies and even
run background tasks. When it terminates it can also dispose of any used resources.
Somewhat less magically, here is the implementation of the interface, and definition of the lifecycle:
package mymodule
import (
graph "github.com/djthorpe/graph"
"reflect"
)
func init() {
// Register mymodule.myUnit as implementation of exported mymodule.MyInterface
graph.RegisterUnit(
reflect.TypeOf(&myUnit{}),
reflect.TypeOf((*MyInterface)(nil))
)
}
type MyInterface interface {
// ... interface definition
}
type myUnit struct {
graph.Unit
graph.Events // Inject event pubsub dependency
// ... other dependencies injected here
}
// New, Run and Dispose define the lifecycle
func (*myUnit) New(graph.State) error {
// ...Initialize myUnit
}
func (*myUnit) Run(context.Context) error {
// ...Run myUnit until cancel or deadline exceeded
}
func (*myUnit) Dispose() error {
// ...Dispose of any resources used by myUnit
}
More information about the lifecycle, passing state between units, testing and so forth is provided in the documentation.
Documentation
More information on usage of Graph is provided in the following documentation:
Project Status
This module is currently in development but is mostly feature-complete.
Community
- File an issue or question on github.
- Licensed under Apache 2.0, please read that license about using and forking Graph. The main conditions require preservation of copyright and license notices. Contributors provide an express grant of patent rights. Licensed works, modifications, and larger works may be distributed under different terms and without source code.