Slide 1

Slide 1 text

Finding Happiness in Functional Programming

Slide 2

Slide 2 text

No content

Slide 3

Slide 3 text

Principles that we benefited from

Slide 4

Slide 4 text

Separation of effects from purity

Slide 5

Slide 5 text

Isolation of side-effects An expression is said to have a side-effect if its execution makes an observable change to the outside world.

Slide 6

Slide 6 text

Isolation of side-effects self.titleLabel.text = user.name

Slide 7

Slide 7 text

Isolation of side-effects func update(text: String, forLabel: UILabel) { label.text = text } update(text: user.name, forLabel: self.titleLabel)

Slide 8

Slide 8 text

Isolation of side-effects self.loginButton.enabled = !self.userTextField.text.isEmpty && !self.passwordTextField.text.isEmpty

Slide 9

Slide 9 text

Isolation of side-effects func updateLoginButtonEnabled() { self.loginButton.enabled = !self.userTextField.text.isEmpty && !self.passwordTextField.text.isEmpty } func emailChanged() { self.updateLoginButtonEnabled() } func passwordChanged() { self.updateLoginButtonEnabled() }

Slide 10

Slide 10 text

Isolation of side-effects // Pure, functional world let emailChanged: Signal let passwordChanged: Signal let loginButtonEnabled = combineLatest(emailChanged, passwordChanged) .map { !$0.isEmpty && !$1.isEmpty } // Side-effect world loginButtonEnabled.observeNext { [weak self] in self?.loginButtonEnabled.enabled = $0 }

Slide 11

Slide 11 text

Isolation of side-effects // Pure, functional world let emailChanged: Signal let passwordChanged: Signal let loginButtonEnabled = combineLatest(emailChanged, passwordChanged) .map { !$0.isEmpty && !$1.isEmpty } // Side-effect world self.loginButton.rac.enabled = loginButtonEnabled

Slide 12

Slide 12 text

Surfacing of co-effects

Slide 13

Slide 13 text

Surfacing of co-effects ????????????????

Slide 14

Slide 14 text

Surfacing of co-effects If an effect is a change to the outside world after executing an expression...

Slide 15

Slide 15 text

Surfacing of co-effects If an effect is a change to the outside world after executing an expression... ...then...

Slide 16

Slide 16 text

Surfacing of co-effects If an effect is a change to the outside world after executing an expression... ...then... ...a co-effect is the state of the world that the expression needs in order to execute.

Slide 17

Slide 17 text

Surfacing of co-effects e.g. Dependency Injection

Slide 18

Slide 18 text

Surfacing of co-effects Dependency Injection func currentUserIsCreator(ofProject project: Project) -> Bool { return User.currentUser.id == project.creator.id } currentUserIsCreator(ofProject: project) // => true or false

Slide 19

Slide 19 text

Surfacing of co-effects Dependency Injection func user(_ user: User, isCreatorOfProject: Project) -> Bool { return user.id == project.creator.id } user(User.currentUser, isCreatorOfProject: project) // => true or false

Slide 20

Slide 20 text

Surfacing of co-effects References — Colin Barrett — Functional Swift Conference 2015 — Structure and Interpretation of Swift Programs — The work of Tomas Petricek — Coeffects: A calculus of context-dependent computation — Coeffects: The next big programming challenge

Slide 21

Slide 21 text

Effect/Co-effect Duality

Slide 22

Slide 22 text

Code to the interface you wish you had, not the interface you were given. - Stephen Celis

Slide 23

Slide 23 text

An interface we were given

Slide 24

Slide 24 text

An interface we were given Storyboards — Very thick abstraction layer — Separates code from data — Constantly catching up to what UIKit can do

Slide 25

Slide 25 text

An interface we wish we had Lenses

Slide 26

Slide 26 text

An interface we wish we had Lenses struct Project { let creator: User let id: Int let name: String }

Slide 27

Slide 27 text

