Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Controlling Complexity in Swift; or, Making Fri...

Controlling Complexity in Swift; or, Making Friends with Value

People tell you that you’re supposed to avoid mutable state, but how can anything happen if you never call a setter? People tell you that you’re supposed to write unit tests, but how can you test a user interaction? People tell you that you’re supposed to make your code reusable, but how can you factor it out of your enormous view controllers?

This talk presents a pragmatic approach to managing complexity in inherently stateful systems. We’ll take the best from the ivory tower and drag it down with us into the muck of the “real world.” You’ll leave with practical strategies for making large swaths of your code stateless and for confining the rest within well-understood boundaries.

Andy Matuschak

January 08, 2015
Tweet

Other Decks in Programming

Transcript

  1. CONTROLLING COMPLEXITY IN SWIFT (or) MAKING FRIENDS WITH VALUE TYPES

    Andy Matuschak ANDYMATUSCHAK.ORG / @ANDY_MATUSCHAK
  2. $ grep -e "^struct " stdlib.swift | wc -l 78

    $ grep -e "^enum " stdlib.swift | wc -l 8
  3. INT, FLOAT, BOOL, ETC. var a = 10 var b

    = a // a = 10; b = 10 b = 5 // a = 10; b = 5
  4. 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]
  5. STRUCTS, ENUMS, TUPLES var a = CGSize(width: 5, height: 5)

    var b = a // a = 5x5; b = 5x5 b.width = 10 // a = 5x5; b = 5x10
  6. OBJECTS var a = UIView() var b = a //

    a.alpha = 1; b.alpha = 1 b.alpha = 0 // a.alpha = 0; b.alpha = 0
  7. extension CGPoint { func distanceTo(_ point: CGPoint) { let dx

    = self.x - point.x let dy = self.y - point.y return sqrt(dx * dx + dy * dy) } }
  8. 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 }
  9. class MyView { var numberOfBloops: Int { didSet { UIView.animateWithDuration(1,

    animations: { center.x = numberOfBloops * 10 }, completion: { _ in center.x = 0 }) } } }
  10. class User { ... } class ViewController { var user:

    User } class NetworkOperation { init(user: User) }
  11. 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 }
  12. let drawing = ... let projectedSample = projectNextTouchSample(drawing.actions.last!.samples) var projectedDrawing

    = drawing projectedDrawing.actions.last!.append(projectedSample) renderDrawing(projectedDrawing)
  13. *

  14. 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)
  15. 1. Incorporate touch into Drawing 2. Estimate touch velocity 3.

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

    Smooth touch sample curves 4. Compute stroke geometry 5. Render stroke
  17. 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
  18. 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
  19. 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
  20. 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
  21. SO

  22. FURTHER READING ▸ Boundaries — Gary Bernhardt ▸ Are We

    There Yet? — Rich Hickey ▸ SICP — Abelson & Sussman ▸ Enemy of the State — Justin Spahr-Summers