pure functions +
immutability
✅ easier to reason
✅ easier to debug
Slide 23
Slide 23 text
focus on what
matters
Slide 24
Slide 24 text
eliminate shared
state so order
does not matter
Slide 25
Slide 25 text
be as functional
as you can
Slide 26
Slide 26 text
tests
△
Slide 27
Slide 27 text
confidence
safeness
Slide 28
Slide 28 text
live documentation
Slide 29
Slide 29 text
feedback
Slide 30
Slide 30 text
accuracy
Slide 31
Slide 31 text
speed
Slide 32
Slide 32 text
reliable feedback
Slide 33
Slide 33 text
e2e is a problem
Slide 34
Slide 34 text
✅
accuracy
✅
speed
✅
reliability
Slide 35
Slide 35 text
how to design our
code?
Slide 36
Slide 36 text
high maintainability
low tech debt
Slide 37
Slide 37 text
maintainability is a
long term concept
Slide 38
Slide 38 text
first attempt:
hexagonal
architecture
Slide 39
Slide 39 text
inner layer: domain model
Slide 40
Slide 40 text
second layer: application
Slide 41
Slide 41 text
third layer: IO
Slide 42
Slide 42 text
separates business
logic from IO
Slide 43
Slide 43 text
tests in isolation with
mocks and stubs
Slide 44
Slide 44 text
dependency injection
Slide 45
Slide 45 text
first discover
Slide 46
Slide 46 text
hard things in OOP can
be easy in FP
(tests)
Slide 47
Slide 47 text
boundaries
Slide 48
Slide 48 text
third layer: IO
Slide 49
Slide 49 text
isolation
Slide 50
Slide 50 text
isolation is the dual
of encapsulation
Slide 51
Slide 51 text
hard to balance between
both
Slide 52
Slide 52 text
not a problem in FP
Slide 53
Slide 53 text
hexagonal architecture
in FP is natural
Slide 54
Slide 54 text
push impure code to the
boundaries
Slide 55
Slide 55 text
good FP design is ports
and adapters
Slide 56
Slide 56 text
great discovery!
Slide 57
Slide 57 text
but, are we levaraging
FP to its max?
Slide 58
Slide 58 text
second layer with
imperative code and
side effects
Slide 59
Slide 59 text
why not imperative?
harder to reason about
harder to compose
harder to test
slower feedback
Slide 60
Slide 60 text
why not imperative?
harder to reason about
harder to compose
harder to test
slower feedback
Slide 61
Slide 61 text
why not imperative?
block!(card, db producer) ; =>
Slide 62
Slide 62 text
why not imperative?
def block!(card, db, producer) do
if Logic.Card.can_block?(card) do
blocked_card = Logic.Card.block(card)
Datomic.Card.update!(blocked_card, db)
Producer.Card.status_changed!(blocked_card, producer)
end
end
Slide 63
Slide 63 text
why not imperative?
harder to reason about
harder to compose
harder to test
slower feedback
Slide 64
Slide 64 text
why not imperative?
def block_all!(customer, card, db, producer) do
cards
|> Enum.map(fn card -> block!(card, db, producer) end)
cards_block_notify!(customer, producer)
end
Slide 65
Slide 65 text
why not imperative?
def block_all!(customer, card, db, producer) do
cards
|> Enum.map (fn card -> block!(card, db, producer) end)
cards_block_notify!(customer, producer)
end
Slide 66
Slide 66 text
why not imperative?
def block_all!(customer, card, db, producer) do
cards
|> Enum.map (fn (card) -> block!(card, db, producer) end)
cards_block_notify!(customer, producer)
end
Slide 67
Slide 67 text
why not imperative?
harder to reason about
harder to compose
harder to test
slower feedback
Slide 68
Slide 68 text
why not imperative?
Mocks & Integration Tests
Slide 69
Slide 69 text
No content
Slide 70
Slide 70 text
why not imperative?
harder to reason about
harder to compose
harder to test
slower feedback
def block!(card) do
if Logic.Card.can_block?(card) do
blocked_card = Logic.Card.block(card)
%{ datoms: [ Effect.Card.update(blocked_card)],
messages: [ Effect.Card.status_changed(blocked_card)]}
end
end
Slide 79
Slide 79 text
easier to compose
def block_all(customer, cards) do
cards
|> Enum.map(fn card -> block(card) end)
|> Effect.Card.card_blocked_notify(customer)
end