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

Ruby Meditation
Ruby MeditationRuby Meditation
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
The Trailblazer Ride from the If Jungle into a Civilised Railway Station - Orban Botond (ENG) | Ruby Meditation 27
The Trailblazer Ride from the If Jungle into a Civilised Railway Station - Orban Botond (ENG) | Ruby Meditation 27
The Trailblazer Ride from the If Jungle into a Civilised Railway Station - Orban Botond (ENG) | Ruby Meditation 27
The Trailblazer Ride from the If Jungle into a Civilised Railway Station - Orban Botond (ENG) | Ruby Meditation 27
Thank you ;)
Botond Orban Enthusiast IT Guy, Architect 

Enthusiastic about Ruby

https://github.com/orbanbotond

@orbanbotond
1 of 49

Recommended

Recursion to iteration automation. by
Recursion to iteration automation.Recursion to iteration automation.
Recursion to iteration automation.Russell Childs
128 views8 slides
C++ L01-Variables by
C++ L01-VariablesC++ L01-Variables
C++ L01-VariablesMohammad Shaker
1.5K views60 slides
Imugi: Compiler made with Python by
Imugi: Compiler made with PythonImugi: Compiler made with Python
Imugi: Compiler made with PythonHan Lee
931 views62 slides
Composition birds-and-recursion by
Composition birds-and-recursionComposition birds-and-recursion
Composition birds-and-recursionDavid Atchley
143 views29 slides
GoLightly: Building VM-Based Language Runtimes with Google Go by
GoLightly: Building VM-Based Language Runtimes with Google GoGoLightly: Building VM-Based Language Runtimes with Google Go
GoLightly: Building VM-Based Language Runtimes with Google GoEleanor McHugh
3.1K views134 slides
Google Go For Ruby Hackers by
Google Go For Ruby HackersGoogle Go For Ruby Hackers
Google Go For Ruby HackersEleanor McHugh
2.3K views352 slides

More Related Content

What's hot

Computer Programming- Lecture 6 by
Computer Programming- Lecture 6Computer Programming- Lecture 6
Computer Programming- Lecture 6Dr. Md. Shohel Sayeed
32.3K views43 slides
C++ L06-Pointers by
C++ L06-PointersC++ L06-Pointers
C++ L06-PointersMohammad Shaker
756 views145 slides
Ch7 C++ by
Ch7 C++Ch7 C++
Ch7 C++Venkateswarlu Vuggam
70 views21 slides
Let's make a contract: the art of designing a Java API by
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 APIMario Fusco
2.7K views92 slides
C++ Presentation by
C++ PresentationC++ Presentation
C++ PresentationCarson Wilber
2.5K views53 slides
Functions123 by
Functions123 Functions123
Functions123 sandhubuta
348 views28 slides

What's hot(20)

Let's make a contract: the art of designing a Java API by Mario Fusco
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
Mario Fusco2.7K views
Functions123 by sandhubuta
Functions123 Functions123
Functions123
sandhubuta348 views
Programming python quick intro for schools by Dan Bowen
Programming python quick intro for schoolsProgramming python quick intro for schools
Programming python quick intro for schools
Dan Bowen1.4K views
Falcon初印象 by 勇浩 赖
Falcon初印象Falcon初印象
Falcon初印象
勇浩 赖1K views
Resource wrappers in C++ by Ilio Catallo
Resource wrappers in C++Resource wrappers in C++
Resource wrappers in C++
Ilio Catallo505 views
Part 3-functions by ankita44
Part 3-functionsPart 3-functions
Part 3-functions
ankita44415 views

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

