-
Notifications
You must be signed in to change notification settings - Fork 3
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
Code Review Suggestions by Jose Chacon. #38
Conversation
private var selectedBuilding: Building? = null | ||
private val viewModel: MainViewModel by viewModel<MainViewModel>() | ||
private val viewModel: MainViewModel by viewModel() |
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.
You can omit the explicit declaration for MainViewModel (Cleaner code)
Source: Clean as you code. (n.d.). https://docs.sonarqube.org/latest/user-guide/clean-as-you-code/
@@ -42,13 +40,12 @@ class MainActivity : ComponentActivity() { | |||
modifier = Modifier.fillMaxSize(), | |||
color = MaterialTheme.colors.background | |||
) { | |||
BuildingName("Android", buildings) | |||
BuildingName(buildings) |
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.
The name variable was unnecessary, it was not being used in the BuildingName function. (Clean as you code - SonarQube)
Source: Clean as you code. (n.d.). https://docs.sonarqube.org/latest/user-guide/clean-as-you-code/
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.
@@ -129,7 +126,7 @@ class MainActivity : ComponentActivity() { | |||
} | |||
|
|||
@Composable | |||
fun BuildingName(name: String, buildings : List<Building> = ArrayList<Building>()) { | |||
fun BuildingName(buildings : List<Building> = ArrayList()) { |
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.
1- name variable was never used, I recommend removing it to avoid issues while reading the code. (Clean as you code - SonarQube)
2- You can omit the second explicit declaration of the ArrayList.
Sources:
- Basic syntax | Kotlin. (n.d.). Kotlin Help. https://kotlinlang.org/docs/basic-syntax.html
- Clean as you code. (n.d.). https://docs.sonarqube.org/latest/user-guide/clean-as-you-code/
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... though I'd keep the generic identifier on ArrayList... or at least the diamond (<>) operator.
@@ -157,7 +154,7 @@ class MainActivity : ComponentActivity() { | |||
Button( | |||
modifier = Modifier.fillMaxWidth(), | |||
onClick = { | |||
var studentComment = StudentComment().apply { | |||
val studentComment = StudentComment().apply { |
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.
The variable studentComment never changed so it can be a val instead.
Source:
- Basic syntax | Kotlin. (n.d.). Kotlin Help. https://kotlinlang.org/docs/basic-syntax.html
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.
@@ -10,13 +10,10 @@ import com.example.uptowncampus.service.BuildingService | |||
import com.example.uptowncampus.service.IBuildingService | |||
import com.google.firebase.firestore.FirebaseFirestore | |||
import com.google.firebase.firestore.FirebaseFirestoreSettings | |||
import com.google.firebase.ktx.Firebase |
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.
Unused import (Clean as you code - SonarQube)
Source:
- Clean as you code. (n.d.). https://docs.sonarqube.org/latest/user-guide/clean-as-you-code/
@@ -26,13 +23,13 @@ class MainViewModel(var buildingService : IBuildingService = BuildingService()) | |||
|
|||
fun fetchBuildings() { | |||
viewModelScope.launch { | |||
var innerBuildings = buildingService.fetchBuilding() | |||
val innerBuildings = buildingService.fetchBuilding() |
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.
innerBuildings variable never changed so it can be a val instead.
Source:
- Basic syntax | Kotlin. (n.d.). Kotlin Help. https://kotlinlang.org/docs/basic-syntax.html
buildings.postValue(innerBuildings) | ||
} | ||
} | ||
|
||
fun save(studentComment: StudentComment) { | ||
val document = if (studentComment.commentId == null || studentComment.commentId.isEmpty()) { | ||
val document = if (studentComment.commentId.isEmpty()) { |
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 some redundancy in the condition which made it a bit more difficult to read. (Avoid redundancy, Kotlin Docs)
Source:
- Coding conventions | Kotlin. (n.d.). Kotlin Help. https://kotlinlang.org/docs/coding-conventions.html
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.
Is commentId a non-nullable type? In other words, is it declared without a question mark? If so, then yes, I'd remove the null check.
|
||
val retrofitInstance : Retrofit? | ||
get() { | ||
// check if this object has been created | ||
if (retrofit == null) { | ||
// create it | ||
retrofit = retrofit2.Retrofit.Builder() | ||
retrofit = Retrofit.Builder() |
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.
You can omit the retrofit2 keyword and save some typing.
Source:
- Clean as you code. (n.d.). https://docs.sonarqube.org/latest/user-guide/clean-as-you-code/
@@ -1,7 +1,5 @@ | |||
package com.example.uptowncampus.dto | |||
|
|||
import com.google.gson.annotations.SerializedName |
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.
Unused import (Clean as you code - SonarQube).
Source:
- Clean as you code. (n.d.). https://docs.sonarqube.org/latest/user-guide/clean-as-you-code/
var results = buildings.await()?.awaitResponse()?.body() | ||
return@withContext results | ||
val buildings = async { service?.getAllBuildings() } | ||
return@withContext buildings.await()?.awaitResponse<ArrayList<Building>>()?.body() |
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.
You can save some typing here and just return what the results variable contained. ("Less code is easier to understand and maintain over time" - Embarcadero)
Source:
- A. (2022, June 19). The Truth About Software Development Is That Less Code Is Better. Embarcadero RAD Studio, Delphi, & C++Builder Blogs. https://blogs.embarcadero.com/the-truth-about-software-development-is-that-less-code-is-better/
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.
This is more typing and honestly more confusing..
@@ -75,7 +73,7 @@ class BuildingUnitTest { | |||
private fun thenResultsShouldContainTeacherDyer() { | |||
//capture results | |||
var allBuildings : List<Building>? = ArrayList<Building>() | |||
var latch = CountDownLatch(1) | |||
val latch = CountDownLatch(1) |
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.
Variable latch never changed so it can be a val instead.
Source:
- Basic syntax | Kotlin. (n.d.). Kotlin Help. https://kotlinlang.org/docs/basic-syntax.html
@@ -100,7 +98,7 @@ class MainActivity : ComponentActivity() { | |||
value = value, | |||
onValueChange = setValue, | |||
label = { Text(label) }, | |||
colors = TextFieldDefaults.outlinedTextFieldColors() | |||
colors = TextFieldDefaults.outlinedTextFieldColors(backgroundColor = Color.White) |
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.
To help with readability, it would be good to use a color that has better contrast. White is a good option. (webAim.org)
Source: WebAIM: Web Accessibility In Mind. (n.d.). https://webaim.org/
@@ -140,24 +138,27 @@ class MainActivity : ComponentActivity() { | |||
value = diningOptions, | |||
onValueChange = { diningOptions = it }, | |||
label = { Text(stringResource(R.string.diningOptions)) }, | |||
modifier = Modifier.fillMaxWidth() | |||
modifier = Modifier.fillMaxWidth(), | |||
colors = TextFieldDefaults.outlinedTextFieldColors(backgroundColor = Color.White) |
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.
To help with the readability of the TextFields, it would be good to use a color that has better contrast. White is a good option. (Minimum contrast of 4:5:1 - webAIM.org)
Source:
- WebAIM: Web Accessibility In Mind. (n.d.). https://webaim.org/
import com.google.gson.annotations.SerializedName | ||
|
||
data class Building(var id : Int = 0, var buildingName : String) { | ||
data class Building(var buildingId : Int = 0, var buildingName : String) { |
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.
Renamed id variable to be more specific ("Choose good names" - Kotlin Docs)
Source:
- Coding conventions | Kotlin. (n.d.). Kotlin Help. https://kotlinlang.org/docs/coding-conventions.html
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.
id was used to match the JSON since I built that too.. I agree with the suggestion, but now this should use SerializeName to work
Several great suggestions here, which reduce technical debt. I recommend the group review and consider merging. |
Very nice code review @ItzSebas10 . You did a great job looking into the details of the code and writing your pull request. Your review has been helpful and I am going to implement most changes. Thank you! |
Changes Made
MainActivity:
MainViewModel:
RetrofitClientInstance:
IBuildingDAO:
Building:
BuildingService:
BuildingUnitTests:
UI:
Analysis of the program
Uptown Campus is a really cool idea and has a lot of potential. While I was doing my code review, I found that the team did an excellent job so far, I had a bad time trying to find issues in their code. They did follow the coding conventions extremely well and I noticed few issues during my analysis. The team managed to build the UI, DTOs, DAOs, Retrofit, ViewModel, etc. All of these worked fine during my testing and followed good coding conventions. The team also built unit tests that worked fine, giving a green check for tests passing. At the same time, they made the tests specific so you know what they are actually doing. Organization-wise it was phenomenal, they followed the class layout coding convention and they also did an excellent job at naming each element of the project (variables, functions, etc). Additionally, they used the correct annotations depending on the situation. The team also included comments in their code to explain what certain elements do and furthermore, they did a good job with lambdas and calling functions. The only issues I found were that in some classes, there were unnecessary imports that were never used, variables that were using var instead of val, explicit declarations that could be skipped, some variables that were never used, and some extra spaces that were not needed. In general, I found that their code was excellent and had little to no issues. The team did an excellent job with their code and it also helped me to learn more about coding conventions and make code not only look great but work great as well.
Was the program available in UC Github on time?
Yes, it was. The last edit from the team was on February 23rd.
Is the program documented/commented well enough for you to understand?
Yes, it is. When I was looking at the code of the team, I was able to understand what each function was doing and why they designed certain things the way they did. The team did include comments in certain parts to explain what each thing was doing except for those functions or variables that were self-explanatory. At the same time, due to the organization of the code, it was really easy to locate each element and understand what it was doing. I didn't have any issues reading the code and I was able to understand it correctly.
Does the program compile?
Yes, it does.
The rationale behind your changes
Most of my changes are saving lines of code, removing unnecessary spaces, variables, or imports, and changing the variable types in case it was necessary (for example using val instead of var when possible). I followed different coding conventions such as Kotlin Docs or SonarQube to see what changes could be done. At the same time, used Adobe Color to see if the contrast was 4:5:1 or better.
My three commits on my group's GitHub:
The three technical concepts I learned from this code review, were:
Autocomplete TextField: I haven't seen this option before and till now I only knew about the conventional TextField but after looking at the code from the team, I noticed that they added an autocomplete function to the TextField.
Example:
@composable
fun TextFieldWithDropdownUsage(dataIn: List, label: String = "") {
val dropDownOptions = remember { mutableStateOf(listOf()) }
val textFieldValue = remember { mutableStateOf(TextFieldValue()) }
val dropDownExpanded = remember { mutableStateOf(false) }
Invoked:
Column {
TextFieldWithDropdownUsage(dataIn = buildings, stringResource(R.string.buildingName))
Firebase: After doing my code review, I managed to learn more about Firebase and how to implement it into an Android Studio project. The team did implement Firebase in their project and while I was looking at the code, I saw how it works.
Example:
private lateinit var firestore : FirebaseFirestore
init {
firestore = FirebaseFirestore.getInstance()
firestore.firestoreSettings = FirebaseFirestoreSettings.Builder().build()
}
Unit Test, ViewModel, and Observer: After looking at the team's project code, I saw how they built the unit test, ViewModel, and Observer and this was really helpful for me. To begin with the Unit Test, I saw how they were able to test the logic of their project and also how specific the unit test was so you can understand what it's doing and what it is about. At the same time, in that same Unit Test, they also used the ViewModel and Observer, and thanks to their code and excellent organization, I was able to understand how these two elements work and what they were doing in the test.
Examples:
UnitTest
@test
fun
given a view model with live data when populated with buildings then results show Teachers-Dyer
() {givenViewModelIsInitializedUsingMockData()
whenBuildingServiceFetchBuildingsInvoked()
thenResultsShouldContainTeacherDyer()
}
ViewModel
private fun givenViewModelIsInitializedUsingMockData() {
//Will contain the building objects
val buildings = ArrayList()
Observer
private fun thenResultsShouldContainTeacherDyer() {
//capture results
var allBuildings : List? = ArrayList()
val latch = CountDownLatch(1)
val observer = object : Observer<List> {
override fun onChanged(buildingsRecieved: List?) {
allBuildings = buildingsRecieved
latch.countDown()
mainViewModel.buildings.removeObserver(this)
}
}
mainViewModel.buildings.observeForever(observer)
//waits for latch countdown to hit 0
latch.await(10, TimeUnit.SECONDS)
References: