SlideShare a Scribd company logo
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
Reinventing the Transaction Script (NDC London 2020)
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
Reinventing the Transaction Script (NDC London 2020)
Reinventing the Transaction Script (NDC London 2020)
Reinventing the Transaction Script (NDC London 2020)
Reinventing the Transaction Script (NDC London 2020)
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

More Related Content

PDF
Domain Modeling Made Functional (DevTernity 2022)
PDF
Domain Driven Design with the F# type System -- F#unctional Londoners 2014
PDF
Domain Modeling with FP (DDD Europe 2020)
PDF
F#入門 ~関数プログラミングとは何か~
PDF
関数型プログラミング入門 with OCaml
PDF
Pipeline oriented programming
PPTX
今こそ知りたいSpring Batch(Spring Fest 2020講演資料)
PDF
Domain Driven Design with the F# type System -- NDC London 2013
Domain Modeling Made Functional (DevTernity 2022)
Domain Driven Design with the F# type System -- F#unctional Londoners 2014
Domain Modeling with FP (DDD Europe 2020)
F#入門 ~関数プログラミングとは何か~
関数型プログラミング入門 with OCaml
Pipeline oriented programming
今こそ知りたいSpring Batch(Spring Fest 2020講演資料)
Domain Driven Design with the F# type System -- NDC London 2013

What's hot (20)

PPTX
世界一わかりやすいClean Architecture
PDF
SQLアンチパターン - ジェイウォーク
PDF
The Power of Composition (NDC Oslo 2020)
PDF
イミュータブルデータモデル(世代編)
PDF
例外設計における大罪
PDF
「実践ドメイン駆動設計」 から理解するDDD (2018年11月)
PDF
関数型プログラミングのデザインパターンひとめぐり
PDF
イミュータブルデータモデルの極意
PDF
MySQLで論理削除と正しく付き合う方法
PDF
DDD x CQRS 更新系と参照系で異なるORMを併用して上手くいった話
PDF
強いて言えば「集約どう実装するのかな、を考える」な話
PDF
イミュータブルデータモデル(入門編)
PDF
DBスキーマもバージョン管理したい!
PDF
ソーシャルゲーム案件におけるDB分割のPHP実装
PDF
良い?悪い?コードコメントの書き方
ODP
Goのサーバサイド実装におけるレイヤ設計とレイヤ内実装について考える
PDF
なぜ、いま リレーショナルモデルなのか(理論から学ぶデータベース実践入門読書会スペシャル)
PDF
実践 NestJS
PDF
PostgreSQLアンチパターン
PDF
オブジェクト指向できていますか?
世界一わかりやすいClean Architecture
SQLアンチパターン - ジェイウォーク
The Power of Composition (NDC Oslo 2020)
イミュータブルデータモデル(世代編)
例外設計における大罪
「実践ドメイン駆動設計」 から理解するDDD (2018年11月)
関数型プログラミングのデザインパターンひとめぐり
イミュータブルデータモデルの極意
MySQLで論理削除と正しく付き合う方法
DDD x CQRS 更新系と参照系で異なるORMを併用して上手くいった話
強いて言えば「集約どう実装するのかな、を考える」な話
イミュータブルデータモデル(入門編)
DBスキーマもバージョン管理したい!
ソーシャルゲーム案件におけるDB分割のPHP実装
良い?悪い?コードコメントの書き方
Goのサーバサイド実装におけるレイヤ設計とレイヤ内実装について考える
なぜ、いま リレーショナルモデルなのか(理論から学ぶデータベース実践入門読書会スペシャル)
実践 NestJS
PostgreSQLアンチパターン
オブジェクト指向できていますか?
Ad

Similar to Reinventing the Transaction Script (NDC London 2020) (20)

PPTX
Improving The Quality of Existing Software
PPTX
Common ASP.NET Design Patterns - Telerik India DevCon 2013
PDF
The Functional Programming Toolkit (NDC Oslo 2019)
PDF
Functional Design Patterns (DevTernity 2018)
PPTX
Seminar - Scalable Enterprise Application Development Using DDD and CQRS
PDF
The Power of Composition
PDF
Functional Programming Patterns (BuildStuff '14)
PPTX
CQRS: Command/Query Responsibility Segregation
PPTX
Software Development: Beyond Training wheels
PPTX
Design Principles
PPTX
How Functional Programming Made Me A Better Developer
PPTX
Functional DDD
PDF
DPC 2019, Amsterdam: Beyond design patterns and principles - writing good OO ...
PDF
Commonly used design patterns
PPTX
2009 Dotnet Information Day: More effective c#
PPTX
Software System Architecture-Lecture 6.pptx
PPTX
Software design principles SOLID
PDF
Introduction to functional programming
PPTX
Lets focus on business value
Improving The Quality of Existing Software
Common ASP.NET Design Patterns - Telerik India DevCon 2013
The Functional Programming Toolkit (NDC Oslo 2019)
Functional Design Patterns (DevTernity 2018)
Seminar - Scalable Enterprise Application Development Using DDD and CQRS
The Power of Composition
Functional Programming Patterns (BuildStuff '14)
CQRS: Command/Query Responsibility Segregation
Software Development: Beyond Training wheels
Design Principles
How Functional Programming Made Me A Better Developer
Functional DDD
DPC 2019, Amsterdam: Beyond design patterns and principles - writing good OO ...
Commonly used design patterns
2009 Dotnet Information Day: More effective c#
Software System Architecture-Lecture 6.pptx
Software design principles SOLID
Introduction to functional programming
Lets focus on business value
Ad

More from Scott Wlaschin (19)

PDF
Building confidence in concurrent code with a model checker: TLA+ for program...
PDF
The lazy programmer's guide to writing thousands of tests
PDF
The Functional Programmer's Toolkit (NDC London 2019)
PDF
The Power Of Composition (DotNext 2019)
PDF
Domain Modeling Made Functional (KanDDDinsky 2019)
PDF
Four Languages From Forty Years Ago (NewCrafts 2019)
PDF
Four Languages From Forty Years Ago
PDF
F# for C# Programmers
PDF
Designing with capabilities (DDD-EU 2017)
PDF
Thirteen ways of looking at a turtle
PDF
Designing with Capabilities
PDF
Dr Frankenfunctor and the Monadster
PDF
Enterprise Tic-Tac-Toe
PDF
An introduction to property based testing
PDF
Functional Programming Patterns (NDC London 2014)
PDF
Swift vs. Language X
PDF
Doge-driven design
PDF
Railway Oriented Programming
PDF
The Theory of Chains
Building confidence in concurrent code with a model checker: TLA+ for program...
The lazy programmer's guide to writing thousands of tests
The Functional Programmer's Toolkit (NDC London 2019)
The Power Of Composition (DotNext 2019)
Domain Modeling Made Functional (KanDDDinsky 2019)
Four Languages From Forty Years Ago (NewCrafts 2019)
Four Languages From Forty Years Ago
F# for C# Programmers
Designing with capabilities (DDD-EU 2017)
Thirteen ways of looking at a turtle
Designing with Capabilities
Dr Frankenfunctor and the Monadster
Enterprise Tic-Tac-Toe
An introduction to property based testing
Functional Programming Patterns (NDC London 2014)
Swift vs. Language X
Doge-driven design
Railway Oriented Programming
The Theory of Chains

Recently uploaded (20)

PPTX
Agentic AI Use Case- Contract Lifecycle Management (CLM).pptx
PPTX
Computer Software and OS of computer science of grade 11.pptx
PDF
iTop VPN Crack Latest Version Full Key 2025
PDF
EN-Survey-Report-SAP-LeanIX-EA-Insights-2025.pdf
PDF
Wondershare Filmora 15 Crack With Activation Key [2025
PDF
iTop VPN Free 5.6.0.5262 Crack latest version 2025
PPTX
AMADEUS TRAVEL AGENT SOFTWARE | AMADEUS TICKETING SYSTEM
PDF
wealthsignaloriginal-com-DS-text-... (1).pdf
PDF
Tally Prime Crack Download New Version 5.1 [2025] (License Key Free
PDF
AutoCAD Professional Crack 2025 With License Key
PDF
Cost to Outsource Software Development in 2025
PDF
Download FL Studio Crack Latest version 2025 ?
PDF
Salesforce Agentforce AI Implementation.pdf
PPTX
Reimagine Home Health with the Power of Agentic AI​
PDF
Internet Downloader Manager (IDM) Crack 6.42 Build 42 Updates Latest 2025
PDF
CapCut Video Editor 6.8.1 Crack for PC Latest Download (Fully Activated) 2025
PDF
AI-Powered Threat Modeling: The Future of Cybersecurity by Arun Kumar Elengov...
PDF
CCleaner Pro 6.38.11537 Crack Final Latest Version 2025
PDF
Design an Analysis of Algorithms II-SECS-1021-03
PDF
Internet Downloader Manager (IDM) Crack 6.42 Build 41
Agentic AI Use Case- Contract Lifecycle Management (CLM).pptx
Computer Software and OS of computer science of grade 11.pptx
iTop VPN Crack Latest Version Full Key 2025
EN-Survey-Report-SAP-LeanIX-EA-Insights-2025.pdf
Wondershare Filmora 15 Crack With Activation Key [2025
iTop VPN Free 5.6.0.5262 Crack latest version 2025
AMADEUS TRAVEL AGENT SOFTWARE | AMADEUS TICKETING SYSTEM
wealthsignaloriginal-com-DS-text-... (1).pdf
Tally Prime Crack Download New Version 5.1 [2025] (License Key Free
AutoCAD Professional Crack 2025 With License Key
Cost to Outsource Software Development in 2025
Download FL Studio Crack Latest version 2025 ?
Salesforce Agentforce AI Implementation.pdf
Reimagine Home Health with the Power of Agentic AI​
Internet Downloader Manager (IDM) Crack 6.42 Build 42 Updates Latest 2025
CapCut Video Editor 6.8.1 Crack for PC Latest Download (Fully Activated) 2025
AI-Powered Threat Modeling: The Future of Cybersecurity by Arun Kumar Elengov...
CCleaner Pro 6.38.11537 Crack Final Latest Version 2025
Design an Analysis of Algorithms II-SECS-1021-03
Internet Downloader Manager (IDM) Crack 6.42 Build 41

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
  • 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
  • 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