Android Guidelines

Setting up a new project

Server Side

While following every step mentioned in git here, there is a small additional step you need to follow:

In bitbucket go to Settings->PULL REQUESTS->Default description and paste the following content:

    ## Description

    ### Why was this change necessary?

    [text here]

    ### How does it address the problem?

    [text here]

    ### Are there any side effects?

    [text here]

    ### Do you want any specific feedback?

    [text here]

    ### Do you have resources that will help the reviewer?

    [MP-](https://grappus.atlassian.net/browse/MP-)

    ### Zeplin screen design links?

    [link here]

    ### Did you run `./gradlew spotlessApply; ./gradlew testDebugUnitTestCoverage;` locally?

    [yes/no]

Client Side

Setting up a new project takes up a lot of effort and forgetting up some edge cases is pretty normal which may lead to some fatal errors which can lead to some serious issues to be handled later.

We have done this job for you. Follow along to see the process.

  1. Clone our base project from here.
  2. Change the required package name. While working with multiple modules few things to keep in mind with the modules package name. For example, take com.android as the base package name:

    (i) The package name of the app module should be com.android.

    (ii) Package name of api module should be com.android.api.

    (iii) Package name of core module should be com.android.core.

    (iv) Package name of logic module should be com.android.logic.

    (v) Ensure that application id in manifest.xml and build.gradle is the same.

    Naming the packages in this format helps in running test cases with Jacoco.

  3. Change the API response structure according to your needs in this file and amend it's test class accordingly in your local project.

  4. Format the code by running ./gradlew spotlessApply command and run tests by running ./gradlew testDebugUnitTestCoverage.
  5. If the above command fails, ensure that you are on java version 1.8 and if not please upgrade or degrade your java version. Degrading java version can be done by running export JAVA_HOME=$(/usr/libexec/java_home -v 1.8) in terminal. More details here.
  6. Delete the .git folder in your project's root directory.
  7. Rename your root project name.
  8. Connect your local repo to a remote source.

if all the above points run successfully and your build is successful then you are ready to roll.

Creating Git Aliases

Aliases are used to create shorter commands that map to longer commands. Here are a few handy git aliases you can make to avoid copy and pasting a command again and again.

  1. alias prcheck="./gradlew spotlessApply; ./gradlew spotlessCheck testDebugUnitTestCoverage;sapply": Add this to your bash profile and you can run prcheck in your directory to assert things are fine before submitting a PR.

Before you start developing

Set up File template in Intellij

We have made an Android studio template to create files required for a fragment and it's related files.

  1. Download the File template from here and follow the instructions written in Readme.txt inside the newly extracted folder.
  2. Navigate to Android Studio and go to File-> Import Settings... and select the settings.zip inside the newly-downloaded file template.
  3. After completing the above processes restart Androids studio and you should see file template as seen in the image in the above-downloaded folder.

While Developing

Few things to remember while developing so that we all can be on the same page.

Architecture:

We are following a mixture of MVI and MVVM architecture in this project with kotlin as the primary language for development. In this project, we heavily use RxJava, RxKotlin and Live Data for managing asynchronous call in API and database. We manage our dependencies using dagger, code test coverage is maintained using Jacoco and mocking of objects including API response is done using mockito.

We strictly follow the Single responsibility principle and therefore this project is divided into 6 modules.

Nomenclature :

Typacilly each fragment contains 5 Files.

    * Fragment: The part where UI events are handled.
    * FragmentBindingModel: The part where UI events processing is done and formatted details 
                               are sent to the fragment.
    * FragmentViewModel: Here the events are processed. It contains all the required data to
                               maintain the state of the fragment.
    * FragmentHandler: It is an interface where we declare the click listeners of UI events.
    * FragmentLayout: It contains the UI design code.

The naming convention of all files should be as described above just replace the above word Fragment with your desired name.

Testcases:

Write the test cases of logic module religiously by covering each ViewEvent including api and database calls by asserting their expected and actual view state update before and after the operation. We strictly maintain a minimum of 70% code coverage in our test cases which include branch testing (there should be an if for every else) and instructions testing.

Any PR which does not satisfy the minimum test coverage criteria shall not be merged. To see your current coverage:

  1. Run ./gradlew testDebugUnitTestCoverage in your terminal.
  2. Navigate to the logic module in the Project view in AS.
  3. Go to build->reports->jacaco->testDebugUnitTestCoverage->html and open index.html in your browser to see your test code coverage to every file in logic module.

Extension functions/properties

Kotlin provides the ability to extend a class with new functionality without having to inherit from the class, this is done via special declarations called extensions. We encourage you to write extension functions, primarily in the logic module and writing its test cases vigorously. Here is a small implementation of Datatype Extensions for your reference and it's test cases are written here.

Writing comments

No need to clutter your code by writing comments for every method but do not forget to write comments whenever you are performing some ad-hoc logic calculation. Do not use random numbers in that method, give them a proper variable name.

Use Vector Assets

Android Studio includes a tool called Vector Asset Studio that helps you add material icons and import Scalable Vector Graphic (SVG) and Adobe Photoshop Document (PSD) files into your project as vector drawable resources. Using vector drawables instead of bitmaps reduces the size of your APK because the same file can be resized for different screen densities without loss of image quality. For older versions of Android that don't support vector drawables, Vector Asset Studio can, at build time, turn your vector drawables into different bitmap sizes for each screen density. You can read more about it here.

Making reusable layouts:

Make the layout's reusable by using <include> tag in the layout and pass data to them using data binding.

Avoid hard coding:

Do not hard code strings in the project. Use them via strings.xml to ease the process of translation in different languages.

Using Kotlin only features:

We encourage you to use kotlin only features such as sealed classes, extension function, Objects, etc.

As said above we heavily use Scope Functions to write clutter-free code and avoid writing the same thing again and again. Please refer to the above link to read more about it.

Raising a PR

  1. Follow the steps as described in git section.
  2. Run prcheck alias in the terminal.
  3. If you have made changes only in a single module, squash all your commits into 1 commit.
  4. If you have made changes in more than 1 module, please divide your PR into 3 commits i.e data, logic and UI. Following is an example commit message where each commit contains its relevant files.
    feat(ALT-33): Adds sign in via OTP screen (data).
    feat(ALT-33): Adds sign in via OTP screen (logic).
    feat(ALT-33): Adds sign in via OTP screen (UI).
    

Responding to feedback on PR

The changes which you have done in your code as suggested in PR comments should be committed separately in a separate commit with the commit message as

fix(*): PR suggestions