A little bit of a discussion based around method n...
# coroutines
c
A little bit of a discussion based around method naming. I essentially have an interface with methods like this. Not all methods have a "oneshot" and "flowable" version, but a lot of them. Some of them will be exclusively oneshot or flowable. But idk how I feel about the names. I could just have a suffix of
Flowable
but that smells like hungarian notiation... but I do remember a book/blog post (effective java?) that said it should be clear when a method is doing stuff with threads/async. Thoughts?
Copy code
interface MyRepository {
    suspend fun getLatestBooks(): List<Book>
    fun getLatestBooksWithLiveUpdates(): Flow<List<Book>>
    suspend fun getBookDetail(): BookDetail
    fun getBookDetailWithLivesUpdates(): Flow<BookDetail>
}
a
usually I treat flows as plurals of what they return, e.g.
val latestBookLists: Flow<List<Book>>
, generally as properties instead of methods unless the flow needs to be recreated+parameterized
1
c
I might go with something more like
getLatestBooksAsFlow()
, taking from the Compose convention of things like
StateFlow.collectAsState()
. Alternatively, you may consider only returning
Flows
, not having any dedicated one-shot methods, and doing
.first()
on those flows in place of the
one-shot
methods (if your data sources allow for that, that is)
a
yeah,
latestBookLists.first()
is generally enough to not require a one-shot get method alongside it, but sometimes situational subscription overhead makes it suitable. If something can change such that you want a flow in some cases, it's also worth asking if exposing one-shot getters encourages weird race conditions somewhere. Often the answer is yes.
c
So idk if this helps. but the additional context is that this is built firebase's firestore. So basically you can take any one-shot query you wrote and convert it into a flowable (i.e. providing real time updates) I do like the "can you just remove all one-shot requests and instead use .first()" idea
val latestBookLists: Flow<List<Book>>
somehow seems confusing to me. Maybe I gotta re-read it a bit more. Wouldn't
latestBooksLists
make more sense? Basically when you land on my app you see a list of the top 10 books, and if a title change or something on the BE, then you see the update live. Hence why I thought
WithLiveUpdates
was kinda nice because it explains the intent a bit?
a
Kinda redundant though, isn't it? What else would a flow be?
c
I suppose so. I guess not having type information baked into the name makes sense. but yeah. theres something about using these in practice where we've shot ourselves in the foot (having a flowable in a flowable) and so I'm trying to make the name more apparent.
e
val latestBookss: Flow<List<Book>>
android badvice
😂 1
a flow inside a flow sounds like a valid thing to use sometimes, though. what kind of foot-gun did you run into?
c
We weren't getting live updates after we did the flow in a flow.
The flow within a flow was accidental. Once we had them be two flows that just run on their own everything was updating just fine.
But anyway. appreciate the thoughts. Looks like generally my hunch of like "dont encode Types into the name" kinda still stands. But the idea of just not having one-shots was interesting. I will play around with it a bit more. thanks
m
I generally name it getX (suspend) vs observeX (flow)
c
oOoOO
m
?
c
I like it! Didn't think of that.
👍 1
u
I call it
loadFoo
for one time and
foo
for flow
k
I don't add suffixes in that case. If you're really interested in type, you can literally just check object type by inspecting the object.
z
get -> T
query -> Flow<T>
Been doing this forever ❤️ Does it seem clear to you? It does to me, but I might just be super-used to it! 🦜
👍 1
c
@Adam Powell re
yeah,
latestBookLists.first()
is generally enough to not require a one-shot get method alongside it, but sometimes situational subscription overhead makes it suitable. If something can change such that you want a flow in some cases, it's also worth asking if exposing one-shot getters encourages weird race conditions somewhere. Often the answer is yes.
Can you expand on "sometimes situational subscription overhead makes it suitable" The way I initially read this was "there is more overhead to calling .first() on a flowable vs just having a one shot method available"
a
yes, there's more overhead to calling
.first()
on a flow
it can range from, "a little bit more overhead from throwing a
CancellationException
to stop the upstream after the first" to, "implementation of the specific flow sets up a two-way subscription over a long-running connection with a server instead of a much simpler REST request/response"
c
Hm. Okay. In my case, I will just keep two separate methods for now. Thanks Adam!