Swappable Dependencies #202
Replies: 1 comment 1 reply
-
Hello @rhysm94, Thanks for sharing :-) Below I'll just share some use cases I met that needed a throwing and varying database access. This is not a direct experience with pointfreeco/swift-dependencies, but it should apply just fine.
In those apps, I also tend to expose a dependency that is not a database connection, but an object that provides database access, just as in your sample application. |
Beta Was this translation helpful? Give feedback.
-
Hey, I’ve been thinking about “swappable” dependencies – ones that might change during the runtime of your application.
For example, creating the initial types for an application that uses GRDB is a failable operation. The initialisers for the
DatabaseWriter
types can fail, as can performing your initial migration(s).In the past, I’ve just force-tried or
fatalError
'd this when creating theliveValue
– but this means it’s out of our control, and isn’t at all safe. e.g. I’ve seen some crashes when the user’s device is out of space, or once where I mucked up a migration, the app crashed on launch without any meaningful error message for the user.I know I could handle this by including an
ActorIsolated
/LockIsolated
variable for anOptional
value ofany DatabaseWriter
, and wrapping every method withbut this approach feels particularly inelegant, having to repeat a lot of boilerplate across every function. To me, there should two entirely separate implementations for the different states – one that always throws, and one that can only be created when passed a non-optional
DatabaseWriter
. Kind of like classic subtype polymorphism.I’ve come up with an approach whereby I use an
actor
to swap between these two different versions of the dependency when themigrate
method is called. Thismigrate
method is throwing, so it can handle creating thoseDatabaseWriter
types, as well as performing the throwing migration work.A repo with sample code is here: https://github.com/rhysm94/SwappableDependencies/
and the
actor
that I'm talking about is here: https://github.com/rhysm94/SwappableDependencies/blob/main/Sources/SwappableDependencies/DatabaseActor.swiftUltimately, this gives me control over when the creation and migration happens, and letting me appropriately react to its failure wherever in my app. The downside to this approach is that everything now needs to become
async
, to interface with the actor, and there's a lot of duplication of the interfaces for my ownDatabase
andDatabaseInterface
types. There's some additional boilerplate to define a secondary type that can be switched between.Does anyone have any kind of feedback on this approach? I'd be interested to know how you're all handling dependencies which need to swap their underlying behaviour like this! I would quite like to simplify my approach if possible, and learn how everyone else is doing this.
Beta Was this translation helpful? Give feedback.
All reactions