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

Networking and Persistence in Mobile Apps at Scale

Avatar for Jake Jake
August 16, 2017

Networking and Persistence in Mobile Apps at Scale

In this talk, I present the concept of a Model Store. This is a black-box system which maintains up-to-date model information for a dynamic app. It necessarily has networking, persistence, caching, and change notification capabilities. Through a series of slides and code examples, I illustrate how a well-designed codebase which includes one or more Model Stores can help developers attain a more well-reasoned and high-quality app.

Avatar for Jake

Jake

August 16, 2017

Other Decks in Technology

Transcript

  1. Jake Schwartz • Top 10 Social Networking app • Over

    10 million MAU • 13 languages Jake Schwartz
  2. Jake Schwartz Mobile Challenges • Mobile data usage • Battery

    consumption • Caching • Updating underlying technologies
  3. Jake Schwartz Bicameral Codebase Core Data HTTP API WebSockets Older

    database Offline mode Cached avatar images Map Pins Chat UI User Profile Circle switcher Loading animation
  4. Jake Schwartz private let modelStore = ModelStore(.coreData, .webSockets) modelStore.getAllMembers() .map

    { member: Member -> MapPin in let mapPin = MapPin( coord: member.coordinate, avatarURL: member.avatarURL, firstName: member.firstName ) return mapPin } .subscribe(onNext: { mapPin in mapView.updatePin(for: mapPin.ID, mapPin) }) .disposed(by: disposeBag)
  5. Jake Schwartz private let modelStore = ModelStore(.coreData, .webSockets) private let

    modelStore = ModelStore(.coreData, .webSockets) modelStore.getAllMembers() .map { member: Member -> MapPin in let mapPin = MapPin( coord: member.coordinate, avatarURL: member.avatarURL, firstName: member.firstName ) return mapPin } .subscribe(onNext: { mapPin in mapView.updatePin(for: mapPin.ID, mapPin) }) .disposed(by: disposeBag)
  6. Jake Schwartz modelStore.getAllMembers() .map { member: Member -> MapPin in

    } private let modelStore = ModelStore(.coreData, .webSockets) modelStore.getAllMembers() .map { member: Member -> MapPin in let mapPin = MapPin( coord: member.coordinate, avatarURL: member.avatarURL, firstName: member.firstName ) return mapPin } .subscribe(onNext: { mapPin in mapView.updatePin(for: mapPin.ID, mapPin) }) .disposed(by: disposeBag)
  7. Jake Schwartz let mapPin = MapPin( coord: member.coordinate, avatarURL: member.avatarURL,

    firstName: member.firstName ) return mapPin private let modelStore = ModelStore(.coreData, .webSockets) modelStore.getAllMembers() .map { member: Member -> MapPin in let mapPin = MapPin( coord: member.coordinate, avatarURL: member.avatarURL, firstName: member.firstName ) return mapPin } .subscribe(onNext: { mapPin in mapView.updatePin(for: mapPin.ID, mapPin) }) .disposed(by: disposeBag)
  8. Jake Schwartz .subscribe(onNext: { mapPin in mapView.updatePin(for: mapPin.ID, mapPin) })

    private let modelStore = ModelStore(.coreData, .webSockets) modelStore.getAllMembers() .map { member: Member -> MapPin in let mapPin = MapPin( coord: member.coordinate, avatarURL: member.avatarURL, firstName: member.firstName ) return mapPin } .subscribe(onNext: { mapPin in mapView.updatePin(for: mapPin.ID, mapPin) }) .disposed(by: disposeBag)
  9. Jake Schwartz private let modelStore = ModelStore(.coreData, .webSockets) modelStore.getAllMembers() .map

    { member: Member -> MapPin in let mapPin = MapPin( coord: member.coordinate, avatarURL: member.avatarURL, firstName: member.firstName ) return mapPin } .subscribe(onNext: { mapPin in mapView.updatePin(for: mapPin.ID, mapPin) }) .disposed(by: disposeBag)
  10. Jake Schwartz Bicameral Codebase Rocks Decoupled code Fewer bugs Faster

    feature development Skill specialization Hiring
  11. Jake Schwartz public protocol ModelStore { associatedtype ModelType: EntityType func

    activate() func deactivate() func create(entity: ModelType) -> Observable<Result<ModelType>> var entities: Observable<[ModelType]> { get } func entity(forID entityID: EntityID) -> Observable<ModelType?> func update(entity: ModelType) -> Observable<Result<ModelType>> func delete(id: EntityID) -> Observable<Result<ModelType>> }
  12. Jake Schwartz public protocol ModelStore { associatedtype ModelType: EntityType func

    activate() func deactivate() func create(entity: ModelType) -> Observable<Result<ModelType>> var entities: Observable<[ModelType]> { get } func entity(forID entityID: EntityID) -> Observable<ModelType?> func update(entity: ModelType) -> Observable<Result<ModelType>> func delete(id: EntityID) -> Observable<Result<ModelType>> }
  13. Jake Schwartz public protocol ModelStore { associatedtype ModelType: EntityType func

    activate() func deactivate() func create(entity: ModelType) -> Observable<Result<ModelType>> var entities: Observable<[ModelType]> { get } func entity(forID entityID: EntityID) -> Observable<ModelType?> func update(entity: ModelType) -> Observable<Result<ModelType>> func delete(id: EntityID) -> Observable<Result<ModelType>> }
  14. Jake Schwartz public protocol ModelStore { associatedtype ModelType: EntityType func

    activate() func deactivate() func create(entity: ModelType) -> Observable<Result<ModelType>> var entities: Observable<[ModelType]> { get } func entity(forID entityID: EntityID) -> Observable<ModelType?> func update(entity: ModelType) -> Observable<Result<ModelType>> func delete(id: EntityID) -> Observable<Result<ModelType>> }
  15. Jake Schwartz iOS + Android • Doubled our team’s software

    design capacity • Shared wiki documents • Architecture diagram • API definitions