-
Notifications
You must be signed in to change notification settings - Fork 731
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes room hierarchy endpoint to stable #5443
Conversation
override suspend fun execute(params: ResolveSpaceInfoTask.Params): SpacesResponse { | ||
return executeRequest(globalErrorReceiver) { | ||
|
||
private lateinit var params: ResolveSpaceInfoTask.Params |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
we can avoid the mutable state by chaining the params
into the getStableSpaceHierarchy/getUnstableSpaceHierarchy
there's also an argument for avoiding lateinit
in places that don't have a strictly documented lifecycle as it can cause unexpected side effects on order changes, eg if the this.params = params
was set after getSpaceHierarchy
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I considered chaining params as an argument into these private functions but deliberately chose to make params as a lateinit instance variable. My reasoning is as follows:
- The class is very cohesive (a.k.a its instance variables are used completely across the class), thus making its intended purpose clearer
- It reduces the cognitive effort of reading each function.
getSpaceHierarchy()
is much easier to read thangetSpaceHierarchy(params)
whereparams
is repeated across every function - I'm aware that a slight change in ordering would cause this to crash, but the contents and intent of the class is clear enough that a contributor shouldn't be led to making this mistake
It's a step I think is explained quite well in Uncle Bob's Clean Code, but if we still think it would be better to do otherwise then I'm happy to change it
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would lean towards the introduction of mutability and state to the class as cognitively heavier than adding function parameters. As soon as we introduce mutability, threading and ordering become sources of bugs, things that we can safely avoid by keeping our logic stateless (ignoring our potentially stateful class dependencies 😅)
override suspend fun execute(params: ResolveSpaceInfoTask.Params): SpacesResponse {
return executeRequest(globalErrorReceiver) {
try {
spaceApi.getSpaceHierarchy(params)
} catch (error: Throwable) {
spaceApi.getSpaceHierarchyUnstable(params)
}
}
}
private suspend fun SpaceApi.getSpaceHierarchy(params: ResolveSpaceInfoTask.Params) = this.getSpaceHierarchy(
spaceId = params.spaceId,
suggestedOnly = params.suggestedOnly,
limit = params.limit,
maxDepth = params.maxDepth,
from = params.from
)
private suspend fun SpaceApi.getSpaceHierarchyUnstable(params: ResolveSpaceInfoTask.Params) = this.getSpaceHierarchyUnstable(
spaceId = params.spaceId,
suggestedOnly = params.suggestedOnly,
limit = params.limit,
maxDepth = params.maxDepth,
from = params.from
)
with that said, for this class I don't have too strong of an opinion as the scope is restricted and it's just 1 property, I would personally avoid vars
and lateinits
unless they serve a functional purpose as kotlin has other ways to reduce boilerplate
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fair enough. I pushed the change!
import org.matrix.android.sdk.test.fakes.FakeSpaceApi | ||
|
||
@ExperimentalCoroutinesApi | ||
class DefaultResolveSpaceInfoTaskTest { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
thanks for adding these and all the setup 💯
|
||
@Test | ||
fun `given stable endpoint works, when execute, then return stable api data`() = runBlockingTest { | ||
spaceApi.givenStableEndpointWorks() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
not a strong opinion just a personal preference, it can be helpful from the test standpoint to be able to relate the inputs and results
// give stable endpoint returns a response, when execute,
spaceApi.givenStableEndpointReturns(A_RESPONSE)
val result = resolveSpaceInfoTask.execute(spaceApi.params)
result shouldBeEqualTo A_RESPONSE
I'm wondering there's a way to relate to get the best of both worlds (with the boilerplate reduction and tightening the relationship between the given and the expected result)
fakeSpaceApi.givenStableEndpointSuccess()
val result = resolveSpaceInfoTask.execute(spaceApi.params)
result shouldBeEqualTo fakeSpaceApi.successResponse
what do you think?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Tbh I like the first option as it gives the test class more flexibility about the types of responses it can test with but still maintains a very readable front. I'll go with that!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
My 2 cents about 404.
Thanks for adding the tests!
|
||
private suspend fun getSpaceHierarchy() = try { | ||
getStableSpaceHierarchy() | ||
} catch (e: Throwable) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would check only 404 here. Other error (such as no network etc.) could be propagated directly
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do we want to check only for 404 specifically? Personally I think it would also be good to fallback even in the case of 500 (internal server error) and such, thus catch a simple HttpException
Also have you checked:
|
I saw the second comment just now. I'm a bit confused with the wording, but I'm guessing this is saying we want to be using |
order = content.order, | ||
viaServers = content.via.orEmpty(), | ||
activeMemberCount = summary.numJoinedMembers, | ||
parentRoomId = spaceId, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@bmarty please pay more attention to this line. This is where {children_state event}.roomId
was being used. I can only assume its intended use was to point to the space id? Please correct me if I'm wrong. I don't have a great understanding of spaces
Edit: Spoke to @clokep to get more info on this. I believe this to be correct
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👍
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
FYI |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Some remark on the code style, else LGTM (I defer the logic about space to other people)
|
||
private suspend fun getSpaceHierarchy(params: ResolveSpaceInfoTask.Params) = try { | ||
getStableSpaceHierarchy(params) | ||
} catch (e: HttpException) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why not using HttpException
. I would have checked for a rather more expected 404, but OK
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think it would be good to protect ourselves from other server related errors (e.g. 500 - internal server error) and fallback to the unstable api in such cases. Anyway happy to discuss this before merging
getSpaceHierarchy(params) | ||
} | ||
|
||
private suspend fun getSpaceHierarchy(params: ResolveSpaceInfoTask.Params) = try { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I found using = try
and spilling into 2 methods less readable than a simple
override suspend fun execute(params: ResolveSpaceInfoTask.Params) {
executeRequest(globalErrorReceiver) {
try {
getUnstableSpaceHierarchy(params)
} catch (e: HttpException) {
getStableSpaceHierarchy(params)
}
}
}
Also I would rename getStableSpaceHierarchy
to getSpaceHierarchy
(rule: never use stable
, just use unstable
, intended to be removed after a while)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good shout!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for the update! I let you merge the PR?
Edit I do it
Type of change
Content
Adds stable room hierarchy endpoint with a fallback to the unstable one
Motivation and context
Closes #4462
Screenshots / GIFs
N/A
Tests
Testing Normal Functionality
Testing Fallback
Tested devices
Checklist