Go and Dependency Injection / Inversion of Control Container

5,406 views
Skip to first unread message

Luke Mauldin

unread,
Sep 2, 2012, 10:52:29 PM9/2/12
to golan...@googlegroups.com
All,

Does anyone have any recommended ways of implementing dependency injection or inversion of control concepts in Go projects?  Java has the Spring framework, .NET has the Spring.NET framework and Unity, and other languages have similar frameworks that allow modules to leverage other modules without needing to know concrete implementors or the object graph buildup.  This can make testing the code substantially easier, but I find the primary value comes from reducing the number of dependencies in my code by allowing me to easily glue various pieces of my code together.  Any thoughts?

Luke

Vanja Pejovic

unread,
Sep 2, 2012, 11:08:00 PM9/2/12
to Luke Mauldin, golan...@googlegroups.com
All of those benefits can be had without a framework. Some of them, like gluing various pieces together, are easier in Go than other languages because of the implicit implementation of interfaces. To do dependency injection without a framework, you only need to do a few things. Have most things implement an interface and refer to most things by their interface type, and not their implementation type. Also, separate your object creation/wiring code from everything else.

I would recommend just writing and reading Go code though. I don't know if many Go projects follow the strict separation of logic and wiring.

I've considered building a dependency injection framework for Go, but until I face a problem that needs it, I won't do it.

Slightly off topic, if you need dependency injection in Java, try Guice. While it still has too many features, it's easier to use than Spring.

Joubin Houshyar

unread,
Sep 3, 2012, 12:09:40 AM9/3/12
to golan...@googlegroups.com


On Sunday, September 2, 2012 10:52:29 PM UTC-4, Luke Mauldin wrote:
All,

Does anyone have any recommended ways of implementing dependency injection or inversion of control concepts in Go projects?  Java has the Spring framework, .NET has the Spring.NET framework and Unity, and other languages have similar frameworks that allow modules to leverage other modules without needing to know concrete implementors or the object graph buildup.  This can make testing the code substantially easier, but I find the primary value comes from reducing the number of dependencies in my code by allowing me to easily glue various pieces of my code together.  Any thoughts?

Both of those platforms allow for trivial data driven instantiation of types at runtime.  Given a Go type's name at runtime (as a string), you can not create a new instance of that type.  It is perhaps possible to work around this -- e.g. type factories and registration via module init() funcs -- but then every module would need to follow a pattern of definition particular to the framework's design.
 

Luke

Larry Clapp

unread,
Sep 3, 2012, 1:11:15 PM9/3/12
to golan...@googlegroups.com
On Monday, September 3, 2012 12:09:40 AM UTC-4, Joubin Houshyar wrote:
every module would need to follow a pattern of definition particular to the framework's design

Why?  Couldn't you, the user, register a module's types without its cooperation?  Admittedly you'd have to do it at compile-time.  But since Go can't load code at runtime, compile-time is the only time that matters.


You could probably even write a code-walker to do it all for you, if you have source.  go/ast

Of course I haven't used Spring, and have used Go for maybe a couple of weeks now, so maybe I'm missing something.  :)

-- Larry

Joubin Houshyar

unread,
Sep 4, 2012, 11:10:47 AM9/4/12
to golan...@googlegroups.com


On Monday, September 3, 2012 1:11:15 PM UTC-4, Larry Clapp wrote:
On Monday, September 3, 2012 12:09:40 AM UTC-4, Joubin Houshyar wrote:
every module would need to follow a pattern of definition particular to the framework's design

Couldn't you, the user, register a module's types without its cooperation?  Admittedly you'd have to do it at compile-time.

Wouldn't it be simpler and more clear to simply call a setter in that case?  DI is really meaningful in the broader context of component orientation and component assembly and deployment by generic containers. Opinion, of course.


Kevin Gillette

unread,
Sep 4, 2012, 1:49:09 PM9/4/12
to golan...@googlegroups.com
The code-generation approach is certainly doable, and you end up with something like SWIG, but you lose a lot of the control over your software (including its quality and safety) which so many Go programmers hold dear. I expect a great many of us would choose the manual approach.

Luke Mauldin

