ProAndroidDev

The latest posts from Android Professionals and Google Developer Experts.

Follow publication

Tips for neater Android development

--

Capri — April 2018 ©

Hi, it’s 2018 and we, Android developers, have been through a lot for nearly 10 years. Here are some tips that could make an Android app development neater (and possibly less painful).

1. Deprecate. No regrets.

Chances are, you were following MVP or your own implementation of MVVM or another design pattern or architecture when Google dropped the Architecture Components bomb last summer. You’ve tried it out in some private projects but you haven’t in your day to day work because you’re worried about the impact on features being built currently. Well, it’s time to let go.

Versioning is key. Think of your base/core classes as APIs that are consumed by all the features your work on. If you have a current set of { BaseActivity, BaseFragment, BasePresenter…etc} consider it as v1.

  • Add a new directory called v1 and move your old common/base classes to it. Add @deprecated annotation to all of them.
  • Add a new directory called v2 and start adding a new set.
  • Start using v1 in new features and then refactor older ones when there’s time.
  • Do the same with v2 and v3 whenever you feel there’s a need for upgrading.

Deprecation and versioning are common practices in software development. You’ll notice a lot of deprecated classes in the Android SDK. Also the support library has different versions with same but updated set of classes.

Tip: Even if some classes are not going to change from v1 to v2, it’s better to keep (copy) the whole stack of classes unless the class is to be removed entirely.

Deprecated v1 and new v2

2. Keep view models thin

Problem: View models (or presenters) can grow incredibly large and the code becomes hard to maintain or update.

Solution: Think how can you delegate to another class, if it makes sense. The thinner the classes the better for our own sanity.

  • In your View Models, delegate functionalities to interactors or use cases. This can be a network call or a database query or an arithmetic or logical operation or any peice of business logic. This way, view models become smaller and hence more readable and testable.
  • The interactor will also be easy to understand and test as it has only a single responsibility.
  • If you’re converting an object to another, extract the conversion/mapping to a mapper class. Common cases for this when preparing a network call parameter or when mapping one object from a layer to another.

Here we’re mapping Recipe and DetailsInfo objects to DetailsViewEntity:

DetailsViewEntityMapper will handle the mapping separately
  • The functionality of DetailsViewEntityMapper will be tested separately
  • DetailsViewModel will just call its toDetailsViewEntity method instead of owning the mapping logic.
  • DetailsViewModel (or presenter) test just needs to verify that the mapper method has been code. It doesn’t care about the actual implementation.

3. Use feature flags

…and merge everything to your main branch (let’s call it develop). Instead of using feature branches and branching from them, why not have a switch that turns on or off the whole feature in develop?

There are two problems with feature branches:

1- You have to update them constantly from develop.

2- You won’t, because you’re too busy working on the branch that you branched from the feature branch and by the time you get back to it, synchronisation could be messy and costly.

Solution 1: Manual config

  • Add the flag to a constant file. It’s value is false in develop so the feature is not bothering anyone else.
  • Change the flag to true in your branch and when you release to QA.
  • Remove the flag or set it to true when feature is completely developed.
A feature flag

Solution 2: Gradle config

A better approach is to use Gradle to determine which build/flavor should has the feature enabled.

  • In your build.gradle file find buildTypes.
  • Assuming you have multiple build types, you can add buildConfigField with different values that enable/disable this feature.
Feature flag set to true in debug builds and false in release builds
  • Gradle will generate the new field IS_FEATURE_A_ENABLED and will add it to BuildConfig file.
  • You can then reference it this way:
  • The same could be done for productFlavors instead of buildTypes.

Note: This also works for refactoring old code. Keep the old code and let the flag decide which code should run, legacy or refactored. After refactoring, delete the flag and throw the legacy code in the bin.

Not a feature flag

4. Use ArrangeBuilder pattern for tests

Instead of this:

Use this:

  • Add an inner ArrangeBuilder class to each test file and move each whenever statement to a separate method.
  • The class might seem to make your test class longer but it will shorten your tests themselves and make them more descriptive.
  • Your test will feels like reading an English sentence and not code anymore.
  • Each whenever statement will be reusable and therefore less duplication all over tests.

5. Consider a new line \n

How agonising is this:

I know it’s Java and not Kotlin but I had to make sure it’s extra ugly

Probably some developer, in good faith, added this constructor with just two parameters not realising that it could grow to become this mess.

How about now?

Nice!

Way cleaner and readable, right?

Rx chains:

Nope:

Messy

Yep:

Pretty

Same goes for method parameters and builder patterns. Always consider if a new line would make the code look better.

To be continued…

Free

Distraction-free reading. No ads.

Organize your knowledge with lists and highlights.

Tell your story. Find your audience.

Membership

Read member-only stories

Support writers you read most

Earn money for your writing

Listen to audio narrations

Read offline with the Medium app

--

--

Published in ProAndroidDev

The latest posts from Android Professionals and Google Developer Experts.

Written by Mina Kamel

Android Developer — Ex-@n26, @hellofreshdev.

No responses yet

Write a response