$30 off During Our Annual Pro Sale. View Details »

Shipping Apps Confidently with Firebase

Shipping Apps Confidently with Firebase

Subhrajyoti Sen

November 06, 2021
Tweet

More Decks by Subhrajyoti Sen

Other Decks in Programming

Transcript

  1. Recording Non-fatal exceptions try { // some code can throw

    an exception } catch (e: Exception) { Log.d(TAG, e.localizedMessage) }
  2. Recording Non-fatal exceptions try { // some code can throw

    an exception } catch (e: Exception) { Log.d(TAG, e.localizedMessage) }
  3. Recording Non-fatal exceptions try { // some code can throw

    an exception } catch (e: Exception) { FirebaseCrashlytics.getInstance().recordException(e) }
  4. Recording Non-fatal exceptions private class CrashReportingTree : Timber.Tree() { override

    fun log(priority: Int, tag: String?, message: String, t: Throwable?) { } }
  5. Recording Non-fatal exceptions private class CrashReportingTree : Timber.Tree() { override

    fun log(priority: Int, tag: String?, message: String, t: Throwable?) { if (priority == Log.ERROR && t != null) { FirebaseCrashlytics.getInstance().recordException(t) } } }
  6. Recording Non-fatal exceptions class MainApplication : Application() { override fun

    onCreate() { super.onCreate() Timber.plant(CrashReportingTree()) } }
  7. Recording Non-fatal exceptions try { // some code can throw

    an exception } catch (e: Exception) { FirebaseCrashlytics.getInstance().recordException(e) }
  8. Recording Non-fatal exceptions try { // some code can throw

    an exception } catch (e: Exception) { Timber.e(e) }
  9. Analytics • • We normally use analytics in isolation from

    crash reporting Usually PMs check the analytics and Devs check the crashes
  10. Analytics • • • We normally use analytics in isolation

    from crash reporting Usually PMs check the analytics and Devs check the crashes What if you can combine them to get a full view?
  11. Analytics class FirebaseAnalyticsProvider( private val rebaseAnalytics: FirebaseAnalytics ): AnalyticsProvider {

    override fun track(analyticEvent: String, properties: Map<String, Any?>?) { rebaseAnalytics.logEvent(analyticEvent, properties) } }
  12. Analytics class FirebaseAnalyticsProvider( private val rebaseAnalytics: FirebaseAnalytics ): AnalyticsProvider {

    override fun track(analyticEvent: String, properties: Map<String, Any?>?) { rebaseAnalytics.logEvent(analyticEvent, properties) } }
  13. Analytics class AnalyticsManager { private val analyticsProviders = mutableListOf<AnalyticsProvider>() fun

    addProvider(provider: AnalyticsProvider) { analyticsProviders.add(provider) } }
  14. Analytics class AnalyticsManager { //... fun track(analyticEvent: String, properties: Map<String,

    Any?>?) { analyticsProviders.forEach { provider -> provider.track(analyticEvent, properties) } } }
  15. What's a feature ag? if (isNewFeatureEnabled) { // allow access

    to shiny new feature } else { // prevent access to shiny new feature }
  16. Use cases • • • A/B Testing Rolling out new

    features Rolling out rewrite of existing features
  17. Use cases • • • • A/B Testing Rolling out

    new features Rolling out rewrite of existing features Merge Work-in-progress features
  18. Types of Feature Flags? • • • Static Decided at

    build time Based on things like versionCode, buildVariant, etc
  19. Types of Feature Flags? • • • • Static Decided

    at build time Based on things like versionCode, buildVariant, etc Dynamic
  20. Types of Feature Flags? • • • • • Static

    Decided at build time Based on things like versionCode, buildVariant, etc Dynamic Can be controlled at runtime either locally using dev settings
  21. Types of Feature Flags? • • • • • •

    Static Decided at build time Based on things like versionCode, buildVariant, etc Dynamic Can be controlled at runtime either locally using dev settings Or remotely via services like Firebase Remote Con g
  22. enum class FeatureFlags( override val key: String, override val default:

    Boolean, override val description: String ): Con g
  23. enum class FeatureFlags( override val key: String, override val default:

    Boolean, override val description: String ): Con g { NEW_CHECKOUT_FLOW( "checkout_ ow_v2", true, "Enable checkout ow V2 for trending items" ) }
  24. class FirebaseFeatureFlagProvider: FeatureFlagProvider { private val remoteCon g = FirebaseRemoteCon

    g.getInstance() override fun getValue(featureFlag: FeatureFlag): Boolean { return remoteCon g.getBoolean(featureFlag.key) } }
  25. class RemoteCon gManager( private val featureFlagProvider: FeatureFlagProvider ) { fun

    isFeatureEnabled(featureFlag: FeatureFlag) = featureFlagProvider.getValue(featureFlag) }
  26. if (remoteCon gManager.isFeatureEnabled(NEW_CHECKOUT_FLOW)) { // allow access to shiny new

    feature } else { // prevent access to shiny new feature }
  27. Using Feature Flags effectively • • • De ne success

    metrics Less Crashes? Smoother experience?
  28. Using Feature Flags effectively • • • • De ne

    success metrics Less Crashes? Smoother experience? Implement using your Analytics library (like Mixpanel)
  29. Using Feature Flags effectively • • • • • De

    ne success metrics Less Crashes? Smoother experience? Implement using your Analytics library (like Mixpanel) Create dashboards to compare