BNE ADD1
BRA NONE1
ADD1 INY ;increment our counter of 1's
NONE1 LDAA TEMP ;reload accumulator A
LSL MASK ;Shift the mask's 1 bit left
BNE LOOP1 ;If we haven't finished our loop, branch
LDAA #$01 ;load new mask into A
STAA MASK ;store the reset mask into MASK
TSX ;pull of return address and store in X
PULA ;pull off A
STAA TEMP ;store the value into temp
TXS ;push return address back onto the stack
LOOP2 LDAA TEMP ;Load A into TEMP
ANDA MASK ;logical AND MASK with A
BNE ADD2 ;add one if we need to
BRA NONE2
ADD2 INY ;increment our counter of 1's
NONE2 LDAA TEMP
LSL MASK ;shift our mask left by one
BNE LOOP2 ;loop back until we've exhausted positions
Slide 6
Slide 6 text
No content
Slide 7
Slide 7 text
Agenda
1. Simplicity is the goal of software development
2. Statefulness is an enemy of simplicity
3. FRP conceals state rather than eliminate it
Slide 8
Slide 8 text
No content
Slide 9
Slide 9 text
Simplicity is the goal
of programming.
Slide 10
Slide 10 text
Obvious? Maybe.
Slide 11
Slide 11 text
What is simple?
• Focused
• Uncombined
• Has one role, one purpose, one concept, etc…
• Simple is not necessarily easy
Slide 12
Slide 12 text
let numbers = [1, 5, 4, -1, 7]
var sum = 0
for var i = 0; i < numbers.count; i++ {
sum += numbers[i]
}
print(sum)
Slide 13
Slide 13 text
let numbers = [1, 5, 4, -1, 7]
let sum = numbers.reduce(0, combine: +)
print(sum)
struct FormHandler {
let callback: Bool -> Void
private let submitter = FormSubmitter()
private let validator = FormValidator()
private let resetter = FormResetter()
...
Slide 44
Slide 44 text
State contained
within the submitter.
Slide 45
Slide 45 text
This is not
pedagogical.
Slide 46
Slide 46 text
I would ship this.
Slide 47
Slide 47 text
(After writing unit tests.)
Slide 48
Slide 48 text
Simpler view
controller.
Slide 49
Slide 49 text
Isolated state.
Slide 50
Slide 50 text
So.
State doesn’t scale.
Slide 51
Slide 51 text
Why?
Slide 52
Slide 52 text
Because…
Brains don’t scale.
Slide 53
Slide 53 text
No content
Slide 54
Slide 54 text
So state is bad…
Slide 55
Slide 55 text
Let’s remove it!
Slide 56
Slide 56 text
Not so fast.
Slide 57
Slide 57 text
Abstraction.
Slide 58
Slide 58 text
–Edsger Dijkstra
“The purpose of abstraction is not to be vague, but to create a new
semantic level in which one can be absolutely precise.”
Slide 59
Slide 59 text
var loginStatus = UserStatus.NotLoggedIn
...
loginStatus = .LoggedIn
Slide 60
Slide 60 text
let loginStatus = Variable(UserStatus.NotLoggedIn)
...
loginStatus.value = .LoggedIn
Slide 61
Slide 61 text
Okay, but why?
Slide 62
Slide 62 text
class LoginNetworkModel {
private let _loginStatus =
Variable(UserStatus.NotLoggedIn)
var loginStatus: Observable {
return _loginStatus.asObservable()
}
...
}
Slide 63
Slide 63 text
class LoginNetworkModel {
private let _loginStatus =
Variable(UserStatus.NotLoggedIn)
var loginStatus: Observable {
return _loginStatus.asObservable()
}
...
}
Slide 64
Slide 64 text
class LoginNetworkModel {
private let _loginStatus =
Variable(UserStatus.NotLoggedIn)
var loginStatus: Observable {
return _loginStatus.asObservable()
}
...
}
Slide 65
Slide 65 text
Conceals state.
Slide 66
Slide 66 text
loginNetworkModel
.loginStatus
.subscribeNext { [weak self] result in
switch result {
case .NotLoggedIn: self?.failedToLogin()
case .LoggedIn: self?.welcomeUser()
}
}
Slide 67
Slide 67 text
loginNetworkModel
.loginStatus
.subscribeNext { [weak self] result in
switch result {
case .NotLoggedIn: self?.failedToLogin()
case .LoggedIn: self?.welcomeUser()
}
}
Slide 68
Slide 68 text
loginNetworkModel
.loginStatus
.subscribeNext { [weak self] result in
switch result {
case .NotLoggedIn: self?.failedToLogin()
case .LoggedIn: self?.welcomeUser()
}
}
loginNetworkModel
.login("ashfurrow", password: ...)
.subscribeNext { [weak self] result in
switch result {
case .NotLoggedIn: self?.failedToLogin()
case .LoggedIn: self?.welcomeUser()
}
}
Slide 78
Slide 78 text
Seems like magic!
Slide 79
Slide 79 text
Sure does.
Slide 80
Slide 80 text
Subscribing “starts”
the Observable.
(-ish)
Slide 81
Slide 81 text
Subscribing returns
a Disposable.
Slide 82
Slide 82 text
Tie disposal to
object deallocation.
Slide 83
Slide 83 text
class LoginViewController: UIViewController {
let disposeBag = DisposeBag()
...
loginNetworkModel
.login("ashfurrow", password: ...)
.subscribeNext { ... }
.addDisposableTo(self.disposeBag)
...
Slide 84
Slide 84 text
OK, cool!
What else?
Slide 85
Slide 85 text
Requirements Change!
• View controller needs access to full user info
• Let’s modify our network model
class LoginViewController {
...
formHandler
.enabled
.bindTo(submitButton.rx_enabled)
.addDisposableTo(disposeBag)
...
}
Slide 104
Slide 104 text
That’s testable, too!
Slide 105
Slide 105 text
github.com/artsy/eidolon
Slide 106
Slide 106 text
Wrap-up
1. Strive for simplicity because brains don’t scale
2. State increases incidental complexity
3. Rather than eliminate state, FRP abstract it away