Slide 1

Slide 1 text

Build.Better. Android.Libraries Nishant Srivastava @nisrulz

Slide 2

Slide 2 text

About me Nishant Srivastava Software Engineer/Founding Team Member (at) Omni Labs, Inc. Lead Organizer (at) GDG, New Delhi, India Open Source enthusiast @nisrulz

Slide 3

Slide 3 text

Before we begin... @nisrulz

Slide 4

Slide 4 text

What Is an Android Library? @nisrulz

Slide 5

Slide 5 text

Android Library is... ...simply put, pre-written reusable logic in code, for android apps... @nisrulz

Slide 6

Slide 6 text

Android Library is... ...simply put, pre-written reusable logic in code, for android apps... @nisrulz

Slide 7

Slide 7 text

Android Library is... Java code + + = @nisrulz

Slide 8

Slide 8 text

Android Library is... Java code + android resources + = @nisrulz

Slide 9

Slide 9 text

Android Library is... Java code + android resources + android manifest stub = @nisrulz

Slide 10

Slide 10 text

Android Library is... Java code + android resources + android manifest stub = Android ARchive (AAR) @nisrulz

Slide 11

Slide 11 text

Why create an Android Library? @nisrulz

Slide 12

Slide 12 text

Why create an Android Library? Short Answer @nisrulz

Slide 13

Slide 13 text

Why create an Android Library? Short Answer You don’t have to @nisrulz

Slide 14

Slide 14 text

Why create an Android Library? Short Answer You don’t have to @nisrulz If a solution already exists, use it

Slide 15

Slide 15 text

Best Practices for building android libraries... @nisrulz ...with that, let us move on to

Slide 16

Slide 16 text

Ease of use Intuitive @nisrulz

Slide 17

Slide 17 text

Ease of use Intuitive ○ It should do what the user of android library expects it to do without having to look up the documentation. @nisrulz

Slide 18

Slide 18 text

Ease of use Intuitive ○ It should do what the user of android library expects it to do without having to look up the documentation. Consistent @nisrulz

Slide 19

Slide 19 text

Ease of use Intuitive ○ It should do what the user of android library expects it to do without having to look up the documentation. Consistent ○ The code for the android library should be well thought and should not change drastically between versions @nisrulz

Slide 20

Slide 20 text

Ease of use Intuitive ○ It should do what the user of android library expects it to do without having to look up the documentation. Consistent ○ The code for the android library should be well thought and should not change drastically between versions Easy to use, hard to misuse @nisrulz

Slide 21

Slide 21 text

Ease of use Intuitive ○ It should do what the user of android library expects it to do without having to look up the documentation. Consistent ○ The code for the android library should be well thought and should not change drastically between versions Easy to use, hard to misuse ○ Validation checks, sane defaults, handle errors @nisrulz

Slide 22

Slide 22 text

Avoid multiple arguments @nisrulz

Slide 23

Slide 23 text

Avoid multiple arguments // Do not DO this void init(String apikey, int refresh, long interval, String type, String username, String email, String password); @nisrulz

Slide 24

Slide 24 text

Avoid multiple arguments // Do not DO this void init(String apikey, int refresh, long interval, String type, String username, String email, String password); @nisrulz // WHY?

Slide 25

Slide 25 text

Avoid multiple arguments // Do not DO this void init(String apikey, int refresh, long interval, String type, String username, String email, String password); @nisrulz // WHY? void init(“0123456789”, true, 1000, “prod”, “nishant”, ”1234”, “nisrulz@gmail.com”);

Slide 26

Slide 26 text

Avoid multiple arguments // Do not DO this void init(String apikey, int refresh, long interval, String type, String username, String email, String password); @nisrulz // WHY? void init(“0123456789”, true, 1000, “prod”, “nishant”, ”1234”, “nisrulz@gmail.com”); // Easy to mess up things here :(

Slide 27

Slide 27 text

Avoid multiple arguments // Do not DO this void init(String apikey, int refresh, long interval, String type, String username, String email, String password); @nisrulz // DO this void init(ApiSecret apisecret);

Slide 28

Slide 28 text

// where ApiSecret public class ApiSecret{ String apikey; int refresh; long interval; String type; String name; String email; String pass; // constructor /* you can define proper checks(such as type safety) and * conditions to validate data before it gets set */ // setter and getters } @nisrulz

Slide 29

Slide 29 text

Avoid multiple arguments // Do not DO this boolean init(String apikey, int refresh, long interval, String type, String username, String email, String password); @nisrulz // DO this boolean init(ApiSecret apisecret); // Or use a Builder Pattern

Slide 30

Slide 30 text