unread,
Sep 4, 2012, 1:59:10 PM9/4/12
to golan...@googlegroups.com
I agree that I do not want to end up with a SWIG like solution.  I also do not want to use strings to represent types so they can be constructed via reflection.  However, I would like my primary logic to be free of wiring concerns.  For example, I don't want my primary code to know what logger it should be using.  Or if I need to get use information, I would like to have an interface "UserInfoProvider" and then in my wiring code construct the object that implements that interface and I would like to be able to seamlessly use that in my primary code.  The code below shows a simple example in C# of what I am trying to achieve.  I am not trying to directly port the approach below to Go (because I don't see how that would work well), but I would like to understand the recommended Go way of solving this sort of problem:

// Create a singleton dependency injection container
private static readonly IContainer Container = ConfigureContainer();

// Configure the container
static IContainer ConfigureContainer() {
    // This is how AutoFac works. Other DI containers have similar
    // mechanisms for configuring the container
    var bld = new ContainerBuilder();

    // Register the types that implement the interfaces that are required
    // for injection. Note that we have robust control over lifetime, in
    // this case ILogService and IIdentService will be singletons, and
    // IDataProvider will provide a new instance each time it's requested
    bld.RegisterType<ConsoleLogger>().As<ILogService>().SingleInstance();
    bld.RegisterType<WindowsIdentService>().As<IIdentService>().SingleInstance();
    bld.RegisterType<DevDataProvider>().As<IDataProvider>();
    return bld.Build();
}

static void Main(string[] args) {

    // ** Using an IoC Container approach **
    var dal = Container.Resolve<IDataProvider>();

David Wright

unread,
Sep 4, 2012, 2:39:11 PM9/4/12
to Luke Mauldin, golan...@googlegroups.com
I'm new to the language, but it might be useful to think about coupling as it's done on unix systems, using sockets, files, and pipes, and to rely on the language for doing more sophisticated things than C with same.

My thought is that the Go version of a DI framework might look more like a framework for interprocess communication, or something like memcached.

David

Ernesto Karim Oltra

unread,
Sep 4, 2012, 3:31:40 PM9/4/12
to golan...@googlegroups.com
I'll make it this way:

type 
ILogService interface {
...methods
}

type consoleLogger struct {
  ...data
}

..implement ILogService methods for *consoleLogger

func NewLogService() ILogService {
return &consoleLogged{....}
}

Anyway, what's the point of using this kind of constructs (IC) everywhere in Go? Some internal fields and interfaces in the correct places can make code easy to test, and it doesn't need ALL to be an interface like in other languages.


Ernesto

Luke Mauldin

unread,
Sep 4, 2012, 4:06:35 PM9/4/12
to golan...@googlegroups.com
Ernesto,

In some of my Go code, I have used the approach you described below.  However, I run into problems trying to determine where to put "NewLogService".  If I put it as a public function in the "logger" package, then it becomes difficult to change the concrete class in my client code without modifying the "logger" package.  If I create a separate package, "appservices" and put the function in the "appservices" package, then it is slightly easier but I still have to modify the "appservices" package each time I want to change loggers, and then how do I handle the scenario of wanting some clients to use one logger implementation and other clients wanting to use another logger implementation?

I have also went down the path of having a map[string]interface{} and populating the map and having the string keys be global.  However, Go lacks generics, and so this leads to quite of a bit type casting.  And none of this solves the dependency injection problem because I want my dependency to be ready for use, I don't want to have to write the code to resolve them.

Luke

hash

unread,
Sep 4, 2012, 5:46:24 PM9/4/12
to golan...@googlegroups.com
Just to be a rubber duck, what problem does what you want, solve in golang?
Is there a problem or are you wanting to solve other paradigm problem in golang world?

Jeremy Wall

unread,
Sep 4, 2012, 5:55:45 PM9/4/12
to Luke Mauldin, golan...@googlegroups.com
There isn't really any recommended way. I've seen people use init
functions to automatically register handlers for for other packages
but this is hit an miss. For the most part everyone just uses
constructors and interfaces with a test harness. Most of the
Dependency Injection frameworks arose because of a particular need in
that languages ecosystem. I don't think anyone doing Go for the most
part have run into that particular need. Perhaps you will be the
first?

If you were going to meet that particular need I think you would end
up using some formalized form of the registered handlers and package
init functions. But other than that I have no idea what else it would
look like.

jorelli

unread,
Sep 4, 2012, 8:05:14 PM9/4/12
to golan...@googlegroups.com
I would do it like this:


if you have a variety of ways of doing some thing, and the inputs and the outputs are all the same, then use some structure that contains a bunch of functions.  Use consts and iota for enumeration-like things, and use interfaces where appropriate.

The hard part about learning Go's type system is absolving yourself of thinking about abstraction in terms of grouping data by what it has, in favor of grouping data by what can be done with that data.  Therein lies the rub.


On Sunday, September 2, 2012 10:52:29 PM UTC-4, Luke Mauldin wrote:

jorelli

unread,
Sep 4, 2012, 8:08:31 PM9/4/12
to golan...@googlegroups.com
and obviously if you want to actually inject something useful into those, you would make your AnimalCreator type be something more like `func(SomethingYouNeed) Animal` or something like that, and then you would pass in that dependency inside of the definition of MakeAnimal.

Ross Light

unread,
Sep 4, 2012, 8:37:08 PM9/4/12
to Jeremy Wall, Luke Mauldin, golan...@googlegroups.com
A while back, I implemented a toy version of Guice in Go as an experiment, and it ended up looking like a clumsy handler registration system.  Go's interfaces seem to obviate the need for DI.

My two cents,

Luke Mauldin

unread,
Sep 5, 2012, 8:48:44 AM9/5/12
to golan...@googlegroups.com, Jeremy Wall, Luke Mauldin, ro...@zombiezen.com
Ross,

That is very interesting to know.  What solution/patterns did you end up using in your Go code?

Luke

Luke Mauldin

unread,
Sep 5, 2012, 8:52:35 AM9/5/12
to golan...@googlegroups.com
Jorelli,

Thank you very much for the code example, I would have never thought to create a function type and use that in the map.  I am not sure that it totally solves my problem because there is not a common interface what distinguishes my components, but I can see situations where that pattern would be useful.
I agree with you that it is difficult to learn to think in terms of Go's type system.  The type system is similar enough to other languages that an experienced programmer can pickup Go and be productive fairly quickly, but the type system is different enough from other major languages that it takes a good while to think in a "Go-way".

Luke

André Moraes

unread,
Sep 5, 2012, 8:54:22 AM9/5/12
to Luke Mauldin, golang-nuts
The Go way of doing that is:

In your package define the interfaces that you need.
In your exported functions include parameters that you can use to pass
something that implements your interface.

Doing that you pass the responsability to provide an interface to the
caller of your package instead of your package itself, this is DI done
in Go. Or to simplify, this is just interfaces done right :)

