"Architecting and testing large iOS apps: lessons from Facebook". Adam Ernst, Facebook
-
date post
21-Oct-2014 -
Category
Technology
-
view
2.973 -
download
2
description
Transcript of "Architecting and testing large iOS apps: lessons from Facebook". Adam Ernst, Facebook
Adam Ernst
Architecting and Testing Large iOS Apps: Lessons from Facebook
Agenda
▪ “Over the wall”: some history
▪Product Teams and the Core Team
▪Scheduling and Stabilizing Releases
▪How We Develop
▪Eating the Dogfood: Builds
▪A Culture of Unit Testing
▪Future of iOS at Facebook
History
Facebook for Mobile
▪Web deeply engrained in Facebook’s DNA
▪Use HTML!/Javascript within “wrapper” native app
▪Developed our own framework for advanced integration(image uploads, photo browsers, mixing native/web elements)
HTML as an app platform
▪What does it bring us?
One CodebaseInstant Updates A/B Testing
HTML as an app platform
A few engineers in a room
▪Facebook for iOS !." began as an experiment
A few engineers in a room
▪Facebook for iOS !." began as an experiment
▪Could we achieve better results with native code?
A few engineers in a room
▪Facebook for iOS !." began as an experiment
▪Could we achieve better results with native code?
▪High barrier: requires rewriting every part of Facebook’s mobile UI!
A few engineers in a room
▪Facebook for iOS !." began as an experiment
▪Could we achieve better results with native code?
▪High barrier: requires rewriting every part of Facebook’s mobile UI!
▪Couldn’t disrupt company for something that might not ship(At the time, few iOS engineers at Facebook anyway)
A few engineers in a room
▪Facebook for iOS !." began as an experiment
▪Could we achieve better results with native code?
▪High barrier: requires rewriting every part of Facebook’s mobile UI!
▪Couldn’t disrupt company for something that might not ship(At the time, few iOS engineers at Facebook anyway)
▪Sequester some engineers in a war room, and have themwrite the product from top to bottom
Reaction
▪Press loved it
▪More importantly…
▪ Perceived Speed way up
▪ User Ratings way up
▪#x Speed increase!
Reaction
▪Press loved it
▪More importantly…
▪ Perceived Speed way up
▪ User Ratings way up
▪#x Speed increase!
Team
A multi-app ecosystem
A multi-app ecosystem
The Team Sandwich
Release Team: Release & Stabilization ProcessRelease Team: Release & Stabilization ProcessRelease Team: Release & Stabilization ProcessRelease Team: Release & Stabilization ProcessRelease Team: Release & Stabilization Process
Photos Feed Search Places Messages
Product Infrastructure Team: Shared LibrariesProduct Infrastructure Team: Shared LibrariesProduct Infrastructure Team: Shared LibrariesProduct Infrastructure Team: Shared LibrariesProduct Infrastructure Team: Shared Libraries
Product Cycle
Fixed Release Cycle
▪Waiting for all features in a release to be “done” slowed us down, and we want to move fast
▪So, ship an update every X weeks
▪ … no matter what
▪Popularized by Mozilla
Building features with an “off switch”
▪Every feature must be built with a way to turn it off
▪ If a feature destabilizes the build or isn’t complete, turn it off and try again next time
▪#defines – or runtime switches (preferred)
Building a new “Like Bar”
Building a new “Like Bar”
Development
Phabricator
Text
Phabricator
Text
Phabricator
Text
Phabricator
Text
Phabricator
Text
Check code
▪ ‘arc lint’
▪Set up rules to catch common mistakes
▪Examples:
▪ Enforce style guidelines
▪ Warn against using certain symbols
▪ Check for common pattern mistakes, and fix them!
@implementation SampleClass
- (void)setupAccessibility{ self.myView.accessibilityTraits = UIAccessibilityTraitHeader;}
- (void)dealloc{ [_myString dealloc]; [super dealloc];}
@end
RegEx Lint Rule
AST Lint Rule
NEW
clang
AST
AST Lint Rules
▪Regular expressions have false positives and negatives
▪ Dot notation vs braces
▪ Even mentioning forbidden API in a comment triggers rule!
▪AST lint rules can “understand the code”
Verify changes: Buildbot
▪Continuous integration
▪Distributed across multiple build machines
▪Sanity check:
▪ Do all projects still build?
▪ Do all unit tests still pass?
▪Emails engineer, and updates Phabricator on failure
Static Analyzer Remote Runs
Buildbot failure email
Builds
Multiple Builds
▪Use different bundle IDs and icons for different types of builds:
▪ Development
▪ Daily Build
▪ App Store release
▪ Special branches
▪Burn your build number into your icon
Branching
▪Two concurrent branches:
▪Master
▪ Engineers make progress on future features
▪ All changes checked in here first
▪ …including bug fixes for Releases
▪Release
▪ Once verified in Master…
▪ …“Release team” pulls them into Release branch
Testing
Testing is important to Facebook
▪Not in Facebook’s culture:
▪ SDEs “in Test”
▪ Large QA departments
▪Definitely in Facebook culture:
▪ High quality, reliable user experience
▪We believe in developer-authored unit tests
Snapshot Unit Tests
typedef NS_ENUM(NSUInteger, FBActionStyle) { FBActionStyleUndefined = 0, FBActionStyleDefault = 1, FBActionStyleProminent = 2, FBActionStyleSubdued = 3,}
static NSArray *FBActionGetStyles() { return @[@"DEFAULT", @"PROMINENT", @"SUBDUED"];}
NSString *FBActionStringFromStyleValue(FBActionStyle styleValue) { NSArray *styles = FBActionGetStyles();
if (styleValue < [styles count]) { return [styles objectAtIndex:styleValue]; } else { return nil; }}
typedef NS_ENUM(NSUInteger, FBActionStyle) { FBActionStyleUndefined = 0, FBActionStyleDefault = 1, FBActionStyleProminent = 2, FBActionStyleSubdued = 3,}
NSString *FBActionStringFromStyleValue(FBActionStyle styleValue) { switch (styleValue) { case FBActionStyleDefault: return @”DEFAULT”; case FBActionStyleProminent: return @”PROMINENT”; case FBActionStyleSubdued: return @”SUBDUED”; } return nil;}
Old Code: New Code:
Snapshot Test Case Failures
2013-09-24 17:59:01.743 FBAppKitTestHost[44975:a0b] If you have Kaleidoscope installed you can run this command to see an image diff:ksdiff "/Users/adamjernst/Library/Application Support/iPhone Simulator/7.0/Applications/D85DEF94-79B2-49AB-ABAA-093044D754CF/tmp/FBMegaphoneViewSnapshotTests/[email protected]" "/Users/adamjernst/Library/Application Support/iPhone Simulator/7.0/Applications/D85DEF94-79B2-49AB-ABAA-093044D754CF/tmp/FBMegaphoneViewSnapshotTests/[email protected]"/Users/adamjernst/Documents/fbobjc/Libraries/FBAppKit/FBAppKitTests/FBMegaphoneViewSnapshotTests.m:276: SenTestFailureException: "comparisonSuccess__" should be true. Snapshot comparison failed: Error Domain=FBTestSnapshotControllerErrorDomain Code=4 "Images different" UserInfo=0x7b660230 {NSLocalizedDescription=Images different}:
273 FBMegaphoneStoryView *view = [FBMegaphoneStoryView viewForMegaphone:megaphone target:nil frame:CGRectMake(0, 0, 768, 320)];274 NSString *newIdentifier = identifier.length ? [NSString stringWithFormat:@"%@_pad", identifier] : @"pad";275 [view sizeToFit];276 FBSnapshotVerifyView(view, newIdentifier); ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
github.com/facebook/ios-snapshot-test-case
NEW
Watchdog Timer
Main Thread work work work work workwork
Watchdog Timer
Main Thread work work work work workwork
Watchdog Thread
ping ac
k
ping ac
k
ping ac
k
ping ac
k
ping ac
k
ping
Uh oh! No ack.Log backtrace.
Watchdog Timer: How it Works
▪Max-priority thread pings main thread every X seconds
▪ If main thread doesn’t respond in time…
▪ Freeze the main thread
▪ Get the backtrace to see what code is running
▪ Log it to our servers for analysis
github.com/facebook/ios-watchdog-timer
NEW
Rage Shake
▪Shake the device to report a bug
▪Captures:
▪ Screen shot (with annotations!)
▪ Network logs
▪ Last crash log
▪ Last x-seconds of logging
▪ Dumps the view hierarchy
▪Automatically files a bug and sends it to Facebook
Internal Settings
▪Toggle features on and off
▪Change parameters
▪Trigger events
Future of iOS @ Facebook