Slide 1

Slide 1 text

FUNCTIONAL OBJECT-ORIENTED PROGRAMMING Chris Keathley / @ChrisKeathley / [email protected]

Slide 2

Slide 2 text

What this talk isn’t about

Slide 3

Slide 3 text

“OO IS EVIL!!!” - People on the internet

Slide 4

Slide 4 text

“OO IS EVIL!!!” - People on the internet Kthnxbye

Slide 5

Slide 5 text

OO vs FP

Slide 6

Slide 6 text

I was trained in this

Slide 7

Slide 7 text

C

Slide 8

Slide 8 text

int main(int argc, char** argv) { mpc_parser_t* Number = mpc_new("number"); mpc_parser_t* Symbol = mpc_new("symbol"); mpc_parser_t* Sexpr = mpc_new("sexpr"); mpc_parser_t* Qexpr = mpc_new("qexpr"); mpc_parser_t* Expr = mpc_new("expr"); mpc_parser_t* Lispy = mpc_new("lispy"); mpca_lang(MPC_LANG_DEFAULT, " \ number : /-?[0-9]+/ ; \ symbol : '+' | '-' | '*' | '/' ; \ sexpr : '(' * ')' ; \ qexpr : '{' * '}' ; \ expr : | | ; \ lispy : /^/ * /$/ ; \ ", Number, Symbol, Sexpr, Qexpr, Expr, Lispy); puts("Crisp Version 0.0.0.1"); puts("Press Ctrl+c to Exit\n"); while (1) { char* input = readline("crisp> "); add_history(input); mpc_result_t r; if (mpc_parse("", input, Lispy, &r)) { lval* x = lval_eval(lval_read(r.output)); lval_println(x); lval_del(x); mpc_ast_delete(r.output); } else { mpc_err_print(r.error); mpc_err_delete(r.error);

Slide 9

Slide 9 text

int main(int argc, char** argv) { mpc_parser_t* Number = mpc_new("number"); mpc_parser_t* Symbol = mpc_new("symbol"); mpc_parser_t* Sexpr = mpc_new("sexpr"); mpc_parser_t* Qexpr = mpc_new("qexpr"); mpc_parser_t* Expr = mpc_new("expr"); mpc_parser_t* Lispy = mpc_new("lispy"); mpca_lang(MPC_LANG_DEFAULT, " \ number : /-?[0-9]+/ ; \ symbol : '+' | '-' | '*' | '/' ; \ sexpr : '(' * ')' ; \ qexpr : '{' * '}' ; \ expr : | | ; \ lispy : /^/ * /$/ ; \ ", Number, Symbol, Sexpr, Qexpr, Expr, Lispy); puts("Crisp Version 0.0.0.1"); puts("Press Ctrl+c to Exit\n"); while (1) { char* input = readline("crisp> "); add_history(input); mpc_result_t r; if (mpc_parse("", input, Lispy, &r)) { lval* x = lval_eval(lval_read(r.output)); lval_println(x); lval_del(x); mpc_ast_delete(r.output); } else { mpc_err_print(r.error); mpc_err_delete(r.error); wtfbbq

Slide 10

Slide 10 text

Java

Slide 11

Slide 11 text

What is Object-Oriented Programming?

Slide 12

Slide 12 text

OBJECT ORIENTED LANGUAGES HAVE… ▸ Behavior + Data (encapsulation) ▸ Classes ▸ Objects (instances of classes) ▸ Inheritance ▸ Methods ▸ Polymorphism

Slide 13

Slide 13 text

OBJECT ORIENTED PROGRAMMING IMPLIES… ▸ State ▸ Mutability ▸ Encapsulation ▸ Domain modeling ▸ Message passing

Slide 14

Slide 14 text

ANIMALS

Slide 15

Slide 15 text

ANIMALS BIRDS

Slide 16

Slide 16 text

ANIMALS BIRDS DOGS

Slide 17

Slide 17 text

How do we use Oop?

Slide 18

Slide 18 text

I read lots of books

Slide 19

Slide 19 text

THE CLASSICS ▸ Design Patterns (Gang of 4) ▸ Growing Object-Oriented Software with Tests ▸ Practical Object-Oriented Design in Ruby ▸ Domain Driven Design ▸ Patterns of Enterprise Application Architecture

Slide 20

Slide 20 text

I Learned best Practices

Slide 21

Slide 21 text

BEST PRACTICES ▸ SOLID ▸ DRY ▸ Law of Demeter ▸ Small Methods ▸ Design by Contract ▸ TDD ▸ BDD ▸ Commands and Queries ▸ Tell don’t ask ▸ Separation of Concerns

Slide 22

Slide 22 text

Un-enforced Best Practices will eventually be violated

Slide 23

Slide 23 text

Complexity “CONSISTING OF MANY DIFFERENT AND CONNECTED PARTS”

Slide 24

Slide 24 text

Simple “COMPOSED OF A SINGLE ELEMENT.”

Slide 25

Slide 25 text

Decoupling

Slide 26

Slide 26 text

Complexity is the death of productivity

Slide 27

Slide 27 text

“the first 90% of all software products is the MVP, the other 90% is maintenance” - Greg O.

Slide 28

Slide 28 text

OOP is complex By Nature

Slide 29

Slide 29 text

Encapsulation STATE BEHAVIOR

Slide 30

Slide 30 text

Inheritance ANIMALS BIRDS

Slide 31

Slide 31 text

Inheritance ANIMALS BIRDS

Slide 32

Slide 32 text

State FOO BAR BAZ

Slide 33

Slide 33 text

State FOO BAR BAZ ME

Slide 34

Slide 34 text

State FOO BAR BAZ ME Foo

Slide 35

Slide 35 text

State FOO BAR BAZ ME Foo Bar

Slide 36

Slide 36 text

State FOO BAR BAZ ME Foo Baz Bar

Slide 37

Slide 37 text

Methods FOO STATE PRIVATE METHOD PRIVATE METHOD

Slide 38

Slide 38 text

I combat complexity with Functional Programming

Slide 39

Slide 39 text

functional Programming pure functions immutable data isolate side-effects Compose pipelines of functions

Slide 40

Slide 40 text

functional Programming pure functions immutable data isolate side-effects Compose pipelines of functions

Slide 41

Slide 41 text

Pure Functions (+2) 3 5 Always return the same result given the same arguments

Slide 42

Slide 42 text

Pure Functions Have no side effects FS DB +

Slide 43

Slide 43 text

Pure Functions # Pure def add(x, y) x + y end # Impure def user_input_add(x) print "Enter a number: " num = gets puts x + num.to_i end

Slide 44

Slide 44 text

functional Programming pure functions immutable data isolate side-effects Compose pipelines of functions

Slide 45

Slide 45 text

Immutability test "users can be fed" do user = User.new assert user.hungry? == true user.feed(Hamburger.new) assert user.hungry? == false end class User def initialize(stomach: []) @stomach = stomach end def feed(item) @stomach << item end end

Slide 46

Slide 46 text

Immutability test "users can be fed" do user = User.new assert user.hungry? == true fed_user = user.feed(Hamburger.new) assert fed_user.hungry? == false end class User def initialize(stomach: []) @stomach = stomach end def feed(item) @stomach << item end end

Slide 47

Slide 47 text

Immutability test "users can be fed" do user = User.new assert user.hungry? == true fed_user = user.feed(Hamburger.new) assert fed_user.hungry? == false end class User def initialize(stomach: []) @stomach = stomach end def feed(item) User.new(stomach: @stomach + [item]) end end

Slide 48

Slide 48 text

Immutability USER WALLABY .feed .feed

Slide 49

Slide 49 text

functional Programming pure functions immutable data isolate side-effects Compose pipelines of functions

Slide 50

Slide 50 text

Isolate side-effects FILE DB HTTP

Slide 51

Slide 51 text

Isolate side-effects FILE DB HTTP

Slide 52

Slide 52 text

Isolate side-effects FILE DB HTTP

Slide 53

Slide 53 text

functional Programming pure functions immutable data isolate side-effects Compose pipelines of functions

Slide 54

Slide 54 text

composing side-effects web_request

Slide 55

Slide 55 text

composing side-effects web_request |> transform_request_into_query

Slide 56

Slide 56 text

composing side-effects web_request |> transform_request_into_query |> execute_query

Slide 57

Slide 57 text

composing side-effects web_request |> transform_request_into_query |> execute_query |> transform_query_result

Slide 58

Slide 58 text

composing side-effects web_request |> transform_request_into_query |> execute_query |> transform_query_result |> return_result_to_user

Slide 59

Slide 59 text

composing side-effects web_request |> transform_request_into_query |> execute_query |> transform_query_result |> return_result_to_user Data

Slide 60

Slide 60 text

composing side-effects web_request |> transform_request_into_query |> execute_query |> transform_query_result |> return_result_to_user Pure Data

Slide 61

Slide 61 text

composing side-effects web_request |> transform_request_into_query |> execute_query |> transform_query_result |> return_result_to_user Pure Impure Data

Slide 62

Slide 62 text

Example

Slide 63

Slide 63 text

class NewTicketService def self.create_ticket(ticket_params) ticket = Ticket.create(ticket_params) TicketNotifier.new(TicketAlertMailer.new(ticket)).send_alert end end

Slide 64

Slide 64 text

class NewTicketService def self.create_ticket(ticket_params) ticket = Ticket.create(ticket_params) TicketNotifier.new(TicketAlertMailer.new(ticket)).send_alert end end class TicketNotifier def initialize(notifier) @notifier = notifier end def send_alert OnCallStaff.all.each do |user| @notifier.notify(user) end end end

Slide 65

Slide 65 text

class NewTicketService def self.create_ticket(ticket_params) ticket = Ticket.create(ticket_params) TicketNotifier.new(TicketAlertMailer.new(ticket)).send_alert end end class TicketNotifier def initialize(notifier) @notifier = notifier end def send_alert OnCallStaff.all.each do |user| @notifier.notify(user) end end end class TicketAlertMailer def initialize(ticket) @ticket end def self.notify(user) email!(user.email, @ticket.id, @ticket.details) end end

Slide 66

Slide 66 text

Separate arrangement & work

Slide 67

Slide 67 text

class NewTicketService def self.create_ticket(ticket_params) ticket = Ticket.create(ticket_params) TicketNotifier.new(TicketAlertMailer.new(ticket)).send_alert end end class TicketNotifier def initialize(notifier) @notifier = notifier end def send_alert OnCallStaff.all.each do |user| @notifier.notify(user) end end end class TicketAlertMailer def initialize(ticket) @ticket end def notify(user) email!(user.email, @ticket.id, @ticket.details) end end

Slide 68

Slide 68 text

class NewTicketService def self.create_ticket(ticket_params) ticket = Ticket.create(ticket_params) TicketNotifier.new(TicketAlertMailer.new(ticket)).send_alert end end class TicketNotifier def initialize(notifier) @notifier = notifier end def send_alert OnCallStaff.all.each do |user| @notifier.notify(user) end end end class TicketAlertMailer def initialize(ticket) @ticket end def notify(user) email!(user.email, @ticket.id, @ticket.details) end end arrangement

Slide 69

Slide 69 text

class NewTicketService def self.create_ticket(ticket_params) ticket = Ticket.create(ticket_params) TicketNotifier.new(TicketAlertMailer.new(ticket)).send_alert end end class TicketNotifier def initialize(notifier) @notifier = notifier end def send_alert OnCallStaff.all.each do |user| @notifier.notify(user) end end end class TicketAlertMailer def initialize(ticket) @ticket end def notify(user) email!(user.email, @ticket.id, @ticket.details) end end arrangement Work

Slide 70

Slide 70 text

class NewTicketService def self.create_ticket(ticket_params) ticket = Ticket.create(ticket_params) TicketNotifier.new(TicketAlertMailer.new(ticket)).send_alert end end class TicketNotifier def initialize(notifier) @notifier = notifier end def send_alert OnCallStaff.all.each do |user| @notifier.notify(user) end end end class TicketAlertMailer def initialize(ticket) @ticket end def notify(user) email!(user.email, @ticket.id, @ticket.details) end end

Slide 71

Slide 71 text

class NewTicketService def self.create_ticket(ticket_params) ticket = Ticket.create(ticket_params) OnCallStaff.all.each do |user| TicketNotifier.new(TicketAlertMailer.new(ticket)).send_alert(user) end end end class TicketNotifier def initialize(notifier) @notifier = notifier end def send_alert(user) @notifier.notify(user) end end class TicketAlertMailer def initialize(ticket) @ticket end def notify(user) email!(user.email, @ticket.id, @ticket.details) end end

Slide 72

Slide 72 text

class NewTicketService def self.create_ticket(ticket_params) ticket = Ticket.create(ticket_params) OnCallStaff.all.each do |user| TicketAlertMailer.new(ticket).send_alert(user) end end end class TicketAlertMailer def initialize(ticket) @ticket end def notify(user) email!(user.email, @ticket.id, @ticket.details) end end

Slide 73

Slide 73 text

class NewTicketService def self.create_ticket(ticket_params) ticket = Ticket.create(ticket_params) OnCallStaff.all.each do |user| TicketAlertMailer.notify(user, ticket) end end end class TicketAlertMailer def notify(user, ticket) email!(user.email, ticket.id, ticket.details) end end

Slide 74

Slide 74 text

class NewTicketService def self.create_ticket(ticket_params) ticket = Ticket.create(ticket_params) OnCallStaff.all.each do |user| TicketAlertMailer.notify(user, ticket) SlackNotifier.notify(user, ticket) end end end class TicketAlertMailer def notify(user, ticket) email!(user.email, ticket.id, ticket.details) end end class SlackNotifier def self.notify(user, ticket) send_slack_message(user.slack_name, ticket.details) end end

Slide 75

Slide 75 text

COULD I MAKE THIS AN API CALL?

Slide 76

Slide 76 text

COULD I MAKE THIS CONCURRENT?

Slide 77

Slide 77 text

COULD I PUT A QUEUE IN BETWEEN THESE OPERATIONS?

Slide 78

Slide 78 text

Conclusion

Slide 79

Slide 79 text

You don’t have to convert all of your code to a new language.

Slide 80

Slide 80 text

Lets stop making problems for ourselves

Slide 81

Slide 81 text

Think about the goals of best practices.

Slide 82

Slide 82 text

Build simpler systems

Slide 83

Slide 83 text

Chris Keathley / @ChrisKeathley / [email protected] Thanks!