SlideShare ist ein Scribd-Unternehmen logo
1 von 49
Downloaden Sie, um offline zu lesen
From The If Jungle to A
Civilised Railway Station
By Botond Orban
About Me
Botond Orban Enthusiast IT Guy, Architect 

Enthusiastic about Ruby

https://github.com/orbanbotond

@orbanbotond
The Origins
The PC made in Ukraine
Code can be written
in a better way!
Railway Oriented Development
With 3 libraries in Parallel!
-classic if jungle
-dry transactions
-monad do notation
-trailblazer operations
def create
user = User.create user_params[:user]
if user.valid?
package = Package.create package_params[:user]
if package.valid?
user.package = package
user.save
SmsService.send_registration_msg(user, package)
EmailService.send_registration_msg(user, package)
SystemNotifierService.send_registration_msg(user,
package)
else
render ...
end
else
render ...
end
end
True If Jungle
Cyclomatic complexity: 2
def create
user = User.create user_params[:user]
if user.valid?
package = Package.create package_params[:user]
if package.valid?
package.user = user
package.save
if params[:coupon].present?
if coupon = Coupon.exists? params[:coupon]
discount = Discount.create params[:coupon]
package.discount = discount
package.save
else
render …
end
end
SmsService.send_registration_msg(user, package)
EmailService.send_registration_msg(user, package)
SystemNotifierService.send_registration_msg(user, package)
else
render ...
end
else
render ...
end
end
True If Jungle
Cyclomatic complexity: 4
True If Jungle
def create
user = User.create user_params[:user]
if user.valid?
package = Package.create package_params[:user]
if package.valid?
package.user = user
package.save
if params[:coupon].present?
if Coupon.exists? params[:coupon]
discount = Discount.create params[:coupon]
if discount.allowsUser? user
package.discount = discount
package.save
else
render ...
end
else
render ...
end
end
SmsService.send_registration_msg(user, package)
EmailService.send_registration_msg(user, package)
SystemNotifierService.send_registration_msg(user, package)
else
render ...
end
else
render ...
end
end
Cyclomatic complexity: 5
Example 1
f(x) = ax+b
No Library
If Jungle
If Jungle Implementation
Specs:
f(a,b) = a+b, a is infinite
context 'add' do
subject { add.call params: params }


