Office Hours — Today, November 7

Tuesday, November 5

Mark M.
has entered the room
Mark M.
turned on guest access
Nov 7
8:30 AM
Urban
has entered the room
Mark M.
hello, Urban!
Urban
Hi Mark. Nice to see you again!
Mark M.
how can I help you today?
Urban
I have a few questions for you once again! Let's start!
First question is quite basic: use of setRetainInstance(true). I have recently seen some posts suggestings one should use sRI(t) only for Thread safety and where extensive data have been fatched beforehand. However, I have been using it sometimes only to deal with config changes. What's your oppinion on that one?
Mark M.
well, mostly, I have been using ViewModel recently, which under the covers uses retained fragments to retain the ViewModel instances across configuration changes
beyond that, there is no "bright line" dividing what you want ("sometimes only to deal with config changes") and the advice that you read
Urban
But is this generally a good measure to use to deal with config changes?
I thought so but then I read it's not reccomended
8:35 AM
Mark M.
well, if the fragment has no data, there is no need to retain the fragment
or, if the fragment gets its data from something else that is retained (such as a ViewModel), there is no need to retain the fragment
if the fragment has data, your choices are the saved instance state Bundle or retained fragments
Urban
SO, basically, you would encourage me to use it with extensive data but not when data is simple/not existant?
Mark M.
IMHO, there is no value in retaining the fragment if there is no data
Urban
I see. Thank you very much for answering that!
Mark M.
where the dividing line is between "simple" and "extensive" is unclear
Urban
Second question is also quite general: use of Activities (A) vs Fragments (F). In my projects, I have been extensively using A as building blocks but recently more and more focus is on using F as building blocks. That being said, would you suggest me to use them more in the future and, if so, to rewrite my projects to use Fragments instead?
Mark M.
Google is steering developers towards fewer activities and more fragments
where many simpler apps might be implemented as single-activity apps
so far, particularly when using the AndroidX fragments, I have not run into problems with Google's vision, and it simplifies some things
Urban
Simplifies what specifically? retaining data?
Mark M.
sharing data and events between screens, such as via shared ViewModels
Urban
You probably refer to using single VM for many Fragments, correct?
8:40 AM
Mark M.
I prefer "shared" to "single", but otherwise, yes
Urban
So in general, you would encourage me to use more Fragments in next projects?
Mark M.
unless you have some clear reason not to, going in Google's direction is usually easier than trying to "fight the current", as it were
Urban
That being said, should I also rewrite my current projects from A to F or would this be an overkill?
Mark M.
I cannot answer that. I would not change the implementation "just because", but if you need to change the architecture for other reasons, switching to fragments might be part of that change.
Urban
Thank you for your thoughts on this one!
Third question is abour Coroutines in Kotlin. More specifically, about "suspend" functions. In general, I do understand that this function enables concurrency. However, I have recently come accross that "suspend" is mandatory if you wish for a function to run on back T whereas I thought that this is solely influenced by use of appropriate Dispatchers on Coroutine. Therefore, should I just mark every function as "suspend" to be safe or is that claim not correct?
Mark M.
suspend has no direct impact on threads
suspend says "feel free to suspend execution of this code at this point and pick it up again later"
and, from a practical standpoint, you add suspend to a function when the compiler yells at you to add suspend to the function :-)
some libraries may use suspend as an indicator that a certain threading model should be used -- Room and Retrofit do this
8:45 AM
Urban
In my case, I was reffering to Retrofit return type yes
Mark M.
if you put suspend on a Retrofit API function or a Room DAO function, then the code generation will arrange to do the network or database I/O on background threads using coroutines
Urban
Ahhh I see. So basically "suspend" only gives a real threading impact for the models you mentioned but not in general
I was confused a little bit on that part as I thought I new suspend has no impact on threading
So, as you suggested, one should only use "suspend" where absoutely neccessarry, correct? Do you have any cases in mind?
Mark M.
well, for example, if you have a Retrofit API, and you are wrapping that in a repository, many of your repository functions will need the suspend keyword, because they are calling functions on the Retrofit API that you marked with suspend
any function that calls a suspend function needs to either be a suspend function itself or wrap the suspend function call in a coroutine builder (e.g., launch())
that's what I meant by the compiler yelling at you -- if you call a suspend function from a regular function, the compiler will complain
Urban
That being said, if you are not using Retrofit nor Room there is no real value adding "suspend" to functions called from coroutine correct?
Mark M.
AFAIK, that is correct
Urban
Thank you very much for answering this one!
8:50 AM
Urban
Next question is about testing in general. I have recently looked more deeply into testing and found out that this is a very broad area where many "basic" tests have to be performed for "banal" purposes (such as zero element check in a new listView,...). Therefore, I can imagine if one has to do all the unit tests for every scenario, a lot of time has to be dedicated for this. That being said, how would you reccomend someone to do the testing. Everything, some specifics or avoid it (as I ddid in the past)?
Mark M.
I definitely would not avoid it
I do tend to avoid Espresso tests, as I find them to be hopelessly flaky
so I focus testing on viewmodels and down (repositories, data sources, etc.)
and I try to push as much logic into those testable layers as possible
with a goal of having activities and fragments that are "as dumb as a box of rocks"
so there is very little that can go wrong directly in that mostly-untested bit of code
Urban
Do you there focus specifically on mocking responses which you can only get very rarely or you try to test all scenarios there?
Mark M.
that depends on how you define "all", I suppose
I try to test both positive and negative scenarios, such as the server returning the actual content with 200 OK and the server returning an error
I only try to test multiple error scenarios if the client-side code cares about those scenarios (e.g., does a login thing for a 401 Unauthorized response and does something else for other errors)
Urban
So you do not test the simple scenarios of every particular class but more on the interaction of components, correct?
Mark M.
I do not really think of it in those terms
8:55 AM
Mark M.
if I have code coverage tools working, I aim for strong coverage of the tested components, though perhaps not 100%
Urban
Aha okay, I must have missunderstood you at the beggingg
begining*
Which tools do you mostly use for this (apart from JUnit)? Mockito, Roboelectric or any else?
Mark M.
I'm a Mockito fan, particularly using the nhaarman mockito-kotlin library
Urban
You mentioned " so I focus testing on viewmodels and down (repositories, data sources, etc.)". You probably meant that you mock responses from repositories/data sources/... and then you see how are they used to populate your UI?
to populate your VM and from there specific component of UI*
Mark M.
for example, when I test a viewmodel, I confirm that all of the viewstates and events emitted by the viewmodel make sense, given the inputs that I have provided in the test
in production, the activity or fragment observe those viewstates and events and take actions -- I do not worry about testing that stuff, as the testing is very complicated for limited value IMHO
9:00 AM
Mark M.
to make that work, though, I try to keep the activities and fragments as lean as possible, so that there is very little real business logic in them
Urban
I see. So instead you focus mainly on testing state of your VM, which basically reflects state of UI (if done correctly).
Mark M.
yes!
Urban
thank you for these - I definetely need to look more in testing which should provide some benefits
We are slowly coming to the end of my questions
View paste
Next question is about immutability. When getting responses (such as from a server), I do see a value in having data classes which you transform to row holder objects as needed. However, I am more in favour of double-way binding non-data class objects when taking user input as introducing new variable/classes/methods to achieve the same with immutability seems overly-complicated. Is having non-data classes reasonable technique for user-input objects or should I always aim to have data classes for all such objects?
(Sorry for paste, dont know what I have done there)
Mark M.
yeah, this chat gets a bit strange with pasted information
personally, I am not a fan of two-way data binding; I prefer unidirectional data flows
and, in my defense, Google seems to be heading that way too with Jetpack Compose
that being said, what I like and what you like do not have to be the same :-)
and Google certainly supports the two-way concept, even baking it into their data binding framework
Urban
Are there any clear benefits having this complicated layer for the immutability?
One possible seems that if two things take one objects which, if immutable, will always be the same
Mark M.
I can't answer that, as I don't implement UI code that way
my general point is that if you are comfortable with your approach, feel free to use it
Urban
Okay, thank you for your answer
9:05 AM
Urban
But probably I need to be more careful when dealing with changed objects, correct?
Mark M.
um, probably, but it's a little difficult to say given just the descriptions here in the chat
Urban
I see. Thank you very much for your opinion on that one.
Now, my last question *hurray*
Last question is about Koin. More specifically, I am interested where should one use "factory" instead of "single" when creating a Koin module. I understant their destinction but cannot see where specifically should a new instance (factory) be genereated every single time (you used it for DataSource instance which fetched POJOs from the server side using Retrofit).
Mark M.
I have not had a need to use factory yet
Urban
I believe you used it in Kotlin Coroutines book
Page 120 of last version
Mark M.
hmmm... you're right
I forget off the top of my head why I chose factory there
Urban
No problem!
I was just interested why you used it (as you did not provide explantion for it)
Mark M.
in some cases, it may be due to changes in the environment
for example, there I use factory for ObservationRemoteDataSource
suppose that the Uri that we needed to use changed based on user input
so we hit different servers based on different user input
in that case, the remote data source might need a new instance each time, so the instance that we get from Koin is set up for the now-current base Uri
Urban
I see! So basically, when we have one non-changable class we use "single" whereas if that instance depends on some user input we use "factory". Am I correct on that one?
9:10 AM
Mark M.
I would phrase it more as "whereas if that instance depends on some external factors we might use "factory""
it would not necessarily need to be user input -- it might be based off of configuration data supplied by a server or something
to be honest, I really do not know why I used factory in this case, though
Urban
But probably where the instance is tightly connected by these factors, right?
I was not sure either
Mark M.
sorry, I did not follow your "tightly connected" comment
in terms of this sample app, the only real input into ObservationRemoteDataSource is the OkHttpClient, which is not changing during runtime, so single should work
Urban
Err ignore it, I understand whay you tried to say before
Mark M.
I have made a note to try to figure out why I used factory here and either replace it with single or explain it more in the book
Urban
Okay, amazing! Glad that I could be of help
that would be everything for now. Thank you again Mark for your help!
Mark M.
you are very welcome!
Urban
And I will see you again soon enough!
Have a nice day :-)
Mark M.
you too!
9:30 AM
Urban
has left the room
Mark M.
turned off guest access

Tuesday, November 5

 

Office Hours

People in this transcript

  • Mark Murphy
  • Urban