Building Quality Code That Lasts: A Dropbox Story. Ashley Nelson-Hornstein

Preview:

DESCRIPTION

Building Quality Code That Lasts: A Dropbox Story

Citation preview

1

Building Quality Code That Lasts: A Dropbox StoryAshley Nelson-Hornstein · 10 - 30 - 14

2

Product

Testing

Background

Case Studies

Future of iOS at Dropbox

TODAY’S TALK

3

Dropbox for iOSDeveloped natively

Team of one engineer

First consumer of Dropbox public APIs

Released for iPhone in 2009

iPad support in 2010

4

Sync SDK

UI Code

Core SDK

Data Layer

5

6

6

6

6

TODAY’S TALK

Product

Testing

Background

Case Studies

Future of iOS at Dropbox

7

Product RoadmapCollaborative process

Mix of

Infrastructure

User facing features

Code modernization

8

Release ManagerRotating role

Feature gatekeeper

Project manager

Task prioritization

Scheduling

Build stabilization

9

Development

10

BranchingDefault branch

All changes are checked in here first

Release branch

hg graft —log from default branch

Verified by release manager

11

12

13

13

Style Guide

14

Coding ConventionsPrefix internal methods with db_

Prefer class methods

Hide implementation detail

Class extensions

15

16

// DBFile.h !

@interface DBFile : NSObject !

@property (readonly, strong) NSData *contents; !

@property (readonly, strong) NSURL *publicShareLink; !

@property (strong) NSDictionary *permissions; !

- (void)copyToNewPath:(NSString *)newPath; !

@end

// DBFile.m !

@interface DBFile () !

@property (readwrite, strong) NSData *contents; !

@property (strong) NSString *localFilePath; @end !

@implementation DBFile !

- (void)copyToNewPath:(NSString *)newPath { ... } @end

Comments// TODO: (ashleynh) 2014-10-30

Reminder for future improvement

// FIXME: (ashleynh) 2014-10-30

Generates compiler warning, not for release

// HAX: (ashleynh) 2014-10-30

Non-obvious API workaround

17

Builds

18

Continuous IntegrationPool of build machines

Executes functional tests

Builds are available to office

State changes are emailed to team

19

20

Crash ReporterDeveloped in-house

Predates other crash report services

Uploads crash logs from device

Groups crashes by stack trace

Provides symbolication

21

22

TODAY’S TALK

Testing

Case Studies

Future of iOS at Dropbox

Background

23

Product

Developer SettingsToggle features on/off

View

Run log

Network and device stats

File cache inspection

24

Shake to ReportInternal bug reporting

Captures

Screenshot

Crash log (if applicable)

Run log

Issues reported directly to bug tracking tool

25

Helper Apps

26

DropolineDeveloped in-house

Tests inter-app workflows

File import/export

Photo backup

Storage provider extension

27

Car KeysDeveloped in-house

Keychain

Inspection

Deletion

28

Automata

29

Automata BackgroundFunctional testing framework

Developed in-house

Run tests locally or using Jenkins

Python API

Rich set of libraries to simplify automation

High productivity

30

Automata BenefitsSeparate process enables inter-app testing

Single test can manipulate two apps

Automating screenshots and screenshot diffs

Objective-C experience not required

Hooks into Objective-C runtime

31

32

Automata

Dropbox Dropoline

32

Automata

Dropbox Dropoline

Automata FutureSupport for iOS 8 extensions

GUI that records test scripts

Open source

33

TODAY’S TALK

Testing

Case Studies

Future of iOS at Dropbox

Background

34

Product

File Cache

35

BackgroundProvides access to user’s Dropbox files

Coordinates with REST API and disk

Critical component

36

IssuesFile names of stored files are Dropbox paths

Unusually long file paths

Unsupported unicode characters

File loading race conditions

Providing readwrite access to file refs

37

/* * Hello there, friend. I wish you luck in your voyage through the following code. * * We need to avoid doing disk I/O in this callback, because it will be called in quick succession * repeatedly on photos tab as we load lots of thumbs. Since we're on the main thread right now, * we can't afford to do costly disk I/O. It will seriously impact scroll performance on photos tab * if we do. * * The following code checks to see if what we just loaded has only a thumbnail repr. If it does, * it updates the cacheSize property of the file to -1. -1 is a special flag, indicating to the LRU cleanup * mechanism that this file doesn't need to be purged from the disk during LRU cleanup. * * Why not cleanup these files during LRU cleanup? Because with the release of photos tab, we may * have thousand of files on disk. And starting them all during LRU cleanup is much too slow. So, * we've opted to just not clean up files that only have thumbnail reprs. * * This code is not "correct". For example, if you load a thumbnail *AND* the BestFit repr, the thumbnail * could now be cleaned up during LRU cleanup. * * This is basically a huge hack to make scrolling performance not stutter in photos tab. * */

38

/* * Hello there, friend. I wish you luck in your voyage through the following code. ! * This is basically a huge hack to make scrolling performance not stutter in photos tab. */

39

GoalsEnsure file name integrity

Operations on separate queue

Smarter file loading system

Defensive return values

40

ApproachUnit Tests

Uncovered existing bugs

Set a baseline for expected behavior

Maintained API for consumers

Limited project scope

41

ImplementationStore files by UUID instead of Dropbox path

File Cache on background serial queue

Return immutable stubs of file refs

LoadingFileManager

42

Consumer FileCache

RO Cached File

Core Data

Disk

Loading File Manager

Single Background Queue

43

BenefitsEasier to understand

Performant

Stable

44

App Delegate

45

[[UIApplication sharedApplication] delegate]

46

47

Issues

48

IssuesApp could be entered in a number of ways

48

IssuesApp could be entered in a number of ways

User initiated

48

IssuesApp could be entered in a number of ways

User initiated

File import

48

IssuesApp could be entered in a number of ways

User initiated

File import

API connection

48

IssuesApp could be entered in a number of ways

User initiated

File import

API connection

Notification

48

IssuesApp could be entered in a number of ways

User initiated

File import

API connection

Notification

Etc.

48

IssuesApp entry state could be

48

IssuesApp entry state could be

Passcode on

48

IssuesApp entry state could be

Passcode on

Passcode off

48

IssuesApp entry state could be

Passcode on

Passcode off

Locked out

48

IssuesApp entry state could be

Passcode on

Passcode off

Locked out

Already displaying a modal

48

Overly complex logic

48

GoalsProperly define app states

Encapsulate state logic

Transition easily between states

Speed launches

49

ImplementationState Pattern

DBState

Initial

NotLoggedIn

ContinueAs

LoggedInNoPasscode

LoggedInPasscode

50

BenefitsReduced 2600 lines to 500 lines

Easier to understand

Encapsulated logic in clear boundaries

51

TODAY’S TALK

Testing

Case Studies

Future of iOS at Dropbox

Background

52

Product

SwiftExcited by the promise

Practical approach

Tooling

Encapsulated features

53

54

Recommended