Upgrade to PRO for Only $50/Year—Limited-Time Offer! 🔥

Boost the Quality of Your App with Firebase (Ma...

Boost the Quality of Your App with Firebase (May 22, 2018 Londroid)

Doug Stevenson

May 24, 2018
Tweet

More Decks by Doug Stevenson

Other Decks in Technology

Transcript

  1. 50% Stability & bugs When leaving a 1 star review,

    50% of the time the user mentions the app stability and bugs Google analysis on Play reviews, top 10 English speaking countries, last 365 days of reviews @CodingDoug
  2. Firebase Test Lab Test Artifacts • Logcat (crashes) • Videos

    • Screenshots • Performance
 CPU
 memory
 network ingress/egress @CodingDoug
  3. Instrumented Tests • Specific to Android • Focus on the

    user story / use case • Espresso / UI Automator • Adds extensions to JUnit • Android Testing Support Library: goo.gl/xSxzoj • Testing Codelab: goo.gl/RHdFBY @CodingDoug
  4. @RunWith(AndroidJUnit4.class) public class NotesScreenTest { @Rule public ActivityTestRule<NotesActivity> mNotesActivityTestRule =

    new ActivityTestRule<>(NotesActivity.class); @Test public void clickAddNoteButton_opensAddNoteUi() throws Exception { // Click on the add note button onView(withId(R.id.fab_add_notes)).perform(click()); // Check if the add note screen is displayed onView(withId(R.id.add_note_title)).check(matches(isDisplayed())); } } @CodingDoug
  5. (Local) Unit Tests • Runs fast on your computer •

    Focus on testing individual classes and methods • Dependency injection / object mocking @CodingDoug
  6. Protip: Run your unit tests along with instrumented tests android

    {
 sourceSets {
 androidTest {
 java.srcDirs += "src/test/java"
 }
 }
 } testImplementation 'org.mockito:mockito-core:2.17.0'
 androidTestImplememntation 'org.mockito:mockito-android:2.17.0' @CodingDoug
  7. Protip: Enable StrictMode when running in Test Lab Turn StrictMode

    violations into actionable crash reports in Test Lab. @CodingDoug
  8. // During Application.onCreate() or ContentProvider.onCreate() private void enableStrictMode() { if

    (shouldEnableStrictMode()) { StrictMode.setThreadPolicy(new StrictMode.ThreadPolicy.Builder() .detectAll() .penaltyLog() .penaltyDeath() .build()); StrictMode.setVmPolicy(new StrictMode.VmPolicy.Builder() .detectAll() .penaltyLog() .penaltyDeath() .build()); } } @CodingDoug
  9. private boolean shouldEnableStrictMode() { ContentResolver resolver = context.getContentResolver(); String isRunningInTestLab

    = Settings.System.getString(resolver, "firebase.test.lab"); return BuildConfig.DEBUG || "true".equals(isRunningInTestLab); } @CodingDoug
  10. // https://issuetracker.google.com/issues/36951662 private void workaroundEnableStrictMode() { enableStrictMode(); if (Build.VERSION.SDK_INT >=

    16) { // restore strict mode after onCreate() returns. new Handler().postAtFrontOfQueue(new Runnable() { @Override public void run() { enableStrictMode(); } }); } } @CodingDoug
  11. Espresso Test Recorder • Android Studio
 Menu → Run →

    ⚫︎Record Espresso Test • Interact with your app • Generates Espresso code to match your actions @CodingDoug
  12. Robo Test • Only an APK with is required •

    Automatically logs in with Google Auth • Can pre-fill form fields (e.g. user/pass login, search) • Configure maximum crawl depth and timeout • Algorithm improves over time • Additional test artifact: Activity map • Roboscript @CodingDoug
  13. Game Loop Test (beta) • Sequence of scenarios driven by

    Android Intents • Performance += FPS • Game Loop Codelab: goo.gl/sn4RNp • “Mechahamster” sample game • Project home: goo.gl/8chQ8p • Test Lab Guide: goo.gl/16xSPn @CodingDoug
  14. gcloud firebase test android run \ --type instrumentation \ --app

    app-debug-unaligned.apk \ --test app-debug-test-unaligned.apk \ --device model=Nexus6,version=21,orientation=portrait \ --device model=Nexus7,version=19,orientation=landscape @CodingDoug
  15. Community Support for testing with CI • Walmart’s “Flank” for

    sharding tests
 goo.gl/5ApxVU • Circle CI integration
 goo.gl/xoPFqY @CodingDoug
  16. Billing for Firebase Test Lab • Spark and Flame payment

    plans: daily limits • Virtual devices: 10 tests/day • Physical devices: 5 tests/day • Blaze payment plan: per-minute billing • Virtual devices: $1/device/hour • Physical devices: $5/device/hour @CodingDoug
  17. Crashlytics features • Unity support • NDK support • Search

    • Webhooks • Cloud Functions trigger • Integration with Google Analytics for Firebase • Integration with Slack (new!) @CodingDoug
  18. public interface UncaughtExceptionHandler { /** * Method invoked when the

    given thread terminates due to the * given uncaught exception. * <p>Any exception thrown by this method will be ignored by the * Java Virtual Machine. * @param t the thread * @param e the exception */ void uncaughtException(Thread t, Throwable e); } @CodingDoug
  19. public class MyHandler implements Thread.UncaughtExceptionHandler { private final Thread.UncaughtExceptionHandler mPriorExceptionHandler;

    public MyHandler(Thread.UncaughtExceptionHandler prior) { mPriorExceptionHandler = prior; } @Override public void uncaughtException(Thread thread, Throwable throwable) { // Deal with throwable here if (mPriorExceptionHandler != null) { mPriorExceptionHandler.uncaughtException(thread, throwable); } } } @CodingDoug
  20. 60% Speed, design & usability When leaving a 5 star

    review, 60% of the time the user mentions the speed, design or usability Google analysis on Play reviews, top 10 English speaking countries, last 365 days of reviews @CodingDoug
  21. Systrace Advantages • Lots of detail • Custom traces Disadvantages

    • App runs slow • You typically have to know what you're looking for • Can't collect data from the wild, only connected devices @CodingDoug
  22. Firebase Performance Monitoring • Runs in production • Negligible overhead

    • Automatic and Custom traces • Automatic HTTP/S traffic metrics @CodingDoug
  23. Trace • A report for a period of time with

    a well-defined beginning and end • Nominally has a duration • Also may contain “metrics" for performance-related events during the trace @CodingDoug
  24. Automatic Traces - no coding necessary! • App Start (cold)

    • Screen (each Activity start / stop) • App in foreground • App in background @CodingDoug
  25. Metrics • Associate a string/int pair to a Trace •

    Typically better to measure ratios than absolute values • Abs value if you want to compare similar metrics between traces cache_hit++ cache_miss++ dropped_frames += 10 @CodingDoug
  26. Android Vitals - get clues for what to measure •

    In the Google Play Console: goo.gl/rkztG1 • Performance-related stats • Slow rendering (jank) • Frozen frames • Stuck WakeLocks @CodingDoug
  27. Automatic HTTP/S transaction metrics • Response time • Payload size

    • Success rate • URL pattern globbing
 
 yourcdn.com/*.jpg
 api.yourdomain.com/v1/users/*
 api.yourdomain.com/v1/users/*/history/* @CodingDoug
  28. HTTP/S transaction metrics breakdown • App version • Device •

    Country • OS level • Carrier • Radio @CodingDoug
  29. How HTTP/S monitoring works Build time bytecode manipulation (with ASM)

    URL url = new URL("https://firebase.google.com");
 HttpsURLConnection conn = (HttpsURLConnection)
 url.openConnection(); URL url = new URL(“https://firebase.google.com”);
 HttpsURLConnection conn = (HttpsURLConnection)
 FirebasePerfUrlConnection.instrument(url.openConnection()); Decorator inside! @CodingDoug
  30. How HTTP/S monitoring works buildscript {
 dependencies { classpath ‘com.google.firebase:firebase-plugins:1.1.5'

    }
 } apply plugin: 'com.google.firebase.firebase-perf' dependencies {
 compile ‘com.google.firebase:firebase-perf:15.2.0'
 } Uses the Transform API: goo.gl/PwBcLE @CodingDoug
  31. Firebase Remote Config • Use it to plan and stage

    rollouts of new features • Quickly back off the new feature if it has problems @CodingDoug
  32. Firebase Remote Config • Find out what your users prefer

    by experimentation • Study the results in Google Analytics for Firebase @CodingDoug
  33. Firebase Remote Config (for perf) • Compare CDN/server performance •

    Compare cache configuration strategies @CodingDoug
  34. final FirebaseRemoteConfig rc = FirebaseRemoteConfig.getInstance(); int cache_size = (int) rc.getLong("cache_size");

    // init cache with cache_size // later... Trace trace = FirebasePerformance.startTrace("my_trace"); Item item = cache.get("some_resource"); if (item != null) { trace.incrementMetric("cache_hit_size_" + cache_size); } else { trace.incrementMetric(“cache_miss_size_" + cache_size); } trace.stop(); @CodingDoug
  35. Resources • Firebase home
 https://firebase.google.com/ • Slack
 https://firebase.community/ • YouTube


    http://youtube.com/firebase • Blog
 http://firebase.googleblog.com/ • Twitter
 https://twitter.com/Firebase