A Type is Worth a Thousand Tests - YOW! Conferences › yowconnected2016 › ...From Objective-C to...

60
Manuel M T Chakravarty Applicative & UNSW Australia A Type is Worth a Thousand Tests mchakravarty TacticalGrace justtesting.org haskellformac.com

Transcript of A Type is Worth a Thousand Tests - YOW! Conferences › yowconnected2016 › ...From Objective-C to...

Page 1: A Type is Worth a Thousand Tests - YOW! Conferences › yowconnected2016 › ...From Objective-C to Swift Higher-order functions & closures Value types (products & sums) Advanced type

Manuel M T ChakravartyApplicative & UNSW Australia

A Type is Worth a Thousand Tests

mchakravartyTacticalGracejusttesting.orghaskellformac.com

Page 2: A Type is Worth a Thousand Tests - YOW! Conferences › yowconnected2016 › ...From Objective-C to Swift Higher-order functions & closures Value types (products & sums) Advanced type

Swift

Let’s talk about…

Language Design Ecosystem

Why is it extraordinary

?

Page 3: A Type is Worth a Thousand Tests - YOW! Conferences › yowconnected2016 › ...From Objective-C to Swift Higher-order functions & closures Value types (products & sums) Advanced type

Unique Event

Page 4: A Type is Worth a Thousand Tests - YOW! Conferences › yowconnected2016 › ...From Objective-C to Swift Higher-order functions & closures Value types (products & sums) Advanced type

Swift

Java

Objective-C

C#

Scala

F#

Kotlin

Page 5: A Type is Worth a Thousand Tests - YOW! Conferences › yowconnected2016 › ...From Objective-C to Swift Higher-order functions & closures Value types (products & sums) Advanced type

Why do languages become popular?

Platforms

UnixC/C++ .NET

C#JVMJava

WebJavaScript

CloudPython/RubyCocoa

Objective-CSwift

Page 6: A Type is Worth a Thousand Tests - YOW! Conferences › yowconnected2016 › ...From Objective-C to Swift Higher-order functions & closures Value types (products & sums) Advanced type

Why will Swift be popular?

Why is it extraordinary

?

Page 7: A Type is Worth a Thousand Tests - YOW! Conferences › yowconnected2016 › ...From Objective-C to Swift Higher-order functions & closures Value types (products & sums) Advanced type

Functional Programming

Page 8: A Type is Worth a Thousand Tests - YOW! Conferences › yowconnected2016 › ...From Objective-C to Swift Higher-order functions & closures Value types (products & sums) Advanced type

From Objective-C to Swift

Higher-order functions

& closures

Value types (products & sums)

Advanced type system

Explicit control of mutability

Explicit optionals

Generics & protocols with

associated types

Type inferenceREPL

Pattern matchingλτ

Page 9: A Type is Worth a Thousand Tests - YOW! Conferences › yowconnected2016 › ...From Objective-C to Swift Higher-order functions & closures Value types (products & sums) Advanced type

“Swift encourages typed functional programming in a

mainstream language.”

Page 10: A Type is Worth a Thousand Tests - YOW! Conferences › yowconnected2016 › ...From Objective-C to Swift Higher-order functions & closures Value types (products & sums) Advanced type

Haskell for Mac

Adopting Swift right out of the gate

Page 11: A Type is Worth a Thousand Tests - YOW! Conferences › yowconnected2016 › ...From Objective-C to Swift Higher-order functions & closures Value types (products & sums) Advanced type

“Swift encourages typed functional programming in a

mainstream language.”

Page 12: A Type is Worth a Thousand Tests - YOW! Conferences › yowconnected2016 › ...From Objective-C to Swift Higher-order functions & closures Value types (products & sums) Advanced type

Why Type Systems?

Page 13: A Type is Worth a Thousand Tests - YOW! Conferences › yowconnected2016 › ...From Objective-C to Swift Higher-order functions & closures Value types (products & sums) Advanced type

Catch bugs & prevent crashes

Page 14: A Type is Worth a Thousand Tests - YOW! Conferences › yowconnected2016 › ...From Objective-C to Swift Higher-order functions & closures Value types (products & sums) Advanced type

