SlideShare a Scribd company logo
1 of 57
Download to read offline
Thinking in Swift: Lessons
Learned from Converting a
Legacy Robotics
Project To Swift
Janie Clayton
About Me
• Software Developer at Black
Pixel
• Team Lead of the Swift Team
for RayWenderlich.com
• Coauthor of “iOS 8 SDK
Development” and “The Swift
Apprentice”
• @RedQueenCoder
• http://redqueencoder.com
Microplotter II
-[NSAlert alertWithError:] called with nil NSError.
A generic error message will be displayed,
but the user deserves better.
Most Common Issues
Silent nil messaging failures
“Faith-based casting”
Unexpected object coupling
Error handling problems
Nil: The Silent Killer
The $10,000 Bug
Silent Failure: Feature or
Bug?
Dereferencing null pointers causes crashes in C and C++.
Null pointers also cause random behavior and memory
corruption.
Rather than crash if there is nothing at the pointer,
Objective-C sends messages to nil, which effectively does
nothing
Does not warn or alert you that the message isn’t being
received by anything.
Nil Messages!!
Nil-Messaging Accessors
Inheriting from NSObject: nil
Int: 0
Float: 0.0
Double: 0.0
Why Required Values are a
Good Thing
In Objective-C, optional values are the default rather
than something you choose to opt into.
Compiler enforced rules force you to ensure your
values are compliant or else it won’t let you build.
These compiler enforced rules catch bugs before they
are released out into the field.
Compile-time prevention > unit test catches > crashes
in QA testing > bugs in the field
Type Safety in Swift
Prevents “faith-based casting”
What does an NSArray take in and give out?
NSNotifications?
Compiler-defined interfaces
Like putting together pieces in a puzzle
Example: fixed-length arrays using tuples
Property List Serialization
NSUserDefaults
Serialize data to make it easily storable
Cocoa way: Use NSCoder to convert types
to NSData to be stored and extracted later.
Issues with NSCoding
Weak type safety, with potential security and stability
issues
Only works on descendants of NSObject, which does
not include Swift structs or enums
NSData is essentially “Grey Goo” in that it is a blob of
data that is not human readable.
struct Coordinate {
let x:Double
let y:Double
let z:Double
init(_ x: Double, _ y:Double, _ z:Double)
{
self.x = x
self.y = y
self.z = z
}
}
protocol PropertyListReadable
{
func propertyListRepresentation() -> NSDictionary
init?(propertyListRepresentation:NSDictionary?)
}
extension Coordinate:PropertyListReadable {
func propertyListRepresentation() -> NSDictionary
{
let representation:[String:AnyObject] =
[“x”:self.x, “y”:self.y, “z”:self.z]
return representation
}
init?(propertyListRepresentation:NSDictionary?) {
guard let values = propertyListRepresentation
else return {nil}
if let xCoordinate = values[“x”] as? Double,
yCoordinate = values[“y”] as? Double,
zCoordinate = values[“z”] as? Double {
self.x = xCoordinate
self.y = yCoordinate
self.z = zCoordinate
} else {
return nil
}
}
1.1
2.0
1.2
func
saveValuesToDefault<T:PropertyListReadable>
(newValues:[T], key:String)
{
let encodedValues = newValues
.map{$0.propertyListRepresentation()}
NSUserDefaults.standardUserDefaults()
.setObject(encodedValues, forKey:key)
}
[“savedPositions”:
[[firstCoordinateNSDictionary],
[secondCoordinateNSDictionary],
[thirdCoordinateNSDictionary]]
]
func
extractValuesFromPropertyListArray<PropertyListReadable>
(propertyListArray:[AnyObject]?) -> [T]
{
guard let encodedArray = propertyListArray as?
[NSDictionary] else {return []}
return encodedArray
.map{T(propertyListRepresentation:$0)}
.filter{ $0 != nil }
.map{ $0! }
}
encodedArray
.map{T(propertyListRepresentation:$0)}
.filter{ $0 != nil }
.map{ $0! }
encodedArray
.flatMap{T(propertyListRepresentation:$0)}
guard let encodedArray = propertyListArray as?
[NSDictionary] else {return []}
guard let encodedArray = propertyListArray
else {return []}
func
extractValuesFromPropertyListArray<PropertyListReadable>
(propertyListArray:[AnyObject]?) -> [T]
{
guard let encodedArray = propertyListArray else
{return []}
return encodedArray.map{$0 as? NSDictionary}
.flatMap{T(propertyListRepresentation:$0)}
}
Reducing Mutability
Why Reducing Mutability is
Good
If a lot of objects look at and can write to the same
object, one can change it underneath another one
Our robotics might expect a value to be one thing, but
another piece of code might change it and confuse the
robotics, which can cause physical damage that is $$$
Creates code coupling, aka Spaghetti Code. Huzzah!
Untestable Code
Code coupling made our code untestable because no
one piece could be isolated from any other piece
The code base became unstable and bugs took longer
and longer to find and to fix
It also became more difficult to add new features to the
code because the code would break
Taking the lessons learned from maintaining a 7-year-
old project allowed us to re-architect the software in a
more stable manner
Values Types vs
Reference Types
Objects and Objective-C
Objects were the only way to encapsulate data and the
code that acted on the data in Objective-C
The Cocoa Frameworks were designed around the
idea that everything would be an object
All Objective-C objects were passed by reference
Swift Structs and Enums
Allowed other ways of encapsulating data besides just
classes.
Far more powerful and feature rich than C structs and
enums
Allows you to differentiate between passing values and
passing references.
When to use a class?
Use a class when you want shared references
Use a class if you need traditional inheritance
Use and enum if you need to represent distinct
options
Use a struct for all other structured values
Error Handling
Where is it most important to make
sure you have error handling?
Interacting with the file system
Interacting with hardware
Communication over a network
Why Error Handling is
Important
You do have complete control over your application.
You don’t have complete control over the outside
world.
You have to deal with error handling when you are
interacting with the outside world and it can fail in weird
ways.
Problems with Objective-C
Error Handling
A method / function can only return one value
✨ Magic constants ✨
Error scribbling and code crashes
http://edgecasesshow.com/007-if-you-look-at-the-
error-you-will-crash.html
Verbose and easy to forget to handle all the failure
states
- (Coordinate *)moveToCoordinate:(Coordinate *)targetCoordinate error:(NSError **)error
{
if (targetCoordinate == nil){
if (error != nil){
*error = [self errorForRoboticsErrorCode:BADCOORDINATE];
}
return nil;
}
if(![self moveUp error:error]){
return nil;
}
if(![self moveOverCoordinate:targetCoordinate error:error]){
return nil;
}
Coordinate *newPosition = [self readCurrentCoordinate:error];
if(newPosition == nil){
return nil;
}
if(!newPosition.isEqualTo(targetCoordinate)){
if (error != NULL){
*error = [self errorForRoboticsErrorCode:MISMATCHEDPOSITIONS]
}
return nil;
}
return newPosition;
}
Swift 1.0 and Result Type
Uses generics and enums with associated values to create a
reusable return type
Two cases: Success(value) and Failure(error)
Forces you to handle the errors if you want the success value
No need for magic constants or inputs as outputs
Allows us use error types other than NSError, like custom
Swift enums
public enum Result<T, U>{
case Success<T>
case Failure<U>
func then<V>(nextOperation:T -> Result<V, U>)
-> Result<V, U> {
switch self {
case let .Failure(error):
return .Failure(error)
case let .Success(value):
return nextOperation(value)
}
}
}
enum RoboticsError {
case MismatchedPosition
case HitObstruction
case NotConnected
}
func moveToCoordinate(targetCoordinate:Coordinate) ->
Result<Coordinate, RoboticsError>
{
return self.moveUp()
.then{self.moveOverCoordinate(targetCoordinate)}
.then{self.moveDownCoordinate(targetCoordinate)}
.then{self.readCurrentCoordinate()}
.then{coordinate -> Result<Coordinate,
RoboticsError> in
if (coordinate != targetCoordinate) {
return .Failure(.MismatchedPosition)
} else {
return .Success(coordinate)
}
}
}
Advantages of Result Error
Handling
Compiler-enforced error handling for return values
Uses less code (go from 38 lines of code to 12)
Inputs are inputs, outputs are outputs
More human readable by removing boilerplate code
Issues with Result Error
Handling
Odd code flow with return statement at top
Really long chained statements can choke the compiler
Have to enclose non-Result-returning functions in
awkward closures
Easy to ignore errors from functions that don’t return
values
Swift 2.0 Error Handling
Introduced a try/catch error handling model
At a glance, very different from Result<T,U>, but in
practice very similar
Not at all NSException
Compiler forces you to handle or rethrow every error,
ensuring proper error handling
Do, Try, Catch, Throw, and
Throws
If you have a method that can provide an error, you
specify that it “throws” in the signature
To call an error throwing function, you must call it with
“try”
First “try” line that fails kicks out of the function / method
To catch the error, you use a “do/catch” block
To bubble the error up, “throw” the error
func moveToCoordinate(targetCoordinate: Coordinate)
throws -> Coordinate
{
try self.moveUp()
try self.moveOverCoordinate(targetCoordinate)
try self.moveDownToCoordinate(targetCoordinate)
let coordinate = try self.readCurrentCoordinate()
if(coordinate != targetCoordinate) {
throw .MismatchedPosition
}
return coordinate
}
Advantages over Result<T,U>
Even fewer lines of code (9 vs. 12)
More natural execution flow (return at end)
Fewer braces, no more artificial closures
Compiler-enforced handling of errors, even for
functions with no return values
Swift Wins
Our current code base is 75% smaller than the legacy
code base
Removed whole classes of bugs so that they can’t
even happen
Identified subtle bugs that would have taken weeks to
track down and have caused thousands of dollars in
damages
We can now implement new features that weren’t
possible before because the code was too fragile
Swift Wins
We now have unit tests that we could not implement in
the old code because of mutability and code coupling.
We are able to do sophisticated unit testing using fake
robots and serial ports in code that don’t require us to
connect to hardware.
Links and Questions
http://www.sunsetlakesoftware.com/2014/12/02/why-were-
rewriting-our-robotics-software-swift
http://redqueencoder.com/property-lists-and-user-defaults-in-swift/
http://www.sunsetlakesoftware.com/2015/06/12/swift-2-error-
handling-practice
https://github.com/LlamaKit/LlamaKit
http://edgecasesshow.com/007-if-you-look-at-the-error-you-will-
crash.html

More Related Content

What's hot

Javascript best practices
Javascript best practicesJavascript best practices
Javascript best practices
Manav Gupta
 
Finding bugs that matter with Findbugs
Finding bugs that matter with FindbugsFinding bugs that matter with Findbugs
Finding bugs that matter with Findbugs
Carol McDonald
 

What's hot (20)

Design patterns illustrated-2015-03
Design patterns illustrated-2015-03Design patterns illustrated-2015-03
Design patterns illustrated-2015-03
 
Javascript best practices
Javascript best practicesJavascript best practices
Javascript best practices
 
Unit I Advanced Java Programming Course
Unit I   Advanced Java Programming CourseUnit I   Advanced Java Programming Course
Unit I Advanced Java Programming Course
 
Objective c runtime
Objective c runtimeObjective c runtime
Objective c runtime
 
One Careful Owner
One Careful OwnerOne Careful Owner
One Careful Owner
 
Zero, one, two, Freddy's coming for you
Zero, one, two, Freddy's coming for youZero, one, two, Freddy's coming for you
Zero, one, two, Freddy's coming for you
 
Javascript
JavascriptJavascript
Javascript
 
JavaScript Basics and Best Practices - CC FE & UX
JavaScript Basics and Best Practices - CC FE & UXJavaScript Basics and Best Practices - CC FE & UX
JavaScript Basics and Best Practices - CC FE & UX
 
Lsl scripts
Lsl scriptsLsl scripts
Lsl scripts
 
Finding bugs that matter with Findbugs
Finding bugs that matter with FindbugsFinding bugs that matter with Findbugs
Finding bugs that matter with Findbugs
 
Clean Code 2
Clean Code 2Clean Code 2
Clean Code 2
 
Python Programming Essentials - M20 - Classes and Objects
Python Programming Essentials - M20 - Classes and ObjectsPython Programming Essentials - M20 - Classes and Objects
Python Programming Essentials - M20 - Classes and Objects
 
Oop2010 Scala Presentation Stal
Oop2010 Scala Presentation StalOop2010 Scala Presentation Stal
Oop2010 Scala Presentation Stal
 
Clean code & design patterns
Clean code & design patternsClean code & design patterns
Clean code & design patterns
 
Google Dart
Google DartGoogle Dart
Google Dart
 
Oop objects_classes
Oop objects_classesOop objects_classes
Oop objects_classes
 
Unethical JavaScript - Giorgio Natili - Codemotion Rome 2017
Unethical JavaScript - Giorgio Natili - Codemotion Rome 2017Unethical JavaScript - Giorgio Natili - Codemotion Rome 2017
Unethical JavaScript - Giorgio Natili - Codemotion Rome 2017
 
Overview Of Msil
Overview Of MsilOverview Of Msil
Overview Of Msil
 
Clean code
Clean codeClean code
Clean code
 
Java script
Java scriptJava script
Java script
 

Similar to Robots in Swift

Linq 1224887336792847 9
Linq 1224887336792847 9Linq 1224887336792847 9
Linq 1224887336792847 9
google
 
Linq To The Enterprise
Linq To The EnterpriseLinq To The Enterprise
Linq To The Enterprise
Daniel Egan
 

Similar to Robots in Swift (20)

Of complicacy of programming, or won't C# save us?
Of complicacy of programming, or won't C# save us?Of complicacy of programming, or won't C# save us?
Of complicacy of programming, or won't C# save us?
 
The First C# Project Analyzed
The First C# Project AnalyzedThe First C# Project Analyzed
The First C# Project Analyzed
 
Start with swift
Start with swiftStart with swift
Start with swift
 
Swift vs Objective-C
Swift vs Objective-CSwift vs Objective-C
Swift vs Objective-C
 
Javascript Best Practices
Javascript Best PracticesJavascript Best Practices
Javascript Best Practices
 
Linq 1224887336792847 9
Linq 1224887336792847 9Linq 1224887336792847 9
Linq 1224887336792847 9
 
Tdd is not about testing
Tdd is not about testingTdd is not about testing
Tdd is not about testing
 
PVS-Studio: analyzing ReactOS's code
PVS-Studio: analyzing ReactOS's codePVS-Studio: analyzing ReactOS's code
PVS-Studio: analyzing ReactOS's code
 
OOP, API Design and MVP
OOP, API Design and MVPOOP, API Design and MVP
OOP, API Design and MVP
 
Linq To The Enterprise
Linq To The EnterpriseLinq To The Enterprise
Linq To The Enterprise
 
HTML5 for the Silverlight Guy
HTML5 for the Silverlight GuyHTML5 for the Silverlight Guy
HTML5 for the Silverlight Guy
 
From C++ to Objective-C
From C++ to Objective-CFrom C++ to Objective-C
From C++ to Objective-C
 
Dsug 05 02-15 - ScalDI - lightweight DI in Scala
Dsug 05 02-15 - ScalDI - lightweight DI in ScalaDsug 05 02-15 - ScalDI - lightweight DI in Scala
Dsug 05 02-15 - ScalDI - lightweight DI in Scala
 
React native
React nativeReact native
React native
 
Looking for Bugs in MonoDevelop
Looking for Bugs in MonoDevelopLooking for Bugs in MonoDevelop
Looking for Bugs in MonoDevelop
 
Solid OOPS
Solid OOPSSolid OOPS
Solid OOPS
 
Working Effectively With Legacy Code
Working Effectively With Legacy CodeWorking Effectively With Legacy Code
Working Effectively With Legacy Code
 
PVS-Studio: analyzing ReactOS's code
PVS-Studio: analyzing ReactOS's codePVS-Studio: analyzing ReactOS's code
PVS-Studio: analyzing ReactOS's code
 
Java Programming
Java ProgrammingJava Programming
Java Programming
 
L04 Software Design Examples
L04 Software Design ExamplesL04 Software Design Examples
L04 Software Design Examples
 

More from Janie Clayton

More from Janie Clayton (10)

Beyond White: Embracing the iOS Design Aesthetic
Beyond White: Embracing the iOS Design AestheticBeyond White: Embracing the iOS Design Aesthetic
Beyond White: Embracing the iOS Design Aesthetic
 
3D Math Primer: CocoaConf Chicago
3D Math Primer: CocoaConf Chicago3D Math Primer: CocoaConf Chicago
3D Math Primer: CocoaConf Chicago
 
GPU Programming: Chicago CocoaConf 2015
GPU Programming: Chicago CocoaConf 2015GPU Programming: Chicago CocoaConf 2015
GPU Programming: Chicago CocoaConf 2015
 
3D Math Primer: CocoaConf Atlanta
3D Math Primer: CocoaConf Atlanta3D Math Primer: CocoaConf Atlanta
3D Math Primer: CocoaConf Atlanta
 
GPU Programming: CocoaConf Atlanta
GPU Programming: CocoaConf AtlantaGPU Programming: CocoaConf Atlanta
GPU Programming: CocoaConf Atlanta
 
3D Math Without Presenter Notes
3D Math Without Presenter Notes3D Math Without Presenter Notes
3D Math Without Presenter Notes
 
The Day You Finally Use Algebra: A 3D Math Primer
The Day You Finally Use Algebra: A 3D Math PrimerThe Day You Finally Use Algebra: A 3D Math Primer
The Day You Finally Use Algebra: A 3D Math Primer
 
GPU Programming 360iDev
GPU Programming 360iDevGPU Programming 360iDev
GPU Programming 360iDev
 
Bug Hunting Safari
Bug Hunting SafariBug Hunting Safari
Bug Hunting Safari
 
Gpu Programming With GPUImage and Metal
Gpu Programming With GPUImage and MetalGpu Programming With GPUImage and Metal
Gpu Programming With GPUImage and Metal
 

Recently uploaded

Recently uploaded (20)

Rising Above_ Dubai Floods and the Fortitude of Dubai International Airport.pdf
Rising Above_ Dubai Floods and the Fortitude of Dubai International Airport.pdfRising Above_ Dubai Floods and the Fortitude of Dubai International Airport.pdf
Rising Above_ Dubai Floods and the Fortitude of Dubai International Airport.pdf
 
Navigating the Deluge_ Dubai Floods and the Resilience of Dubai International...
Navigating the Deluge_ Dubai Floods and the Resilience of Dubai International...Navigating the Deluge_ Dubai Floods and the Resilience of Dubai International...
Navigating the Deluge_ Dubai Floods and the Resilience of Dubai International...
 
How to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected WorkerHow to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected Worker
 
EMPOWERMENT TECHNOLOGY GRADE 11 QUARTER 2 REVIEWER
EMPOWERMENT TECHNOLOGY GRADE 11 QUARTER 2 REVIEWEREMPOWERMENT TECHNOLOGY GRADE 11 QUARTER 2 REVIEWER
EMPOWERMENT TECHNOLOGY GRADE 11 QUARTER 2 REVIEWER
 
AWS Community Day CPH - Three problems of Terraform
AWS Community Day CPH - Three problems of TerraformAWS Community Day CPH - Three problems of Terraform
AWS Community Day CPH - Three problems of Terraform
 
Apidays New York 2024 - APIs in 2030: The Risk of Technological Sleepwalk by ...
Apidays New York 2024 - APIs in 2030: The Risk of Technological Sleepwalk by ...Apidays New York 2024 - APIs in 2030: The Risk of Technological Sleepwalk by ...
Apidays New York 2024 - APIs in 2030: The Risk of Technological Sleepwalk by ...
 
Exploring Multimodal Embeddings with Milvus
Exploring Multimodal Embeddings with MilvusExploring Multimodal Embeddings with Milvus
Exploring Multimodal Embeddings with Milvus
 
MINDCTI Revenue Release Quarter One 2024
MINDCTI Revenue Release Quarter One 2024MINDCTI Revenue Release Quarter One 2024
MINDCTI Revenue Release Quarter One 2024
 
Corporate and higher education May webinar.pptx
Corporate and higher education May webinar.pptxCorporate and higher education May webinar.pptx
Corporate and higher education May webinar.pptx
 
DEV meet-up UiPath Document Understanding May 7 2024 Amsterdam
DEV meet-up UiPath Document Understanding May 7 2024 AmsterdamDEV meet-up UiPath Document Understanding May 7 2024 Amsterdam
DEV meet-up UiPath Document Understanding May 7 2024 Amsterdam
 
Vector Search -An Introduction in Oracle Database 23ai.pptx
Vector Search -An Introduction in Oracle Database 23ai.pptxVector Search -An Introduction in Oracle Database 23ai.pptx
Vector Search -An Introduction in Oracle Database 23ai.pptx
 
ProductAnonymous-April2024-WinProductDiscovery-MelissaKlemke
ProductAnonymous-April2024-WinProductDiscovery-MelissaKlemkeProductAnonymous-April2024-WinProductDiscovery-MelissaKlemke
ProductAnonymous-April2024-WinProductDiscovery-MelissaKlemke
 
Six Myths about Ontologies: The Basics of Formal Ontology
Six Myths about Ontologies: The Basics of Formal OntologySix Myths about Ontologies: The Basics of Formal Ontology
Six Myths about Ontologies: The Basics of Formal Ontology
 
CNIC Information System with Pakdata Cf In Pakistan
CNIC Information System with Pakdata Cf In PakistanCNIC Information System with Pakdata Cf In Pakistan
CNIC Information System with Pakdata Cf In Pakistan
 
Introduction to Multilingual Retrieval Augmented Generation (RAG)
Introduction to Multilingual Retrieval Augmented Generation (RAG)Introduction to Multilingual Retrieval Augmented Generation (RAG)
Introduction to Multilingual Retrieval Augmented Generation (RAG)
 
Connector Corner: Accelerate revenue generation using UiPath API-centric busi...
Connector Corner: Accelerate revenue generation using UiPath API-centric busi...Connector Corner: Accelerate revenue generation using UiPath API-centric busi...
Connector Corner: Accelerate revenue generation using UiPath API-centric busi...
 
Repurposing LNG terminals for Hydrogen Ammonia: Feasibility and Cost Saving
Repurposing LNG terminals for Hydrogen Ammonia: Feasibility and Cost SavingRepurposing LNG terminals for Hydrogen Ammonia: Feasibility and Cost Saving
Repurposing LNG terminals for Hydrogen Ammonia: Feasibility and Cost Saving
 
DBX First Quarter 2024 Investor Presentation
DBX First Quarter 2024 Investor PresentationDBX First Quarter 2024 Investor Presentation
DBX First Quarter 2024 Investor Presentation
 
Strategize a Smooth Tenant-to-tenant Migration and Copilot Takeoff
Strategize a Smooth Tenant-to-tenant Migration and Copilot TakeoffStrategize a Smooth Tenant-to-tenant Migration and Copilot Takeoff
Strategize a Smooth Tenant-to-tenant Migration and Copilot Takeoff
 
Apidays New York 2024 - Scaling API-first by Ian Reasor and Radu Cotescu, Adobe
Apidays New York 2024 - Scaling API-first by Ian Reasor and Radu Cotescu, AdobeApidays New York 2024 - Scaling API-first by Ian Reasor and Radu Cotescu, Adobe
Apidays New York 2024 - Scaling API-first by Ian Reasor and Radu Cotescu, Adobe
 

Robots in Swift