// Builder Pattern AwesomeLib awesomelib = new AwesomeLib.AwesomeLibBuilder() .apisecret(mApisecret) .refresh(mRefresh) .interval(mInterval) .type(mType) .username(mUsername) .email(mEmail) .password(mPassword) .build(); } @nisrulz

Slide 31

Slide 31 text

Minimize Permissions Use Intents @nisrulz

Slide 32

Slide 32 text

Minimize Permissions Use Intents ○ Let dedicated apps do the work for you. @nisrulz

Slide 33

Slide 33 text

Minimize Permissions Use Intents ○ Let dedicated apps do the work for you. Reduce the no. of permissions @nisrulz

Slide 34

Slide 34 text

Minimize Permissions Use Intents ○ Let dedicated apps do the work for you. Reduce the no. of permissions Check for permission, use fallbacks @nisrulz

Slide 35

Slide 35 text

Minimize Permissions Use Intents ○ Let dedicated apps do the work for you. Reduce the no. of permissions Check for permission, use fallbacks ○ public boolean hasPermission(Context context, String permission) { int result = context.checkCallingOrSelfPermission(permission); return result == PackageManager.PERMISSION_GRANTED; } @nisrulz

Slide 36

Slide 36 text

Minimize Requisites // Do not do this @nisrulz

Slide 37

Slide 37 text

Minimize Requisites // Do not do this // Use this String feature = PackageManager.FEATURE_BLUETOOTH; public boolean isFeatureAvailable(Context context, String feature) { return context.getPackageManager().hasSystemFeature(feature); } @nisrulz

Slide 38

Slide 38 text

Minimize Requisites // Do not do this // Use this String feature = PackageManager.FEATURE_BLUETOOTH; public boolean isFeatureAvailable(Context context, String feature) { return context.getPackageManager().hasSystemFeature(feature); } // Enable/Disable the functionality dependent on the // feature as per requirement @nisrulz

Slide 39

Slide 39 text

Support different versions /* RULE OF THUMB : Support the full spectrum of android * versions */ @nisrulz

Slide 40

Slide 40 text

Support different versions /* RULE OF THUMB : Support the full spectrum of android * versions */ android { ... defaultConfig { .. minSdkVersion 9 targetSdkVersion 25 .. } } @nisrulz

Slide 41

Slide 41 text

Support different versions /* RULE OF THUMB : Enable/Disable features or use a fallback * based on detected version */ @nisrulz

Slide 42

Slide 42 text

Support different versions /* RULE OF THUMB : Enable/Disable features or use a fallback * based on detected version */ // Method to check if the Android Version on the device is greater than or equal to Marshmallow. public boolean isMarshmallow(){ return Build.VERSION.SDK_INT>= Build.VERSION_CODES.M; } @nisrulz

Slide 43

Slide 43 text

Do not log in production @nisrulz

Slide 44

Slide 44 text

Do not log in production @nisrulz ...just Don’t. Seriously don’t.

Slide 45

Slide 45 text

Do not log in production Use Build Variants @nisrulz

Slide 46

Slide 46 text

Do not log in production Use Build Variants Flagged Logging @nisrulz

Slide 47

Slide 47 text

Do not log in production Use Build Variants Flagged Logging ○ MyAwesomeLibrary.init(apisecret,BuildConfig.DEBUG); @nisrulz

Slide 48

Slide 48 text

Do not log in production Use proguard // add to your proguard file -assumenosideeffects class android.util.Log { public static boolean isLoggable(java.lang.String, int); public static int v(...); public static int i(...); public static int w(...); public static int d(...); public static int e(...); } @nisrulz

Slide 49

Slide 49 text

Do not log in production Use proguard // enable proguard in build.gradle, switch to proguard-android-optimize .txt android { ... buildTypes { release { ... minifyEnabled false proguardFiles getDefaultProguardFile('proguard-android-optimize .txt'), 'proguard-rules.pro' } } } @nisrulz

Slide 50

Slide 50 text

… we do not want this to happen! @nisrulz

Slide 51

Slide 51 text

Do not crash silently and fail fast @nisrulz Log Errors and Exception

Slide 52

Slide 52 text

// Provide flexibility to log when debug flag is true void init(ApiSecret apisecret,boolean debuggable){ ... try{ ... } catch(Exception ex){ If (debuggable){ // This is printed only when debuggable is true ex.printStackTrace(); } } .... } @nisrulz

Slide 53

Slide 53 text

Degrade gracefully in an event of an error @nisrulz Don’t crash the app, Disable functionality

Slide 54

Slide 54 text

Catch specific exception @nisrulz // Do not do this try { // ... } catch(Exception e) { // ... }

Slide 55

Slide 55 text

Catch specific exception @nisrulz // Do this try { // ... } catch(NullpointerException e) { // ... }

