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

One Way Flow of Data

Sponsored · Ship Features Fearlessly Turn features on and off without deploys. Used by thousands of Ruby developers.
Avatar for kathryneh kathryneh
November 11, 2015

One Way Flow of Data

At Square's Women Engineering Lightning Talk event, #hearandnow, Square engineer Kat Hawthorne presents an alternative iOS application architecture that her team designed to build a new version of Square Register.

Avatar for kathryneh

kathryneh

November 11, 2015
Tweet

Other Decks in Programming

Transcript

  1. RETHINKING IOS APP ARCHITECTURE USING A ONE WAY DATA FLOW

    kat hawthorne, software engineer @square #hearandnow | @khhawthorne
  2. VIEW CONTROLLERS OUT OF CONTROL SHARED DATA CAUSES HARD TO

    DISCOVER BUGS CODE WITH TOO MUCH RESPONSIBILITY IS HARD TO TEST COMMON PROBLEMS IN IOS APPLICATIONS #hearandnow | @khhawthorne
  3. VIEW CONTROLLERS HAVE TOO MUCH RESPONSIBILITY SHARED DATA CAUSES HARD

    TO DISCOVER BUGS CODE WITH TOO MUCH RESPONSIBILITY IS HARD TO TEST #hearandnow | @khhawthorne
  4. SHIRT $20 CHECKOUT 1 ITEM FOR $21 TAX $1 TOTAL

    $21 CART #hearandnow | @khhawthorne
  5. SHIRT $20 CHECKOUT 1 ITEM FOR $21 TAX $1 TOTAL

    $21 [JIRA] (LST-99) CHECKOUT BUTTON COLOR DOES NOT UPDATE CART #hearandnow | @khhawthorne
  6. VIEW CONTROLLERS HAVE TOO MUCH RESPONSIBILITY SHARED DATA CAUSES HARD

    TO DISCOVER BUGS CODE WITH TOO MUCH RESPONSIBILITY IS HARD TO TEST #hearandnow | @khhawthorne
  7. SHIRT $20 CART CALCULATE TOTAL HAT $20 X [JIRA] (LST-100)

    APP CRASHES WHEN CALCULATING TOTAL AND DELETING ITEM SIMULTANEOUSLY* #hearandnow | @khhawthorne
  8. VIEW CONTROLLERS HAVE TOO MUCH RESPONSIBILITY SHARED DATA CAUSES HARD

    TO DISCOVER BUGS CODE WITH TOO MUCH RESPONSIBILITY IS HARD TO TEST #hearandnow | @khhawthorne
  9. EMPTY CART CART WITH ITEMS ERROR STATE SUCCESS STATE VIEW

    CONTROLLER TESTS #hearandnow | @khhawthorne
  10. EMPTY CART CART WITH ITEMS ERROR STATE SUCCESS STATE ERROR

    STATE SUCCESS STATE VIEW CONTROLLER TESTS #hearandnow | @khhawthorne
  11. EMPTY CART CART WITH ITEMS ERROR STATE SUCCESS STATE ERROR

    STATE SUCCESS STATE AND SO ON… VIEW CONTROLLER TESTS #hearandnow | @khhawthorne
  12. ONE WAY FLOW OF DATA: THE CYCLE RENDERER PRESENTER VIEW

    CONTROLLER VIEW SERVICE REPOSITORY VIEW MODEL CONTEXT #hearandnow | @khhawthorne
  13. ONE WAY FLOW OF DATA: PUTTING IT TOGETHER RENDERER PRESENTER

    VIEW CONTROLLER VIEW SERVICE REPOSITORY VIEW MODEL CONTEXT #hearandnow | @khhawthorne
  14. RENDERER PRESENTER VIEW CONTROLLER VIEW SERVICE REPOSITORY VIEW MODEL CONTEXT

    RENDERER class Renderer { func render() { let cartViewModel = CartPresenter.present( accountService: context.accountService, cartService: context.cartService, errorService: context.errorService, itemService: context.itemService ) cartViewController.update(cartViewModel) } } #hearandnow | @khhawthorne
  15. RENDERER PRESENTER VIEW CONTROLLER VIEW SERVICE REPOSITORY VIEW MODEL CONTEXT

    CONTEXT class AppContext { private(set) lazy var cartService: CartService = CartService( cartState: self.cartState, catalogService: self.catalogService, accountService: self.accountService, render: self.render ) } #hearandnow | @khhawthorne
  16. RENDERER PRESENTER VIEW CONTROLLER VIEW SERVICE REPOSITORY VIEW MODEL CONTEXT

    PRESENTER final class CartPresenter { class func present( accountService: AccountService, cartService: CartService, errorService: ErrorService, itemService: ItemService ) -> CartViewModel? {…} } #hearandnow | @khhawthorne
  17. RENDERER PRESENTER VIEW CONTROLLER VIEW SERVICE REPOSITORY VIEW MODEL CONTEXT

    VIEW MODEL struct CartViewModel { let preSubtotalLineItems: [LineItem] let emptyCartMessage: String? let displayTotal: String? … } #hearandnow | @khhawthorne
  18. RENDERER PRESENTER VIEW CONTROLLER VIEW SERVICE REPOSITORY VIEW MODEL CONTEXT

    VIEW CONTROLLER final class CartViewController : UIViewController { private(set) cartView: CartView = CartView() func update(viewModel: CartViewModel?){ cartView.emptyCartMessage = viewModel.emptyCartMessage cartView.displayTotalLabel = viewModel.displayTotal … } } #hearandnow | @khhawthorne
  19. RENDERER PRESENTER VIEW CONTROLLER VIEW SERVICE REPOSITORY VIEW MODEL CONTEXT

    VIEW final class CartView : UIView { let emptyCartMessage: UILabel let displayTotalLabel: UILabel … } #hearandnow | @khhawthorne
  20. RENDERER PRESENTER VIEW CONTROLLER VIEW SERVICE REPOSITORY VIEW MODEL CONTEXT

    SERVICE class CartService { func addSKU(sku: String) { let item = catalog.getItem(sku: SKU) let cart = self.cart.mutableCopy() cart.mutableLineItems.addItemization(item) self.cart = cart.copy() render() } } #hearandnow | @khhawthorne
  21. ONE WAY FLOW OF DATA: PUTTING IT TOGETHER RENDERER PRESENTER

    VIEW CONTROLLER VIEW SERVICE REPOSITORY VIEW MODEL CONTEXT #hearandnow | @khhawthorne
  22. VIEW CONTROLLERS OUT OF CONTROL SHARED DATA CAUSES HARD TO

    DISCOVER BUGS CODE WITH TOO MUCH RESPONSIBILITY IS HARD TO TEST COMMON PROBLEMS IN IOS APPLICATIONS #hearandnow | @khhawthorne
  23. MULTI-LAYERED ARCHITECTURE SINGLE RESPONSIBILITY PRINCIPLE VIEW CONTROLLERS HAVE TOO MUCH

    RESPONSIBILITY LESS CODE = LESS MENTAL OVERHEAD #hearandnow | @khhawthorne
  24. MINIMAL STATE IN THE APP CLEAR DELINEATION OF WHAT CAN

    MODIFY STATE SHARED DATA CAUSES HARD TO DISCOVER BUGS ONE WAY FLOW OF DATA ELIMINATES UNEXPECTED BEHAVIOR #hearandnow | @khhawthorne
  25. THIN APPLICATION LAYERS DEPENDENCY INJECTION RATHER THAN RELYING ON SHARED

    STATE CODE WITH TOO MUCH RESPONSIBILITY IS HARD TO TEST #hearandnow | @khhawthorne
  26. ONE WAY FLOW OF DATA: PUTTING IT TOGETHER RENDERER PRESENTER

    VIEW CONTROLLER VIEW SERVICE REPOSITORY VIEW MODEL CONTEXT #hearandnow | @khhawthorne