Skip to content

ividence/go-ioc

 
 

Repository files navigation

Go Package - ioc GoDoc

Package ioc provides inversion of control containers, reflection helpers (GetNamedSetter, GetNamedInstance, GetNamedType) and Factory helpers (Resolve/ResolveNamed).

The ioc.Container and ioc.Values structs implement the Factory interface.

Package ioc is designed with the following goals in mind:

  • Well defined behavior (noted in comments and ensured by tests)
  • Idiomatic Go usage (within reason)
  • Cater for different use cases (e.g. ResolveNamed within Factory functions, MustResolvedNamed for web request scopes)
  • Robust runtime behavior (crash safe)
    • avoid infinite recursion on resolve
    • raise errors on configuration and behavioral errors
    • custom ioc.Error struct for diagnosing configuration and behavioral issues, containing the following metadata: calling function, file and line number, called function on package ioc, requested type and name, and an error code representing the type of error.
  • Predictable and reasonably efficient performance and memory usage (*to be ensured by benchmark tests)

Package ioc is not dependent on the net/http package.

Please note that package ioc is of production quality, but hasn't been thoroughly tested in production.

Installation

Current Version: 0.1.0

Go Version: 1.2+

go get -u github.com/shelakel/go-ioc

Documentation

See GoDoc on Github

License

This project is under the MIT License. See the LICENSE file for the full license text.

Usage

Please see GoDoc on Github and *_test.go files.

Performance

Due to the use of the reflect package, ioc.Container and ioc.Values are not well suited for temporary storage (e.g. passing state to functions on a hot path).

More benchmarks to be added during optimization.

go test -run=XXX -bench=. -benchmem=true

See reflect_cpu_prof_latest.svg for a CPU profile of the runtime reflection functions.

Benchmark Iterations Avg Alloc # Alloc
BenchmarkGetNamedSetter_Int 20000000 92.0 ns/op 33 B/op 1 allocs/op
BenchmarkGetNamedSetter_String 20000000 92.9 ns/op 33 B/op 1 allocs/op
BenchmarkGetNamedSetter_Interface 20000000 96.5 ns/op 33 B/op 1 allocs/op
BenchmarkGetNamedSetter_AnonStruct 20000000 114 ns/op 33 B/op 1 allocs/op
BenchmarkGetNamedSetter_Struct 20000000 93.3 ns/op 33 B/op 1 allocs/op
BenchmarkGetNamedSetter_DblPtr 20000000 109 ns/op 33 B/op 1 allocs/op
BenchmarkGetNamedInstance_Int 20000000 102 ns/op 33 B/op 1 allocs/op
BenchmarkGetNamedInstance_String 20000000 102 ns/op 33 B/op 1 allocs/op
BenchmarkGetNamedInstance_Interface 20000000 108 ns/op 33 B/op 1 allocs/op
BenchmarkGetNamedInstance_AnonStruct 20000000 120 ns/op 33 B/op 1 allocs/op
BenchmarkGetNamedInstance_Struct 20000000 101 ns/op 33 B/op 1 allocs/op
BenchmarkGetNamedInstance_DblPtr 20000000 120 ns/op 33 B/op 1 allocs/op
BenchmarkGetNamedType_Int 100000000 20.8 ns/op 0 B/op 0 allocs/op
BenchmarkGetNamedType_String 100000000 20.9 ns/op 0 B/op 0 allocs/op
BenchmarkGetNamedType_Interface 100000000 20.8 ns/op 0 B/op 0 allocs/op
BenchmarkGetNamedType_AnonStruct 50000000 33.4 ns/op 0 B/op 0 allocs/op
BenchmarkGetNamedType_Struct 100000000 20.9 ns/op 0 B/op 0 allocs/op
BenchmarkGetNamedType_DblPtr 50000000 33.4 ns/op 0 B/op 0 allocs/op

Preliminary benchmarking on my machine (i7-4770K, 2400MHz RAM) yielded 200 ns per Set/Get operation on ioc.Values, 400 ns per cached/singleton Resolve and 1300 ns per request to resolve via the factory function.

Tests

Tests are written using Ginkgo with the Gomega matchers.

Benchmark functions are written using the testing package.

TODO

  • This package isn't actively being worked on *
  • Improve performance - for now it is what it is due to the inherent limitations/cost of reflection in Go. This package is well suited for constructing singletons, not so much for use in a 'per request' type scenario.
  • Populate function that uses a Factory to populate struct instances via dependency injection on tagged fields. The current thinking is to support dynamic population e.g. standard ioc="constant", dynamic ioc_route="id" via ResolveNamed((*Factory),"route") -> (dynamic Factory).ResolveNamed((type), "id").
  • Improve README with Usage examples and topics.

Contributing

Contributions are welcome, especially in the area of additional tests and performance enhancements.

  1. Find an issue that bugs you / open a new one.
  2. Discuss.
  3. Branch off the develop branch, commit, test.
  4. Submit a pull request / attach the commits to the issue.