Goldi: lazy dependency injection framework for go

Hey forum,

Coming from a Java and PHP background I was wondering if the concept of dependency injection framework would be useful to go as well so I started to create github.com/fgrosse/goldi as a toy project just for myself. This was mostly a project for the weekend to continue learning different aspects of go and have some fun with the language.

Now that I have spend quite some time with the framework I still havent decided if this is approach is actually useful. Sometimes it feels really cool to plug whole applications together like I used to in bigger framework from other languages (mostly symfony 2 as biggest influence for me). Then again I dont see any similar approach in other go frameworks which lets me doubt the value of the API again.

So I started to write a web framework with a heavy focus on DI to see where I would end up and how it would feel to create an application with this. So far its pretty cool but I still havent decided if I like the approach better. For smaller apps it is probably overkill but for bigger ones with more code it might be worth it.

Now I would like to know what you think on the topic and the presented packages. Have you used DI yet in any bigger go applications? Why do you think this is not so much of a deal in go? I would be interested in discussing the topic in general but also in getting some feedback on what I implemented. So far everything was pretty much in a vaccuum and I would like to change that at least a bit.

best regards
Friedrich

I’ve written a few small projects ~7000LOC range.

It depends what you mean by DI, there are many forms of it. Simplest form would be to accept an interface as an argument to a constructor. The most complicated would be to use some configuration file to setup the object structures.

This is DI in it’s simplest form:


type Logger interface {
    Println(xs ...interface{})
}

type Service struct {
    logger Logger
}

func New(logger Logger) *Service {
    return &Service{logger}
}

So the clearest answer would be… I’ve never needed a DI library.

I believe you are confusing a DI library with DI the principle. So, I’m answering “Why DI library is not necessary?”

  1. Idiomatic Go uses package by value rather than by form, which means there is less need to inject arbitrary services.
  2. Interfaces can be used instead of DI in some cases.
  3. It’s not hard to implement custom constructor that handles the injection.

If you haven’t read it, read this: http://codegangsta.io/blog/2014/05/19/my-thoughts-on-martini/

Also this: Keynote: 8 Lines of Code 

1 Like

I believe you are confusing a DI library with DI the principle. So, I’m answering “Why DI library is not necessary?”

Maybe my question was not entirely clear but yes thats exactly what I meant.
The DI principle in general is independent of the used language and really nothing uncommon in go applications.

Arguably the simplest form of DI in go is already

type Foo struct{
    Bar Baz 
}

type Baz struct{}


f := Foo{Bar: Baz{}}

which is a very common idiom in go.

In my opinion a DI framework doesn’t want to replace that or stop you from writing such code.
After playing with it for a while I would name the following insights on a DI framework like goldi:

Configuring an application is really easy
After you defined the types, everything is basically wired up and the library will give you the correctly configured instance of each type you want.
This removes any need for a Configuration type or another shared context like global variables.

Replacing (third party) dependencies
Sometimes it is useful to have control over the types another framework is using. This can be the case in tests where you want to mock out certain behaviour or just have an alternative implementation.
Sure you can easily have this without a DI (e.g. http.DefaultClient = &MyClient{}) but using a DI encourages you to use that kind of design.

It also encourages patterns where any other third party code can be plugged into your application like its common in the sql packages. An example of this plug and play are the servo bundles like servo-logxi.

Its not intrusive
As you can see in the servo-example the only code that knows about the DI library is in the main function when everything is wired together.
All other code in lib and endpoints is entirely agnostic of the DI library.

All in all I am currently not really sure if smallish applications can take an advantage of a DI framework but for the bigger ones there might be an actual usecase.

Ah and thanks for the codegansta blogpost. I would totally agree with him on:

[…] Martini allows you to inject all the things and that leads to a level of indirection that, while modular, requires a certain amount of cognitive overhead to fully understand what is actually going on.

Instead of not needing to configure it in the first place?

How often do you actually need to replace third-party dependencies. And when you do change, how long will this decision lasts?

Anyways… yes, all the statements you made are correct, but I think you are over-estimating the cost and need to change dependencies. If code is well designed, it’s not hard to substitute the service. When you need to substitute, you probably need to add some code as well, so it’s probably not necessary at runtime/start-time. When those substitutions are made, they probably last for a long time.

DI frameworks come with a cost on comprehensibility. Yes, there might be use cases, but without those actual use-cases you cannot understand what would be the best way of implementing DI framework. Similarly, the cost of implementing your own DI framework, when it is actually very low (when considering where it would eventually be needed)… and will be better, because you can exactly implement parts what you need and skip all the parts that you don’t need.

I think you know the following, but haven’t fully internalized it. DI frameworks have their costs and pros. Everything does. It’s not about taking advantage of things – but rather about making the right trade-offs.

You pay in code comprehension to gain (that specific) flexibility.

Yes, you could add that flexibility to small projects, but the main question is, how much actual value you gain from it for the end-user. How much do you hinder your value producing capability? How big is the cost of integrating a DI framework? When you don’t have a concrete real-world use-case for DI framework, how do you know it has any value? How do you know how much value it has compared to alternative implementations?

What I’m trying to say:

Stop thinking about the technical details, they are less important than creating value. If you don’t understand the value you are producing, stop… and make sure you understand it. How does your decision to write DI framework make a persons, who isn’t competent in computers, life easier? Are all the steps in this value stream sound? Are there any easier or faster ways of creating the same value?

I’m not saying that technical details don’t matter, they do. Currently you don’t have a full understanding of the value-stream – hence you don’t know whether you are making good decisions or not.

I’m not saying that you are an incompetent engineer. Definitely not. Based on your code, you can write pretty well. But, I was “in that place” for a long time – overly focused on the technical details and techniques instead of figuring out the best and fastest way of providing value. I have wasted a lot of time worrying about the wrong things. Once you understand the full value-stream, you understand the necessity of those engineering concernss

1 Like

This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.