(no title)
B-Con | 3 months ago
For example, if you only use S3, it is premature abstraction to accept an interface for something that may not be S3. Just accept the S3 client itself as input.
Then the S3 client can be designed to be testable by itself by having the lowest-level dependencies (ie, network calls) stubbed out. For example, it can take a fake implementation that has hard-coded S3 URLs mapped to blobs. Everything that tests code with S3 simply has to pre-populate a list of URLs and blobs they need for the test, which itself can be centralized or distributed as necessary depending on the way the code is organized.
Generally, I/O is great level to use an interface and to stub out. Network, disk, etc. Then if you have good dependency injection practicies, it becomes fairly easy to use real structs in testing and to avoid interfaces purely for testing.
Related reading from the Google style guide, but focused specifically on the transport layer: https://google.github.io/styleguide/go/best-practices.html#u...
imiric|3 months ago
So I don't see dependency injection with interfaces as being premature abstractions. You're simply explicitly specifying the API your code depends on, instead of depending on a concrete type of which you might only use one or two methods. I think this is a good pattern to follow in general, with no practical drawbacks.
B-Con|3 months ago
The reality of development is we have to merge different design philosophies into one code base. Things can get messy. 100% agreed.
The approach I advocate for is more for a) organizing the code you do own, and b) designing in a way that you play nice with others who may import your code.