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

Stealing the Web's Best Feature (Droidcon NY 2016)

Stealing the Web's Best Feature (Droidcon NY 2016)

Square Cash recently moved some core business logic out of Java and into an embedded scripting language. This allows the web, iOS, and Android clients to share the same code, as well as update that logic on the fly without requiring an app update. Learn the background behind this decision, how we leverage the technology on Android, and how you can do the same with your app.

Matthew Precious

September 29, 2016
Tweet

More Decks by Matthew Precious

Other Decks in Programming

Transcript

  1. L Business logic • What is a valid username? •

    4-20 characters • [a-zA-Z0-9_\-]
  2. Business logic • Is your password secure enough? • 8+

    characters • 1+ lowercase • 1+ uppercase
  3. Business logic • Is your password secure enough? • 8+

    characters • 1+ lowercase • 1+ uppercase • 1+ number
  4. Business logic • Is your password secure enough? • 8+

    characters • 1+ lowercase • 1+ uppercase • 1+ number • 1+ special character
  5. Business logic • When do you nag for a rating?

    • After 1 week? • After 3 successful payments?
  6. Business logic • How do you render your data? •

    Status text is green/red/grey • Show appropriate icon
  7. Business logic • How do you render your data? •

    Status text is green/red/grey • Show appropriate icon • enum —> String
  8. Business logic • How does your referral program work? •

    $1 per referral? • $10 after referring 5 people?
  9. Client • Bake the logic into your APK • Logic

    is fixed for a given app version
  10. Client + Fast feedback loop - Requires an app update

    to change - Duplicated across all platforms
  11. Client + Fast feedback loop - Requires an app update

    to change - Duplicated across all platforms - Potential mismatch between platforms
  12. Server • Client doesn't care • Send the data to

    the server and let the server handle it
  13. Server + Logic can be updated independent of app updates

    + All platforms are in sync - Slow feedback loop
  14. Server + Logic can be updated independent of app updates

    + All platforms are in sync - Slow feedback loop - Client must be online
  15. Server + Logic can be updated independent of app updates

    + All platforms are in sync - Slow feedback loop - Client must be online - Harder client complexity (new round trips)
  16. Client + Server • Client bakes in variable logic •

    Values are provided by the server
  17. Client + Server • Client bakes in variable logic •

    Values are provided by the server • Feature/experiment flags
  18. Client + Server + Fast feedback loop + Logic updated

    independent of app updates* + All platforms are in sync*
  19. Client + Server + Fast feedback loop + Logic updated

    independent of app updates* + All platforms are in sync* - Requires app update to add new rules
  20. Client + Server + Fast feedback loop + Logic updated

    independent of app updates* + All platforms are in sync* - Requires app update to add new rules - Platforms can fall out of sync with new rules
  21. Client + Server + Fast feedback loop + Logic updated

    independent of app updates* + All platforms are in sync* - Requires app update to add new rules - Platforms can fall out of sync with new rules - Duplicated across all platforms
  22. Client + Server + Fast feedback loop + Logic updated

    independent of app updates* + All platforms are in sync* - Requires app update to add new rules - Platforms can fall out of sync with new rules - Duplicated across all platforms - Medium-hard client complexity
  23. Username validation function validateUsername(username) {
 if (username.length < 4 

    username.length > 20) {
 return "Username must be between 4 and 20 characters.";
 }
 
 return null;
 }
  24. Username validation interface Validator {
 String validateUsername(String username);
 }x var

    Validator = {
 validateUsername: function(username) {
 // Validate username.
 }
 };
  25. Username validation Validator validator = duktape.get("Validator", Validator.class); String usernameErrorMessage =

    (String) duktape.evaluate( String.format("validateUsername(\"%s\");", username));
  26. Username validation Validator validator = duktape.get("Validator", Validator.class); String usernameErrorMessage =

    (String) duktape.evaluate( String.format("validateUsername(\"%s\");", username));
  27. Username validation Validator validator = duktape.get("Validator", Validator.class); String usernameErrorMessage =

    (String) duktape.evaluate( String.format("validateUsername(\"%s\");", username));
  28. Username validation Validator validator = duktape.get("Validator", Validator.class);
 String usernameErrorMessage =

    (String) duktape.evaluate( String.format("validateUsername(\"%s\");", username));
  29. Username validation Validator validator = duktape.get("Validator", Validator.class);
 String usernameErrorMessage =

    (String) duktape.evaluate( String.format("validateUsername(\"%s\");", username));
  30. Java from JS: Logging JsLogger jsLogger = new JsLogger() {


    @Override public void d(String message) {
 Timber.d(message);
 }x
 };
  31. Java from JS: Logging JsLogger jsLogger = new JsLogger() {


    @Override public void d(String message) {
 Timber.d(message);
 }x
 }; duktape.set("JsLogger", JsLogger.class, jsLogger);
  32. Java from JS: Logging JsLogger jsLogger = new JsLogger() {


    @Override public void d(String message) {
 Timber.d(message);
 }
 }; duktape.set("JsLogger", JsLogger.class, jsLogger);
  33. Java from JS: Logging JsLogger jsLogger = new JsLogger() {


    @Override public void d(String message) {
 Timber.d(message);
 }
 }; duktape.set("JsLogger", JsLogger.class, jsLogger);
  34. Java from JS: Logging JsLogger jsLogger = new JsLogger() {


    @Override public void d(String message) {
 Timber.d(message);
 }
 }; duktape.set("JsLogger", JsLogger.class, jsLogger);
  35. Java from JS: Date formatting DateFormatter dateFormatter = new DateFormatter()

    {
 @Override String format(long millis) {
 return DateUtils.formatDateTime(context, millis, FORMAT_SHOW_DATE | FORMAT_SHOW_YEAR);
 }x
 };
  36. Java from JS: Date formatting DateFormatter dateFormatter = new DateFormatter()

    {
 @Override String format(long millis) {
 return DateUtils.formatDateTime(context, millis, FORMAT_SHOW_DATE | FORMAT_SHOW_YEAR);
 }x
 }; duktape.set("DateFormatter", DateFormatter.class, dateFormatter);
  37. Java from JS: Storage interface Storage {
 void write(String key,

    String value);
 String read(String key);
 }
  38. JS

  39. Gradle download task import de.undercouch.gradle.tasks.download.Download task updateScript(type: Download) {
 src

    'https://myserver.com/my-script.js'
 dest file('src/main/res/raw/my_script.js')
 }
  40. JavaScript + Fast feedback loop + Logic can be updated

    independent of app updates + All platforms are in sync
  41. JavaScript + Fast feedback loop + Logic can be updated

    independent of app updates + All platforms are in sync - Medium client complexity for first integration (easy for subsequent)
  42. Square Cash: Activity v1 get-payments $ $ $ $ $

    $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $
  43. duktape-android pro-tips • Duktape is mutable! • Be very careful

    if you’re sharing it between threads • Or don't share it!
  44. duktape-android pro-tips • Duktape is mutable! • Be very careful

    if you’re sharing it between threads • Or don't share it! • ECMAScript E5/E5.1