3 ms·
DI in its most fundamental form is common in Go via interfaces. People just declare that arguments to their functions must implement some interface, and the cal
by dgunay 2y ago
DI in its most fundamental form is common in Go via interfaces. People just declare that arguments to their functions must implement some interface, and the caller provides something that satisfies it.
"DI" in the sense of having a more complex purpose-built DI container is less common. They exist, but I don't see them used a lot.
If your application code has a ton of dependencies, the direct injection/low magic style favored by Go can get kind of boilerplate-y. I'm not going to comment on which style is better.
- CharlieDigital 2y ago.NET's DI has constructor injection so I suppose this is similar; you just write your constructor saying "I need an `IDataProvider`" and it can come from DI or direct. Question I have for Go though. Without DI, what is the idiomatic way of supplying one of n implementations? An if-else block? Like if I had 5 possible implementations (AzureBlobStore, AwsBlobStore, GcpBlobStore, CFBlobStore, FSBlobStore) and I need to supply 10 dependent services with access to `IBlobStore` what would that code look like? In .NET, it would look like: // Resolve the concreteImpl in DI IBlobStore concreteImpl = switch (config.BlobStoreType) { case "Azure": new AzureBlobStore(); case "Aws": new AwsBlobStore(); default: new FSBlobStore(); }; // Register services.AddSingleton<IBlobStore>(concreteImpl) services.AddScoped<Svc1>(); services.AddScoped<Svc2>(); // Services just use primary constructor and receive impl public class Svc1(IBlobStore store) { } public class Svc2(IBlobStore store) { } // But I can also manually supply (e.g. unit testing) var mockBlobStore = new MockBlobStore(); var svc2 = new Svc2(mockBlobStore);
- dgunay 2y agoYeah it basically is just an if-else or switch block. type BlobStore interface { /* methods */ } // later, when initializing stuff var foo BlobStore switch { case isAzure: foo = AzureBlobStore{} default: foo = FSBlobStore{} } svc1 := NewSvc1(foo) // Constructors are just functions and are totally // convention/arbitrary. If the fields are public you // can instantiate the struct directly. svc2 := Svc2{ BlobStore: foo }