apex-enterprise-patterns/force-di

Multiple bindings for a developer name

osieckiAdam opened this issue ยท 5 comments

Hey, first of all, I would like to say thanks for this library, it really saved me a tons of time, great work!
I'm working on switching my org to unlocked packages, so I want to remove compile-time dependencies wherever possible and obviously dependency injection is a great technique to achieve that.
However I came across an issue, and I'm wondering now if my understanding of the problem is correct. I want to separate the implementation of some of my features (let's take a logger as an example) from the interface, as described here https://medium.com/salesforce-architects/5-anti-patterns-in-package-dependency-design-and-how-to-avoid-them-87bb50331cb8 (point 3). What is recommended there is to create package-a containing mock and interface to keep actual implementation separated from the interface.
image
Let's say that the logger feature (package-b) is depending on multiple different packages, and when a developer wants to use logger in his package, I don't want it to be necessary to install the package with the concrete implementation.
I would like also to be possible in the future to have multiple different orgs with different concrete implementations of the logger. This is why I came to a conclusion that I would like to have some basic implementation in 'package-a' which is mocking the logger both in tests and in normal code execution. Package-a contains a base, mock implementation and custom metadata record, but when the package with concrete implementation is installed on org (package-b), I would like force-di to use that one instead. This is the part where I would see multiple bindings for a single entity (let's say class) to be possible. Right now this is possible for SObject bindings (thanks to field Sequence we can order multiple bindings for some objects). I want to have this option for all bindings not only those related to SObjects.
I know that this could be easily achieved by implementing my own di_Module, but what do you think about making it more 'native'? I created this on my feature branch https://github.com/osieckiAdam/force-di/tree/feature/enable-multiple-bindings-for-developer-name but the reason why I'm not creating a pull request is that I'm not sure if this is a good idea in general to use this multi-binding approach

G'day @osieckiAdam, Thanks for raising this question.

A quick question. Is your intent to have multiple bindings to the same class, order them by sequence number, and then just utilize the "first instance on the stack" based on which combination of packages that you have installed at any given moment?

If that is your intention then would you not be concerned about non-deterministic behavior occurring in other packages that may also have a logger feature class that they would like to use?

Yes, exactly this is my point.
In general, I'm not concerned about that because I have common interface, so no matter what is the implementation I know what is the expected input and output. As a developer, I don't care what is under the hood.

I'm not sure what do you mean by non-deterministic, no matter what happens I know that there is some kind of contract that needs to be fulfilled. I want to manage the package combinations externally so that each org could have a different implementation if needed. In that case, I just need to change dependencies in sfdx-project file, and the dependency framework will do the job, I don't need to manage different sets of bindings for each org (which is also not that bad option) but the advantage of this approach is developer experience. I don't have to install heavy, dependent packages every time I need to change some small thing in the core package - my problem is that due to heavy and slow managed package which is tightly coupled with approx. 50% of metadata in my org I would need to dedicate more or less 1hr to create scratch org.

Having only apex stub in the 'package-a' will make unit tests possible, but I can't check the code 'in action', do some manual tests, etc. That's why I want to have a runtime dependency and mock implementation in package-a (with some low value of sequence so that will always be the 'last instance on the stack' )

However this is not something written in stone, I'm just looking for other people experience in that topic and wondering if adding 'multiple bindings to the same class' could be the right approach and if merging this feature into the framework makes sense

Ok. I believe that I see where you are going. I would suggest that the next step would be to open the PR so everyone can review the changes and we can discuss from there.

FYI: Pull request is opened here: #82

@osieckiAdam, thanks for opening the PR. At first glance, this is an interesting idea. If you don't mind, please give me and my colleagues some time to mull these changes over.