Slide 1

Slide 1 text

CONTROLLING COMPLEXITY IN SWIFT (or) MAKING FRIENDS WITH VALUE TYPES Andy Matuschak ANDYMATUSCHAK.ORG / @ANDY_MATUSCHAK

Slide 2

Slide 2 text

COMPLEXITY

Slide 3

Slide 3 text

TASTE VS ABILITY

Slide 4

Slide 4 text

FOCUSING OUR PATHS

Slide 5

Slide 5 text

FOCUSING OUR CONTROL FLOW

Slide 6

Slide 6 text

FOCUSING OUR DEPENDENCIES

Slide 7

Slide 7 text

FOCUSING OUR EFFECTS

Slide 8

Slide 8 text

FOCUSING OUR thought

Slide 9

Slide 9 text

No content

Slide 10

Slide 10 text

VALUES

Slide 11

Slide 11 text

1. THE VALUE OF VALUES

Slide 12

Slide 12 text

1. THE VALUE OF VALUES 2. THE OBJECT OF OBJECTS

Slide 13

Slide 13 text

1. THE VALUE OF VALUES 2. THE OBJECT OF OBJECTS 3. EVERYTHING IN ITS PLACE

Slide 14

Slide 14 text

1. THE VALUE OF VALUES

Slide 15

Slide 15 text

@interface Object.new

Slide 16

Slide 16 text

STDLIB?!

Slide 17

Slide 17 text

$ grep -e "^class " stdlib.swift | wc -l 1

Slide 18

Slide 18 text

$ grep -e "^struct " stdlib.swift | wc -l 78 $ grep -e "^enum " stdlib.swift | wc -l 8

Slide 19

Slide 19 text

“VALUE TYPES”

Slide 20

Slide 20 text

“VALUE TYPES” COPIED ON ASSIGNMENT SINGLE OWNER

Slide 21

Slide 21 text

INT, FLOAT, BOOL, ETC. var a = 10 var b = a // a = 10; b = 10 b = 5 // a = 10; b = 5

Slide 22

Slide 22 text

STRING, ARRAY, DICTIONARY var a = [1, 2, 3] var b = a // a = [1, 2, 3]; b = [1, 2, 3] b.append(4) // a = [1, 2, 3]; b = [1, 2, 3, 4]

Slide 23

Slide 23 text

STRUCTS, ENUMS, TUPLES var a = CGSize(width: 5, height: 5) var b = a // a = 5x5; b = 5x5 b.width = 10 // a = 5x5; b = 5x10

Slide 24

Slide 24 text

“REFERENCE TYPES” SHARED ON ASSIGNMENT MULTIPLE OWNERS

Slide 25

Slide 25 text

OBJECTS var a = UIView() var b = a // a.alpha = 1; b.alpha = 1 b.alpha = 0 // a.alpha = 0; b.alpha = 0

Slide 26

Slide 26 text

INTUITION: OBJECTS ARE LIKE OBJECTS

Slide 27

Slide 27 text

INTUITION: VALUES ARE LIKE DATA

Slide 28

Slide 28 text

VALUES ARE SIMPLER

Slide 29

Slide 29 text

extension CGPoint { func distanceTo(_ point: CGPoint) { let dx = self.x - point.x let dy = self.y - point.y return sqrt(dx * dx + dy * dy) } }

Slide 30

Slide 30 text

struct Drawing { var actions: [DrawingAction] } struct DrawingAction { var samples: [TouchSample] var tool: Tool enum Tool { case Pencil(color: UIColor) case Eraser(width: CGFloat) } } struct TouchSample { var location: CGPoint var timestamp: NSTimeInterval }

Slide 31

Slide 31 text

SWIFT <3 VALUES

Slide 32

Slide 32 text

THE 3 I'S 1. INERT 2. ISOLATED 3. INTERCHANGEABLE

Slide 33

Slide 33 text

1. INERT

Slide 34

Slide 34 text

class MyView { var numberOfBloops: Int { didSet { UIView.animateWithDuration(1, animations: { center.x = numberOfBloops * 10 }, completion: { _ in center.x = 0 }) } } }

Slide 35

Slide 35 text

2. ISOLATED

Slide 36

Slide 36 text

class User { ... } class ViewController { var user: User } class NetworkOperation { init(user: User) }

Slide 37

Slide 37 text

3. INTERCHANGEABLE

Slide 38

Slide 38 text

EVER TRIED MAKING A UITouch?

Slide 39

Slide 39 text

YOU CAN'T MOVE YOUR BOUNDARIES

Slide 40

Slide 40 text

struct Drawing { var actions: [DrawingAction] } struct DrawingAction { var samples: [TouchSample] var tool: Tool enum Tool { case Pencil(color: UIColor) case Eraser(width: CGFloat) } } struct TouchSample { var location: CGPoint var timestamp: NSTimeInterval }

Slide 41

Slide 41 text

func renderDrawing(drawing: Drawing) -> UIImage

Slide 42

Slide 42 text

extension TouchSample { static func projectNextTouchSample (fromSamples: [TouchSample]) -> TouchSample }

Slide 43

Slide 43 text

let drawing = ... let projectedSample = projectNextTouchSample(drawing.actions.last!.samples) var projectedDrawing = drawing projectedDrawing.actions.last!.append(projectedSample) renderDrawing(projectedDrawing)

Slide 44

Slide 44 text

MOCKING

Slide 45

Slide 45 text

THE 3 I'S 1. INERT 2. ISOLATED 3. INTERCHANGEABLE

