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.

Eefb68011178f8d4e7ae59d1d8f0b0b5?s=128

Matthew Precious

September 29, 2016
Tweet

Transcript

  1. Matt Precious Stealing the Web's Best Feature

  2. l Business Logic

  3. L Business logic

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

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

    4-20 characters
  6. L Business logic • What is a valid username? •

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

  8. Business logic • Is your password secure enough? • 8+

    characters
  9. Business logic • Is your password secure enough? • 8+

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

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

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

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

  14. Business logic • When do you nag for a rating?

    • After 1 week?
  15. Business logic • When do you nag for a rating?

    • After 1 week? • After 3 successful payments?
  16. Business logic • Maximum length of a tweet?

  17. Business logic • Maximum length of a tweet? • 140

    characters
  18. Business logic • Maximum length of a tweet? • 140…ish

    characters
  19. Business logic • How do you render your data?

  20. Business logic • How do you render your data? •

    Status text is green/red/grey
  21. Business logic • How do you render your data? •

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

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

  24. Business logic • How does your referral program work? •

    $1 per referral?
  25. Business logic • How does your referral program work? •

    $1 per referral? • $10 after referring 5 people?
  26. Where should business logic live?

  27. Where should business logic live? Server Client

  28. Where should business logic live? Server

  29. Where should business logic live? Server Client

  30. Where should business logic live? Server Client

  31. Client

  32. Client • Bake the logic into your APK

  33. Client • Bake the logic into your APK • Logic

    is fixed for a given app version
  34. Client + Fast feedback loop

  35. Client + Fast feedback loop - Requires an app update

    to change
  36. Client + Fast feedback loop - Requires an app update

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

    to change - Duplicated across all platforms - Potential mismatch between platforms
  38. Where should business logic live? Server Client

  39. Where should business logic live? Server Client

  40. Server

  41. Server • Client doesn't care

  42. Server • Client doesn't care • Send the data to

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

  44. Server + Logic can be updated independent of app updates

    + All platforms are in sync
  45. Server + Logic can be updated independent of app updates

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

    + All platforms are in sync - Slow feedback loop - Client must be online
  47. 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)
  48. Where should business logic live? Server Client

  49. Where should business logic live? Server Client

  50. Client + Server

  51. Client + Server • Client bakes in variable logic

  52. Client + Server • Client bakes in variable logic •

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

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

  55. Client + Server + Fast feedback loop + Logic updated

    independent of app updates*
  56. Client + Server + Fast feedback loop + Logic updated

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

    independent of app updates* + All platforms are in sync* - Requires app update to add new rules
  58. 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
  59. 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
  60. 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
  61. Where should business logic live? Server Client

  62. tl;dr: If business logic lives on…

  63. tl;dr: If business logic lives on… Client PM is

  64. tl;dr: If business logic lives on… Server Users are Client

    PM is
  65. tl;dr: If business logic lives on… Client + Server Developers

    are Server Users are Client PM is
  66. Hybrid app

  67. Hybrid app (WebView++)

  68. Hybrid app (WebView++) PhoneGap Cordova

  69. Hybrid app (WebView++) HTML JavaScript Android bits + +

  70. Hybrid app (WebView++) HTML JavaScript Android bits + +

  71. Hybrid app (WebView++) HTML JavaScript Android bits + +

  72. Hybrid app (WebView++) HTML JavaScript Android bits + +

  73. Hybrid app (WebView++) HTML JavaScript Android bits + +

  74. JavaScript

  75. JavaScript Web

  76. JavaScript Web Yes

  77. JavaScript Web iOS Yes

  78. JavaScript Web iOS Yes Yes

  79. JavaScript Web iOS Server Yes Yes

  80. JavaScript Web iOS Server Yes Yes Probably

  81. JavaScript Web iOS Server Android Yes Yes Probably

  82. JavaScript Web iOS Server Android Yes Yes Probably ?

  83. duktape-android https://github.com/square/duktape-android

  84. Username validation function validateUsername(username) {
 return username.length >= 4 &&

    username.length <= 20;
 }
  85. Username validation function validateUsername(username) {
 if (username.length < 4 

    username.length > 20) {
 return "Username must be between 4 and 20 characters.";
 }
 
 return null;
 }
  86. Username validation Duktape duktape = Duktape.create();
 duktape.evaluate(myScript, "my_script.js");

  87. Username validation Duktape duktape = Duktape.create();
 duktape.evaluate(myScript, "my_script.js");

  88. Username validation Duktape duktape = Duktape.create();
 duktape.evaluate(myScript, "my_script.js");

  89. Username validation String usernameErrorMessage = (String) duktape.evaluate( String.format("validateUsername(\"%s\");", username));

  90. Username validation interface Validator {
 String validateUsername(String username);
 }x

  91. Username validation interface Validator {
 String validateUsername(String username);
 }x var

    Validator = {
 validateUsername: function(username) {
 // Validate username.
 }
 };
  92. Username validation String usernameErrorMessage = (String) duktape.evaluate( String.format("validateUsername(\"%s\");", username));

  93. Username validation Validator validator = duktape.get("Validator", Validator.class); String usernameErrorMessage =

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

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

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

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

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

    validator.validateUsername(username);
  99. Username validation Validator validator = duktape.get("Validator", Validator.class);
 String usernameErrorMessage =

    validator.validateUsername(username);
  100. Java from JS

  101. Java from JS: Logging interface JsLogger {
 void d(String message);


    }
  102. Java from JS: Logging JsLogger jsLogger = new JsLogger() {


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


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


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


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


    @Override public void d(String message) {
 Timber.d(message);
 }
 }; duktape.set("JsLogger", JsLogger.class, jsLogger);
  107. Java from JS: Logging JsLogger.d("Username length > 20");

  108. Java from JS: Date formatting interface DateFormatter {
 String format(long

    millis);
 }
  109. 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
 };
  110. 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);
  111. Java from JS: Date formatting DateFormatter.format(Date.now());

  112. Java from JS: Storage interface Storage {
 void write(String key,

    String value);
 String read(String key);
 }
  113. None
  114. JS APK

  115. JS

  116. JS JS

  117. JS JS

  118. JS JS

  119. 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')
 }
  120. JavaScript

  121. JavaScript + Fast feedback loop

  122. JavaScript + Fast feedback loop + Logic can be updated

    independent of app updates
  123. JavaScript + Fast feedback loop + Logic can be updated

    independent of app updates + All platforms are in sync
  124. 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)
  125. None
  126. Square Cash: Activity v1

  127. Square Cash: Activity v1

  128. Square Cash: Activity v1 get-payments

  129. Square Cash: Activity v1 get-payments $ $ $ $ $

    $ $
  130. Square Cash: Activity v1

  131. Square Cash: Activity v1 get-payments

  132. Square Cash: Activity v1 get-payments $ $ $ $ $

    $ $
  133. Square Cash: Activity v1 get-payments $ $ $ $ $

    $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $
  134. Square Cash: Activity v1

  135. Square Cash: Activity v2

  136. Square Cash: Activity v2

  137. Square Cash: Activity v2 get-payments

  138. Square Cash: Activity v2 get-payments $ $ $ $ $

    $ $
  139. Square Cash: Activity v2 get-payments $ $ $ $ $

    $ $ syncTokenA
  140. Square Cash: Activity v2

  141. Square Cash: Activity v2 get-payments, syncTokenA

  142. Square Cash: Activity v2 get-payments, syncTokenA Ø

  143. Square Cash: Activity v2

  144. Square Cash: Activity v2 get-payments, syncTokenA

  145. Square Cash: Activity v2 get-payments, syncTokenA $ $ $ syncTokenB

  146. None
  147. None
  148. None
  149. None
  150. None
  151. None
  152. None
  153. None
  154. None
  155. None
  156. None
  157. None
  158. None
  159. None
  160. None
  161. Square Cash: Activity v2?

  162. Square Cash: Activity v2? get-payments

  163. Square Cash: Activity v2? get-payments get-strings

  164. None
  165. None
  166. Square Cash: Activity v2? get-payments get-strings

  167. Square Cash: Activity v2? get-payments get-strings description: { time_1: string_1,

    time_2: string_2 }
  168. Square Cash: Activity v2!

  169. Square Cash: Activity v2! get-payments

  170. Square Cash: Activity v2! get-payments

  171. Square Cash: Activity v2! get-payments JS

  172. Square Cash: Activity v2! get-payments JS

  173. Square Cash: Activity v2! get-payments JS

  174. Square Cash: Activity v2! get-payments JS js_data: "{}"

  175. Square Cash: Activity v2! get-payments JS

  176. duktape-android pro-tips

  177. duktape-android pro-tips • Duktape is mutable!

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

    if you’re sharing it between threads
  179. duktape-android pro-tips • Duktape is mutable! • Be very careful

    if you’re sharing it between threads • Or don't share it!
  180. 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
  181. What is the web's best feature?

  182. Matt Precious Stealing the Web's Best Feature +MatthewPrecious @mattprec