  • 1. Thinking in Swift: Lessons Learned from Converting a Legacy Robotics Project To Swift Janie Clayton
  • 2. About Me • Software Developer at Black Pixel • Team Lead of the Swift Team for RayWenderlich.com • Coauthor of “iOS 8 SDK Development” and “The Swift Apprentice” • @RedQueenCoder • http://redqueencoder.com
  • 3.
  • 5.
  • 6. -[NSAlert alertWithError:] called with nil NSError. A generic error message will be displayed, but the user deserves better.
  • 7. Most Common Issues Silent nil messaging failures “Faith-based casting” Unexpected object coupling Error handling problems
  • 8. Nil: The Silent Killer The $10,000 Bug
  • 9. Silent Failure: Feature or Bug? Dereferencing null pointers causes crashes in C and C++. Null pointers also cause random behavior and memory corruption. Rather than crash if there is nothing at the pointer, Objective-C sends messages to nil, which effectively does nothing Does not warn or alert you that the message isn’t being received by anything.
  • 11. Nil-Messaging Accessors Inheriting from NSObject: nil Int: 0 Float: 0.0 Double: 0.0
  • 12.
  • 13. Why Required Values are a Good Thing In Objective-C, optional values are the default rather than something you choose to opt into. Compiler enforced rules force you to ensure your values are compliant or else it won’t let you build. These compiler enforced rules catch bugs before they are released out into the field. Compile-time prevention > unit test catches > crashes in QA testing > bugs in the field
  • 14. Type Safety in Swift Prevents “faith-based casting” What does an NSArray take in and give out? NSNotifications? Compiler-defined interfaces Like putting together pieces in a puzzle Example: fixed-length arrays using tuples
  • 15. Property List Serialization NSUserDefaults Serialize data to make it easily storable Cocoa way: Use NSCoder to convert types to NSData to be stored and extracted later.
  • 16. Issues with NSCoding Weak type safety, with potential security and stability issues Only works on descendants of NSObject, which does not include Swift structs or enums NSData is essentially “Grey Goo” in that it is a blob of data that is not human readable.
  • 17.
  • 18. struct Coordinate { let x:Double let y:Double let z:Double init(_ x: Double, _ y:Double, _ z:Double) { self.x = x self.y = y self.z = z } }
  • 19. protocol PropertyListReadable { func propertyListRepresentation() -> NSDictionary init?(propertyListRepresentation:NSDictionary?) }
  • 20. extension Coordinate:PropertyListReadable { func propertyListRepresentation() -> NSDictionary { let representation:[String:AnyObject] = [“x”:self.x, “y”:self.y, “z”:self.z] return representation } init?(propertyListRepresentation:NSDictionary?) { guard let values = propertyListRepresentation else return {nil} if let xCoordinate = values[“x”] as? Double, yCoordinate = values[“y”] as? Double, zCoordinate = values[“z”] as? Double { self.x = xCoordinate self.y = yCoordinate self.z = zCoordinate } else { return nil } } 1.1 2.0 1.2
  • 21. func saveValuesToDefault<T:PropertyListReadable> (newValues:[T], key:String) { let encodedValues = newValues .map{$0.propertyListRepresentation()} NSUserDefaults.standardUserDefaults() .setObject(encodedValues, forKey:key) }
  • 23. func extractValuesFromPropertyListArray<PropertyListReadable> (propertyListArray:[AnyObject]?) -> [T] { guard let encodedArray = propertyListArray as? [NSDictionary] else {return []} return encodedArray .map{T(propertyListRepresentation:$0)} .filter{ $0 != nil } .map{ $0! } }
  • 26. guard let encodedArray = propertyListArray as? [NSDictionary] else {return []}
  • 27. guard let encodedArray = propertyListArray else {return []}
  • 28. func extractValuesFromPropertyListArray<PropertyListReadable> (propertyListArray:[AnyObject]?) -> [T] { guard let encodedArray = propertyListArray else {return []} return encodedArray.map{$0 as? NSDictionary} .flatMap{T(propertyListRepresentation:$0)} }
  • 30.
  • 31. Why Reducing Mutability is Good If a lot of objects look at and can write to the same object, one can change it underneath another one Our robotics might expect a value to be one thing, but another piece of code might change it and confuse the robotics, which can cause physical damage that is $$$ Creates code coupling, aka Spaghetti Code. Huzzah!
  • 32.
  • 33. Untestable Code Code coupling made our code untestable because no one piece could be isolated from any other piece The code base became unstable and bugs took longer and longer to find and to fix It also became more difficult to add new features to the code because the code would break Taking the lessons learned from maintaining a 7-year- old project allowed us to re-architect the software in a more stable manner
  • 35. Objects and Objective-C Objects were the only way to encapsulate data and the code that acted on the data in Objective-C The Cocoa Frameworks were designed around the idea that everything would be an object All Objective-C objects were passed by reference
  • 36. Swift Structs and Enums Allowed other ways of encapsulating data besides just classes. Far more powerful and feature rich than C structs and enums Allows you to differentiate between passing values and passing references.
  • 37. When to use a class? Use a class when you want shared references Use a class if you need traditional inheritance Use and enum if you need to represent distinct options Use a struct for all other structured values
  • 39.
  • 40. Where is it most important to make sure you have error handling? Interacting with the file system Interacting with hardware Communication over a network
  • 41. Why Error Handling is Important You do have complete control over your application. You don’t have complete control over the outside world. You have to deal with error handling when you are interacting with the outside world and it can fail in weird ways.
  • 42. Problems with Objective-C Error Handling A method / function can only return one value ✨ Magic constants ✨ Error scribbling and code crashes http://edgecasesshow.com/007-if-you-look-at-the- error-you-will-crash.html Verbose and easy to forget to handle all the failure states
  • 43. - (Coordinate *)moveToCoordinate:(Coordinate *)targetCoordinate error:(NSError **)error { if (targetCoordinate == nil){ if (error != nil){ *error = [self errorForRoboticsErrorCode:BADCOORDINATE]; } return nil; } if(![self moveUp error:error]){ return nil; } if(![self moveOverCoordinate:targetCoordinate error:error]){ return nil; } Coordinate *newPosition = [self readCurrentCoordinate:error]; if(newPosition == nil){ return nil; } if(!newPosition.isEqualTo(targetCoordinate)){ if (error != NULL){ *error = [self errorForRoboticsErrorCode:MISMATCHEDPOSITIONS] } return nil; } return newPosition; }
  • 44. Swift 1.0 and Result Type Uses generics and enums with associated values to create a reusable return type Two cases: Success(value) and Failure(error) Forces you to handle the errors if you want the success value No need for magic constants or inputs as outputs Allows us use error types other than NSError, like custom Swift enums
  • 45. public enum Result<T, U>{ case Success<T> case Failure<U> func then<V>(nextOperation:T -> Result<V, U>) -> Result<V, U> { switch self { case let .Failure(error): return .Failure(error) case let .Success(value): return nextOperation(value) } } }
  • 46. enum RoboticsError { case MismatchedPosition case HitObstruction case NotConnected }
  • 47. func moveToCoordinate(targetCoordinate:Coordinate) -> Result<Coordinate, RoboticsError> { return self.moveUp() .then{self.moveOverCoordinate(targetCoordinate)} .then{self.moveDownCoordinate(targetCoordinate)} .then{self.readCurrentCoordinate()} .then{coordinate -> Result<Coordinate, RoboticsError> in if (coordinate != targetCoordinate) { return .Failure(.MismatchedPosition) } else { return .Success(coordinate) } } }
  • 48. Advantages of Result Error Handling Compiler-enforced error handling for return values Uses less code (go from 38 lines of code to 12) Inputs are inputs, outputs are outputs More human readable by removing boilerplate code
  • 49. Issues with Result Error Handling Odd code flow with return statement at top Really long chained statements can choke the compiler Have to enclose non-Result-returning functions in awkward closures Easy to ignore errors from functions that don’t return values
  • 50.
  • 51. Swift 2.0 Error Handling Introduced a try/catch error handling model At a glance, very different from Result<T,U>, but in practice very similar Not at all NSException Compiler forces you to handle or rethrow every error, ensuring proper error handling
  • 52. Do, Try, Catch, Throw, and Throws If you have a method that can provide an error, you specify that it “throws” in the signature To call an error throwing function, you must call it with “try” First “try” line that fails kicks out of the function / method To catch the error, you use a “do/catch” block To bubble the error up, “throw” the error
  • 53. func moveToCoordinate(targetCoordinate: Coordinate) throws -> Coordinate { try self.moveUp() try self.moveOverCoordinate(targetCoordinate) try self.moveDownToCoordinate(targetCoordinate) let coordinate = try self.readCurrentCoordinate() if(coordinate != targetCoordinate) { throw .MismatchedPosition } return coordinate }
  • 54. Advantages over Result<T,U> Even fewer lines of code (9 vs. 12) More natural execution flow (return at end) Fewer braces, no more artificial closures Compiler-enforced handling of errors, even for functions with no return values
  • 55. Swift Wins Our current code base is 75% smaller than the legacy code base Removed whole classes of bugs so that they can’t even happen Identified subtle bugs that would have taken weeks to track down and have caused thousands of dollars in damages We can now implement new features that weren’t possible before because the code was too fragile
  • 56. Swift Wins We now have unit tests that we could not implement in the old code because of mutability and code coupling. We are able to do sophisticated unit testing using fake robots and serial ports in code that don’t require us to connect to hardware.