Best Practices for Factory Container Usage in Large-Scale Applications #262
Replies: 3 comments 3 replies
-
|
Same question here. I really like the idea of Factory, and in my opinion, it’s the cleanest DI library available. However, with Factory, it seems I would need to proxy or wrap a lot of functionality in the adapter, including the If I decide to replace Factory with another framework in four years, what are the chances that the new framework will have the exact same API? So I kinda stuck here because I have a huge app with 30+ modules in it :) |
Beta Was this translation helpful? Give feedback.
-
|
So... there are quite a few libraries out there that basically do Second, if you're doing func myService() -> MyServiceType {
resolve(MyServiceType.*)
}Which in turn means that, yes, you'd have to have to rewrite the factories. We did the same in an app the switched from Swinject and, while boring, got most of it done in a day. Third, it's possible to mask Factory's definitions by doing something similar like. func myService() -> MyServiceType {
self { MyService() }()
}Then again, you lose access to the ability to override the service type. Also seen: var myService: MyServiceType { _myService() }
var _myService: Factory<MyServiceType> { self { MyService() } }More boilerplate, but masks Factory to most call sites. I've also seen these little gems added to a Container. func resolve<T>(_ path: KeyPath<ResolvingContainer, Factory<T>>) -> T {
self[keyPath: path]()
}
func register<T>(_ path: KeyPath<ResolvingContainer, Factory<T>>, _ factory: @escaping @Sendable () -> T) {
self[keyPath: path].register(factory: factory)
}Allowing... Container.shared.register(\.service) { MockService() }
...
var service = Container.shared.resolve(\.service)These are starting to grow on me, actually. Might add them to the library. But yes, all of these are more complex than a simple register/resolve interface. That's kind of the price one pays for the compile-time safety aspects. |
Beta Was this translation helpful? Give feedback.
-
|
@psi-gh So what did you think of func resolve<T>(_ path: KeyPath<ResolvingContainer, Factory<T>>) -> T {
self[keyPath: path]()
}
func register<T>(_ path: KeyPath<ResolvingContainer, Factory<T>>, _ factory: @escaping @Sendable () -> T) {
self[keyPath: path].register(factory: factory)
}Allowing... Container.shared.register(\.service) { MockService() }
...
var service = Container.shared.resolve(\.service)Thinking of adding them... and they're definitely easier to stub. |
Beta Was this translation helpful? Give feedback.
Uh oh!
There was an error while loading. Please reload this page.
-
Hello,
I'm working on migrating a large-scale monolithic iOS application from Resolver to Factory for dependency injection. We want to implement service locator kind of functionality, so the general classes are agnostic to DI Library used.
I wanted to know what is the best practice then it comes to using custom containers in a large application.
Our current proposed approach is apart from shared container to have Flow-Level Containers: Each major flow (feature) has its own container. It contains low-specific repositories, controllers, coordinators etc. We are planning to have service locators for individual view models (where some objects are resolved either from flow or shared containers).
We were thinking if we should create even more granular containers at the scene level?
Open for all suggestions, If you need more information please let me know.
Beta Was this translation helpful? Give feedback.
All reactions