context 'negative cases' do
context 'params infinite' do
let(:params) { [(1.0/0.0), 2] }
specify 'Be a failure with a proper error
message' do
expect(subject[:validation]).to eq 'must
be a real number'
end
end
end
add = ->(params:) do
return { validation: 'must be a real
number' } if params.any?{|x|x.infinite?}
end
Code:
If Jungle Implementation
f(a,b) = a+b, a is infinite
Specs:
context 'add' do
subject { add.call params: params }
let(:params) { [2,3,4] }
context 'negative cases' do …
context 'positive cases' do
specify 'Be a success with the proper correct
output' do
expect(subject[:operation_result]).to
eq(params.reduce(0) { |acc, x| acc + x })
end
end
end
If Jungle Implementation
f(a,b) = a+b,
Code:
add = ->(params:) do
return { validation: 'must be a real
number' } if params.any?{|x|x.infinite?}
result = params.reduce(0) { |acc, x| acc
+ x }
return { operation_result: result }
end
If Jungle Implementation
f(a,b) = a+b,
linear_function = ->(params:) do
result = multiply.call(params: params[-2..-1])
if(result[:operation_result])
return add.call(params:
[result[:operation_result], params[0]])
else
return result
end
end
rspec spec/railway_oriented_development/if_jungle_spec.rb
.......
7 examples, 0 failures
If Jungle Implementation
f(a,b,x) = a.x+b, Linear function
Building Blocks
Add Operation

-Guard Condition

-Business Logic: +

Multiply Operation

-Guard Condition

-Business Logic: *

LinearFunction

-Delegation

-Conditional

-Delegation

-Return a Result
If Jungle Implementation
1st library
Dry Transactions
Specs:
context 'add' do
subject { DryTransactions::Add.new.call params }


context 'negative cases' do
context 'params infinite' do
let(:params) { {params:[(1.0/0.0), 2]} }
specify 'Be a failure with a proper error
message' do
expect(subject).to be_failure
expect(subject.failure).to eq 'must be a
real number'
end
end
end
Dry Transactions
f(a,b) = a+b, a is infinite
Code:
module DryTransactions
class Add
include Dry::Transaction
step :validate
step :add
private
…
…
Dry Transactions
f(a,b) = a+b, a is infinite
Railway Oriented Approach
Code:
module DryTransactions
class Add
…
private
def validate(input)
return Failure('must be a real number') unless input.all?{|x|
x.finite?}
Success(input)
end

def add(input)
ret = input.reduce(0) { |acc, x| acc + x }
Success(ret)
end
…
Dry Transactions
f(a,b) = a+b, a is infinite
class LinearOperation
include Dry::Transaction
# a*x
step :multiply
# previous_result + b
step :assembling_partial_results
private
…
end
Dry Transactions
f(a, b, x) = a.x+b, Linear Function
class ComplexOperation
include Dry::Transaction
…
def multiply(input)
partialValue = Multiply.new.call(params: [input[:params]
[1], input[:params][2]])
partialValue.bind do |value|
Success(input.merge(multiplication_result:
partialValue.value!))
end
end
def assembling_partial_results(input)
Add.new.call( params: [input[:params][0],
input[:multiplication_result]])
end
end
rspec spec/railway_oriented_development/dry_transactions_spec.rb
.......
7 examples, 0 failures
Dry Transactions
f(a, b, x) = a.x+b, a is infinite
Dry Transaction Implementation
Add Operation

-Guard Step

-Business Logic Step: +

Multiply Operation

-Guard Step

-Business Step: *

LinearFunction

-Multiply Step

-Assemble Step

Note: 

-no conditional compared to the If Jungle Solution!

-linear execution by enlisting the steps!
2rd library
Monad Do Notation
Specs:
context 'add' do
subject { MonadDoNotation::Add.new.call params }


context 'negative cases' do
context 'params infinite' do
let(:params) { [(1.0/0.0), 2] }
specify 'Be a failure with a proper error
message' do
expect(subject).to be_failure
expect(subject.failure[:validation]).to eq
'must be a real number'
end
end
end
Monad Do Notation
f(a,b) = a+b, a is infinite
Code:
class Add
include Dry::Monads::Result::Mixin
include Dry::Monads::Do::All
def call(arguments)
validation_result = yield validate(arguments)
operation_result = yield add(arguments)
Success validation_result.merge( operation_result)
end
…
end
Monad Do Notation
f(a,b) = a+b, a is infinite
Code:
class Add
…
def validate(input)
return Failure(validation: 'must be a real
number') unless input.all?{|x|x.finite?}
Success(validation: :ok)
end
def add(input)
ret = input.reduce(0) { |acc, x| acc + x }
Success(operation_result: ret)
end
end
…
Monad Do Notation
f(a,b) = a+b, a is infinite
class LinearOperation
include Dry::Monads::Result::Mixin
include Dry::Monads::Do::All
def call(input)
multiplication = yield
multiply(input[-2..-1])
addition = yield add([input[0],
multiplication[:operation_result]])
Success(addition)
end
private …
Monad Do Notation
f(a, b, x) = a.x+b,
class LinearOperation
include Dry::Monads::Result::Mixin
include Dry::Monads::Do::All
…
private
def multiply(args)
Multiply.new.call args
end
def add(args)
Add.new.call args
end
end
rspec spec/railway_oriented_development/monad_do_notation_spec.rb
.......
7 examples, 0 failures
Monad Do Notation
f(a, b, x) = a.x+b,
Add Operation

-Validate Method

-Business Logic Method: +

Multiply Operation

-Validate Method

-Business Logic Method: *

LinearFunction

-Multiply Method

-Add Method Step

Note: 

-no conditional compared to the If Jungle Solution!

-linear execution!

-pure Ruby! *****

Monad Do Notation Implementation
3rd library
Trailblazer Operations
Specs:
context 'add' do
subject { TrailblazerOperations::Add.call params: params }


context 'negative cases' do
context 'params infinite' do
let(:params) { [(1.0/0.0), 2] }
specify 'Be a failure with a proper error message' do
expect(subject).to be_failure
expect(subject[:validation]).to eq 'must be a real
number'
end
end
end
Trailblazer Operations
f(a,b) = a+b, a is infinite
Code:
module TrailblazerOperations
class Add < Trailblazer::Operation
step :validate
step :add
private
…
end
End
Trailblazer Operations
f(a,b) = a+b, a is infinite
Railway Oriented Approach
Code:
module TrailblazerOperations
class Add < Trailblazer::Operation
…
private
def validate(options, params:)
unless params.all?{|x|x.finite?}
options[:validation] = 'must be a real number'
return Railway.fail!
end
Railway.pass!
end
def add(options, params:, **rest)
ret = params.reduce(0) { |acc, x| acc + x }
options[:operation_result] = ret
end
end
end
end
Code:
class LinearOperation < Trailblazer::Operation
step Nested( Multiply,
input: -> (options, params:, **) do
options.merge params: params[-2..-1]
end
)
step Nested( Add,
input: -> (options, params:, **) do
options.to_hash.except(:operation_result).merge
params: [params[0], options[:operation_result]]
end
)
end
rspec spec/railway_oriented_development/trailblazer_operations_spec.rb
.......
7 examples, 0 failures
Trailblazer Operations
f(a, b, x) = a.x+b,
Add Operation

-Validate Step

-Business Logic Step: +

Multiply Operation

-Validate Step

-Business Logic Step: *

LinearFunction

-Delegates to the Multiply Operation by Nesting

-Delegates to the Add Operation by Nesting

Note:

-no conditional compared to the If Jungle Solution!

-linear execution!

-DSL for reuse!

Trailblazer Implementation
Dry-Transaction Monad Do Notation Trailblazer
Steps Steps
Ruby Code Wrapped
With Yield
Steps
Code Reuse Ruby Call
Ruby Code Wrapped
With Yield
DSL for other
Operation Reuse!
True If Jungle
def create
user = User.create user_params[:user]
if user.valid?
package = Package.create package_params[:user]
if package.valid?
package.user = user
package.save
if params[:coupon].present?
if Coupon.exists? params[:coupon]
discount = Discount.create params[:coupon]
if discount.allowsUser? user
package.discount = discount
package.save
else
render ...
end
else
render ...
end
end
SmsService.send_registration_msg(user, package)
EmailService.send_registration_msg(user, package)
SystemNotifierService.send_registration_msg(user, package)
else
render ...
end
else
render ...
end
end
Cyclomatic complexity: 5
Railway Oriented Development
Cyclomatic complexity: 1-2
class Add < Trailblazer::Operation
step :persist_user
step :persist_package
step :add_coupon_based_discount
step :notify_about_registration
...
end
Railway Oriented Development
Cyclomatic complexity: 1-2
class Add < Trailblazer::Operation
step :persist_user
failure :log_user_persistance
step :persist_package
failure :log_package_persistance
step :add_coupon_based_discount
failure :log_discount_creation
step :notify_about_registration
...
end
Railway Oriented Development
Cyclomatic complexity: 1-2
class Add < Trailblazer::Operation
step :persist_user
failure :log_user_persistance
step :persist_package
failure :log_package_persistance
step :add_coupon_based_discount
failure :log_discount_creation
step :notify_about_registration
step :notify_facebook_friends
…
end
Contract for every input (entity & other use case)



Basement:

-Operations for CRUD



Crud (and Other) Reuse (DRY):

-Operations for Onboarding

-Operations for Admin

-Operations for handling Business Use Cases
Trailblazer Operations & Contracts (Reform)
My Best Practice
Thank you ;)
Botond Orban Enthusiast IT Guy, Architect 

Enthusiastic about Ruby

https://github.com/orbanbotond

@orbanbotond

Weitere ähnliche Inhalte

Was ist angesagt?

User defined functions
User defined functionsUser defined functions
User defined functions
shubham_jangid
 
Falcon初印象
Falcon初印象Falcon初印象
Falcon初印象
勇浩 赖
 
Part 3-functions
Part 3-functionsPart 3-functions
Part 3-functions
ankita44
 

Was ist angesagt? (20)

Computer Programming- Lecture 6
Computer Programming- Lecture 6Computer Programming- Lecture 6
Computer Programming- Lecture 6
 
C++ L06-Pointers
C++ L06-PointersC++ L06-Pointers
C++ L06-Pointers
 
Ch7 C++
Ch7 C++Ch7 C++
Ch7 C++
 
Let's make a contract: the art of designing a Java API
Let's make a contract: the art of designing a Java APILet's make a contract: the art of designing a Java API
Let's make a contract: the art of designing a Java API
 
C++ Presentation
C++ PresentationC++ Presentation
C++ Presentation
 
Functions123
Functions123 Functions123
Functions123
 
Functions12
Functions12Functions12
Functions12
 
Svitla talks 2021_03_25
Svitla talks 2021_03_25Svitla talks 2021_03_25
Svitla talks 2021_03_25
 
Computer Programming- Lecture 3
Computer Programming- Lecture 3Computer Programming- Lecture 3
Computer Programming- Lecture 3
 
C++ Language
C++ LanguageC++ Language
C++ Language
 
User defined functions
User defined functionsUser defined functions
User defined functions
 
C++ L05-Functions
C++ L05-FunctionsC++ L05-Functions
C++ L05-Functions
 
Programming python quick intro for schools
Programming python quick intro for schoolsProgramming python quick intro for schools
Programming python quick intro for schools
 
Computer Programming- Lecture 7
Computer Programming- Lecture 7Computer Programming- Lecture 7
Computer Programming- Lecture 7
 
Falcon初印象
Falcon初印象Falcon初印象
Falcon初印象
 
Resource wrappers in C++
Resource wrappers in C++Resource wrappers in C++
Resource wrappers in C++
 
C++ L10-Inheritance
C++ L10-InheritanceC++ L10-Inheritance
C++ L10-Inheritance
 
Part 3-functions
Part 3-functionsPart 3-functions
Part 3-functions
 
Computer Programming- Lecture 10
Computer Programming- Lecture 10Computer Programming- Lecture 10
Computer Programming- Lecture 10
 
Computer Programming- Lecture 8
Computer Programming- Lecture 8Computer Programming- Lecture 8
Computer Programming- Lecture 8
 

Ähnlich wie The Trailblazer Ride from the If Jungle into a Civilised Railway Station - Orban Botond (ENG) | Ruby Meditation 27

Столпы функционального программирования для адептов ООП, Николай Мозговой
Столпы функционального программирования для адептов ООП, Николай МозговойСтолпы функционального программирования для адептов ООП, Николай Мозговой
Столпы функционального программирования для адептов ООП, Николай Мозговой
Sigma Software
 
Rubinius @ RubyAndRails2010
Rubinius @ RubyAndRails2010Rubinius @ RubyAndRails2010
Rubinius @ RubyAndRails2010
Dirkjan Bussink
 

Ähnlich wie The Trailblazer Ride from the If Jungle into a Civilised Railway Station - Orban Botond (ENG) | Ruby Meditation 27 (20)

Hermes2D FEM Library
Hermes2D FEM LibraryHermes2D FEM Library
Hermes2D FEM Library
 
Things about Functional JavaScript
Things about Functional JavaScriptThings about Functional JavaScript
Things about Functional JavaScript
 
What's new in Python 3.11
What's new in Python 3.11What's new in Python 3.11
What's new in Python 3.11
 
MP in Clojure
MP in ClojureMP in Clojure
MP in Clojure
 
Introducing Middy, Node.js middleware engine for AWS Lambda (FrontConf Munich...
Introducing Middy, Node.js middleware engine for AWS Lambda (FrontConf Munich...Introducing Middy, Node.js middleware engine for AWS Lambda (FrontConf Munich...
Introducing Middy, Node.js middleware engine for AWS Lambda (FrontConf Munich...
 
Use Applicative where applicable!
Use Applicative where applicable!Use Applicative where applicable!
Use Applicative where applicable!
 
ForLoopandUserDefinedFunctions.pptx
ForLoopandUserDefinedFunctions.pptxForLoopandUserDefinedFunctions.pptx
ForLoopandUserDefinedFunctions.pptx
 
Geeks Anonymes - Le langage Go
Geeks Anonymes - Le langage GoGeeks Anonymes - Le langage Go
Geeks Anonymes - Le langage Go
 
functions
functionsfunctions
functions
 
Introduction to functional programming using Ocaml
Introduction to functional programming using OcamlIntroduction to functional programming using Ocaml
Introduction to functional programming using Ocaml
 
What's New In Python 2.5
What's New In Python 2.5What's New In Python 2.5
What's New In Python 2.5
 
The Road To Monad Transformers
The Road To Monad TransformersThe Road To Monad Transformers
The Road To Monad Transformers
 
Promises - Asynchronous Control Flow
Promises - Asynchronous Control FlowPromises - Asynchronous Control Flow
Promises - Asynchronous Control Flow
 
Столпы функционального программирования для адептов ООП, Николай Мозговой
Столпы функционального программирования для адептов ООП, Николай МозговойСтолпы функционального программирования для адептов ООП, Николай Мозговой
Столпы функционального программирования для адептов ООП, Николай Мозговой
 
Zope component architechture
Zope component architechtureZope component architechture
Zope component architechture
 
Chapter 02 functions -class xii
Chapter 02   functions -class xiiChapter 02   functions -class xii
Chapter 02 functions -class xii
 
Functional programming ii
Functional programming iiFunctional programming ii
Functional programming ii
 
Python lambda functions with filter, map & reduce function
Python lambda functions with filter, map & reduce functionPython lambda functions with filter, map & reduce function
Python lambda functions with filter, map & reduce function
 
golang_getting_started.pptx
golang_getting_started.pptxgolang_getting_started.pptx
golang_getting_started.pptx
 
Rubinius @ RubyAndRails2010
Rubinius @ RubyAndRails2010Rubinius @ RubyAndRails2010
Rubinius @ RubyAndRails2010
 

Mehr von Ruby Meditation

Mehr von Ruby Meditation (20)

Is this Legacy or Revenant Code? - Sergey Sergyenko | Ruby Meditation 30
Is this Legacy or Revenant Code? - Sergey Sergyenko  | Ruby Meditation 30Is this Legacy or Revenant Code? - Sergey Sergyenko  | Ruby Meditation 30
Is this Legacy or Revenant Code? - Sergey Sergyenko | Ruby Meditation 30
 
Life with GraphQL API: good practices and unresolved issues - Roman Dubrovsky...
Life with GraphQL API: good practices and unresolved issues - Roman Dubrovsky...Life with GraphQL API: good practices and unresolved issues - Roman Dubrovsky...
Life with GraphQL API: good practices and unresolved issues - Roman Dubrovsky...
 
Where is your license, dude? - Viacheslav Miroshnychenko | Ruby Meditation 29
Where is your license, dude? - Viacheslav Miroshnychenko | Ruby Meditation 29Where is your license, dude? - Viacheslav Miroshnychenko | Ruby Meditation 29
Where is your license, dude? - Viacheslav Miroshnychenko | Ruby Meditation 29
 
Dry-validation update. Dry-validation vs Dry-schema 1.0 - Aleksandra Stolyar ...
Dry-validation update. Dry-validation vs Dry-schema 1.0 - Aleksandra Stolyar ...Dry-validation update. Dry-validation vs Dry-schema 1.0 - Aleksandra Stolyar ...
Dry-validation update. Dry-validation vs Dry-schema 1.0 - Aleksandra Stolyar ...
 
How to cook Rabbit on Production - Bohdan Parshentsev | Ruby Meditation 28
How to cook Rabbit on Production - Bohdan Parshentsev | Ruby Meditation 28 How to cook Rabbit on Production - Bohdan Parshentsev | Ruby Meditation 28
How to cook Rabbit on Production - Bohdan Parshentsev | Ruby Meditation 28
 
How to cook Rabbit on Production - Serhiy Nazarov | Ruby Meditation 28
How to cook Rabbit on Production - Serhiy Nazarov | Ruby Meditation 28How to cook Rabbit on Production - Serhiy Nazarov | Ruby Meditation 28
How to cook Rabbit on Production - Serhiy Nazarov | Ruby Meditation 28
 
Reinventing the wheel - why do it and how to feel good about it - Julik Tarkh...
Reinventing the wheel - why do it and how to feel good about it - Julik Tarkh...Reinventing the wheel - why do it and how to feel good about it - Julik Tarkh...
Reinventing the wheel - why do it and how to feel good about it - Julik Tarkh...
 
Performance Optimization 101 for Ruby developers - Nihad Abbasov (ENG) | Ruby...
Performance Optimization 101 for Ruby developers - Nihad Abbasov (ENG) | Ruby...Performance Optimization 101 for Ruby developers - Nihad Abbasov (ENG) | Ruby...
Performance Optimization 101 for Ruby developers - Nihad Abbasov (ENG) | Ruby...
 
Use cases for Serverless Technologies - Ruslan Tolstov (RUS) | Ruby Meditatio...
Use cases for Serverless Technologies - Ruslan Tolstov (RUS) | Ruby Meditatio...Use cases for Serverless Technologies - Ruslan Tolstov (RUS) | Ruby Meditatio...
Use cases for Serverless Technologies - Ruslan Tolstov (RUS) | Ruby Meditatio...
 
What/How to do with GraphQL? - Valentyn Ostakh (ENG) | Ruby Meditation 27
What/How to do with GraphQL? - Valentyn Ostakh (ENG) | Ruby Meditation 27What/How to do with GraphQL? - Valentyn Ostakh (ENG) | Ruby Meditation 27
What/How to do with GraphQL? - Valentyn Ostakh (ENG) | Ruby Meditation 27
 
New features in Rails 6 - Nihad Abbasov (RUS) | Ruby Meditation 26
New features in Rails 6 -  Nihad Abbasov (RUS) | Ruby Meditation 26New features in Rails 6 -  Nihad Abbasov (RUS) | Ruby Meditation 26
New features in Rails 6 - Nihad Abbasov (RUS) | Ruby Meditation 26
 
Security Scanning Overview - Tetiana Chupryna (RUS) | Ruby Meditation 26
Security Scanning Overview - Tetiana Chupryna (RUS) | Ruby Meditation 26Security Scanning Overview - Tetiana Chupryna (RUS) | Ruby Meditation 26
Security Scanning Overview - Tetiana Chupryna (RUS) | Ruby Meditation 26
 
Teach your application eloquence. Logs, metrics, traces - Dmytro Shapovalov (...
Teach your application eloquence. Logs, metrics, traces - Dmytro Shapovalov (...Teach your application eloquence. Logs, metrics, traces - Dmytro Shapovalov (...
Teach your application eloquence. Logs, metrics, traces - Dmytro Shapovalov (...
 
Best practices. Exploring - Ike Kurghinyan (RUS) | Ruby Meditation 26
Best practices. Exploring - Ike Kurghinyan (RUS) | Ruby Meditation 26Best practices. Exploring - Ike Kurghinyan (RUS) | Ruby Meditation 26
Best practices. Exploring - Ike Kurghinyan (RUS) | Ruby Meditation 26
 
Road to A/B testing - Alexey Vasiliev (ENG) | Ruby Meditation 25
Road to A/B testing - Alexey Vasiliev (ENG) | Ruby Meditation 25Road to A/B testing - Alexey Vasiliev (ENG) | Ruby Meditation 25
Road to A/B testing - Alexey Vasiliev (ENG) | Ruby Meditation 25
 
Concurrency in production. Real life example - Dmytro Herasymuk | Ruby Medita...
Concurrency in production. Real life example - Dmytro Herasymuk | Ruby Medita...Concurrency in production. Real life example - Dmytro Herasymuk | Ruby Medita...
Concurrency in production. Real life example - Dmytro Herasymuk | Ruby Medita...
 
Data encryption for Ruby web applications - Dmytro Shapovalov (RUS) | Ruby Me...
Data encryption for Ruby web applications - Dmytro Shapovalov (RUS) | Ruby Me...Data encryption for Ruby web applications - Dmytro Shapovalov (RUS) | Ruby Me...
Data encryption for Ruby web applications - Dmytro Shapovalov (RUS) | Ruby Me...
 
Rails App performance at the limit - Bogdan Gusiev
Rails App performance at the limit - Bogdan GusievRails App performance at the limit - Bogdan Gusiev
Rails App performance at the limit - Bogdan Gusiev
 
GDPR. Next Y2K in 2018? - Anton Tkachov | Ruby Meditation #23
GDPR. Next Y2K in 2018? - Anton Tkachov | Ruby Meditation #23GDPR. Next Y2K in 2018? - Anton Tkachov | Ruby Meditation #23
GDPR. Next Y2K in 2018? - Anton Tkachov | Ruby Meditation #23
 
Postgres vs Elasticsearch while enriching data - Vlad Somov | Ruby Meditaiton...
Postgres vs Elasticsearch while enriching data - Vlad Somov | Ruby Meditaiton...Postgres vs Elasticsearch while enriching data - Vlad Somov | Ruby Meditaiton...
Postgres vs Elasticsearch while enriching data - Vlad Somov | Ruby Meditaiton...
 

Kürzlich hochgeladen

Artificial Intelligence: Facts and Myths
Artificial Intelligence: Facts and MythsArtificial Intelligence: Facts and Myths
Artificial Intelligence: Facts and Myths
Joaquim Jorge
 
Histor y of HAM Radio presentation slide
Histor y of HAM Radio presentation slideHistor y of HAM Radio presentation slide
Histor y of HAM Radio presentation slide
vu2urc
 

Kürzlich hochgeladen (20)

Understanding Discord NSFW Servers A Guide for Responsible Users.pdf
Understanding Discord NSFW Servers A Guide for Responsible Users.pdfUnderstanding Discord NSFW Servers A Guide for Responsible Users.pdf
Understanding Discord NSFW Servers A Guide for Responsible Users.pdf
 
Artificial Intelligence: Facts and Myths
Artificial Intelligence: Facts and MythsArtificial Intelligence: Facts and Myths
Artificial Intelligence: Facts and Myths
 
Presentation on how to chat with PDF using ChatGPT code interpreter
Presentation on how to chat with PDF using ChatGPT code interpreterPresentation on how to chat with PDF using ChatGPT code interpreter
Presentation on how to chat with PDF using ChatGPT code interpreter
 
Exploring the Future Potential of AI-Enabled Smartphone Processors
Exploring the Future Potential of AI-Enabled Smartphone ProcessorsExploring the Future Potential of AI-Enabled Smartphone Processors
Exploring the Future Potential of AI-Enabled Smartphone Processors
 
Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...
Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...
Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...
 
Powerful Google developer tools for immediate impact! (2023-24 C)
Powerful Google developer tools for immediate impact! (2023-24 C)Powerful Google developer tools for immediate impact! (2023-24 C)
Powerful Google developer tools for immediate impact! (2023-24 C)
 
Automating Google Workspace (GWS) & more with Apps Script
Automating Google Workspace (GWS) & more with Apps ScriptAutomating Google Workspace (GWS) & more with Apps Script
Automating Google Workspace (GWS) & more with Apps Script
 
[2024]Digital Global Overview Report 2024 Meltwater.pdf
[2024]Digital Global Overview Report 2024 Meltwater.pdf[2024]Digital Global Overview Report 2024 Meltwater.pdf
[2024]Digital Global Overview Report 2024 Meltwater.pdf
 
The Role of Taxonomy and Ontology in Semantic Layers - Heather Hedden.pdf
The Role of Taxonomy and Ontology in Semantic Layers - Heather Hedden.pdfThe Role of Taxonomy and Ontology in Semantic Layers - Heather Hedden.pdf
The Role of Taxonomy and Ontology in Semantic Layers - Heather Hedden.pdf
 
Finology Group – Insurtech Innovation Award 2024
Finology Group – Insurtech Innovation Award 2024Finology Group – Insurtech Innovation Award 2024
Finology Group – Insurtech Innovation Award 2024
 
Boost PC performance: How more available memory can improve productivity
Boost PC performance: How more available memory can improve productivityBoost PC performance: How more available memory can improve productivity
Boost PC performance: How more available memory can improve productivity
 
GenCyber Cyber Security Day Presentation
GenCyber Cyber Security Day PresentationGenCyber Cyber Security Day Presentation
GenCyber Cyber Security Day Presentation
 
04-2024-HHUG-Sales-and-Marketing-Alignment.pptx
04-2024-HHUG-Sales-and-Marketing-Alignment.pptx04-2024-HHUG-Sales-and-Marketing-Alignment.pptx
04-2024-HHUG-Sales-and-Marketing-Alignment.pptx
 
Axa Assurance Maroc - Insurer Innovation Award 2024
Axa Assurance Maroc - Insurer Innovation Award 2024Axa Assurance Maroc - Insurer Innovation Award 2024
Axa Assurance Maroc - Insurer Innovation Award 2024
 
Histor y of HAM Radio presentation slide
Histor y of HAM Radio presentation slideHistor y of HAM Radio presentation slide
Histor y of HAM Radio presentation slide
 
Raspberry Pi 5: Challenges and Solutions in Bringing up an OpenGL/Vulkan Driv...
Raspberry Pi 5: Challenges and Solutions in Bringing up an OpenGL/Vulkan Driv...Raspberry Pi 5: Challenges and Solutions in Bringing up an OpenGL/Vulkan Driv...
Raspberry Pi 5: Challenges and Solutions in Bringing up an OpenGL/Vulkan Driv...
 
Breaking the Kubernetes Kill Chain: Host Path Mount
Breaking the Kubernetes Kill Chain: Host Path MountBreaking the Kubernetes Kill Chain: Host Path Mount
Breaking the Kubernetes Kill Chain: Host Path Mount
 
A Domino Admins Adventures (Engage 2024)
A Domino Admins Adventures (Engage 2024)A Domino Admins Adventures (Engage 2024)
A Domino Admins Adventures (Engage 2024)
 
TrustArc Webinar - Stay Ahead of US State Data Privacy Law Developments
TrustArc Webinar - Stay Ahead of US State Data Privacy Law DevelopmentsTrustArc Webinar - Stay Ahead of US State Data Privacy Law Developments
TrustArc Webinar - Stay Ahead of US State Data Privacy Law Developments
 
2024: Domino Containers - The Next Step. News from the Domino Container commu...
2024: Domino Containers - The Next Step. News from the Domino Container commu...2024: Domino Containers - The Next Step. News from the Domino Container commu...
2024: Domino Containers - The Next Step. News from the Domino Container commu...
 

The Trailblazer Ride from the If Jungle into a Civilised Railway Station - Orban Botond (ENG) | Ruby Meditation 27

  • 1. From The If Jungle to A Civilised Railway Station By Botond Orban
  • 2. About Me Botond Orban Enthusiast IT Guy, Architect Enthusiastic about Ruby
 https://github.com/orbanbotond
 @orbanbotond
  • 3. The Origins The PC made in Ukraine
  • 4. Code can be written in a better way!
  • 5. Railway Oriented Development With 3 libraries in Parallel! -classic if jungle -dry transactions -monad do notation -trailblazer operations
  • 6. def create user = User.create user_params[:user] if user.valid? package = Package.create package_params[:user] if package.valid? user.package = package user.save SmsService.send_registration_msg(user, package) EmailService.send_registration_msg(user, package) SystemNotifierService.send_registration_msg(user, package) else render ... end else render ... end end True If Jungle Cyclomatic complexity: 2
  • 7. def create user = User.create user_params[:user] if user.valid? package = Package.create package_params[:user] if package.valid? package.user = user package.save if params[:coupon].present? if coupon = Coupon.exists? params[:coupon] discount = Discount.create params[:coupon] package.discount = discount package.save else render … end end SmsService.send_registration_msg(user, package) EmailService.send_registration_msg(user, package) SystemNotifierService.send_registration_msg(user, package) else render ... end else render ... end end True If Jungle Cyclomatic complexity: 4
  • 8. True If Jungle def create user = User.create user_params[:user] if user.valid? package = Package.create package_params[:user] if package.valid? package.user = user package.save if params[:coupon].present? if Coupon.exists? params[:coupon] discount = Discount.create params[:coupon] if discount.allowsUser? user package.discount = discount package.save else render ... end else render ... end end SmsService.send_registration_msg(user, package) EmailService.send_registration_msg(user, package) SystemNotifierService.send_registration_msg(user, package) else render ... end else render ... end end Cyclomatic complexity: 5
  • 11. If Jungle Implementation Specs: f(a,b) = a+b, a is infinite context 'add' do subject { add.call params: params } 
 context 'negative cases' do context 'params infinite' do let(:params) { [(1.0/0.0), 2] } specify 'Be a failure with a proper error message' do expect(subject[:validation]).to eq 'must be a real number' end end end
  • 12. add = ->(params:) do return { validation: 'must be a real number' } if params.any?{|x|x.infinite?} end Code: If Jungle Implementation f(a,b) = a+b, a is infinite
  • 13. Specs: context 'add' do subject { add.call params: params } let(:params) { [2,3,4] } context 'negative cases' do … context 'positive cases' do specify 'Be a success with the proper correct output' do expect(subject[:operation_result]).to eq(params.reduce(0) { |acc, x| acc + x }) end end end If Jungle Implementation f(a,b) = a+b,
  • 14. Code: add = ->(params:) do return { validation: 'must be a real number' } if params.any?{|x|x.infinite?} result = params.reduce(0) { |acc, x| acc + x } return { operation_result: result } end If Jungle Implementation f(a,b) = a+b,
  • 15. linear_function = ->(params:) do result = multiply.call(params: params[-2..-1]) if(result[:operation_result]) return add.call(params: [result[:operation_result], params[0]]) else return result end end rspec spec/railway_oriented_development/if_jungle_spec.rb ....... 7 examples, 0 failures If Jungle Implementation f(a,b,x) = a.x+b, Linear function
  • 16. Building Blocks Add Operation -Guard Condition -Business Logic: + Multiply Operation -Guard Condition -Business Logic: * LinearFunction -Delegation -Conditional -Delegation -Return a Result If Jungle Implementation
  • 18. Specs: context 'add' do subject { DryTransactions::Add.new.call params } 
 context 'negative cases' do context 'params infinite' do let(:params) { {params:[(1.0/0.0), 2]} } specify 'Be a failure with a proper error message' do expect(subject).to be_failure expect(subject.failure).to eq 'must be a real number' end end end Dry Transactions f(a,b) = a+b, a is infinite
  • 19. Code: module DryTransactions class Add include Dry::Transaction step :validate step :add private … … Dry Transactions f(a,b) = a+b, a is infinite
  • 21. Code: module DryTransactions class Add … private def validate(input) return Failure('must be a real number') unless input.all?{|x| x.finite?} Success(input) end
 def add(input) ret = input.reduce(0) { |acc, x| acc + x } Success(ret) end … Dry Transactions f(a,b) = a+b, a is infinite
  • 22. class LinearOperation include Dry::Transaction # a*x step :multiply # previous_result + b step :assembling_partial_results private … end Dry Transactions f(a, b, x) = a.x+b, Linear Function
  • 23. class ComplexOperation include Dry::Transaction … def multiply(input) partialValue = Multiply.new.call(params: [input[:params] [1], input[:params][2]]) partialValue.bind do |value| Success(input.merge(multiplication_result: partialValue.value!)) end end def assembling_partial_results(input) Add.new.call( params: [input[:params][0], input[:multiplication_result]]) end end rspec spec/railway_oriented_development/dry_transactions_spec.rb ....... 7 examples, 0 failures Dry Transactions f(a, b, x) = a.x+b, a is infinite
  • 24. Dry Transaction Implementation Add Operation -Guard Step -Business Logic Step: + Multiply Operation -Guard Step -Business Step: * LinearFunction -Multiply Step -Assemble Step Note: -no conditional compared to the If Jungle Solution! -linear execution by enlisting the steps!
  • 26. Specs: context 'add' do subject { MonadDoNotation::Add.new.call params } 
 context 'negative cases' do context 'params infinite' do let(:params) { [(1.0/0.0), 2] } specify 'Be a failure with a proper error message' do expect(subject).to be_failure expect(subject.failure[:validation]).to eq 'must be a real number' end end end Monad Do Notation f(a,b) = a+b, a is infinite
  • 27. Code: class Add include Dry::Monads::Result::Mixin include Dry::Monads::Do::All def call(arguments) validation_result = yield validate(arguments) operation_result = yield add(arguments) Success validation_result.merge( operation_result) end … end Monad Do Notation f(a,b) = a+b, a is infinite
  • 28. Code: class Add … def validate(input) return Failure(validation: 'must be a real number') unless input.all?{|x|x.finite?} Success(validation: :ok) end def add(input) ret = input.reduce(0) { |acc, x| acc + x } Success(operation_result: ret) end end … Monad Do Notation f(a,b) = a+b, a is infinite
  • 29. class LinearOperation include Dry::Monads::Result::Mixin include Dry::Monads::Do::All def call(input) multiplication = yield multiply(input[-2..-1]) addition = yield add([input[0], multiplication[:operation_result]]) Success(addition) end private … Monad Do Notation f(a, b, x) = a.x+b,
  • 30. class LinearOperation include Dry::Monads::Result::Mixin include Dry::Monads::Do::All … private def multiply(args) Multiply.new.call args end def add(args) Add.new.call args end end rspec spec/railway_oriented_development/monad_do_notation_spec.rb ....... 7 examples, 0 failures Monad Do Notation f(a, b, x) = a.x+b,
  • 31. Add Operation -Validate Method -Business Logic Method: + Multiply Operation -Validate Method -Business Logic Method: * LinearFunction -Multiply Method -Add Method Step Note: -no conditional compared to the If Jungle Solution! -linear execution! -pure Ruby! ***** Monad Do Notation Implementation
  • 33. Specs: context 'add' do subject { TrailblazerOperations::Add.call params: params } 
 context 'negative cases' do context 'params infinite' do let(:params) { [(1.0/0.0), 2] } specify 'Be a failure with a proper error message' do expect(subject).to be_failure expect(subject[:validation]).to eq 'must be a real number' end end end Trailblazer Operations f(a,b) = a+b, a is infinite
  • 34. Code: module TrailblazerOperations class Add < Trailblazer::Operation step :validate step :add private … end End Trailblazer Operations f(a,b) = a+b, a is infinite
  • 36. Code: module TrailblazerOperations class Add < Trailblazer::Operation … private def validate(options, params:) unless params.all?{|x|x.finite?} options[:validation] = 'must be a real number' return Railway.fail! end Railway.pass! end def add(options, params:, **rest) ret = params.reduce(0) { |acc, x| acc + x } options[:operation_result] = ret end end end end
  • 37. Code: class LinearOperation < Trailblazer::Operation step Nested( Multiply, input: -> (options, params:, **) do options.merge params: params[-2..-1] end ) step Nested( Add, input: -> (options, params:, **) do options.to_hash.except(:operation_result).merge params: [params[0], options[:operation_result]] end ) end rspec spec/railway_oriented_development/trailblazer_operations_spec.rb ....... 7 examples, 0 failures Trailblazer Operations f(a, b, x) = a.x+b,
  • 38. Add Operation -Validate Step -Business Logic Step: + Multiply Operation -Validate Step -Business Logic Step: * LinearFunction -Delegates to the Multiply Operation by Nesting -Delegates to the Add Operation by Nesting Note: -no conditional compared to the If Jungle Solution! -linear execution! -DSL for reuse! Trailblazer Implementation
  • 39. Dry-Transaction Monad Do Notation Trailblazer Steps Steps Ruby Code Wrapped With Yield Steps Code Reuse Ruby Call Ruby Code Wrapped With Yield DSL for other Operation Reuse!
  • 40. True If Jungle def create user = User.create user_params[:user] if user.valid? package = Package.create package_params[:user] if package.valid? package.user = user package.save if params[:coupon].present? if Coupon.exists? params[:coupon] discount = Discount.create params[:coupon] if discount.allowsUser? user package.discount = discount package.save else render ... end else render ... end end SmsService.send_registration_msg(user, package) EmailService.send_registration_msg(user, package) SystemNotifierService.send_registration_msg(user, package) else render ... end else render ... end end Cyclomatic complexity: 5
  • 41. Railway Oriented Development Cyclomatic complexity: 1-2 class Add < Trailblazer::Operation step :persist_user step :persist_package step :add_coupon_based_discount step :notify_about_registration ... end
  • 42. Railway Oriented Development Cyclomatic complexity: 1-2 class Add < Trailblazer::Operation step :persist_user failure :log_user_persistance step :persist_package failure :log_package_persistance step :add_coupon_based_discount failure :log_discount_creation step :notify_about_registration ... end
  • 43. Railway Oriented Development Cyclomatic complexity: 1-2 class Add < Trailblazer::Operation step :persist_user failure :log_user_persistance step :persist_package failure :log_package_persistance step :add_coupon_based_discount failure :log_discount_creation step :notify_about_registration step :notify_facebook_friends … end
  • 44. Contract for every input (entity & other use case)
 
 Basement:
 -Operations for CRUD 
 Crud (and Other) Reuse (DRY): -Operations for Onboarding -Operations for Admin -Operations for handling Business Use Cases Trailblazer Operations & Contracts (Reform) My Best Practice
  • 45.
  • 46.
  • 47.
  • 48.
  • 49. Thank you ;) Botond Orban Enthusiast IT Guy, Architect Enthusiastic about Ruby
 https://github.com/orbanbotond
 @orbanbotond