--
André Moraes
http://amoraes.info

Luke Mauldin

unread,
Sep 5, 2012, 8:59:40 AM9/5/12
to golan...@googlegroups.com
Here is an example of a real Go problem I am trying to solve.  Let's say I have three packages, a logger package (which contains both an ILogger interface and a default implementation), a userinfo package (which contains an IGetUserInfo interface and a default implementation), and a main package to run my application.  Let's also assume that the logger package needs the ability to look-up user information because I want to store some basic user information with the log entry.  I want my main package to do the wire-up between the logger package and the userinfo package to instruct the logger package to use the default implementation provided in the userinfo package.  In some other languages (ie  Java using Guice), the main package could create a container and register the userinfo and logger implementations with the container.  The logger package could then use the container to look-up at runtime an instance that implements IGetUserInfo.

Luke  

Luke Mauldin

unread,
Sep 5, 2012, 9:02:16 AM9/5/12
to golan...@googlegroups.com, Luke Mauldin
So in this instance, I would have package level variables for each of the interfaces that the package depends on and I would have exported functions that set those package level variables.  The consumers of my package would then be responsible for calling the exported functions to set the package level variables, is that correct?

Luke

Vanja Pejovic

unread,
Sep 5, 2012, 9:21:03 AM9/5/12
to Luke Mauldin, golan...@googlegroups.com
I think you would do this in Go like this:

package logger
type UserInfoProvider interface {
  // functions that your logger needs
}
type ILogger interface { // please don't actually call it ILogger. Just Logger, or even just L, since your package is called logger
  //functions that your logger has
}
type Logger struct {
  userInfoProvider UserInfoProvider
  // any other fields your logger needs
}
func NewLogger(userInfoProvider UserInfoProvider, /* other fields */) *Logger {
  return &Logger{userInfoProvider, /* other fields */}
}

package main
import "logger"
import "useinfo"
func main() {
  getUserInfo := userinfo.NewGetUserInfo()
  l := logger.NewLogger(getUserInfo, /* other fields */)
}

Note that the logger package does not need to know anything about the userinfo package. The NewLogger function specifies the parameters it needs in order to do whatever it does. Because of the implicit implementations of interfaces, you just need to make sure that the value returned by userinfo.NewGetUserInfo() implements the methods defined in logger.UserInfoProvider.

Ross Light