Slide 56

Slide 56 text

@nisrulz

Slide 57

Slide 57 text

Handle poor network conditions @nisrulz

Slide 58

Slide 58 text

Handle poor network conditions 1. Prepare for unreliable/flaky network conditions @nisrulz

Slide 59

Slide 59 text

Handle poor network conditions 1. Prepare for unreliable/flaky network conditions 2. Batch your network calls @nisrulz

Slide 60

Slide 60 text

Handle poor network conditions 1. Prepare for unreliable/flaky network conditions 2. Batch your network calls 3. Prefetch data ahead of time @nisrulz

Slide 61

Slide 61 text

Handle poor network conditions 1. Prepare for unreliable/flaky network conditions 2. Batch your network calls 3. Prefetch data ahead of time 4. Replace JSON/XML with flatbuffers @nisrulz

Slide 62

Slide 62 text

Handle poor network conditions 1. Prepare for unreliable/flaky network conditions 2. Batch your network calls 3. Prefetch data ahead of time 4. Replace JSON/XML with flatbuffers @nisrulz

Slide 63

Slide 63 text

@nisrulz

Slide 64

Slide 64 text

@nisrulz

Slide 65

Slide 65 text

@nisrulz

Slide 66

Slide 66 text

Reluctance to include large libraries as dependencies @nisrulz

Slide 67

Slide 67 text

Reluctance to include large libraries as dependencies WHY ? @nisrulz

Slide 68

Slide 68 text

Reluctance to include large libraries as dependencies WHY ? Methods Counts! @nisrulz

Slide 69

Slide 69 text

Do not require dependencies unless you very much have to Avoid bloating the library with dependencies @nisrulz

Slide 70

Slide 70 text

Do not require dependencies unless you very much have to Get the developer to provide you those dependencies @nisrulz

Slide 71

Slide 71 text

Do not require dependencies unless you very much have to Get the developer to provide you those dependencies dependencies { // for gradle version 2.12 and below provided 'com.squareup.okhttp3:okhttp:3.7.0' // or for gradle version 2.12+ compileOnly 'com.squareup.okhttp3:okhttp:3.7.0' } @nisrulz

Slide 72

Slide 72 text

Do not require dependencies unless you very much have to Enable/disable features based on availability of dependency @nisrulz

Slide 73

Slide 73 text

Do not require dependencies unless you very much have to Enable/disable features based on availability of dependency private boolean hasOKHttpOnClasspath() { try { Class.forName("com.squareup.okhttp3.OkHttpClient"); return true; } catch (ClassNotFoundException ex) { ex.printStackTrace(); } return false; } @nisrulz

Slide 74

Slide 74 text

Try not to hog the startup @nisrulz

Slide 75

Slide 75 text

Try not to hog the startup @nisrulz

Slide 76

Slide 76 text

Remove features and functionalities gracefully @nisrulz

Slide 77

Slide 77 text

Remove features and functionalities gracefully Mark @Deprecated before removing a public API

Slide 78

Slide 78 text

Make your code testable @nisrulz

Slide 79

Slide 79 text

Document Everything! @nisrulz

Slide 80

Slide 80 text

Document Everything! 1. Create a Readme.md file @nisrulz

Slide 81

Slide 81 text

Document Everything! 1. Create a Readme.md file 2. Have Javadoc comments @nisrulz

Slide 82

Slide 82 text

Document Everything! 1. Create a Readme.md file 2. Have Javadoc comments 3. Bundle a sample app @nisrulz

Slide 83

Slide 83 text

Document Everything! 1. Create a Readme.md file 2. Have Javadoc comments 3. Bundle a sample app 4. Keep a detailed changelog of releases @nisrulz

Slide 84

Slide 84 text

Document Everything! @nisrulz

Slide 85

Slide 85 text

Provide a most minimalistic sample app @nisrulz

Slide 86

Slide 86 text

Consider putting up a license @nisrulz https://choosealicense.com/

Slide 87

Slide 87 text

Get feedback, lots of them @nisrulz

Slide 88

Slide 88 text

As a rule of thumb follow the rule of SPOIL-ing your Library Simple — Briefly and Clearly expressed Purposeful — Having or showing resolve Opensource — Universal Access, Free license Idiomatic — Natural to the native environment Logical — Clear, Sound Reasoning @nisrulz

Slide 89

Slide 89 text

References BlogPost: https://android.jlelse.eu/things-i-wish-i-knew-when-i-started-bu ilding-android-sdk-libraries-dba1a524d619 Open Source android libraries I have made: https://github.com/nisrulz/nisrulz.github.io#android-librariessdk @nisrulz

Slide 90

Slide 90 text

Thank You Questions? @nisrulz