Open utterances-bot opened 11 months ago
Thank you for this article. It's really interesting, but how we should make DI without interfaces?
@croked91 Great question. At its core dependency injection says nothing about mocking, or whether you should satisfy your dependencies via interfaces. DI is about how components obtain their dependencies not what those dependencies are. The simplest example I can present you with, is connecting to a database. By using the DI principle, we instantiate a DB connection and pass it to our other components, rather than making them implicitly create the connection themselves.
// Do this
func NewCustomerService(db *sql.DB) *CustomerService {
// attach the DB instance at construction
// ...
}
// Don't do this
func NewCustomerService() *CustomerService {
// attach the DB instance at construction
db, err := sql.Open(/*...*/)
// ...
}
Notice that I am passing a pure sql.DB
here, not an interface. However, even without an interface, I have the power to tell my components what other database to use when testing, for example. You’ll see lots of examples where people use PostgreSQL/MySQL in production, and an in-memory SQLite variant when testing. Those are extremely fast to set up and you can throw them away after each test, as they basically live in the RAM.
So, long story short, DI is about how you are passing your dependencies, not what you should be passing. It's all about being pragmatic and not over-complicating your code in the end.
Hope that makes sense.
Great. Thank you for the answer!
Hello. Thank you for the article. Interesting thoughts.
I'm a bit confused. Here you're talking about an idea but it's not transparent how you suggest to handle entity nesting. I understand it could sound a bit silly but could you please provide some valuable examples. I have database repos, a service that works with a few repos, and a controller handler that processes incoming request data and passes it into the service. It's really interesting how you manage this kind of dependency nesting.
This is great. Recently we did this. We had a large back-end system with lots of interface abstractions that really were there just to do unit-testing with mocks between the layers (http handlers, service and repository). Then we started just doing integration testing with https://github.com/ory/dockertest so we didn't have much more use for those interface and mocks. We removed all those big interfaces and used the actual implementations directly. The code is many times easier to follow now. And those unit tests with mocks were useless really since they didn't test the real thing, but just mocks.
I also agree so much with the RoundTripped example to just abstract the IO part of it. Its genius 👏👏👏
Great article.
Are you developing a library or an application? Interfaces are more likely to make use in library code than in applications.
I personally would disagree with this point(unless I misunderstood it). I would think that interfaces are best created/used by applications rather than libraries. That view also fits well with the view in; https://go.dev/wiki/CodeReviewComments#interfaces which I can summarise as; define interfaces in the consumer side not on the producer
I also agree with @komuw. I understand that defining interfaces might feel like boilerplate, but I feel that relying directly on the implementations goes against the dependency inversion principle and clean code architecture. Shouldn't we strive for our business logic to lead where our projects go and for our architecture to reflect that? What I mean by this is your services should be defining the interfaces you want to use and the repositories/http clients should implement them afterwards, being in a way "led" by the business requirements.
I understand that the same can be achieved by not defining interfaces for dependency injection in your services, but I feel like the other approach reflects better the way the code in the different layers emerges, rather than the opposite. This is by no means a critique on your post, I'm just interested on hearing your viewpoint on this.
Interfaces Are Not Meant for That · Preslav Rachev
I am a software engineer with a decade-long experience developing software in Python, Go, and Java.
https://preslav.me/2023/12/15/golang-interfaces-are-not-meant-for-that/