←back to thread

257 points pmig | 1 comments | | HN request time: 0.211s | source
Show context
epolanski ◴[] No.43096608[source]
Very ignorant about Go, is dependency injection not a thing there?

E.g. I like declaring interfaces in other languages that model some service (e.g. the database), focus on the API, and then be able to provide different implementations that may use completely different technologies behind them.

I know that some people don't see the point, but I'll make an example. At my primary client the database layer is abstracted and provided at runtime (or compile time, depends) with the repository pattern. How's that useful? Developers can use a filesystem-based database when working, and don't need to setup docker images that provide databases, anything they do is saved on their machine's filesystem. E2Es can run against an in-memory database, which makes it very simple to parallelise tons of different tests as there are no race conditions. And yes, the saved formats are the same and can be imported in the other databases, which is very useful for debugging (you can dump the prod database data you need and run it against your implementation).

There's many other situations where this is useful, one of the core products I work on interfaces with different printing systems. Developers don't have printers at home and my clients have different printing networks. Again, abstracting all of it through DI makes for a very sane and scalable experience.

I don't see how can this be achieved as easily without DI. It's a very nice tool for many use cases.

replies(6): >>43096619 #>>43096645 #>>43096738 #>>43096799 #>>43096998 #>>43097708 #
1. alexjplant ◴[] No.43097708[source]
> Very ignorant about Go, is dependency injection not a thing there?

It is but there isn't a heavy emphasis on a DI framework per se. At its core DI is "inversion of control" insofar as an object constructor receives what it needs to do its job as opposed to the constructor instantiating said requirements itself. In my experience Golang devs don't use of a bunch of meta-programming via tags/annotations/decorators to tell a third-party framework what reflect-y magic it has to do at runtime; they typically just abstract everything behind an interface and pass instances of what you need to a New function that instantiates the consumer object. I personally prefer this to Spring-type frameworks because it's more verbose and checked at compile time. This means one can easily follow what's going on instead of having to dig through a bunch of nested stack traces riddled with Aspect4J esoterica to find out why some magical Maven dependency suddenly broke your entire app for no reason at all.

Then again the last time I had to bootstrap a complex Spring project was in 2014. Since then I've used Spring Boot for simple 3-tier microservices and it worked fine... it's likely improved since then but I still wouldn't use it for anything greenfield after the loop it threw me for.