Slide 46

Slide 46 text

*

Slide 47

Slide 47 text

* struct Hmmmm { let someData: Int let aView: UIView }

Slide 48

Slide 48 text

1. THE VALUE OF VALUES 2. THE OBJECT OF OBJECTS 3. EVERYTHING IN ITS PLACE

Slide 49

Slide 49 text

2. THE OBJECT OF OBJECTS

Slide 50

Slide 50 text

OBJECTS BEHAVE AND RESPOND

Slide 51

Slide 51 text

BUT VALUES ARE DEAD

Slide 52

Slide 52 text

No content

Slide 53

Slide 53 text

MANY DEAD VALUES CAN MAKE ONE LIVING IDENTITY

Slide 54

Slide 54 text

class CanvasController { var currentDrawing: Drawing /* ... */ } struct Drawing { /* ... */ }

Slide 55

Slide 55 text

STATE: AN IDENTITY'S VALUE AT SOME TIME

Slide 56

Slide 56 text

VALUE: INERT DATA (DRAWING) IDENTITY: VALUES RELATED IN TIME (DRAWING) > (DRAWING) > (DRAWING) > (DRAWING) STATE: AN IDENTITY'S VALUE AT SOME TIME (DRAWING) > (DRAWING) > (DRAWING) > (DRAWING)

Slide 57

Slide 57 text

SO, OBJECTS

Slide 58

Slide 58 text

OBJECTS REPRESENT IDENTITY MANAGE STATE TRANSITIONS PERFORM SIDE EFFECTS

Slide 59

Slide 59 text

class CanvasController { var currentDrawing: Drawing func handleTouch(touch: UITouch) { currentDrawing = ... } }

Slide 60

Slide 60 text

1. THE VALUE OF VALUES 2. THE OBJECT OF OBJECTS 3. EVERYTHING IN ITS PLACE

Slide 61

Slide 61 text

3. EVERYTHING IN ITS PLACE

Slide 62

Slide 62 text

OBJECT LAYER VALUE LAYER

Slide 63

Slide 63 text

OBJECT LAYER VALUE LAYER

Slide 64

Slide 64 text

WHY SEPARATE?

Slide 65

Slide 65 text

“SEPARATE LOGIC FROM ACTION”

Slide 66

Slide 66 text

THE VALUE GAME

Slide 67

Slide 67 text

THE VALUE GAME MAXIMIZE THE VALUE LAYER

Slide 68

Slide 68 text

1. Incorporate touch into Drawing

Slide 69

Slide 69 text

1. Incorporate touch into Drawing 2. Estimate touch velocity

Slide 70

Slide 70 text

1. Incorporate touch into Drawing 2. Estimate touch velocity 3. Smooth touch sample curves

Slide 71

Slide 71 text

1. Incorporate touch into Drawing 2. Estimate touch velocity 3. Smooth touch sample curves 4. Compute stroke geometry

Slide 72

Slide 72 text

1. Incorporate touch into Drawing 2. Estimate touch velocity 3. Smooth touch sample curves 4. Compute stroke geometry 5. Render stroke

Slide 73

Slide 73 text

UIVIEW!

Slide 74

Slide 74 text

UIVIEW! MEHHH

Slide 75

Slide 75 text

extension TouchSample { static func estimateVelocities(samples: [TouchSample]) -> [CGPoint] } 1. Incorporate touch into Drawing 2. Estimate touch velocity 3. Smooth touch sample curves 4. Compute stroke geometry 5. Render stroke

Slide 76

Slide 76 text

extension TouchSample { static func smoothTouchSamples(samples: [TouchSample]) -> [TouchSample] } 1. Incorporate touch into Drawing 2. Estimate touch velocity 3. Smooth touch sample curves 4. Compute stroke geometry 5. Render stroke

Slide 77

Slide 77 text

struct PencilBrush { func pathForDrawingAction(action: DrawingAction) -> UIBezierPath } 1. Incorporate touch into Drawing 2. Estimate touch velocity 3. Smooth touch sample curves 4. Compute stroke geometry 5. Render stroke

Slide 78

Slide 78 text

extension Drawing { mutating func appendTouchSample(sample: TouchSample) } 1. Incorporate touch into Drawing (+ update state) 2. Estimate touch velocity 3. Smooth touch sample curves 4. Compute stroke geometry 5. Render stroke

Slide 79

Slide 79 text

OBJECT LAYER VALUE LAYER

Slide 80

Slide 80 text

FUNCTIONAL CORE IMPERATIVE SHELL

Slide 81

Slide 81 text

1. THE VALUE OF VALUES 2. THE OBJECT OF OBJECTS 3. EVERYTHING IN ITS PLACE

Slide 82

Slide 82 text

SO

Slide 83

Slide 83 text

FOCUSING OUR CONTROL FLOW

Slide 84

Slide 84 text

FOCUSING OUR DEPENDENCIES

Slide 85

Slide 85 text

FOCUSING OUR EFFECTS

Slide 86

Slide 86 text

OBJECT LAYER VALUE LAYER

Slide 87

Slide 87 text

FURTHER READING ▸ Boundaries — Gary Bernhardt ▸ Are We There Yet? — Rich Hickey ▸ SICP — Abelson & Sussman ▸ Enemy of the State — Justin Spahr-Summers

Slide 88

Slide 88 text

Thanks.

Slide 89

Slide 89 text

‽ ANDYMATUSCHAK.ORG @ANDY_MATUSCHAK