Less testing!

Page 15: A Type is Worth a Thousand Tests - YOW! Conferences › yowconnected2016 › ...From Objective-C to Swift Higher-order functions & closures Value types (products & sums) Advanced type

“What if you could gain the same confidence in correctness

with fewer or simpler tests?”

Page 16: A Type is Worth a Thousand Tests - YOW! Conferences › yowconnected2016 › ...From Objective-C to Swift Higher-order functions & closures Value types (products & sums) Advanced type

Possible states of your application

Error states

Tested states

eliminate bugs

eliminate tests

with types

Page 17: A Type is Worth a Thousand Tests - YOW! Conferences › yowconnected2016 › ...From Objective-C to Swift Higher-order functions & closures Value types (products & sums) Advanced type

Are types restraints?

Page 18: A Type is Worth a Thousand Tests - YOW! Conferences › yowconnected2016 › ...From Objective-C to Swift Higher-order functions & closures Value types (products & sums) Advanced type

Types are a design tool!

Page 19: A Type is Worth a Thousand Tests - YOW! Conferences › yowconnected2016 › ...From Objective-C to Swift Higher-order functions & closures Value types (products & sums) Advanced type

Type Systems

Lang

uage

s Programs

“Make undesirable states unrepresentable.”

Page 20: A Type is Worth a Thousand Tests - YOW! Conferences › yowconnected2016 › ...From Objective-C to Swift Higher-order functions & closures Value types (products & sums) Advanced type

“Swift encourages typed functional programming in a

mainstream language.”Value typesImmutable model & UI state machines

Protocols with associated typesGeneric change propagation

Page 21: A Type is Worth a Thousand Tests - YOW! Conferences › yowconnected2016 › ...From Objective-C to Swift Higher-order functions & closures Value types (products & sums) Advanced type

Goals.app

Page 22: A Type is Worth a Thousand Tests - YOW! Conferences › yowconnected2016 › ...From Objective-C to Swift Higher-order functions & closures Value types (products & sums) Advanced type

Value Types Localise & structure change

Page 23: A Type is Worth a Thousand Tests - YOW! Conferences › yowconnected2016 › ...From Objective-C to Swift Higher-order functions & closures Value types (products & sums) Advanced type

Value types in Swift

struct Point { var x: Double var y: Double }

struct

enum Result<ResultType> { case result(value: ResultType) case error(err: NSError) }

enum with associated values

generic type parameter

Page 24: A Type is Worth a Thousand Tests - YOW! Conferences › yowconnected2016 › ...From Objective-C to Swift Higher-order functions & closures Value types (products & sums) Advanced type

Reference types versus value types

var v: RefPnt

class RefPnt { var x, y: Double … }

v = RefPnt(x: 0, y: 0) w = v w.x = 10

x: 0, y: 0var w: RefPnt

x: 10, y: 0

Page 25: A Type is Worth a Thousand Tests - YOW! Conferences › yowconnected2016 › ...From Objective-C to Swift Higher-order functions & closures Value types (products & sums) Advanced type

Reference types versus value types

var v: Point

struct Point { var x, y: Double }

v = Point(x: 0, y: 0) w = v w.x = 10

x: 0, y: 0

var w: Point x: 0, y: 0x: 10, y: 0

Page 26: A Type is Worth a Thousand Tests - YOW! Conferences › yowconnected2016 › ...From Objective-C to Swift Higher-order functions & closures Value types (products & sums) Advanced type

var v: Point x: 0, y: 0

var w: Point x: 0, y: 0x: 10, y: 0

Localise change

Facilitate local reasoning

Value types

Page 27: A Type is Worth a Thousand Tests - YOW! Conferences › yowconnected2016 › ...From Objective-C to Swift Higher-order functions & closures Value types (products & sums) Advanced type

Value Types Immutable Model

Page 28: A Type is Worth a Thousand Tests - YOW! Conferences › yowconnected2016 › ...From Objective-C to Swift Higher-order functions & closures Value types (products & sums) Advanced type

MVC & MVVM Architectures

Controller

ViewC Model

View ModelC

passed around as reference type

╳ Accidental changes

╳ Changes in wrong order

