[Practical] Functional Programming in Rails

Preview:

DESCRIPTION

Tired of writing messy messy "if" statements for all your exception handling? Learn how to take full advantage of functional programming theory, without the theory, Ruby-style! https://github.com/mindeavor/solid_use_case

Citation preview

FUNCTIONALPROGRAMMINGPr

actical!

RAILSRUBYIN

ON

BY

Overview

• What is a Service Layer? • Railway Oriented Programming • Creating Beautifully Composable Services

What is a

LAYER?

SERVICE

What is a

LAYER

SERVICE??

A Service is an object that represents a process.

A process is something you do.

• Typically initiated by the user • Usually implemented as a dedicated class • Named with verbs, not nouns • Examples: SignupUser, PurchaseItem, etc.

SERVICES

SignupUser

Purchase Item

RAILS

SERVICES

SERVICE LAYER

Payout Account

A Service in Rails

SERVICES

CODE EXAMPLE

A ServiceUsage in Controller

[Naive] ValidationsCODE EXAMPLE

A Service

Usage in Controller

SERVICES

Why a Service useful?

• It encapsulates domain logic • It thins out your models & controllers • It ties together cross-cutting concerns • It makes your Rails app easier to test.

SERVICES

A service layer is about clear separation.

• Rails depends on the service layer • The service layer knows nothing about Rails (routes, controllers, & views)

• Other things could depend on the service layer (REST API, web sockets, rake tasks, etc.)

• ActiveRecord is unavoidable, however.SERVICES

SERVICES

Quick Recap

• A service is an object that represents a process • Services encapsulate domain logic for specific

processes • No functional programming (yet).

SERVICES

RAILWAY ORIENTED

PROGRAMMING

http://fsharpforfunandprofit.com/posts/recipe-part2/

Services: Another Perspective

A service is a sequence of steps • They often involve a lot of setup • Authentication, authorization, validation, etc.

Any one of these steps could fail • How to handle failure??

RAILWAY

Naive ValidationsCODE EXAMPLE (REVISITED)

A Service RAILWAY

Can we do be!er?

RAILWAY

What if each step was an independent method?

How would each step communicate?

Source: http://www.slideshare.net/ScottWlaschin/railway-oriented-programming RAILWAY

The “Switch”

Input → Success!

Failure.

fetch_item

DIAGRAM

RAILWAY

The “Switch”

Input → Success!

Failure

fetch_item

CODE EXAMPLE

RAILWAY

The “Switch”

Input → Success!

Failure.

fetch_item

CODE EXAMPLE

Failure.Success!

Source: http://www.slideshare.net/ScottWlaschin/railway-oriented-programming RAILWAY

Our Target Flow

on successSuccess!

Failure.

Input →

fetch_item validate

on failure

Source: http://www.slideshare.net/ScottWlaschin/railway-oriented-programming RAILWAY

Our Target Flow

Success!Failure.

Input →create_ordervalidatefetch_item

Source: http://www.slideshare.net/ScottWlaschin/railway-oriented-programming RAILWAY

Our Target Flow

Success!Failure.

Input →create_ordervalidatefetch_item

IT’D BE COOL IF WE COULD CONNECT THESE TOGETHER

Source: http://www.slideshare.net/ScottWlaschin/railway-oriented-programming RAILWAY

Connecting Switches

Success!Failure.

Input →create_ordervalidatefetch_item

create_ordervalidatefetch_item

Source: http://www.slideshare.net/ScottWlaschin/railway-oriented-programming RAILWAY

Connecting Switches

Success!Failure.

Input →create_ordervalidatefetch_item

create_ordervalidatefetch_item

create_ordervalidatefetch_item

Success!Failure.

RAILWAY

Connecting SwitchesCODE EXAMPLES

create_ordervalidatefetch_item

?? ??

RAILWAY

Connecting SwitchesCODE EXAMPLES

create_ordervalidatefetch_item

?? ??

HOW DO WE CONNECTIT ALL TOGETHER?

? ????

??

?

RAILWAY

Answer:

RAILWAY

¯\_(ツ)_/¯ Answer:

RAILWAY

¯\_(ツ)_/¯ Answer:

IT DOESN’T MATTER!

RAILWAY

¯\_(ツ)_/¯ Answer:

IT DOESN’T MATTER! :D

RAILWAY

¯\_(ツ)_/¯ Answer:

IT DOESN’T MATTER! :D

(actual answer: monads)

There’s a gem for that!Doesn’t matter.

RAILWAY

github.com/mindeavor/solid_use_case

There’s a gem for that!Don’t worry.

Handling failures?

RAILWAY

What about

github.com/mindeavor/solid_use_case

Quick Recap

• Split steps into methods • Return a success or failure in each one • Elegant (with gem) error handling! • Steps can be tested independently

RAILWAY

COMPOSING SERVICES

FOR MAXIMUM COOLNESS

Source: http://www.slideshare.net/ScottWlaschin/railway-oriented-programming COMPOSE

Remember This?

Success!Failure

Input →create_ordervalidatefetch_item

create_ordervalidatefetch_item

create_ordervalidatefetch_item

Success!Failure

Source: http://www.slideshare.net/ScottWlaschin/railway-oriented-programming COMPOSE

Input → Success!Failure

create_ordervalidatefetch_item

What if we treat it like a single thing…

Source: http://www.slideshare.net/ScottWlaschin/railway-oriented-programming COMPOSE

Input → Success!FailurePurchaseItem

What if we treat it like a single thing…

Source: http://www.slideshare.net/ScottWlaschin/railway-oriented-programming COMPOSE

Input → PurchaseItem Success!Failure

What if we treat it like a single thing…

Source: http://www.slideshare.net/ScottWlaschin/railway-oriented-programming COMPOSE

…and then connect it to other things??

Input →PurchaseItem

Success!

Failure

Source: http://www.slideshare.net/ScottWlaschin/railway-oriented-programming COMPOSE

Input →PurchaseItem EmailReceipt

Success!

Failure

…and then connect it to other things??

Service CompositionCODE EXAMPLE

COMPOSE

Service CompositionCODE EXAMPLE

Another Service!

COMPOSE

Service CompositionCODE EXAMPLE

Another Service!

COMPOSE

Recap

• We can compose services like we can steps (in fact we can compose anything that returns our success or failure)

• Functional programming rocks!

COMPOSE

Conclusion

• Service layers are great for apps more complex than CRUD

• Railway oriented programming is great for seamless error handling

• Functional programming gives us composable services!

In the end, don’t take my word for it.

TRY IT YOURSELF!

Thanks!Hurrah!

END.THE

BY

- Gilbert (@mindeavor)

Further Reading

• http://martinfowler.com/eaaCatalog/serviceLayer.html • https://gist.github.com/blaix/5764401 • http://fsharpforfunandprofit.com/posts/recipe-part2/ • The gem: https://github.com/mindeavor/solid_use_case

Recommended