Which one would you go for: 1. Implementing your ...
# announcements
a
Which one would you go for: 1. Implementing your repository/manager directly
Copy code
interface Manager { ... }

class ManagerImpl(...) : Manager {

    override fun functionality(): SomeShenanigans {
        return Shenanigans.create { ... }
    }

    ...
}
2. Dividing implementation into multiple small functions
Copy code
interface/typealias Functionality: () -> SomeShenanigans

fun functionalyImpl(): SomeShenanigans = Shenanigans.create { ... }

class ManagerImpl(f: Functionality, ...) : Manager {

    override fun functionality(): SomeShenanigans {
        return f.invoke()
    }

    ...
}
The former is much more compact but can cause circular dependencies and would require some weird shenanigans to solve, while the later solves the issues with circular dependencies but would require much more boilerplate.
t
Unless there are other overriding reasons not to, I would always go with the one that’s easiest to read and understand, so in this case 1. I would (and have) gone for 2) when I needed some kind of pluggable strategy for the actual functionality
👍 1
a
I’d go for case 1. If you start having circular dependencies with such approach, something is not right in the design imho
👍 1
a
@tddmonkey That makes sense.
@alexey_gusev In my case, I have an
AuthManager
which depends on a
RemoteRepository
to store the users' data an
Authenticator
to do the actual authentication. The problem is that the
RemoteRepository
requires the user to be signed in for all of its functionalities so it would need to depend on the
AuthManager
to check if the condition applies, which is bad design on its own but it would also introduce circular dependency between the
RemoteRepository
and the
AuthManager
. I could move the authentication check to the
AuthManager
but it feels like leaking implementation details to an outer layer. I would really appreciate any suggestions on how to solve this.
a
looks like you need some sort of state object oe broker perhaps?
👍 1
repo should not know about manager
👍 1
👌 1
a
@alexey_gusev Do you have any examples for that, maybe? I also need to be able to observe the state and not just check it, it would look something like this:
Copy code
override fun findSignedInUser(id: UserId): Flowable<Either<Throwable, SignedInUser?>> {
    return observeUserAuthState()
            .subscribeOn(<http://Schedulers.io|Schedulers.io>())
            .observeOn(<http://Schedulers.io|Schedulers.io>())
            .flatMap { isUserSignedIn ->
                if (isUserSignedIn) {
                    createFlowable(id)
                } else {
Flowable.just(NoUserException().left())
                }
            }.flatMap { ... }
a
I’d suggest to have a class/interface like AuthState and then update and observe it, a-la LiveData on Android
👍 1