Pro Yearly is on sale from $80 to $50! »

Server Driven UI Workflow

Server Driven UI Workflow

Video: https://youtu.be/eHGFpRj_3Vk

Deploying an Android app to the play store always contains some cost in it. Furthermore the user isn't always keen to download (again) our latest versioned app. How about doubling the cost of development with the iOS app into account (or Web)?
At Square, we came up with a system in which the server owns the workflow of the client. This means the client doesn't know before hand which screen, which image or text it's gonna show next.

In this talk, we'll:

- Know why Square ended up choosing this system.
- Discover how we built it.
- Look at the challenges, the pros and cons of such an architecture.
- Talk about how we want to alter it for the future.

Attendees to this talk will be expose to solutions for problems every company is facing but don't address.

05162bc961c3654218bf1839974a4f35?s=128

Benoît Quenaudon

April 24, 2019
Tweet

Transcript

  1. Server Driven UI workflow Benoît Quenaudon @oldergod Cash App

  2. None
  3. A

  4. A

  5. None
  6. None
  7. None
  8. A

  9. None
  10. A

  11. A

  12. None
  13. A

  14. None
  15. A

  16. None
  17. A

  18. None
  19. A

  20. None
  21. A

  22. None
  23. A

  24. A

  25. None
  26. A

  27. None
  28. A

  29. None
  30. None
  31. Cash 1.0

  32. A

  33. A

  34. A

  35. None
  36. Steps

  37. Steps • LINK_CARD • IDENTIFICATION_VERIFICATION (IDV) • CONFIRMATION

  38. enum Steps { LINK_CARD = 1; IDV = 2; CONFIRMATION

    = 3; }
  39. Cash 2.0

  40. None
  41. None
  42. enum Steps { LINK_CARD = 1; IDV = 2; CONFIRMATION

    = 3; }
  43. Blockers

  44. message IdentityVerificationBlocker { optional bool requires_birthdate = 1; optional bool

    requires_full_ssn = 2; optional bool requires_last_four_ssn = 3; optional bool requires_full_name = 4; optional bool requires_address = 5; }
  45. ...and the app kept growing

  46. Server sends back ExecuteContractResponse if (response is ExecuteContractResponse) { return

    R.layout.status_result_view; } Pass ExecuteContractResponse#statusResult to the view
  47. Server sends back ExecuteContractResponse if (response is ExecuteContractResponse) { return

    R.layout.status_result_view; } Pass ExecuteContractResponse#statusResult to the view
  48. Server sends back ExecuteContractResponse if (response is ExecuteContractResponse) { return

    R.layout.status_result_view; } Pass ExecuteContractResponse#statusResult to the view
  49. message StatusResult {a }d

  50. B C D message StatusResult {a enum Icon {b SUCCESS

    = 1; PENDING = 2; FAILURE = 3; ACTION_REQUIRED = 4; NONE = 5; }c optionaloIcon icon = 1; }d
  51. a C D message StatusResult {a enum Icon {b SUCCESS

    = 1; PENDING = 2; FAILURE = 3; ACTION_REQUIRED = 4; NONE = 5; }c optionaloIcon icon = 1; optionalostring text = 2; }d
  52. B a C message StatusResult {a enum Icon {b SUCCESS

    = 1; PENDING = 2; FAILURE = 3; ACTION_REQUIRED = 4; NONE = 5; }c optionaloIcon icon = 1; optionalostring text = 2; optionaloStatusResultButton primary_button = 3; optionaloStatusResultButton secondary_button = 4; }d
  53. B a C message StatusResult {a enum Icon {b SUCCESS

    = 1; PENDING = 2; FAILURE = 3; ACTION_REQUIRED = 4; NONE = 5; }c optionaloIcon icon = 1; optionalostring text = 2; optionaloStatusResultButton primary_button = 3; optionaloStatusResultButton secondary_button = 4; }d message StatusResultButton { enumoButtonAction { HOME_SCREENz=z1; LINK_CARDz=z2; OPEN_URLz=z3; } optionalnButtonAction actionz=z1; optionalnstring textz=z2; optionalnstring urlz=z3; }
  54. B a D message StatusResult {a enum Icon {b SUCCESS

    = 1; PENDING = 2; FAILURE = 3; ACTION_REQUIRED = 4; NONE = 5; }c optionaloIcon icon = 1; optionalostring text = 2; optionaloStatusResultButton primary_button = 3; optionaloStatusResultButton secondary_button = 4; optionalostring promo_textw=w5; }d
  55. message StatusResult {a enum Icon {b SUCCESS = 1; PENDING

    = 2; FAILURE = 3; ACTION_REQUIRED = 4; NONE = 5; }c optionaloIcon icon = 1; optionalostring text = 2; optionaloStatusResultButton primary_button = 3; optionaloStatusResultButton secondary_button = 4; optionalostring promo_textw=w5; }d
  56. ...and the app kept growing

  57. None
  58. Cash 3.0

  59. • Skippability • Ordering • Scalability

  60. Form Blocker

  61. ButtonElement LocalImageElement RemoteImageElement MoneyElement SpacerElement TextElement CustomizedCardElement AddressElement TextInputElement OptionPickerElement

    DetailRowElement CurrencyConversionFlagsElement
  62. message FormBlocker { oneof Element { ButtonElement button_element = 1;

    LocalImageElement local_image_element = 2; RemoteImageElement remote_image_element = 3; MoneyElement money_element = 4; SpacerElement spacer_element = 5; TextElement text_element = 6; CustomizedCardElement customized_card_element = 7; AddressElement address_element = 9; TextInputElement text_input_element = 10; OptionPickerElement option_picker_element = 11; DetailRowElement detail_row_element = 12; CurrencyConversionFlagsElement currency_conversion_flags_element = 13; } repeated Element elements = 1; optional BlockerAction primary_action = 2; optional BlockerAction secondary_action = 3; } ButtonElement LocalImageElement RemoteImageElement MoneyElement SpacerElement TextElement CustomizedCardElement AddressElement TextInputElement OptionPickerElement DetailRowElement CurrencyConversionFlagsElement
  63. message FormBlocker { oneof Element { ButtonElement button_element = 1;

    LocalImageElement local_image_element = 2; RemoteImageElement remote_image_element = 3; MoneyElement money_element = 4; SpacerElement spacer_element = 5; TextElement text_element = 6; CustomizedCardElement customized_card_element = 7; AddressElement address_element = 9; TextInputElement text_input_element = 10; OptionPickerElement option_picker_element = 11; DetailRowElement detail_row_element = 12; CurrencyConversionFlagsElement currency_conversion_flags_element = 13; } repeated Element elements = 1; optional BlockerAction primary_action = 2; optional BlockerAction secondary_action = 3; }
  64. None
  65. Option Picker Element Primary Action Text Element Primary Action Text

    Input Element Text Element
  66. Data Format Sharing

  67. [On iOS, we use a] convoluted series of script

  68. Challenges

  69. Backporting

  70. Percent of users active per app versions since January 2019

  71. 0.744% ≈ 50・000 customers

  72. • Force update • Redirect to Web App • Smoke&Mirror

    usage of old blockers • Use fallback blocker • Don't send blocker - skip it
  73. • Backporting • Bug Hunting • Complexity • Integration Challenges

  74. Pros

  75. • Real logic lives in only one platform • Lot

    of features/fixes don't involve clients at all • Client logic is simple - to some degree • Changes available without client updates
  76. Server Driven Design System?

  77. Benoît Quenaudon @oldergod Fin Cash App