Hermes2D FEM Library by
Hermes2D FEM LibraryHermes2D FEM Library
Hermes2D FEM LibraryLukas Korous
219 views70 slides
Things about Functional JavaScript by
Things about Functional JavaScriptThings about Functional JavaScript
Things about Functional JavaScriptChengHui Weng
324 views74 slides
What's new in Python 3.11 by
What's new in Python 3.11What's new in Python 3.11
What's new in Python 3.11Henry Schreiner
246 views36 slides
MP in Clojure by
MP in ClojureMP in Clojure
MP in ClojureKent Ohashi
4.1K views53 slides
Introducing Middy, Node.js middleware engine for AWS Lambda (FrontConf Munich... by
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...Luciano Mammino
2.8K views18 slides
Use Applicative where applicable! by
Use Applicative where applicable!Use Applicative where applicable!
Use Applicative where applicable!Hermann Hueck
252 views149 slides

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

Hermes2D FEM Library by Lukas Korous
Hermes2D FEM LibraryHermes2D FEM Library
Hermes2D FEM Library
Lukas Korous219 views
Things about Functional JavaScript by ChengHui Weng
Things about Functional JavaScriptThings about Functional JavaScript
Things about Functional JavaScript
ChengHui Weng324 views
MP in Clojure by Kent Ohashi
MP in ClojureMP in Clojure
MP in Clojure
Kent Ohashi4.1K views
Introducing Middy, Node.js middleware engine for AWS Lambda (FrontConf Munich... by Luciano Mammino
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...
Luciano Mammino2.8K views
Use Applicative where applicable! by Hermann Hueck
Use Applicative where applicable!Use Applicative where applicable!
Use Applicative where applicable!
Hermann Hueck252 views
ForLoopandUserDefinedFunctions.pptx by AaliyanShaikh
ForLoopandUserDefinedFunctions.pptxForLoopandUserDefinedFunctions.pptx
ForLoopandUserDefinedFunctions.pptx
AaliyanShaikh3 views
Geeks Anonymes - Le langage Go by Geeks Anonymes
Geeks Anonymes - Le langage GoGeeks Anonymes - Le langage Go
Geeks Anonymes - Le langage Go
Geeks Anonymes237 views
Introduction to functional programming using Ocaml by pramode_ce
Introduction to functional programming using OcamlIntroduction to functional programming using Ocaml
Introduction to functional programming using Ocaml
pramode_ce6K views
What's New In Python 2.5 by Richard Jones
What's New In Python 2.5What's New In Python 2.5
What's New In Python 2.5
Richard Jones1.7K views
The Road To Monad Transformers by Pawel Lisewski
The Road To Monad TransformersThe Road To Monad Transformers
The Road To Monad Transformers
Pawel Lisewski295 views
Столпы функционального программирования для адептов ООП, Николай Мозговой by Sigma Software
Столпы функционального программирования для адептов ООП, Николай МозговойСтолпы функционального программирования для адептов ООП, Николай Мозговой
Столпы функционального программирования для адептов ООП, Николай Мозговой
Sigma Software128 views
Chapter 02 functions -class xii by praveenjigajinni
Chapter 02   functions -class xiiChapter 02   functions -class xii
Chapter 02 functions -class xii
praveenjigajinni21.5K views
Python lambda functions with filter, map & reduce function by ARVIND PANDE
Python lambda functions with filter, map & reduce functionPython lambda functions with filter, map & reduce function
Python lambda functions with filter, map & reduce function
ARVIND PANDE269 views
golang_getting_started.pptx by Guy Komari
golang_getting_started.pptxgolang_getting_started.pptx
golang_getting_started.pptx
Guy Komari99 views

More from Ruby Meditation

Is this Legacy or Revenant Code? - Sergey Sergyenko | Ruby Meditation 30 by
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 30Ruby Meditation
207 views22 slides
Life with GraphQL API: good practices and unresolved issues - Roman Dubrovsky... by
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...Ruby Meditation
462 views141 slides
Where is your license, dude? - Viacheslav Miroshnychenko | Ruby Meditation 29 by
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 29Ruby Meditation
210 views49 slides
Dry-validation update. Dry-validation vs Dry-schema 1.0 - Aleksandra Stolyar ... by
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 ...Ruby Meditation
1.6K views59 slides
How to cook Rabbit on Production - Bohdan Parshentsev | Ruby Meditation 28 by
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 Ruby Meditation
366 views23 slides
How to cook Rabbit on Production - Serhiy Nazarov | Ruby Meditation 28 by
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 28Ruby Meditation
459 views20 slides

More from Ruby Meditation(20)

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

Recently uploaded

Five Things You SHOULD Know About Postman by
Five Things You SHOULD Know About PostmanFive Things You SHOULD Know About Postman
Five Things You SHOULD Know About PostmanPostman
25 views43 slides
[2023] Putting the R! in R&D.pdf by
[2023] Putting the R! in R&D.pdf[2023] Putting the R! in R&D.pdf
[2023] Putting the R! in R&D.pdfEleanor McHugh
38 views127 slides
Combining Orchestration and Choreography for a Clean Architecture by
Combining Orchestration and Choreography for a Clean ArchitectureCombining Orchestration and Choreography for a Clean Architecture
Combining Orchestration and Choreography for a Clean ArchitectureThomasHeinrichs1
68 views24 slides
"Role of a CTO in software outsourcing company", Yuriy Nakonechnyy by
"Role of a CTO in software outsourcing company", Yuriy Nakonechnyy"Role of a CTO in software outsourcing company", Yuriy Nakonechnyy
"Role of a CTO in software outsourcing company", Yuriy NakonechnyyFwdays
40 views21 slides
Upskilling the Evolving Workforce with Digital Fluency for Tomorrow's Challen... by
Upskilling the Evolving Workforce with Digital Fluency for Tomorrow's Challen...Upskilling the Evolving Workforce with Digital Fluency for Tomorrow's Challen...
Upskilling the Evolving Workforce with Digital Fluency for Tomorrow's Challen...NUS-ISS
23 views70 slides
PharoJS - Zürich Smalltalk Group Meetup November 2023 by
PharoJS - Zürich Smalltalk Group Meetup November 2023PharoJS - Zürich Smalltalk Group Meetup November 2023
PharoJS - Zürich Smalltalk Group Meetup November 2023Noury Bouraqadi
113 views17 slides

Recently uploaded(20)

Five Things You SHOULD Know About Postman by Postman
Five Things You SHOULD Know About PostmanFive Things You SHOULD Know About Postman
Five Things You SHOULD Know About Postman
Postman25 views
[2023] Putting the R! in R&D.pdf by Eleanor McHugh
[2023] Putting the R! in R&D.pdf[2023] Putting the R! in R&D.pdf
[2023] Putting the R! in R&D.pdf
Eleanor McHugh38 views
Combining Orchestration and Choreography for a Clean Architecture by ThomasHeinrichs1
Combining Orchestration and Choreography for a Clean ArchitectureCombining Orchestration and Choreography for a Clean Architecture
Combining Orchestration and Choreography for a Clean Architecture
ThomasHeinrichs168 views
"Role of a CTO in software outsourcing company", Yuriy Nakonechnyy by Fwdays
"Role of a CTO in software outsourcing company", Yuriy Nakonechnyy"Role of a CTO in software outsourcing company", Yuriy Nakonechnyy
"Role of a CTO in software outsourcing company", Yuriy Nakonechnyy
Fwdays40 views
Upskilling the Evolving Workforce with Digital Fluency for Tomorrow's Challen... by NUS-ISS
Upskilling the Evolving Workforce with Digital Fluency for Tomorrow's Challen...Upskilling the Evolving Workforce with Digital Fluency for Tomorrow's Challen...
Upskilling the Evolving Workforce with Digital Fluency for Tomorrow's Challen...
NUS-ISS23 views
PharoJS - Zürich Smalltalk Group Meetup November 2023 by Noury Bouraqadi
PharoJS - Zürich Smalltalk Group Meetup November 2023PharoJS - Zürich Smalltalk Group Meetup November 2023
PharoJS - Zürich Smalltalk Group Meetup November 2023
Noury Bouraqadi113 views
"Thriving Culture in a Product Company — Practical Story", Volodymyr Tsukur by Fwdays
"Thriving Culture in a Product Company — Practical Story", Volodymyr Tsukur"Thriving Culture in a Product Company — Practical Story", Volodymyr Tsukur
"Thriving Culture in a Product Company — Practical Story", Volodymyr Tsukur
Fwdays40 views
Architecting CX Measurement Frameworks and Ensuring CX Metrics are fit for Pu... by NUS-ISS
Architecting CX Measurement Frameworks and Ensuring CX Metrics are fit for Pu...Architecting CX Measurement Frameworks and Ensuring CX Metrics are fit for Pu...
Architecting CX Measurement Frameworks and Ensuring CX Metrics are fit for Pu...
NUS-ISS32 views
Samsung: CMM-H Tiered Memory Solution with Built-in DRAM by CXL Forum
Samsung: CMM-H Tiered Memory Solution with Built-in DRAMSamsung: CMM-H Tiered Memory Solution with Built-in DRAM
Samsung: CMM-H Tiered Memory Solution with Built-in DRAM
CXL Forum105 views
Transcript: The Details of Description Techniques tips and tangents on altern... by BookNet Canada
Transcript: The Details of Description Techniques tips and tangents on altern...Transcript: The Details of Description Techniques tips and tangents on altern...
Transcript: The Details of Description Techniques tips and tangents on altern...
BookNet Canada119 views
Future of Learning - Yap Aye Wee.pdf by NUS-ISS
Future of Learning - Yap Aye Wee.pdfFuture of Learning - Yap Aye Wee.pdf
Future of Learning - Yap Aye Wee.pdf
NUS-ISS38 views
.conf Go 2023 - Data analysis as a routine by Splunk
.conf Go 2023 - Data analysis as a routine.conf Go 2023 - Data analysis as a routine
.conf Go 2023 - Data analysis as a routine
Splunk90 views
MemVerge: Past Present and Future of CXL by CXL Forum
MemVerge: Past Present and Future of CXLMemVerge: Past Present and Future of CXL
MemVerge: Past Present and Future of CXL
CXL Forum110 views
The details of description: Techniques, tips, and tangents on alternative tex... by BookNet Canada
The details of description: Techniques, tips, and tangents on alternative tex...The details of description: Techniques, tips, and tangents on alternative tex...
The details of description: Techniques, tips, and tangents on alternative tex...
BookNet Canada110 views
TE Connectivity: Card Edge Interconnects by CXL Forum
TE Connectivity: Card Edge InterconnectsTE Connectivity: Card Edge Interconnects
TE Connectivity: Card Edge Interconnects
CXL Forum96 views
Future of Learning - Khoong Chan Meng by NUS-ISS
Future of Learning - Khoong Chan MengFuture of Learning - Khoong Chan Meng
Future of Learning - Khoong Chan Meng
NUS-ISS31 views
Empathic Computing: Delivering the Potential of the Metaverse by Mark Billinghurst
Empathic Computing: Delivering  the Potential of the MetaverseEmpathic Computing: Delivering  the Potential of the Metaverse
Empathic Computing: Delivering the Potential of the Metaverse
Mark Billinghurst449 views

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
  • 49. Thank you ;) Botond Orban Enthusiast IT Guy, Architect Enthusiastic about Ruby
 https://github.com/orbanbotond
 @orbanbotond