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

Android: Code Generation Beyond APT

Android: Code Generation Beyond APT

Presented in May '17 Blrdroid meetup.
https://www.meetup.com/blrdroid/events/239270928

Ragunath Jawahar

May 06, 2017
Tweet

More Decks by Ragunath Jawahar

Other Decks in Programming

Transcript

  1. Analytics Code MixpanelAPI mixpanel = MixpanelAPI.getInstance(this, token); try { JSONObject

    payload  = new JSONObject(); payload.put("Gender", "Female"); payload.put("Logged  in", false); payload.put("Source", "Twitter"); mixpanel.track("Signup", payload); } catch (JSONException exception) { Log.e("Frodo", "JsonException", exception); }
  2. Analytics Code MixpanelAPI mixpanel = MixpanelAPI.getInstance(this, token); try  { JSONObject

    payload  =  new  JSONObject(); payload.put("Gender",  "Female"); payload.put("Logged  in",  false); payload.put("Source",  "Twitter"); mixpanel.track("Signup",  payload); }  catch  (JSONException exception)  { Log.e("Frodo",  "JsonException",  exception); }
  3. Analytics Code MixpanelAPI mixpanel =  MixpanelAPI.getInstance(this,  token); try  { JSONObject

    payload  = new JSONObject(); payload.put("Gender", "Female"); payload.put("Logged  in", false); payload.put("Source", "Twitter"); mixpanel.track("Signup",  payload); }  catch  (JSONException exception)  { Log.e("Frodo",  "JsonException",  exception); }
  4. Analytics Code MixpanelAPI mixpanel =  MixpanelAPI.getInstance(this,  token); try  { JSONObject

    payload  =  new  JSONObject(); payload.put("Gender",  "Female"); payload.put("Logged  in",  false); payload.put("Source",  "Twitter"); mixpanel.track("Signup", payload); }  catch  (JSONException exception)  { Log.e("Frodo",  "JsonException",  exception); }
  5. Requirements • Accuracy • Accommodate Changes • Don’t Leak Cognitive

    Resources • Testability • Support Multiple Apps and Platforms
  6. AOP

  7. AOP

  8. Java Poet – Method MethodSpec mainMethod = MethodSpec.methodBuilder("main") .addModifiers(Modifier.PUBLIC, Modifier.STATIC)

    .addParameter(String[].class, "args") .addStatement( "$T.out.println($S)", System.class, "Hello,  World!" ).build();
  9. Java Poet – Method MethodSpec mainMethod =  MethodSpec.methodBuilder("main") .addModifiers(Modifier.PUBLIC,  Modifier.STATIC)

    .addParameter(String[].class,  "args") .addStatement( "$T.out.println($S)", System.class, "Hello,  World!" ).build();
  10. Java Poet – Method MethodSpec mainMethod =  MethodSpec.methodBuilder("main") .addModifiers(Modifier.PUBLIC, Modifier.STATIC)

    .addParameter(String[].class,  "args") .addStatement( "$T.out.println($S)", System.class, "Hello,  World!" ).build();
  11. Java Poet – Method MethodSpec mainMethod =  MethodSpec.methodBuilder("main") .addModifiers(Modifier.PUBLIC,  Modifier.STATIC)

    .addParameter(String[].class, "args") .addStatement( "$T.out.println($S)", System.class, "Hello,  World!" ).build();
  12. Java Poet – Method MethodSpec mainMethod =  MethodSpec.methodBuilder("main") .addModifiers(Modifier.PUBLIC,  Modifier.STATIC)

    .addParameter(String[].class,  "args") .addStatement( "$T.out.println($S)", System.class, "Hello,  World!" ).build();
  13. Java Poet – Method MethodSpec mainMethod =  MethodSpec.methodBuilder("main") .addModifiers(Modifier.PUBLIC,  Modifier.STATIC)

    .addParameter(String[].class,  "args") .addStatement( "$T.out.println($S)", System.class, "Hello,  World!" ).build();
  14. Java Poet – Generated Class package in.kitecash; import java.lang.String; import

    java.lang.System; public class Greeter { public static void main(String[] args) { System.out.println("Hello,  World!"); } }
  15. workflow().screen().event() •Methods present inside Analytics class •Workflows are generated as

    top-level classes •Workflows encapsulate Screen inner classes
  16. workflow().screen().event() •Methods present inside Workflow classes •Screens are generated as

    inner classes in Workflows •Screens encapsulate event methods
  17. Analytics •Contains  Workflow methods  that  provide   instances  of  Workflow

    classes •Instantiated  by  supplying  a  Tracker implementation
  18. versus this? MixpanelAPI mixpanel =  MixpanelAPI.getInstance(this,  token); try  { JSONObject

    payload  =  new  JSONObject(); payload.put("Gender",  "Female"); payload.put("Logged  in",  false); payload.put("Source",  "Twitter"); mixpanel.track("Signup",  payload); }  catch  (JSONException exception)  { Log.e("Frodo",  "JsonException",  exception); }
  19. LogcatTracker public class LogcatTracker implements Tracker { private static final

    String TAG  = "LogcatTracker"; @Override public void track(String trigger, Map<String, String> payload) { Log.d(TAG, "Received  trigger:  " + trigger  +  ",  " + payload); } }
  20. LogcatTracker public  class  LogcatTracker implements  Tracker  { private  static  final

     String  TAG  =  "LogcatTracker"; @Override public  void  track(String  trigger,  Map<String,  String>  payload)  { Log.d(TAG, "Received  trigger:  " + trigger  +  ",  " + payload); } }
  21. AlertDialogTracker public class AlertDialogTracker implements Tracker { private final Context

    context; public AlertDialogTracker(Context context) { this.context = context; } @Override public void track(String trigger, Map<String, String> payload) { StringBuilder messageBuilder = new StringBuilder(); //  Create  a  String  message  from  the  payload... showAlertDialog(trigger, stringBuilder.toString()); } }
  22. AlertDialogTracker public  class  AlertDialogTracker implements  Tracker  { private  final  Context

     context; public  AlertDialogTracker(Context  context)  { this.context =  context; } @Override public  void  track(String  trigger,  Map<String,  String>  payload)  { StringBuilder messageBuilder = new StringBuilder(); //  Create  a  String  message  from  the  payload... showAlertDialog(trigger, stringBuilder.toString()); } }
  23. MixpanelTracker public class MixpanelTracker implements Tracker { private final MixpanelAPI

    mixpanel; public MixpanelTracker(Context context, String projectToken) { this.mixpanel = MixpanelAPI.getInstance(context, projectToken); } @Override public void track(String trigger, Map<String, String> payload) { JSONObject properties  = new JSONObject(); //  Populate  the  JSONObject from  payload... mixpanel.track(trigger, properties); } }
  24. MixpanelTracker public  class  MixpanelTracker implements  Tracker  { private  final  MixpanelAPI

    mixpanel; public  MixpanelTracker(Context context, String projectToken)  { this.mixpanel =  MixpanelAPI.getInstance(context,  projectToken); } @Override public  void  track(String  trigger,  Map<String,  String>  payload)  { JSONObject properties  =  new  JSONObject(); //  Populate  the  JSONObject from  payload... mixpanel.track(trigger,  properties); } }
  25. MixpanelTracker public  class  MixpanelTracker implements  Tracker  { private  final  MixpanelAPI

    mixpanel; public  MixpanelTracker(Context  context,  String  projectToken)  { this.mixpanel =  MixpanelAPI.getInstance(context,  projectToken); } @Override public  void  track(String  trigger,  Map<String,  String>  payload)  { JSONObject properties  = new JSONObject(); //  Populate  the  JSONObject from  payload... mixpanel.track(trigger, properties); } }
  26. Overview • Export spreadsheet from BI team as CSV •

    Check exported CSV into analytics project • Run Gradle task to generate source code from CSV • Copy generated source code into Android projects • Send generated source code to iOS team • iOS team includes transpiled source code to iOS projects
  27. Code Generation Tips • Iterate through the design several times

    • Doesn’t have to be DRY • Use a prefix in generated source files • Add “Auto-Generated” comments and Javadoc • Prefer abstract classes over interfaces • Extract platform-specific code, use abstraction
  28. 2 Moar Cents •Make tools work for you •Communicate with

    all teams that are involved, this is the key