-
Notifications
You must be signed in to change notification settings - Fork 0
Description
This is a review of the entire codebase at commit cd8465c.
Of course, we don't expect you to change all of your code (some parts of the review can be subjective), what’s important is that you understand why better alternatives may exist.
Please ask us if you have any question about the code review, whether it is by writing a comment below or by sending us an email.
Important : if you try to fix these, don't break your app. We prefer that the app works even if you don't manage to fix anything. It may be too hard to rework some of the issues below.
General Remarks
Code Structure
- The package structure is relatively well organized
- You do not use an abstraction for login/logout/user management: Firebase is directly used in your views. You should really use an abstraction layer between Firebase and your views. You will find more details in the detailed code review below.
- Your abstraction for the Database seems hardly manageable in the long term because you only use one interface for all your database operations. You should split it and have one interface for each data type you are managing.
- We really think you should use Dependency Injection to make your life easier. See for example the Hilt framework.
Code Style
Globally, your code style is consistent. In some files however we saw some variations: single line comments had no space (i.e. you did //comment instead of // comment), no spaces around a ==... We suggest you use the automatic code reformatting from Android Studio before commiting code.
You should also have a look at the results of the linter, which can be found at Analyze > Inspect Code in Android Studio. In general, most warnings are relevant, but if you think they are not you can choose to ignore them using @SuppressWarning with a comment, or disable some of the checks entirely in your project settings.
Finally, you use Kotlin, which supports a nice syntax to access view elements from your code (instead of the good old but cumbersome findViewById). See a quick intro here: https://medium.com/androiddevelopers/use-view-binding-to-replace-findviewbyid-c83942471fc. You're free to not use this :P
By File
Only files for which we have a comment are referenced here.
Packageadapter
EventItemAdapter
- (Nit) Small issue at line 39: use a resource string with placeholder instead of a concatenation
ItemAdapter
- In general, please try to avoid pushing debug/incomplete code to
master - You're probably still working on this, but it is not a good practice to query the database directly from the adapter. Your adapter should only receive a List (or a MutableLiveData) and handle displaying it to respect separation of concerns (as you did in the two other adapters).
Package database
Database
- Line 9:
mutableCurrentDatabaseshould probably be private - In general: we tend to prefer Dependency Injection (DI) to a static singleton like yours, but it seems to work so you don't have to switch to DI if you don't like it.
DatabaseInterface
-
(Important) You should have one database interface for each data-type, instead of one huge database interface that handles all data
-
This will also be usefull later when you will implement local data caching, since this will use a local database such as Room instead of a remote one such as Firebase
-
You may realize that it's too cumbersome to use your
Databaseobject for all these new database instances. DI is nice for that, we recommend using Hilt.
-
-
It is better to separate your database from your view using the Repository pattern, see here: https://developer.android.com/codelabs/kotlin-android-training-repository?index=..%2F..android-kotlin-fundamentals#5
-
You should use asynchronous methods to query your database, the abstraction used for
getUserInformation(...)is nice (although the documentation for this method is incorrect)
FakeDatabase
- At the end of the semester, when you no longer need "fake data" to showcase your views, make sure that the FakeDatabase is moved to
androidTestsince it's not good to have test code mixed with the production code.
FirestoreDatabaseProvider
- Same remark as
DatabaseInterface: this is too long, you should definitely have one firebase provider for each collection of data (users, items, events, ...)
Package database.observe
Very nice and clean abstraction, we had some trouble understanding its purpose as it seems to be equivalent to the features offered by LiveData, but it's very cool!
Package exceptions
InsufficientAmountException
- You should add doc to describe when this exception is supposed to be thrown and how to handle it.
Package fragments
AdminHubFragment
- Doc: line 19, the method
newInstancedoesn't exist
HomeFragment
- Your usage of the
LinearLayoutseems very close to a RecyclerView. Why not use that instead? - (Nit) You have useless imports: before commiting, it's a good practice to reformat your code and optimize imports. It seems well respected in the project overall.
ListFragment
- You could use a repository between your view and database (see https://developer.android.com/codelabs/kotlin-android-training-repository?index=..%2F..android-kotlin-fundamentals#5).
LoginFragment
- Your fragment directly calls Firebase and Google Sign In. You should add an abstraction layer between your display and the backend. This abstraction layer should be generic enough to be replaced by a stub while testing, and maybe by other providers if you need that later.
- Some variable names are not very transparent. Example: line 117,
newValue2. - This class lacks documentation. Private methods are not obvious, a few lines of KDoc would help other developers from the team understand what your code does.
MapsFragment
PERMISSIONS_REQUEST_ACCESS_FINE_LOCATIONshould be declared as const
MoreFragment
- Doc: line 21, the method
newInstancedoesn't exist - Doc: it's unclear what this fragment does
- Naming: (you already have a todo on that)
ARG_PARAM{1,2}are unused and badly named
ProfileFragment
- L25-27: "User that we can set manually for testing": you should really use dependency injection for that. Have a
UserManagerorUserRepositorystore the current user. Make it use Firebase in prod, and have a test implementation that uses an arbitrary user that you can set manually. Have all classes use this manager/repository instead of this field. - L47: similar remark here (and similar to login fragment): you should not use firebase code directly in your activity, use an abstraction layer as described before.
Package helper
GoogleMapHelper
- Using a
Contextin an object is bad practice. Why use a singleton here? You should make it a class and simply store the instance in the fragment. You could also wrap theGoogleMapinstance (use it as a constructor parameter and make it immutable)
HelperFunctions
- (Nit)
DateToLocalTimeandLocalDateToTimeToDate: in Java/Kotlin, conventions require method names to start with a lowercase letter.
Package model
Your entities are well-thought and clean, good job!
Depot
- Not an entity, should be in the database package and rewritten+named accordingly (
InventoryRepositor?).
Package util
Converting database data from/to your own data format should be the role of the Database and/or Repository classes.
You could also create a new interface DocumentSerializable that would define a toDocument method to produce a hashmap. Reading from a map could be achieved with a similar fromDocument method (but your class would need an empty constructor and be mutable ; you can also use a static method in a companion object).
In our opinion, all the objects from this package contain features that should be implemented somewhere else. The implementation is however very clean.
FirebaseUserAdapter
- Converting to/from your internal user class could be a very nice job for the
UserManagerwe suggested before.
Tests
Your tests look very good, kudos for that
Conclusion
Your code is very good overall, you have nice abstractions and lots of efforts put in. The documentation and maning are mostly clear and understable, the codestyle is mostly consistent. The app design is very cool. Keep up the good work!