"architecting and testing large ios apps: lessons from facebook". adam ernst, facebook
Post on 21-Oct-2014
2.973 views
DESCRIPTION
In 2012 Facebook relaunched their iOS app to use native code. This was a big shift in architecting and implementing the Facebook app experience, the most widely used third party app on the entire iOS platform. Adam Ernst will speak about how the decision was made to switch to native code and how the company prepared to rewrite the app. He will share an inside look at the APIs and technical architecture Facebook uses to enable dozens of iOS developers to work on the same application. Automated testing is very important to Facebook, so Adam will also speak about how Facebook uses testing on iOS to keep the app reliable.TRANSCRIPT
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