unread,
Sep 5, 2012, 10:14:49 AM9/5/12
to Luke Mauldin, golan...@googlegroups.com
It looked like Guice code, more or less. (I don't have the original
package handy, so some details of this snippet are probably wrong.)

http://play.golang.org/p/OCga000jHV

I don't particularly endorse this approach; I dropped it after
proof-of-concept because it made my code worse. It overused the
reflect API and ultimately made my code less type-safe than if I just
managed it the Go way -- not to mention the stuttering.

It can work, but it's not as big of a win as you would think. To quote
John Carmack, "Sometimes, the elegant implementation is just a
function. Not a method. Not a class. Not a framework. Just a
function."

Ross Light
http://www.zombiezen.com/

Ross Light

unread,
Sep 5, 2012, 11:00:56 AM9/5/12
to Luke Mauldin, GoLang Nuts
Package-level variables, or possibly a package-level function if the
setup is complex.

Ross Light
http://www.zombiezen.com/


On Wed, Sep 5, 2012 at 7:49 AM, Luke Mauldin <lukem...@gmail.com> wrote:
> Ross,
>
> Yes, I tried something similar as well in one implementation and I also
> ended up with the problem of type safety and alot of casts. You said that
> you ultimately decided to do it the Go way, was that package level variables
> or another method?

jorelli

unread,
Sep 5, 2012, 12:09:56 PM9/5/12
to golan...@googlegroups.com
a logger package (which contains both an ILogger interface and a default implementation),

logger.ILogger?  NO! NO NO NO NO NO!  Let me repeat this, because it bears repeating:  NO!!!!

logger.Interface or just logger.Logger.  In your situation, I would most likely call it logger.Backend.

type Item struct {
    Message string
    Timestamp time.Time
}

type Backend interface {
    Log(*Item) error
}

type defaultBackend struct {
    io.Writer
}

func New(w io.Writer) Backend {  // notice that the return type is the interface type!
    return defaultBackend{w}
}

and then your UserInfo would just embed a backend:

type UserInfo struct {
    logger.Backend
    Firstname string
    Whatever sometType
    Etc yougetit
}

func (u *UserInfo) LogSomething() error {
    return u.Backend.Log(&logger.Item{
        Timestamp: time.Now(),
        Message: "this is blah blah whatever",
    })
}

and maybe if you need to log to a file or something you just do something like

f, err := os.Open("/path/to/some/file")
if err != nil {
    // do something
}

user := &UserInfo{Backend: logger.New(f)}
user.LogSomething()

but to be honest I would just use the standard log package because they've already figured most of this out.  (all code untested)

Glenn Brown

unread,
Sep 6, 2012, 12:55:47 AM9/6/12
to Luke Mauldin, Glenn Brown, golan...@googlegroups.com
I've put a simple Dependency Injection example with pedantic comments at https://github.com/glenn-brown/golang-di-example .  In Go, the language itself allows "modules to leverage other modules without needing to know concrete implementors or the object graph buildup."  In my example, logclient.go doesn't know the implementor or object graph.  logclient_test.go injects an implementation, building the graph, and performs a trivial output test.

I've been using DI a lot lately, and have been very impressed by the resulting simplicity, flexibility, and testability.

--Glenn

Luke Mauldin

unread,
Sep 11, 2012, 7:48:47 PM9/11/12
to golan...@googlegroups.com, Luke Mauldin, Glenn Brown
Thank you for the example, this seems to be the common way to solve this problem in Go.  Thanks to everyone who gave their input.

Luke

Raph

unread,
Sep 12, 2012, 4:25:13 AM9/12/12
to golan...@googlegroups.com, Luke Mauldin, Glenn Brown
While this is technically DI (the dependency is injected into the Logger), it's not IoC - at least not what IoC stands for in other languages such as C# and Java. IoC typically involves a framework to glue the dependencies together, which sometimes involves yukky XML configuration and more recently configuration in code.

The motivation behind those containers is mostly loose coupling of modules and run-time scanning/loading of interface implementations - things which I think don't work well (read: at all) in Go given it's lack of dynamic loading (which I know there has already been much discussion about).

egon

unread,
Apr 24, 2013, 5:11:59 PM4/24/13
to golan...@googlegroups.com
So I got bored and made a proof of concept: http://play.golang.org/p/HdJBd2VlD6
The basic idea is to change binding targets through generic pointers.

(only use it, if you really need it... keep it simple)

+egon
Reply all
Reply to author
Forward
0 new messages