This is basically "Use DI, and move towards SOLID"
Well, yeah! Those are great principles in any language - I find it concerning (and maybe indicative of something) that the Go community has voted this up. These are fundamental requirements to building testable, scalable systems in teams. Having global variables has been bad practice for what, 20 years? One of the first lines in Javascript, the Good Parts (closest book handy) is:
JavaScript is built on some very good ideas and a few very bad ones. ... The bad ideas include a programming >model based on global variables.
It's relevant because the Go community needs to rebuild all this, and is re-discovering that they can learn from existing patterns that many claimed were irrelevant because Go was so simple and so different.
Plus the lack of runtime control means you are essentially forced to do explicit DI, or you have an untestable mess. Hopefully the DI libs will catch up to e.g. Java's sophistication within a year or two.
Explicit DI is far better than a DI framework is your languages supports a sane syntax for composing structures. Java is a boilerplate-laden language and so it profits from a DI framework whereas Go doesn't. Building a DI framework isn't hard (contrary to your post, Go has the necessary runtime support), simply no one is interested. :)
What do you mean by "sane syntax for composing structures"? I use both Go and Java at work, and when it comes to constructing complex objects they both seem to have the same amount of boilerplate.
You know that most languages support those things right?
And they have virtually nothing to do with DI?
If you are going to make an argument for more natural support for DI in go than other "strongly" typed languages it starts and ends with structural typing.
Java doesn't. C# doesn't. C++ doesn't (or maybe it does as of the last few years). And the languages which have them (or something passably close) don't use DI frameworks (Python, JS, etc). They might exist in those languages, but they're fare from common. The point is that DI frameworks reduce boilerplate. Go head less boilerplate than, say Java.
Are you suggesting that the fact that the language has special syntax for initializing a few types means it has better support for dependency injection?
I don't even understand the basic premise of that argument. It seems nonsensical.
I wouldn't put it that way; it simply means the ROI for a framework is lower, and in Go's case, it's zero or less. It makes perfect sense because Go's syntax servers the same main purpose as a DI framework--to reduce initialization boilerplate.
The primary purpose of a DI framework is to alleviate boilerplate by offering a simpler mechanism for describing compositions than provided by the language. If a language already has a handy initialization/composition syntax, you don't get anything from a DI framework. Different frameworks have different bells and whistles, so this is a general point.
Again, I find for constructing things Golang is no more or less boilerplate-y than Java. Can you give an explicit example (like, with code) where Golang's struct literal syntax allows you to construct objects with less boilerplate than Java?
Sure. Anything with hash map or list literals (heaven forbid a list of hash maps!), off the top of my head. I'm not near a computer or I'd type out the example.
Well Java does have array literals. They don't have hash map literals, but I really don't use map literals very often in Go except for constants. And you can make a HashMap in Java in the same number of lines as Golang (though not for an array of hash maps). I really don't see that as a killer feature.
Arrays aren't equivalent to slices in Go. Map literals are nice for things like the driver pattern (a map of strings to some interface type; the user specifies which driver implementation should be used to handle some input). It's not about the number of lines, it's about having a declarative initialization syntax. In other words, it's about the number of expressions.
This isn't a killer feature, it jjust means Go requires less boilerplate when doing explicit DI, so the ROI offered by a DI framework is low. If you don't agree that initialization in Go requires less boilerplate, maybe you should be asking yourself what you gain from your DI framework?
DI frameworks were not originally introduced to replace boilerplate.
They were originally intended to move the behavior changes provided by DI from compile time to configuration time.
This was especially valuable when you are delivering enterprise software to sites you don't control and you need to support a wide array of integrations.
They also happen to reduce boilerplate & DI can help with test-ability so they were adopted for that as well, but if you are only doing DI for tests and only using a framework to reduce lines of code it's a fairly widely accepted anti pattern.
I believe your basic assumptions about DI are wrong. The reason it hasn't taken off in the golang world is that the kind of software it was used for is less common & if you are writing it you'd not use golang for a host of reasons, none related to initializer syntax.
oooh no, people are interested. Go DI frameworks are appearing rapidly. Simple ones are indeed simple (and often all you need, which is great), but that's nowhere near all there is to the field.
It wouldn't. It is for when you want to swap out that library, or test business logic using that library beyond simple unit tests.
DI is also great for creating modular code you compose, instead of monoliths. It encourages the use of interfaces and information hiding - you should look into it, it's a very powerful technique.
Instead of asking how it would improve an arbitrary library, ask yourself "how screwed am I if 100% of the API surface for this library changes tomorrow?" Dependency injection would help you out of that faster that rewriting everything.
this article falls into a particular genre "sensible advice that is either so internalized in other languages or the language itself prevents the pathology so why would you write that."
It's a winning combo because you can recycle old and simple ideas for a whole new context.
[edit] felt bad because rereading this it implies the author has bad intentions. Don't mean that. Just mean it's cute to watch the golang community learn Java.
In some ways, I consider Go to be a bit of a redo of the early ideas of Java, but with a bit more focus on tooling, and a stronger aim towards simplicity. And Go's standard library authors have the benefit of seeing how Java's early days played out.
I do enjoy that Go gives a bit more obvious control over memory layout than Java did, and I enjoy using it as a small projects language. I've never used it in full anger/production, so I haven't seen the worst of it.
One funny thing about Guice(mentioned elsewhere): I've heard more than one Googler say that dislike the framework quite a bit, due to how heavily it can be abused.
One bit of advice that seems to have gone either missing in Java/JVM, or common knowledge, is the idea that only main/binary packages should have config options via flags/env vars. Many, many JVM libraries do not follow that convention, and I've had to hunt down a log4j XML file for Spark in order to turn down the logging levels before. Would much rather have that be controlled via a flag.
Yes, flags vs. config files in Unix are a classic example of dependency injection vs. side effects, but at the process level rather than the programming language level.
At Google pretty much all server configuration is done with flags. Binaries can and do have thousands of flags. And I view that as a much better solution than a config file that is searched for.
The idea is that modular units like processes and functions don't "search for configuration", they just accept parameters, and led the higher level application configure them. Then the code becomes very straightforward to read and debug.
I'm not sure what you're describing, but it's not Dependency Injection. People are downvoting you for ignorance, which is unfair. Here is what we are discussing, it does not relate to value object declaration syntax.
You use the syntax to inject the dependencies. I'm not ignorant about DI, I was probably downvoted for being unclear. I could also imagine some people down voting because they don't understand that DI is a general concept and not a framework or class of frameworks (at least this confusion seems common).
I think many Go converts (myself included) came to the language because it's type system (composition, structural subtyping), syntax, standard library, and conventions all work together towards DI/SOLID.
I interpret these upvotes as more of a "Yes, we get this right" than a "Wow, what a great idea!"
In particular, Go programs are much more likely in my experience to be SOLID/DI than JS, Python, Java, C#, etc, mostly because the language was designed to support it.
Well, yeah! Those are great principles in any language - I find it concerning (and maybe indicative of something) that the Go community has voted this up. These are fundamental requirements to building testable, scalable systems in teams. Having global variables has been bad practice for what, 20 years? One of the first lines in Javascript, the Good Parts (closest book handy) is: