SlideShare une entreprise Scribd logo
1  sur  138
Télécharger pour lire hors ligne
Reinventing the
Transaction Script
(NDC London 2020)
@ScottWlaschin
fsharpforfunandprofit.com
Are transaction scripts
a Bad Thing?
Are transaction scripts
a Bad Thing?
No!
Part I
What is a "Transaction Script"?
What is a "Transaction Script"?
Question:
How should you organize
your domain logic?
Transaction Script
• Most business applications can be thought of
as a series of transactions.
• A "Transaction Script" organizes this logic as a
single procedure, making calls directly to the
database or through a thin database wrapper.
• Each transaction will have its ownTransaction
Script
The PEAA patterns for domain logic
• Transaction script: each procedure handles a
single request
• Table Module: one instance handles the
business logic for all rows in a database
table/view.
• Domain Model: An object model of the domain
that incorporates both behavior and data.
• Service Layer: a layer of services that
establishes a set of available operations
The PEAA patterns for domain logic
• Transaction script
• Table Module
• Domain Model
• Service Layer
Too simple, too "anemic"
Too db centric
Nice and complex!
The developer's curse
Simple Complex
Transaction scripts have a bad rep
• The reputation
– It's for people who are stuck in the 1990s
– It's for people who use Cobol
– It's only for uncool people
• The truth
– It can be reinvented using functional programming
– Therefore, it can now be cool again!
The pros and cons of
Transaction Scripts
A typical transaction script
get data from DB
do some business logic
write some data to DB
some more business logic
if some condition then
some more DB access
some more business logic
some more DB access
else
some more business logic
some more DB access
Pro: Easy to understand.
One directional.
Pro: Focused!
All code is relevant.
YAGNI for free
A typical transaction script
get data from DB
do some business logic
write some data to DB
some more business logic
if some condition then
some more DB access
some more business logic
some more DB access
else
some more business logic
some more DB access
Con: Hard to modify
A typical transaction script
get data from DB
do some business logic
write some data to DB
some more business logic
if some condition then
some more DB access
some more business logic
some more DB access
else if some other condition then
some more business logic
else
some more business logic
some more DB access
Con: Hard to modify
and evolve.
No graceful path to
richer behavior
A typical transaction script
get data from DB
do some business logic
write some data to DB
some more business logic
if some condition then
some more DB access
some more business logic
some more DB access
else
some more business logic
some more DB access
Con: Hard to reuse.
No rich domain model.
How do you reuse this bit only?
A typical transaction script
get data from DB
do some business logic
write some data to DB
some more business logic
if some condition then
some more DB access
some more business logic
some more DB access
else
some more business logic
some more DB access
Con: Hard to test
Business logic is
mixed up with DB access
A typical transaction script
get data from DB
do some business logic
write some data to DB
some more business logic
if some condition then
some more DB access
some more business logic
some more DB access
else
some more business logic
some more DB access
Con: Hard to test
How can you test
just these bits?
A typical transaction script
get data from DB
do some business logic
write some data to DB
some more business logic
if some condition then
some more DB access
some more business logic
some more DB access
else
some more business logic
some more DB access
Can we fix
these problems?
Yes, we can!
The fix:
Use Functional Programming
& Domain Driven Design
High coolness score
Part II
Intro to Functional Programming
Function
The Tunnel of
Transformation
Function
apple -> banana
A function is a thing which
transforms inputs to outputs
A function is a standalone thing,
not attached to a class
It can be used for inputs and outputs
of other functions
input
A function can be an output
A function is a standalone thing
output
A function can be an input
A function is a standalone thing
input output
A function can be a parameter
A function is a standalone thing
Core FP principle:
Composition everywhere
What is Composition?
Lego Philosophy
1. All pieces are designed to be connected
2. The pieces are reusable in many contexts
3. Connect two pieces together and get
another "piece" that can still be connected
All pieces are designed to be connected
The pieces are reusable in different contexts
Connect two pieces together and
get another "piece" that can still be connected
Make big things from small things in the same way
Function Composition
Function composition
Function 1
apple -> banana
Function 2
banana -> cherry
Function composition
>>
Function 1
apple -> banana
Function 2
banana -> cherry
Function composition
New Function
apple -> cherry
Can't tell it was built
from smaller functions!
Where did the banana go?
(abstraction)
Building big things from functions
It's compositions all the way up
Low-level operation
ToUpper
stringstring
Low-level operation
Service
AddressValidator
Validation
Result
Address
Low-level operation Low-level operation
Service
Use-case
UpdateProfileData
ChangeProfile
Result
ChangeProfile
Request
Service Service
Use-case
Web application
Http
Response
Http
Request
Use-case Use-case
Http
Response
Http
Request
Check out my "Power
of Composition" talk
for more details.
Composition everywhere:
Types can be composed too
Algebraic type system
New types are built from smaller types by:
Composing with “AND”
Composing with “OR”
Example: pairs, tuples, records
FruitSalad = One each of and and
Compose with “AND”
type FruitSalad = {
Apple: AppleVariety
Banana: BananaVariety
Cherry: CherryVariety
}
Snack = or or
Compose with “OR”
type Snack =
| Apple of AppleVariety
| Banana of BananaVariety
| Cherry of CherryVariety
Real world example
of type composition
Example of some requirements:
We accept three forms of payment:
Cash, PayPal, or Card.
For Cash we don't need any extra information
For PayPal we need an email address
For Cards we need a card type and card number
interface IPaymentMethod
{..}
class Cash() : IPaymentMethod
{..}
class PayPal(string emailAddress): IPaymentMethod
{..}
class Card(string cardType, string cardNo) : IPaymentMethod
{..}
In OO design you would probably implement it as an
interface and a set of subclasses, like this:
type EmailAddress = string
type CardNumber = string
In FP you would probably implement by composing
types, like this:
type EmailAddress = ...
type CardNumber = …
type CardType = Visa | Mastercard
type CreditCardInfo = {
CardType : CardType
CardNumber : CardNumber
}
type EmailAddress = ...
type CardNumber = ...
type CardType = ...
type CreditCardInfo = ...
type PaymentMethod =
| Cash
| PayPal of EmailAddress
| Card of CreditCardInfo
type EmailAddress = ...
type CardNumber = ...
type CardType = ...
type CreditCardInfo = ...
type PaymentMethod =
| Cash
| PayPal of EmailAddress
| Card of CreditCardInfo
type PaymentAmount = decimal
type Currency = EUR | USD
type EmailAddress = ...
type CardNumber = ...
type CardType = ...
type CreditCardInfo = ...
type PaymentMethod =
| Cash
| PayPal of EmailAddress
| Card of CreditCardInfo
type PaymentAmount = decimal
type Currency = EUR | USD
type Payment = {
Amount : PaymentAmount
Currency: Currency
Method: PaymentMethod }
type EmailAddress = ...
type CardNumber = ...
type CardType = ...
type CreditCardInfo = ...
type PaymentMethod =
| Cash
| PayPal of EmailAddress
| Card of CreditCardInfo
type PaymentAmount = decimal
type Currency = EUR | USD
type Payment = {
Amount : PaymentAmount
Currency: Currency
Method: PaymentMethod }
Applying FP principles to
Transaction Scripts
Introducing "Workflows"
A.k.a. "Transaction", "Story" , "Use-case"
Check out "Event Storming" for
understanding business events
Implementing workflows
A workflow will be
implemented by a function!
Composable
Type
Composable
Type
Implementing workflows
Inputs and outputs are
defined by composable types
Implementing workflows
We will compose a workflow
from smaller components
Each component is a
standalone function
Part III
Intro to Domain-Driven Design
The DDD book came out just
after PEAA in 2003
"Focus on the domain and domain
logic rather than technology"
-- Eric Evans
Agile
Agile
Domain-Driven Design
Domain-Driven Design
• Agile contribution:
– Rapid feedback during design
• DDD contribution:
– Stakeholders have a shared mental model
– …which is also represented in the code
How can we do design right?
Key DDD principle:
Communicate the design
in the code
Can you really make code
represent the domain?
What some source code looks like
module CardGame =
type Suit = Club | Diamond | Spade | Heart
type Rank = Two |Three | Four | Five | Six | Seven | Eight
| Nine |Ten | Jack | Queen | King
type Card = Suit * Rank
type Hand = Card list
type Deck = Card list
type Player = {Name:string; Hand:Hand}
type Game = {Deck:Deck; Players: Player list}
type Deal = Deck –› (Deck * Card)
type PickupCard = (Hand * Card) –› Hand
Sharedlanguage What DDD source code
*should* look like
(this is F#)
module CardGame =
type Suit = Club | Diamond | Spade | Heart
type Rank = Two |Three | Four | Five | Six | Seven | Eight
| Nine |Ten | Jack | Queen | King
type Card = Suit * Rank
type Hand = Card list
type Deck = Card list
type Player = {Name:string; Hand:Hand}
type Game = {Deck:Deck; Players: Player list}
type Deal = Deck –› (Deck * Card)
type PickupCard = (Hand * Card) –› Hand
* means a pair. Choose one from each type
list type is built in
Deal
(original)
Deck
(remaining)
Deck
(on table)
Card
Modeling a workflow with a function
type Deal = Deck -> (Deck * Card)
Input Output
Pickup Card
(updated)
Hand
(original)
Hand
(on table)
Card
Modeling a workflow with a function
type PickupCard = (Hand * Card) –> Hand
Input Output
module CardGame =
type Suit = Club | Diamond | Spade | Heart
type Rank = Two |Three | Four | Five | Six | Seven | Eight
| Nine |Ten | Jack | Queen | King
type Card = Suit * Rank
type Hand = Card list
type Deck = Card list
type Player = { Name:string; Hand:Hand }
type Game = { Deck:Deck; Players: Player list }
type Deal = Deck –› (Deck * Card)
type PickupCard = (Hand * Card) –› Hand
module CardGame =
type Suit = Club | Diamond | Spade | Heart
type Rank = Two |Three | Four | Five | Six | Seven | Eight
| Nine |Ten | Jack | Queen | King
type Card = Suit * Rank
type Hand = Card list
type Deck = Card list
type Player = { Name:string; Hand:Hand }
type Game = { Deck:Deck; Players: Player list }
type Deal = Deck –› (Deck * Card)
type PickupCard = (Hand * Card) –› Hand
module CardGame =
type Suit = Club | Diamond | Spade | Heart
type Rank = Two |Three | Four | Five | Six | Seven | Eight
| Nine |Ten | Jack | Queen | King
type Card = Suit * Rank
type Hand = Card list
type Deck = Card list
type Player = { Name:string; Hand:Hand }
type Game = { Deck:Deck; Players: Player list }
type Deal = Deck –› (Deck * Card)
type PickupCard = (Hand * Card) –› Hand
Can non-programmers provide
useful feedback?
module CardGame =
type Suit = Club | Diamond | Spade | Heart
type Rank = Two |Three | Four | Five | Six | Seven | Eight | …
type Card = Suit * Rank
type Hand = Card list
type Deck = Card list
type Player = { Name:string; Hand:Hand }
type Game = { Deck:Deck; Players: Player list }
type Deal = Deck –› (Deck * Card)
type PickupCard = (Hand * Card) –› Hand
module CardGame =
type Suit = Club | Diamond | Spade | Heart
type Rank = Two |Three | Four | Five | Six | Seven | Eight | …
type Card = Suit * Rank
type Hand = Card list
type Deck = Card list
type Player = { Name:string; Hand:Hand }
type Game = { Deck:Deck; Players: Player list }
type Deal = Deck –› (Deck * Card)
type PickupCard = (Hand * Card) –› Hand
In the real world
Suit
Rank
Card
Hand
Deck
Player
Deal
In the code
Suit
Rank
Card
Hand
Deck
Player
Deal
In the real world
Suit
Rank
Card
Hand
Deck
Player
Deal
In the code
Suit
Rank
Card
Hand
Deck
Player
Deal
PlayerController
DeckBase
AbstractCardProxyFactoryBean

module CardGame =
type Suit = Club | Diamond | Spade | Heart
type Rank = Two |Three | Four | Five | Six | Seven | Eight | …
type Card = Suit * Rank
type Hand = Card list
type Deck = Card list
type Player = { Name:string; Hand:Hand }
type Game = { Deck:Deck; Players: Player list }
type Deal = Deck –› (Deck * Card)
type PickupCard = (Hand * Card) –› Hand
Key DDD principle:
Communicate the design
in the code

Introducing "bounded contexts"
Grouping functionality in the domain
A bounded
context
Why "Bounded Context"?
• "Context"
– Specialized knowledge and common language
– Information taken out of context is confusing or
unusable
• "Bounded"
– Contexts must be autonomous so they can
evolve independently.
– Boundaries keep you focused! No scope creep!
Bounded context
Bounded context with workflows
A bounded context contains a set of
related workflows
Bounded context with workflows
A bounded context contains a set of
related workflows/functions
Part IV
Reinventing the Transaction Script
• FP contribution:
– Transactions are functions
– Build them from components using composition
• Functional Domain Modeling contribution:
– Use composable types for a rich domain model
– The domain actions are standalone/reusable
– Use autonomous bounded contexts to group and
manage the workflows
Reinventing the Transaction Script
Pros and cons of Transaction Scripts
Pros
• Easy to understand
• Focused: All code is
relevant.
Cons
• Hard to modify/evolve
• Hard to reuse
• No rich domain model
• Hard to test
Claim:
FP-style transaction scripts
are easier to comprehend than
OO domain models.
FP workflow
All arrows go left to right
Example: a web backend
One directional flow,
even with branching
Object Oriented workflow
Arrows go in all directions
We don't design microservices this way!
Real-world OO dependency graph
Multiple cyclic dependencies 
Real-world FP dependency graph
All arrows go left to right 
Same functionality
as the OO example
Claim:
FP-style transaction scripts
are resistant to bloat
Some OO-style interfaces
interface IRepository {
Insert
InsertAsync
Delete
DeleteAsync
Update
UpdateAsync
CommitChanges
CommitChangesAsync
Query
QueryByKey
QueryWithFilter
QueryWithSpecification
Contains
Count
QuerySummary
QuerySummaryV2
ChangePassword
ChangePasswordV2
DeleteAllRows
LaunchMissiles
LaunchMissilesV2
}
One interface that supports *every*
possible workflow!
Where's the
Interface segregation principle?
FP workflow
Transaction script style functions
only contain what they need.
Every part is relevant.
You get the ISP for free.
Claim:
FP-style transaction scripts
can be modified with confidence
Modifying a workflow
Replace a component
Static type checking ensures that
sub-components are used correctly
Minimizing the amount of code that I touch
Add features to a workflow
Insert new logic
Minimizing the amount of code that I touch
Add branching to a workflow
Add conditional logic
Parameterizing a workflow for reuse
Swap out parameters for reuse
as long as input and output types match
Claim:
FP-style transaction scripts
can have a rich domain model
type Deal = Deck –› (Deck * Card)
type PickupCard = (Hand * Card) –› Hand
A rich domain model...
These functions are independent, so these
workflows can still evolve independently
...used in functions
Sharing rich domain components
Shared component
Yes, complex domain logic *is*
compatible with transaction scripts
Claim:
FP-style transaction scripts
are the natural evolution of
Onion/Clean/Hexagonal
Architecture
Traditional layered model
A change to the way that a workflow works
means that you need to touch every layer.
Vertical slices
Each workflow contains all the code it needs to get its job done.
When the requirements change for a workflow, only the code in
that particular vertical slice needs to change.
Vertical slices stretched out
Confusing!

The "onion" architecture
Core domain is pure, and all I/O is at the edges

See "Functional Core/Imperative Shell"
Claim:
FP-style transaction scripts
are easy to test
Review of Key Testing Concepts
• The SUT (System Under Test) should be a unit of
business value
– Test transactions, not classes
• Tests should apply to the boundaries of a system
not its internals
– Tests should be done at the transaction level
• A "Unit" test means the test is isolated
– That is, it produces no side effects and can be run in
isolation.
– A unit is not a class!
In a functional design, all
I/O is at the edges.
A FP-style transaction script
Database Database
Load data
Process it
Save it
DeterministicNon-deterministic Non-deterministic
This makes testing easy!
I/O in the middle of a workflow
Keep them separate
FP style transactions work
on the front end too!
event-driven!
MVU is a FP style approach
As seen in Elm, Redux, etc
MVU is a FP style approach
Deterministic
function
Deterministic
function
Non-deterministic
actions ("I/O")
PartV
Deployment options for
FP-style transaction scripts
3 different architectures…
• For monoliths:
– Each bounded context is a separate module with a
well-defined interface
• For service-oriented architecture:
– Each bounded context is a separate container
• For serverless:
– Each individual workflow is deployed separately
In conclusion:
The ReinventedTransaction Script
The ReinventedTransaction Script
• Most business applications can be thought of
as a series of transactions.
• A "Transaction Script" organizes this logic as a
single function, with a deterministic core
and I/O at the edges.
• Each transaction will have its own,
autonomous, evolvableTransaction Script
In conclusion…
Transaction scripts should be more popular
• Business-focused not technology-focused
• Great for agile:
– "Transaction" as the unit of development
• Easy to understand: dataflow is one directional
• Less bloat. You get ISP andYAGNI for free!
In conclusion…
Problems are solved by
• FP composability
• Separation of I/O
New, improved transaction scripts!
• Have a rich domain
• Are easy to modify
• Are easy to test
• Are microservice and serverless friendly!
"Reinventing theTransaction Script"
– Slides and video will be posted at
• fsharpforfunandprofit.com/transactionscript
Related talks
– "The Power of Composition"
• fsharpforfunandprofit.com/composition
– "Domain Modeling Made Functional"
• fsharpforfunandprofit.com/ddd
Thanks!
Twitter: @ScottWlaschin

Contenu connexe

Tendances

サービス開発における フロントエンド・ドメイン駆動設計の実践
サービス開発における フロントエンド・ドメイン駆動設計の実践サービス開発における フロントエンド・ドメイン駆動設計の実践
サービス開発における フロントエンド・ドメイン駆動設計の実践
TakefumiYoshii
 

Tendances (20)

Domain Modeling Made Functional (KanDDDinsky 2019)
Domain Modeling Made Functional (KanDDDinsky 2019)Domain Modeling Made Functional (KanDDDinsky 2019)
Domain Modeling Made Functional (KanDDDinsky 2019)
 
Go初心者がGoでコマンドラインツールの作成に挑戦した話
Go初心者がGoでコマンドラインツールの作成に挑戦した話Go初心者がGoでコマンドラインツールの作成に挑戦した話
Go初心者がGoでコマンドラインツールの作成に挑戦した話
 
イミュータブルデータモデルの極意
イミュータブルデータモデルの極意イミュータブルデータモデルの極意
イミュータブルデータモデルの極意
 
Tackling Complexity
Tackling ComplexityTackling Complexity
Tackling Complexity
 
サービス開発における フロントエンド・ドメイン駆動設計の実践
サービス開発における フロントエンド・ドメイン駆動設計の実践サービス開発における フロントエンド・ドメイン駆動設計の実践
サービス開発における フロントエンド・ドメイン駆動設計の実践
 
ドメイン駆動設計 基本を理解する
ドメイン駆動設計 基本を理解するドメイン駆動設計 基本を理解する
ドメイン駆動設計 基本を理解する
 
SQLアンチパターン - 開発者を待ち受ける25の落とし穴 (拡大版)
SQLアンチパターン - 開発者を待ち受ける25の落とし穴 (拡大版)SQLアンチパターン - 開発者を待ち受ける25の落とし穴 (拡大版)
SQLアンチパターン - 開発者を待ち受ける25の落とし穴 (拡大版)
 
世界一わかりやすいClean Architecture
世界一わかりやすいClean Architecture世界一わかりやすいClean Architecture
世界一わかりやすいClean Architecture
 
The Power of Composition (NDC Oslo 2020)
The Power of Composition (NDC Oslo 2020)The Power of Composition (NDC Oslo 2020)
The Power of Composition (NDC Oslo 2020)
 
良いコードとは
良いコードとは良いコードとは
良いコードとは
 
PostgreSQLアンチパターン
PostgreSQLアンチパターンPostgreSQLアンチパターン
PostgreSQLアンチパターン
 
マイクロにしすぎた結果がこれだよ!
マイクロにしすぎた結果がこれだよ!マイクロにしすぎた結果がこれだよ!
マイクロにしすぎた結果がこれだよ!
 
DDD x CQRS 更新系と参照系で異なるORMを併用して上手くいった話
DDD x CQRS   更新系と参照系で異なるORMを併用して上手くいった話DDD x CQRS   更新系と参照系で異なるORMを併用して上手くいった話
DDD x CQRS 更新系と参照系で異なるORMを併用して上手くいった話
 
例外設計における大罪
例外設計における大罪例外設計における大罪
例外設計における大罪
 
Where狙いのキー、order by狙いのキー
Where狙いのキー、order by狙いのキーWhere狙いのキー、order by狙いのキー
Where狙いのキー、order by狙いのキー
 
Python 3のWebシステムでDDDに入門してみた
Python 3のWebシステムでDDDに入門してみたPython 3のWebシステムでDDDに入門してみた
Python 3のWebシステムでDDDに入門してみた
 
Rustで DDD を実践しながら API サーバーを実装・構築した(つもり)
Rustで DDD を実践しながら API サーバーを実装・構築した(つもり)Rustで DDD を実践しながら API サーバーを実装・構築した(つもり)
Rustで DDD を実践しながら API サーバーを実装・構築した(つもり)
 
トランザクションスクリプトのすすめ
トランザクションスクリプトのすすめトランザクションスクリプトのすすめ
トランザクションスクリプトのすすめ
 
エンジニアの個人ブランディングと技術組織
エンジニアの個人ブランディングと技術組織エンジニアの個人ブランディングと技術組織
エンジニアの個人ブランディングと技術組織
 
リッチなドメインモデル 名前探し
リッチなドメインモデル 名前探しリッチなドメインモデル 名前探し
リッチなドメインモデル 名前探し
 

Similaire à Reinventing the Transaction Script (NDC London 2020)

Get a Little Help with Your Help Desk Application
Get a Little Help with Your Help Desk ApplicationGet a Little Help with Your Help Desk Application
Get a Little Help with Your Help Desk Application
Iron Speed
 
.NET Architecture for Enterprises
.NET Architecture for Enterprises.NET Architecture for Enterprises
.NET Architecture for Enterprises
Wade Wegner
 

Similaire à Reinventing the Transaction Script (NDC London 2020) (20)

The Power of Composition
The Power of CompositionThe Power of Composition
The Power of Composition
 
Rubyconf2016 - Solving communication problems in distributed teams with BDD
Rubyconf2016 - Solving communication problems in distributed teams with BDDRubyconf2016 - Solving communication problems in distributed teams with BDD
Rubyconf2016 - Solving communication problems in distributed teams with BDD
 
Get a Little Help with Your Help Desk Application
Get a Little Help with Your Help Desk ApplicationGet a Little Help with Your Help Desk Application
Get a Little Help with Your Help Desk Application
 
Modular Web Applications With Netzke
Modular Web Applications With NetzkeModular Web Applications With Netzke
Modular Web Applications With Netzke
 
2006 DDD4: Data access layers - Convenience vs. Control and Performance?
2006 DDD4: Data access layers - Convenience vs. Control and Performance?2006 DDD4: Data access layers - Convenience vs. Control and Performance?
2006 DDD4: Data access layers - Convenience vs. Control and Performance?
 
Ibm redbook
Ibm redbookIbm redbook
Ibm redbook
 
Modernizing i5 Applications
Modernizing i5 ApplicationsModernizing i5 Applications
Modernizing i5 Applications
 
Data Workflows for Machine Learning - SF Bay Area ML
Data Workflows for Machine Learning - SF Bay Area MLData Workflows for Machine Learning - SF Bay Area ML
Data Workflows for Machine Learning - SF Bay Area ML
 
.NET Architecture for Enterprises
.NET Architecture for Enterprises.NET Architecture for Enterprises
.NET Architecture for Enterprises
 
Taming the Legacy Beast: Turning wild old code into a sleak new thoroughbread.
Taming the Legacy Beast: Turning wild old code into a sleak new thoroughbread.Taming the Legacy Beast: Turning wild old code into a sleak new thoroughbread.
Taming the Legacy Beast: Turning wild old code into a sleak new thoroughbread.
 
CQRS recipes or how to cook your architecture
CQRS recipes or how to cook your architectureCQRS recipes or how to cook your architecture
CQRS recipes or how to cook your architecture
 
Neo4j Presentation
Neo4j PresentationNeo4j Presentation
Neo4j Presentation
 
Thinking about graphs
Thinking about graphsThinking about graphs
Thinking about graphs
 
Building data pipelines at Shopee with DEC
Building data pipelines at Shopee with DECBuilding data pipelines at Shopee with DEC
Building data pipelines at Shopee with DEC
 
Brutal refactoring, lying code, the Churn, and other emotional stories from L...
Brutal refactoring, lying code, the Churn, and other emotional stories from L...Brutal refactoring, lying code, the Churn, and other emotional stories from L...
Brutal refactoring, lying code, the Churn, and other emotional stories from L...
 
XPDays Ukraine: Legacy
XPDays Ukraine: LegacyXPDays Ukraine: Legacy
XPDays Ukraine: Legacy
 
Catalyst - refactor large apps with it and have fun!
Catalyst - refactor large apps with it and have fun!Catalyst - refactor large apps with it and have fun!
Catalyst - refactor large apps with it and have fun!
 
Data Workflows for Machine Learning - Seattle DAML
Data Workflows for Machine Learning - Seattle DAMLData Workflows for Machine Learning - Seattle DAML
Data Workflows for Machine Learning - Seattle DAML
 
Cucumber & BDD
Cucumber & BDDCucumber & BDD
Cucumber & BDD
 
Old code doesn't stink - Detroit
Old code doesn't stink - DetroitOld code doesn't stink - Detroit
Old code doesn't stink - Detroit
 

Plus de Scott Wlaschin

Plus de Scott Wlaschin (20)

Pipeline oriented programming
Pipeline oriented programmingPipeline oriented programming
Pipeline oriented programming
 
Building confidence in concurrent code with a model checker: TLA+ for program...
Building confidence in concurrent code with a model checker: TLA+ for program...Building confidence in concurrent code with a model checker: TLA+ for program...
Building confidence in concurrent code with a model checker: TLA+ for program...
 
The lazy programmer's guide to writing thousands of tests
The lazy programmer's guide to writing thousands of testsThe lazy programmer's guide to writing thousands of tests
The lazy programmer's guide to writing thousands of tests
 
The Functional Programmer's Toolkit (NDC London 2019)
The Functional Programmer's Toolkit (NDC London 2019)The Functional Programmer's Toolkit (NDC London 2019)
The Functional Programmer's Toolkit (NDC London 2019)
 
The Power Of Composition (DotNext 2019)
The Power Of Composition (DotNext 2019)The Power Of Composition (DotNext 2019)
The Power Of Composition (DotNext 2019)
 
The Functional Programming Toolkit (NDC Oslo 2019)
The Functional Programming Toolkit (NDC Oslo 2019)The Functional Programming Toolkit (NDC Oslo 2019)
The Functional Programming Toolkit (NDC Oslo 2019)
 
Four Languages From Forty Years Ago (NewCrafts 2019)
Four Languages From Forty Years Ago (NewCrafts 2019)Four Languages From Forty Years Ago (NewCrafts 2019)
Four Languages From Forty Years Ago (NewCrafts 2019)
 
Functional Design Patterns (DevTernity 2018)
Functional Design Patterns (DevTernity 2018)Functional Design Patterns (DevTernity 2018)
Functional Design Patterns (DevTernity 2018)
 
Four Languages From Forty Years Ago
Four Languages From Forty Years AgoFour Languages From Forty Years Ago
Four Languages From Forty Years Ago
 
F# for C# Programmers
F# for C# ProgrammersF# for C# Programmers
F# for C# Programmers
 
Designing with capabilities (DDD-EU 2017)
Designing with capabilities (DDD-EU 2017)Designing with capabilities (DDD-EU 2017)
Designing with capabilities (DDD-EU 2017)
 
Thirteen ways of looking at a turtle
Thirteen ways of looking at a turtleThirteen ways of looking at a turtle
Thirteen ways of looking at a turtle
 
Designing with Capabilities
Designing with CapabilitiesDesigning with Capabilities
Designing with Capabilities
 
Dr Frankenfunctor and the Monadster
Dr Frankenfunctor and the MonadsterDr Frankenfunctor and the Monadster
Dr Frankenfunctor and the Monadster
 
Enterprise Tic-Tac-Toe
Enterprise Tic-Tac-ToeEnterprise Tic-Tac-Toe
Enterprise Tic-Tac-Toe
 
An introduction to property based testing
An introduction to property based testingAn introduction to property based testing
An introduction to property based testing
 
Functional Programming Patterns (NDC London 2014)
Functional Programming Patterns (NDC London 2014)Functional Programming Patterns (NDC London 2014)
Functional Programming Patterns (NDC London 2014)
 
Functional Programming Patterns (BuildStuff '14)
Functional Programming Patterns (BuildStuff '14)Functional Programming Patterns (BuildStuff '14)
Functional Programming Patterns (BuildStuff '14)
 
Swift vs. Language X
Swift vs. Language XSwift vs. Language X
Swift vs. Language X
 
Doge-driven design
Doge-driven designDoge-driven design
Doge-driven design
 

Dernier

introduction-to-automotive Andoid os-csimmonds-ndctechtown-2021.pdf
introduction-to-automotive Andoid os-csimmonds-ndctechtown-2021.pdfintroduction-to-automotive Andoid os-csimmonds-ndctechtown-2021.pdf
introduction-to-automotive Andoid os-csimmonds-ndctechtown-2021.pdf
VishalKumarJha10
 
AI Mastery 201: Elevating Your Workflow with Advanced LLM Techniques
AI Mastery 201: Elevating Your Workflow with Advanced LLM TechniquesAI Mastery 201: Elevating Your Workflow with Advanced LLM Techniques
AI Mastery 201: Elevating Your Workflow with Advanced LLM Techniques
VictorSzoltysek
 
%+27788225528 love spells in Atlanta Psychic Readings, Attraction spells,Brin...
%+27788225528 love spells in Atlanta Psychic Readings, Attraction spells,Brin...%+27788225528 love spells in Atlanta Psychic Readings, Attraction spells,Brin...
%+27788225528 love spells in Atlanta Psychic Readings, Attraction spells,Brin...
masabamasaba
 
+971565801893>>SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHAB...
+971565801893>>SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHAB...+971565801893>>SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHAB...
+971565801893>>SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHAB...
Health
 
The title is not connected to what is inside
The title is not connected to what is insideThe title is not connected to what is inside
The title is not connected to what is inside
shinachiaurasa2
 

Dernier (20)

%in Stilfontein+277-882-255-28 abortion pills for sale in Stilfontein
%in Stilfontein+277-882-255-28 abortion pills for sale in Stilfontein%in Stilfontein+277-882-255-28 abortion pills for sale in Stilfontein
%in Stilfontein+277-882-255-28 abortion pills for sale in Stilfontein
 
Chinsurah Escorts ☎️8617697112 Starting From 5K to 15K High Profile Escorts ...
Chinsurah Escorts ☎️8617697112  Starting From 5K to 15K High Profile Escorts ...Chinsurah Escorts ☎️8617697112  Starting From 5K to 15K High Profile Escorts ...
Chinsurah Escorts ☎️8617697112 Starting From 5K to 15K High Profile Escorts ...
 
Direct Style Effect Systems - The Print[A] Example - A Comprehension Aid
Direct Style Effect Systems -The Print[A] Example- A Comprehension AidDirect Style Effect Systems -The Print[A] Example- A Comprehension Aid
Direct Style Effect Systems - The Print[A] Example - A Comprehension Aid
 
%in Lydenburg+277-882-255-28 abortion pills for sale in Lydenburg
%in Lydenburg+277-882-255-28 abortion pills for sale in Lydenburg%in Lydenburg+277-882-255-28 abortion pills for sale in Lydenburg
%in Lydenburg+277-882-255-28 abortion pills for sale in Lydenburg
 
%in Harare+277-882-255-28 abortion pills for sale in Harare
%in Harare+277-882-255-28 abortion pills for sale in Harare%in Harare+277-882-255-28 abortion pills for sale in Harare
%in Harare+277-882-255-28 abortion pills for sale in Harare
 
introduction-to-automotive Andoid os-csimmonds-ndctechtown-2021.pdf
introduction-to-automotive Andoid os-csimmonds-ndctechtown-2021.pdfintroduction-to-automotive Andoid os-csimmonds-ndctechtown-2021.pdf
introduction-to-automotive Andoid os-csimmonds-ndctechtown-2021.pdf
 
%in Midrand+277-882-255-28 abortion pills for sale in midrand
%in Midrand+277-882-255-28 abortion pills for sale in midrand%in Midrand+277-882-255-28 abortion pills for sale in midrand
%in Midrand+277-882-255-28 abortion pills for sale in midrand
 
call girls in Vaishali (Ghaziabad) 🔝 >༒8448380779 🔝 genuine Escort Service 🔝✔️✔️
call girls in Vaishali (Ghaziabad) 🔝 >༒8448380779 🔝 genuine Escort Service 🔝✔️✔️call girls in Vaishali (Ghaziabad) 🔝 >༒8448380779 🔝 genuine Escort Service 🔝✔️✔️
call girls in Vaishali (Ghaziabad) 🔝 >༒8448380779 🔝 genuine Escort Service 🔝✔️✔️
 
AI Mastery 201: Elevating Your Workflow with Advanced LLM Techniques
AI Mastery 201: Elevating Your Workflow with Advanced LLM TechniquesAI Mastery 201: Elevating Your Workflow with Advanced LLM Techniques
AI Mastery 201: Elevating Your Workflow with Advanced LLM Techniques
 
%+27788225528 love spells in Atlanta Psychic Readings, Attraction spells,Brin...
%+27788225528 love spells in Atlanta Psychic Readings, Attraction spells,Brin...%+27788225528 love spells in Atlanta Psychic Readings, Attraction spells,Brin...
%+27788225528 love spells in Atlanta Psychic Readings, Attraction spells,Brin...
 
Right Money Management App For Your Financial Goals
Right Money Management App For Your Financial GoalsRight Money Management App For Your Financial Goals
Right Money Management App For Your Financial Goals
 
%in Durban+277-882-255-28 abortion pills for sale in Durban
%in Durban+277-882-255-28 abortion pills for sale in Durban%in Durban+277-882-255-28 abortion pills for sale in Durban
%in Durban+277-882-255-28 abortion pills for sale in Durban
 
The Ultimate Test Automation Guide_ Best Practices and Tips.pdf
The Ultimate Test Automation Guide_ Best Practices and Tips.pdfThe Ultimate Test Automation Guide_ Best Practices and Tips.pdf
The Ultimate Test Automation Guide_ Best Practices and Tips.pdf
 
Announcing Codolex 2.0 from GDK Software
Announcing Codolex 2.0 from GDK SoftwareAnnouncing Codolex 2.0 from GDK Software
Announcing Codolex 2.0 from GDK Software
 
%in kempton park+277-882-255-28 abortion pills for sale in kempton park
%in kempton park+277-882-255-28 abortion pills for sale in kempton park %in kempton park+277-882-255-28 abortion pills for sale in kempton park
%in kempton park+277-882-255-28 abortion pills for sale in kempton park
 
+971565801893>>SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHAB...
+971565801893>>SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHAB...+971565801893>>SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHAB...
+971565801893>>SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHAB...
 
%in Hazyview+277-882-255-28 abortion pills for sale in Hazyview
%in Hazyview+277-882-255-28 abortion pills for sale in Hazyview%in Hazyview+277-882-255-28 abortion pills for sale in Hazyview
%in Hazyview+277-882-255-28 abortion pills for sale in Hazyview
 
The title is not connected to what is inside
The title is not connected to what is insideThe title is not connected to what is inside
The title is not connected to what is inside
 
%in Bahrain+277-882-255-28 abortion pills for sale in Bahrain
%in Bahrain+277-882-255-28 abortion pills for sale in Bahrain%in Bahrain+277-882-255-28 abortion pills for sale in Bahrain
%in Bahrain+277-882-255-28 abortion pills for sale in Bahrain
 
Generic or specific? Making sensible software design decisions
Generic or specific? Making sensible software design decisionsGeneric or specific? Making sensible software design decisions
Generic or specific? Making sensible software design decisions
 

Reinventing the Transaction Script (NDC London 2020)

  • 1. Reinventing the Transaction Script (NDC London 2020) @ScottWlaschin fsharpforfunandprofit.com
  • 3. Are transaction scripts a Bad Thing? No!
  • 4. Part I What is a "Transaction Script"?
  • 5. What is a "Transaction Script"?
  • 6. Question: How should you organize your domain logic?
  • 7. Transaction Script • Most business applications can be thought of as a series of transactions. • A "Transaction Script" organizes this logic as a single procedure, making calls directly to the database or through a thin database wrapper. • Each transaction will have its ownTransaction Script
  • 8. The PEAA patterns for domain logic • Transaction script: each procedure handles a single request • Table Module: one instance handles the business logic for all rows in a database table/view. • Domain Model: An object model of the domain that incorporates both behavior and data. • Service Layer: a layer of services that establishes a set of available operations
  • 9. The PEAA patterns for domain logic • Transaction script • Table Module • Domain Model • Service Layer Too simple, too "anemic" Too db centric Nice and complex!
  • 11. Transaction scripts have a bad rep • The reputation – It's for people who are stuck in the 1990s – It's for people who use Cobol – It's only for uncool people • The truth – It can be reinvented using functional programming – Therefore, it can now be cool again!
  • 12. The pros and cons of Transaction Scripts
  • 13. A typical transaction script get data from DB do some business logic write some data to DB some more business logic if some condition then some more DB access some more business logic some more DB access else some more business logic some more DB access Pro: Easy to understand. One directional. Pro: Focused! All code is relevant. YAGNI for free
  • 14. A typical transaction script get data from DB do some business logic write some data to DB some more business logic if some condition then some more DB access some more business logic some more DB access else some more business logic some more DB access Con: Hard to modify
  • 15. A typical transaction script get data from DB do some business logic write some data to DB some more business logic if some condition then some more DB access some more business logic some more DB access else if some other condition then some more business logic else some more business logic some more DB access Con: Hard to modify and evolve. No graceful path to richer behavior
  • 16. A typical transaction script get data from DB do some business logic write some data to DB some more business logic if some condition then some more DB access some more business logic some more DB access else some more business logic some more DB access Con: Hard to reuse. No rich domain model. How do you reuse this bit only?
  • 17. A typical transaction script get data from DB do some business logic write some data to DB some more business logic if some condition then some more DB access some more business logic some more DB access else some more business logic some more DB access Con: Hard to test Business logic is mixed up with DB access
  • 18. A typical transaction script get data from DB do some business logic write some data to DB some more business logic if some condition then some more DB access some more business logic some more DB access else some more business logic some more DB access Con: Hard to test How can you test just these bits?
  • 19. A typical transaction script get data from DB do some business logic write some data to DB some more business logic if some condition then some more DB access some more business logic some more DB access else some more business logic some more DB access Can we fix these problems? Yes, we can!
  • 20. The fix: Use Functional Programming & Domain Driven Design High coolness score
  • 21. Part II Intro to Functional Programming Function
  • 22. The Tunnel of Transformation Function apple -> banana A function is a thing which transforms inputs to outputs
  • 23. A function is a standalone thing, not attached to a class It can be used for inputs and outputs of other functions
  • 24. input A function can be an output A function is a standalone thing
  • 25. output A function can be an input A function is a standalone thing
  • 26. input output A function can be a parameter A function is a standalone thing
  • 29. Lego Philosophy 1. All pieces are designed to be connected 2. The pieces are reusable in many contexts 3. Connect two pieces together and get another "piece" that can still be connected
  • 30. All pieces are designed to be connected
  • 31. The pieces are reusable in different contexts
  • 32. Connect two pieces together and get another "piece" that can still be connected
  • 33. Make big things from small things in the same way
  • 34.
  • 36. Function composition Function 1 apple -> banana Function 2 banana -> cherry
  • 37. Function composition >> Function 1 apple -> banana Function 2 banana -> cherry
  • 38. Function composition New Function apple -> cherry Can't tell it was built from smaller functions! Where did the banana go? (abstraction)
  • 39. Building big things from functions It's compositions all the way up
  • 44. Http Response Http Request Check out my "Power of Composition" talk for more details.
  • 47. New types are built from smaller types by: Composing with “AND” Composing with “OR”
  • 48. Example: pairs, tuples, records FruitSalad = One each of and and Compose with “AND” type FruitSalad = { Apple: AppleVariety Banana: BananaVariety Cherry: CherryVariety }
  • 49. Snack = or or Compose with “OR” type Snack = | Apple of AppleVariety | Banana of BananaVariety | Cherry of CherryVariety
  • 50. Real world example of type composition
  • 51. Example of some requirements: We accept three forms of payment: Cash, PayPal, or Card. For Cash we don't need any extra information For PayPal we need an email address For Cards we need a card type and card number
  • 52. interface IPaymentMethod {..} class Cash() : IPaymentMethod {..} class PayPal(string emailAddress): IPaymentMethod {..} class Card(string cardType, string cardNo) : IPaymentMethod {..} In OO design you would probably implement it as an interface and a set of subclasses, like this:
  • 53. type EmailAddress = string type CardNumber = string In FP you would probably implement by composing types, like this:
  • 54. type EmailAddress = ... type CardNumber = … type CardType = Visa | Mastercard type CreditCardInfo = { CardType : CardType CardNumber : CardNumber }
  • 55. type EmailAddress = ... type CardNumber = ... type CardType = ... type CreditCardInfo = ... type PaymentMethod = | Cash | PayPal of EmailAddress | Card of CreditCardInfo
  • 56. type EmailAddress = ... type CardNumber = ... type CardType = ... type CreditCardInfo = ... type PaymentMethod = | Cash | PayPal of EmailAddress | Card of CreditCardInfo type PaymentAmount = decimal type Currency = EUR | USD
  • 57. type EmailAddress = ... type CardNumber = ... type CardType = ... type CreditCardInfo = ... type PaymentMethod = | Cash | PayPal of EmailAddress | Card of CreditCardInfo type PaymentAmount = decimal type Currency = EUR | USD type Payment = { Amount : PaymentAmount Currency: Currency Method: PaymentMethod }
  • 58. type EmailAddress = ... type CardNumber = ... type CardType = ... type CreditCardInfo = ... type PaymentMethod = | Cash | PayPal of EmailAddress | Card of CreditCardInfo type PaymentAmount = decimal type Currency = EUR | USD type Payment = { Amount : PaymentAmount Currency: Currency Method: PaymentMethod }
  • 59. Applying FP principles to Transaction Scripts
  • 60. Introducing "Workflows" A.k.a. "Transaction", "Story" , "Use-case" Check out "Event Storming" for understanding business events
  • 61. Implementing workflows A workflow will be implemented by a function!
  • 62. Composable Type Composable Type Implementing workflows Inputs and outputs are defined by composable types
  • 63. Implementing workflows We will compose a workflow from smaller components Each component is a standalone function
  • 64. Part III Intro to Domain-Driven Design
  • 65. The DDD book came out just after PEAA in 2003 "Focus on the domain and domain logic rather than technology" -- Eric Evans
  • 66. Agile
  • 67. Agile
  • 70. • Agile contribution: – Rapid feedback during design • DDD contribution: – Stakeholders have a shared mental model – …which is also represented in the code How can we do design right?
  • 71. Key DDD principle: Communicate the design in the code
  • 72. Can you really make code represent the domain?
  • 73. What some source code looks like
  • 74. module CardGame = type Suit = Club | Diamond | Spade | Heart type Rank = Two |Three | Four | Five | Six | Seven | Eight | Nine |Ten | Jack | Queen | King type Card = Suit * Rank type Hand = Card list type Deck = Card list type Player = {Name:string; Hand:Hand} type Game = {Deck:Deck; Players: Player list} type Deal = Deck –› (Deck * Card) type PickupCard = (Hand * Card) –› Hand Sharedlanguage What DDD source code *should* look like (this is F#)
  • 75. module CardGame = type Suit = Club | Diamond | Spade | Heart type Rank = Two |Three | Four | Five | Six | Seven | Eight | Nine |Ten | Jack | Queen | King type Card = Suit * Rank type Hand = Card list type Deck = Card list type Player = {Name:string; Hand:Hand} type Game = {Deck:Deck; Players: Player list} type Deal = Deck –› (Deck * Card) type PickupCard = (Hand * Card) –› Hand * means a pair. Choose one from each type list type is built in
  • 76. Deal (original) Deck (remaining) Deck (on table) Card Modeling a workflow with a function type Deal = Deck -> (Deck * Card) Input Output
  • 77. Pickup Card (updated) Hand (original) Hand (on table) Card Modeling a workflow with a function type PickupCard = (Hand * Card) –> Hand Input Output
  • 78. module CardGame = type Suit = Club | Diamond | Spade | Heart type Rank = Two |Three | Four | Five | Six | Seven | Eight | Nine |Ten | Jack | Queen | King type Card = Suit * Rank type Hand = Card list type Deck = Card list type Player = { Name:string; Hand:Hand } type Game = { Deck:Deck; Players: Player list } type Deal = Deck –› (Deck * Card) type PickupCard = (Hand * Card) –› Hand
  • 79. module CardGame = type Suit = Club | Diamond | Spade | Heart type Rank = Two |Three | Four | Five | Six | Seven | Eight | Nine |Ten | Jack | Queen | King type Card = Suit * Rank type Hand = Card list type Deck = Card list type Player = { Name:string; Hand:Hand } type Game = { Deck:Deck; Players: Player list } type Deal = Deck –› (Deck * Card) type PickupCard = (Hand * Card) –› Hand
  • 80. module CardGame = type Suit = Club | Diamond | Spade | Heart type Rank = Two |Three | Four | Five | Six | Seven | Eight | Nine |Ten | Jack | Queen | King type Card = Suit * Rank type Hand = Card list type Deck = Card list type Player = { Name:string; Hand:Hand } type Game = { Deck:Deck; Players: Player list } type Deal = Deck –› (Deck * Card) type PickupCard = (Hand * Card) –› Hand Can non-programmers provide useful feedback?
  • 81. module CardGame = type Suit = Club | Diamond | Spade | Heart type Rank = Two |Three | Four | Five | Six | Seven | Eight | … type Card = Suit * Rank type Hand = Card list type Deck = Card list type Player = { Name:string; Hand:Hand } type Game = { Deck:Deck; Players: Player list } type Deal = Deck –› (Deck * Card) type PickupCard = (Hand * Card) –› Hand
  • 82. module CardGame = type Suit = Club | Diamond | Spade | Heart type Rank = Two |Three | Four | Five | Six | Seven | Eight | … type Card = Suit * Rank type Hand = Card list type Deck = Card list type Player = { Name:string; Hand:Hand } type Game = { Deck:Deck; Players: Player list } type Deal = Deck –› (Deck * Card) type PickupCard = (Hand * Card) –› Hand
  • 83. In the real world Suit Rank Card Hand Deck Player Deal In the code Suit Rank Card Hand Deck Player Deal
  • 84. In the real world Suit Rank Card Hand Deck Player Deal In the code Suit Rank Card Hand Deck Player Deal PlayerController DeckBase AbstractCardProxyFactoryBean 
  • 85. module CardGame = type Suit = Club | Diamond | Spade | Heart type Rank = Two |Three | Four | Five | Six | Seven | Eight | … type Card = Suit * Rank type Hand = Card list type Deck = Card list type Player = { Name:string; Hand:Hand } type Game = { Deck:Deck; Players: Player list } type Deal = Deck –› (Deck * Card) type PickupCard = (Hand * Card) –› Hand
  • 86. Key DDD principle: Communicate the design in the code 
  • 88. Grouping functionality in the domain A bounded context
  • 89. Why "Bounded Context"? • "Context" – Specialized knowledge and common language – Information taken out of context is confusing or unusable • "Bounded" – Contexts must be autonomous so they can evolve independently. – Boundaries keep you focused! No scope creep!
  • 91. Bounded context with workflows A bounded context contains a set of related workflows
  • 92. Bounded context with workflows A bounded context contains a set of related workflows/functions
  • 93. Part IV Reinventing the Transaction Script
  • 94. • FP contribution: – Transactions are functions – Build them from components using composition • Functional Domain Modeling contribution: – Use composable types for a rich domain model – The domain actions are standalone/reusable – Use autonomous bounded contexts to group and manage the workflows Reinventing the Transaction Script
  • 95. Pros and cons of Transaction Scripts Pros • Easy to understand • Focused: All code is relevant. Cons • Hard to modify/evolve • Hard to reuse • No rich domain model • Hard to test
  • 96. Claim: FP-style transaction scripts are easier to comprehend than OO domain models.
  • 97. FP workflow All arrows go left to right
  • 98. Example: a web backend One directional flow, even with branching
  • 99. Object Oriented workflow Arrows go in all directions We don't design microservices this way!
  • 100. Real-world OO dependency graph Multiple cyclic dependencies 
  • 101. Real-world FP dependency graph All arrows go left to right  Same functionality as the OO example
  • 103. Some OO-style interfaces interface IRepository { Insert InsertAsync Delete DeleteAsync Update UpdateAsync CommitChanges CommitChangesAsync Query QueryByKey QueryWithFilter QueryWithSpecification Contains Count QuerySummary QuerySummaryV2 ChangePassword ChangePasswordV2 DeleteAllRows LaunchMissiles LaunchMissilesV2 } One interface that supports *every* possible workflow! Where's the Interface segregation principle?
  • 104. FP workflow Transaction script style functions only contain what they need. Every part is relevant. You get the ISP for free.
  • 105. Claim: FP-style transaction scripts can be modified with confidence
  • 106. Modifying a workflow Replace a component Static type checking ensures that sub-components are used correctly Minimizing the amount of code that I touch
  • 107. Add features to a workflow Insert new logic Minimizing the amount of code that I touch
  • 108. Add branching to a workflow Add conditional logic
  • 109. Parameterizing a workflow for reuse Swap out parameters for reuse as long as input and output types match
  • 110. Claim: FP-style transaction scripts can have a rich domain model
  • 111. type Deal = Deck –› (Deck * Card) type PickupCard = (Hand * Card) –› Hand A rich domain model... These functions are independent, so these workflows can still evolve independently ...used in functions
  • 112. Sharing rich domain components Shared component Yes, complex domain logic *is* compatible with transaction scripts
  • 113. Claim: FP-style transaction scripts are the natural evolution of Onion/Clean/Hexagonal Architecture
  • 114. Traditional layered model A change to the way that a workflow works means that you need to touch every layer.
  • 115. Vertical slices Each workflow contains all the code it needs to get its job done. When the requirements change for a workflow, only the code in that particular vertical slice needs to change.
  • 116. Vertical slices stretched out Confusing! 
  • 117. The "onion" architecture Core domain is pure, and all I/O is at the edges  See "Functional Core/Imperative Shell"
  • 119. Review of Key Testing Concepts • The SUT (System Under Test) should be a unit of business value – Test transactions, not classes • Tests should apply to the boundaries of a system not its internals – Tests should be done at the transaction level • A "Unit" test means the test is isolated – That is, it produces no side effects and can be run in isolation. – A unit is not a class!
  • 120. In a functional design, all I/O is at the edges. A FP-style transaction script
  • 124. I/O in the middle of a workflow Keep them separate
  • 125. FP style transactions work on the front end too! event-driven!
  • 126. MVU is a FP style approach As seen in Elm, Redux, etc
  • 127. MVU is a FP style approach Deterministic function Deterministic function Non-deterministic actions ("I/O")
  • 129. 3 different architectures… • For monoliths: – Each bounded context is a separate module with a well-defined interface • For service-oriented architecture: – Each bounded context is a separate container • For serverless: – Each individual workflow is deployed separately
  • 130.
  • 131.
  • 132.
  • 133.
  • 135. The ReinventedTransaction Script • Most business applications can be thought of as a series of transactions. • A "Transaction Script" organizes this logic as a single function, with a deterministic core and I/O at the edges. • Each transaction will have its own, autonomous, evolvableTransaction Script
  • 136. In conclusion… Transaction scripts should be more popular • Business-focused not technology-focused • Great for agile: – "Transaction" as the unit of development • Easy to understand: dataflow is one directional • Less bloat. You get ISP andYAGNI for free!
  • 137. In conclusion… Problems are solved by • FP composability • Separation of I/O New, improved transaction scripts! • Have a rich domain • Are easy to modify • Are easy to test • Are microservice and serverless friendly!
  • 138. "Reinventing theTransaction Script" – Slides and video will be posted at • fsharpforfunandprofit.com/transactionscript Related talks – "The Power of Composition" • fsharpforfunandprofit.com/composition – "Domain Modeling Made Functional" • fsharpforfunandprofit.com/ddd Thanks! Twitter: @ScottWlaschin