An interface we wish we had Lenses Project.lens.name // => Lens

Slide 28

Slide 28 text

An interface we wish we had Lenses Project.lens.name // => Lens Project.lens.name .~ "Advanced Swift" // => Project -> Project

Slide 29

Slide 29 text

An interface we wish we had Lenses Project.lens.name // => Lens Project.lens.name .~ "Advanced Swift" // => Project -> Project project |> Project.lens.name .~ "Advanced Swift"

Slide 30

Slide 30 text

An interface we wish we had Lenses project |> Project.lens.name .~ "Advanced Swift" |> Project.lens.creator.name .~ "Chris Eidhof"

Slide 31

Slide 31 text

An interface we wish we had UIKit Lenses

Slide 32

Slide 32 text

An interface we wish we had UIKit Lenses UIView.lens.backgroundColor // => Lens

Slide 33

Slide 33 text

An interface we wish we had UIKit Lenses UIView.lens.backgroundColor // => Lens UIView.lens.backgroundColor .~ .redColor() // => UIView -> UIView

Slide 34

Slide 34 text

An interface we wish we had UIKit Lenses UIView.lens.backgroundColor // => Lens UIView.lens.backgroundColor .~ .redColor() // => UIView -> UIView view |> UIView.lens.backgroundColor .~ .redColor() |> UIView.lens.layer.cornerRadius .~ 4 |> UIView.lens.layer.masksToBounds .~ true

Slide 35

Slide 35 text

An interface we wish we had UIKit Lenses func roundedStyle(cornerRadius: CGFloat) -> (UIView) -> UIView { return UIView.lens.layer.cornerRadius .~ 4 <> UIView.lens.layer.masksToBounds .~ true } view |> roundedStyle(cornerRadius: 4) |> UIView.lens.backgroundColor .~ .redColor()

Slide 36

Slide 36 text

An interface we wish we had UIKit Lenses let baseButtonStyle = roundedStyle(cornerRadius: 4) <> UIButton.lens.titleLabel.font .~ UIFont(size: 16) <> UIButton.lens.contentEdgeInsets .~ .init(topBottom: 6, leftRight: 12) let greenButtonStyle = baseButtonStyle <> UIButton.lens.backgroundColor(forState: .Normal) .~ .greenColor()

Slide 37

Slide 37 text

An interface we wish we had UIKit Lenses let bigButtonStyle = baseButtonStyle <> UIButton.lens.contentEdgeInsets %~ { .init(top: $0.top * 2, left: $0.left * 2, bottom: $0.bottom * 2, right: $0.right * 2) }

Slide 38

Slide 38 text

An interface we wish we had UIKit Lenses let baseButtonStyle = roundedStyle(cornerRadius: 4) <> UIButton.lens.titleLabel.font %~~ { _, button in button.traitCollection.verticalSizeClass == .Compact ? UIFont(size: 12) : UIFont(size: 14) } <> UIButton.lens.contentEdgeInsets .~ .init(topBottom: 6, leftRight: 12)

Slide 39

Slide 39 text

Principles that we did not benefit so much from: — D.R.Y. — S.R.P. — S.O.L.I.D. — Objects

Slide 40

Slide 40 text

The Result

Slide 41

Slide 41 text

Testing

Slide 42

Slide 42 text

Test-Driven Development

Slide 43

Slide 43 text

Test-Driven Bug Fixing

Slide 44

Slide 44 text

Playground-Driven Development

Slide 45

Slide 45 text

Screenshot testing

Slide 46

Slide 46 text

Event Tracking

Slide 47

Slide 47 text

Event Tracking

Slide 48

Slide 48 text

Accessibility

Slide 49

Slide 49 text

Love for UIKit

Slide 50

Slide 50 text

Be!er working relationship with Product Managers, Designers and Engineers

Slide 51

Slide 51 text

Finding Happiness in Functional Programming

Slide 52

Slide 52 text

Finding Happiness in Functional Programming brandon@kickstarter.com