Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Analytics in an Aspect Oriented manner V2.0

Analytics in an Aspect Oriented manner V2.0

The presentation took place at GDG Android Athens meetup. https://www.meetup.com/GDG-Android-Athens/events/251174805/

Spiros Economakis

June 13, 2018
Tweet

More Decks by Spiros Economakis

Other Decks in Programming

Transcript

  1. Why analytics are important? • Help to build an efficient

    marketing strategy • Measure performance of the features
  2. Why analytics are important? • Help to build an efficient

    marketing strategy • Measure performance of the features • Measure retention of the users
  3. Why analytics are important? • Help to build an efficient

    marketing strategy • Measure performance of the features • Measure retention of the users • Optimise flow processes/funnels
  4. More tracking, more code @OnClick(R.id.signUpBtn) fun signUpClicked() { KISSmetricsAPI.sharedAPI().record("signupStartEvent") FirebaseAnalytics.getInstance(this).logEvent("signupStartEvent",

    null) Answers.getInstance().logCustom(CustomEvent("signupStartEvent")) AppEventsLogger.newLogger(this).logEvent("signupStartEvent") }
  5. More tracking, more code @OnClick(R.id.signUpBtn) fun signUpClicked() { KISSmetricsAPI.sharedAPI().record("signupStartEvent") FirebaseAnalytics.getInstance(this).logEvent("signupStartEvent",

    null) Answers.getInstance().logCustom(CustomEvent("signupStartEvent")) AppEventsLogger.newLogger(this).logEvent("signupStartEvent") }
  6. More tracking, more code @OnClick(R.id.signUpBtn) fun signUpClicked() { KISSmetricsAPI.sharedAPI().record("signupStartEvent") FirebaseAnalytics.getInstance(this).logEvent("signupStartEvent",

    null) Answers.getInstance().logCustom(CustomEvent("signupStartEvent")) AppEventsLogger.newLogger(this).logEvent("signupStartEvent") }
  7. Tracking with data private val stateObserver = Observer<SignUpViewState> { state

    -> state.let { when (state) { is SignUpSuccessViewState -> { this.renderSuccess(state.user) } } } }
  8. Tracking with data private fun renderSuccess(user: UserViewModel) { val trackingData

    = mapOf("id" to user.id, "name" to user.fulName) KISSmetricsAPI.sharedAPI().record("signupSuccess", trackingData) Answers.getInstance().logSignUp(SignUpEvent().putSuccess(true)) val trackingBundle = Bundle().apply { putString("id", user.id) putString("name", user.fulName) } FirebaseAnalytics.getInstance(this).logEvent("signupSuccess", trackingBundle) AppEventsLogger.newLogger(this).logEvent("signupSuccess", trackingBundle) }
  9. More tracking data, 
 more code private fun renderSuccess(user: UserViewModel)

    { val trackingData = mapOf("id" to user.id, "name" to user.fulName) KISSmetricsAPI.sharedAPI().record("signupSuccess", trackingData) Answers.getInstance().logSignUp(SignUpEvent().putSuccess(true)) val trackingBundle = Bundle().apply { putString("id", user.id) putString("name", user.fulName) } FirebaseAnalytics.getInstance(this).logEvent("signupSuccess", trackingBundle) AppEventsLogger.newLogger(this).logEvent("signupSuccess", trackingBundle) }
  10. More tracking data, 
 more code private fun renderSuccess(user: UserViewModel)

    { val trackingData = mapOf("id" to user.id, "name" to user.fulName) KISSmetricsAPI.sharedAPI().record("signupSuccess", trackingData) Answers.getInstance().logSignUp(SignUpEvent().putSuccess(true)) val trackingBundle = Bundle().apply { putString("id", user.id) putString("name", user.fulName) } FirebaseAnalytics.getInstance(this).logEvent("signupSuccess", trackingBundle) AppEventsLogger.newLogger(this).logEvent("signupSuccess", trackingBundle) }
  11. Hide - Singleton object AnalyticsTracker { fun initialise(ctx: Context) {

    //initialise tools } fun log(event: String) { //all tools to track } fun log(event: String, data: Map<String, Any>) { //all tools to track } }
  12. Hide - Singleton private fun renderSuccess(user: UserViewModel) { val trackingData

    = mapOf("id" to user.id, "name" to user.fulName) AnalyticsTracker.log("signupSuccess", trackingData) }
  13. Composition class TrackingDelegator constructor(ctx: Context) { fun onSignUpClicked() { //all

    tools to track } fun onSignUpSuccess(user: UserViewModel) { //all tools to track } }
  14. Tracking is a Cross-Cutting Concern The concerns representing functionalities for

    secondary requirements are referred to as crosscutting concerns or system-wide concerns.
  15. Definition Aspect-oriented programming entails breaking down program logic into "concerns".

    This means, that with AOP, we can add executable blocks to some source code without explicitly changing it. This programming paradigm pretends that “cross-cutting concerns” should be implemented once and injected it many times into those places.
  16. Terminology Join point: Join points are points in the execution

    of the system, such as method calls or method entry Pointcut: An expression which tells a code injection tool where to inject a particular piece of code eg. to which join points to apply a particular advice. Advice: The code that is injected to a class file. Typically we talk about before, after, and around advices, which are executed before, after, or instead of a target method.
  17. Terminology Join point: Join points are points in the execution

    of the system, such as method calls or method entry Pointcut: An expression which tells a code injection tool where to inject a particular piece of code eg. to which join points to apply a particular advice. Advice: The code that is injected to a class file. Typically we talk about before, after, and around advices, which are executed before, after, or instead of a target method.
  18. Terminology Join point: Join points are points in the execution

    of the system, such as method calls or method entry Pointcut: An expression which tells a code injection tool where to inject a particular piece of code eg. to which join points to apply a particular advice. Advice: The code that is injected to a class file. Typically we talk about before, after, and around advices, which are executed before, after, or instead of a target method.
  19. Terminology Aspect: The combination of the pointcut and the advice

    is termed an aspect. For instance, we add a tracking aspect to our application by defining a pointcut and giving the correct advice. Weaving: The process of injecting code – advices – into the target places – join points.
  20. Terminology Aspect: The combination of the pointcut and the advice

    is termed an aspect. For instance, we add a tracking aspect to our application by defining a pointcut and giving the correct advice. Weaving: The process of injecting code – advices – into the target places – join points.
  21. Pointcuts with Annotations @TrackEvent - constructor & method @TrackEventAttribute -

    method params only @TrackStaticAttribute - method params only
  22. Pointcuts with Annotations @TrackEvent - constructor & method
 @TrackEventAttribute -

    method params only @TrackStaticAttribute - method params only
  23. Pointcuts with Annotations @TrackEvent - constructor & method @TrackEventAttribute -

    method params only
 @TrackStaticAttribute - method params only
  24. Aspect @Aspect class TrackEventAspect { @Pointcut("execution(@com.clueso.tracking.annotation.TrackEvent * *(..))") fun methodAnnotatedWithTrackEvent()

    { } @Pointcut("execution(@com.clueso.tracking.annotation.TrackEvent *.new(..))") fun constructorAnnotatedTrackEvent() { } @Around("methodAnnotatedWithTrackEvent() || constructorAnnotatedTrackEvent()") @Throws(Throwable::class) fun weaveJoinPointTrackEvent(joinPoint: ProceedingJoinPoint): Any { } }
  25. Aspect @Aspect class TrackEventAspect { @Pointcut("execution(@com.clueso.tracking.annotation.TrackEvent * *(..))") fun methodAnnotatedWithTrackEvent()

    { } @Pointcut("execution(@com.clueso.tracking.annotation.TrackEvent *.new(..))") fun constructorAnnotatedTrackEvent() { } @Around("methodAnnotatedWithTrackEvent() || constructorAnnotatedTrackEvent()") @Throws(Throwable::class) fun weaveJoinPointTrackEvent(joinPoint: ProceedingJoinPoint): Any { } }
  26. Aspect @Aspect class TrackEventAspect { @Pointcut("execution(@com.clueso.tracking.annotation.TrackEvent * *(..))") fun methodAnnotatedWithTrackEvent()

    { } @Pointcut("execution(@com.clueso.tracking.annotation.TrackEvent *.new(..))") fun constructorAnnotatedTrackEvent() { } @Around("methodAnnotatedWithTrackEvent() || constructorAnnotatedTrackEvent()") @Throws(Throwable::class) fun weaveJoinPointTrackEvent(joinPoint: ProceedingJoinPoint): Any { } }
  27. Aspect @Aspect class TrackEventAspect { @Pointcut("execution(@com.clueso.tracking.annotation.TrackEvent * *(..))") fun methodAnnotatedWithTrackEvent()

    { } @Pointcut("execution(@com.clueso.tracking.annotation.TrackEvent *.new(..))") fun constructorAnnotatedTrackEvent() { } @Around("methodAnnotatedWithTrackEvent() || constructorAnnotatedTrackEvent()") @Throws(Throwable::class) fun weaveJoinPointTrackEvent(joinPoint: ProceedingJoinPoint): Any { } }
  28. Tracking Adapters class AnswersTrackingAdapter : TrackAdapter { override fun track(event:

    TrackEvent, attributes: Map<String, Any>) { //tracking } }
  29. Tracking Adapters class AnswersTrackingAdapter : TrackAdapter { override fun track(event:

    TrackEvent, attributes: Map<String, Any>) { //tracking } }
  30. Create Clueso val answersAdapter = AnswersTrackingAdapter() val firebaseAdapter = FirebaseTrackingAdapter()

    Clueso.create { isDebuggable = true adapters = listOf(answersAdapter, firebaseAdapter) }
  31. Create Clueso val answersAdapter = AnswersTrackingAdapter() val firebaseAdapter = FirebaseTrackingAdapter()

    Clueso.create { isDebuggable = true adapters = listOf(answersAdapter, firebaseAdapter) }
  32. Polyglot AOP AOP within the language, or as an external

    library: • Python • Haskell • Ruby • Swift • Lua • Delphi
  33. Conclusion • Enhance SRP of the SOLID principles • Clean,

    readable and reusable code • Increases modularity
  34. Conclusion • Enhance SRP of the SOLID principles • Clean,

    readable and reusable code • Increases modularity • Testable code
  35. Conclusion • Enhance SRP of the SOLID principles • Clean,

    readable and reusable code • Increases modularity • Testable code • Build or load time code injection. Source-code weaving