Page 29: A Type is Worth a Thousand Tests - YOW! Conferences › yowconnected2016 › ...From Objective-C to Swift Higher-order functions & closures Value types (products & sums) Advanced type

Immutable Goals

struct Goal { let uuid: UUID // fast equality var colour: UIColor var title: String var interval: GoalInterval var frequency: Int }

typealias GoalProgress = (goal: Goal, count: Int?)

typealias Goals = [GoalProgress] // array

Page 30: A Type is Worth a Thousand Tests - YOW! Conferences › yowconnected2016 › ...From Objective-C to Swift Higher-order functions & closures Value types (products & sums) Advanced type

Immutable Models Do Scale!

Haskell for MacUses an immutable model

Adopts Cocoa Document Architecture

“Functional Programming in a Stateful World” YOW! Lambda Jam 2015

(on speakerdeck.com)

Page 31: A Type is Worth a Thousand Tests - YOW! Conferences › yowconnected2016 › ...From Objective-C to Swift Higher-order functions & closures Value types (products & sums) Advanced type

But what if…

“Use an immutable wrapper API to wrap mutable structures.”

✓ React (Native)Virtual DOM wraps DOM

✓ Haskell SpriteKit — Haskell library bindingAlgebraic data type wraps SpriteKit’s mutable object graph

Page 32: A Type is Worth a Thousand Tests - YOW! Conferences › yowconnected2016 › ...From Objective-C to Swift Higher-order functions & closures Value types (products & sums) Advanced type

Replacing Tests

✓ Avoid accidental changes of model stateReplaces integration tests

✓ Avoid races on concurrent threadsOften not properly tested

Page 33: A Type is Worth a Thousand Tests - YOW! Conferences › yowconnected2016 › ...From Objective-C to Swift Higher-order functions & closures Value types (products & sums) Advanced type

Enums with Associated Values UI State Machines

Page 34: A Type is Worth a Thousand Tests - YOW! Conferences › yowconnected2016 › ...From Objective-C to Swift Higher-order functions & closures Value types (products & sums) Advanced type

Is goal active?

typealias GoalProgress = (goal: Goal, count: Int?) typealias Goals = [GoalProgress]

Need to be careful not to lose progress info

Page 35: A Type is Worth a Thousand Tests - YOW! Conferences › yowconnected2016 › ...From Objective-C to Swift Higher-order functions & closures Value types (products & sums) Advanced type

var goalsActivity: [Bool]

Not valid outside of editing mode

Page 36: A Type is Worth a Thousand Tests - YOW! Conferences › yowconnected2016 › ...From Objective-C to Swift Higher-order functions & closures Value types (products & sums) Advanced type

enum GoalsEditState { case displaying case editing(goalsActivity: [Bool]) }

var goalsActivity: [Bool]

Page 37: A Type is Worth a Thousand Tests - YOW! Conferences › yowconnected2016 › ...From Objective-C to Swift Higher-order functions & closures Value types (products & sums) Advanced type

enum GoalsEditState { case displaying case editing(goalsActivity: [Bool]) }

var editState: GoalsEditState = .displaying … switch editState { // change mode case .displaying: navigationItem.setLeftBarButton(nil, …) editState = .editing(goalsActivity: dataSource.goalsActivity)

case .editing(let goalsActivity): navigationItem.setLeftBarButton(addButton, …) dataSource.commitGoalsActivity(goalsActivity) editState = .displaying }

GoalsController: UITableViewController

* Animations* Highlight anything?

alter UI state

Page 38: A Type is Worth a Thousand Tests - YOW! Conferences › yowconnected2016 › ...From Objective-C to Swift Higher-order functions & closures Value types (products & sums) Advanced type

guard case .editing(var goalsActivity) = editState else { return }

let newIsActive = !goalsActivity[indexPath.item] cell.editingAccessoryType = newIsActive ? .checkmark : .none

access to mode-specific state is guarded

enum GoalsEditState { case displaying case editing(goalsActivity: [Bool]) }

GoalsController

Page 39: A Type is Worth a Thousand Tests - YOW! Conferences › yowconnected2016 › ...From Objective-C to Swift Higher-order functions & closures Value types (products & sums) Advanced type

Replacing Tests

✓ Avoid inconsistent state changesReplaces UI tests

✓ Avoid non-exhaustive transitionsReplaces exhaustiveness tests

Page 40: A Type is Worth a Thousand Tests - YOW! Conferences › yowconnected2016 › ...From Objective-C to Swift Higher-order functions & closures Value types (products & sums) Advanced type

Protocols with associated types Structured change propagation

Page 41: A Type is Worth a Thousand Tests - YOW! Conferences › yowconnected2016 › ...From Objective-C to Swift Higher-order functions & closures Value types (products & sums) Advanced type

“Now that the model layer is immutable, how do we change

anything?”

Page 42: A Type is Worth a Thousand Tests - YOW! Conferences › yowconnected2016 › ...From Objective-C to Swift Higher-order functions & closures Value types (products & sums) Advanced type

25Δt: 0sMutable Variable

Page 43: A Type is Worth a Thousand Tests - YOW! Conferences › yowconnected2016 › ...From Objective-C to Swift Higher-order functions & closures Value types (products & sums) Advanced type

7Δt: 1sMutable Variable

Page 44: A Type is Worth a Thousand Tests - YOW! Conferences › yowconnected2016 › ...From Objective-C to Swift Higher-order functions & closures Value types (products & sums) Advanced type

11Δt: 2sMutable Variable

Page 45: A Type is Worth a Thousand Tests - YOW! Conferences › yowconnected2016 › ...From Objective-C to Swift Higher-order functions & closures Value types (products & sums) Advanced type

73Δt: 3sMutable Variable

Page 46: A Type is Worth a Thousand Tests - YOW! Conferences › yowconnected2016 › ...From Objective-C to Swift Higher-order functions & closures Value types (products & sums) Advanced type

42Δt: 4sMutable Variable

Page 47: A Type is Worth a Thousand Tests - YOW! Conferences › yowconnected2016 › ...From Objective-C to Swift Higher-order functions & closures Value types (products & sums) Advanced type

Δt0 1 2 3 4

427311725

✓ Flow of changes explicit in code

✓Changes can be processed with combinators (map, fold, accumulate, and so on)

Page 48: A Type is Worth a Thousand Tests - YOW! Conferences › yowconnected2016 › ...From Objective-C to Swift Higher-order functions & closures Value types (products & sums) Advanced type

Changes API

protocol Observable: class { associatedtype ObservedValue

func observe<Context: AnyObject>( withContext context: Context, observer: (Context, ObservedValue) -> ()) -> ()

}

registered observer call back

Page 49: A Type is Worth a Thousand Tests - YOW! Conferences › yowconnected2016 › ...From Objective-C to Swift Higher-order functions & closures Value types (products & sums) Advanced type

class Changing<Value>: Observable { typealias ObservedValue = Value func announce(change: Value) { … } func observe … { … } }

Ephemeral stream of changes

protocol Observable: class { associatedtype ObservedValue

func observe<Context: AnyObject>( withContext context: Context, observer: (Context, ObservedValue) -> ()) -> ()

}

Add another change value into the stream

Page 50: A Type is Worth a Thousand Tests - YOW! Conferences › yowconnected2016 › ...From Objective-C to Swift Higher-order functions & closures Value types (products & sums) Advanced type

protocol Observable: class { associatedtype ObservedValue

func observe<Context: AnyObject>( withContext context: Context, observer: (Context, ObservedValue) -> ()) -> ()

}

class Accumulating<Value, Accumulator>: Observable { typealias ObservedValue = Accumulator init <Observed: Observable where …> ( observing observed: Observed, startingFrom initial: Accumulator, accumulate: (Value, Accumulator) -> Accumulator) func observe … { … } }

Accumulating value

Accumulating change

Page 51: A Type is Worth a Thousand Tests - YOW! Conferences › yowconnected2016 › ...From Objective-C to Swift Higher-order functions & closures Value types (products & sums) Advanced type

extension Observable {

}

map apply function to each observed value

merge combine two streams of observations

accumulatecombine the values of a stream ofobservations using an accumulationfunction

Page 52: A Type is Worth a Thousand Tests - YOW! Conferences › yowconnected2016 › ...From Objective-C to Swift Higher-order functions & closures Value types (products & sums) Advanced type

Change Propagation in Goals

G0 3

G1 nil

G2 1

observe

ModelViews

Accumulating<Edit, Goals>

Edits

accumulate

ProgressEdits

merge

GoalEdits

observe

Page 53: A Type is Worth a Thousand Tests - YOW! Conferences › yowconnected2016 › ...From Objective-C to Swift Higher-order functions & closures Value types (products & sums) Advanced type

Accumulating<Edit, Goals>

Edits

ProgressEdits

GoalEdits

Page 54: A Type is Worth a Thousand Tests - YOW! Conferences › yowconnected2016 › ...From Objective-C to Swift Higher-order functions & closures Value types (products & sums) Advanced type

typealias GoalEdits = Changing<GoalEdit>

enum GoalEdit { case add(goal: Goal) case delete(goal: Goal) case update(goal: Goal) case setActivity(activity: [Bool]) }

extension GoalEdit { func transform(_ goals: Goals) -> Goals { switch self { case .add(let newGoal): …

Accumulating<Edit, Goals>

Edits

ProgressEdits

GoalEdits

Page 55: A Type is Worth a Thousand Tests - YOW! Conferences › yowconnected2016 › ...From Objective-C to Swift Higher-order functions & closures Value types (products & sums) Advanced type

typealias ProgressEdits = Changing<ProgressEdit>

enum ProgressEdit { case bump(goal: Goal) }

extension ProgressEdit { func transform(_ goals: Goals) -> Goals { … } }

typealias Edits = Changing<Edit>

enum Edit { case goalEdit(edit: GoalEdit) case progressEdit(edit: ProgressEdit) }

Accumulating<Edit, Goals>

Edits

ProgressEdits

GoalEdits

Page 56: A Type is Worth a Thousand Tests - YOW! Conferences › yowconnected2016 › ...From Objective-C to Swift Higher-order functions & closures Value types (products & sums) Advanced type

let model: Accumulating<Edit, Goals> = edits.accumulate(startingFrom: initialGoals) { edit, currentGoals in return edit.transform(currentGoals) }

Accumulating<Edit, Goals>

Edits

ProgressEdits

GoalEdits

Page 57: A Type is Worth a Thousand Tests - YOW! Conferences › yowconnected2016 › ...From Objective-C to Swift Higher-order functions & closures Value types (products & sums) Advanced type

Replacing Tests

✓ Avoid changes from unexpected placesReplaces integration tests

✓ Avoid conflicting state changesReplaces integration tests

Page 58: A Type is Worth a Thousand Tests - YOW! Conferences › yowconnected2016 › ...From Objective-C to Swift Higher-order functions & closures Value types (products & sums) Advanced type

mchakravartyTacticalGracejusttesting.org

haskellformac.com

Type systems are a design tool

Swift encourages typed functional programming

Types replace entire categories of tests

Check out the source code of Goals.app!https://github.com/mchakravarty/goalsapp

types >< state

Page 59: A Type is Worth a Thousand Tests - YOW! Conferences › yowconnected2016 › ...From Objective-C to Swift Higher-order functions & closures Value types (products & sums) Advanced type

Thank you!

Page 60: A Type is Worth a Thousand Tests - YOW! Conferences › yowconnected2016 › ...From Objective-C to Swift Higher-order functions & closures Value types (products & sums) Advanced type

Wikimedia

https://www.flickr.com/photos/30998987@N03/5408763997

Image Attribution

https://commons.wikimedia.org/wiki/File:Nile_blue_05.jpg

https://dribbble.com/shots/1667698-Free-vector-Macbook-Ipad-and-Iphone

https://www.flickr.com/photos/provisions/7986149891/

https://commons.wikimedia.org/wiki/File:Handcuffs01_2008-07-27.jpghttps://commons.wikimedia.org/wiki/File:Set_square_Geodreieck.svg

https://www.flickr.com/photos/digitalcurrency/2438119267https://www.flickr.com/photos/pviojoenchile/2760021279/

https://openclipart.org/detail/463/heart