Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.
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" or...
The PEAA patterns for domain logic
• Transaction script: each procedure handles a
single request
• Table Module: one insta...
The PEAA patterns for domain logic
• Transaction script
• Table Module
• Domain Model
• Service Layer
Too simple, too "ane...
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...
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 som...
A typical transaction script
get data from DB
do some business logic
write some data to DB
some more business logic
if som...
A typical transaction script
get data from DB
do some business logic
write some data to DB
some more business logic
if som...
A typical transaction script
get data from DB
do some business logic
write some data to DB
some more business logic
if som...
A typical transaction script
get data from DB
do some business logic
write some data to DB
some more business logic
if som...
A typical transaction script
get data from DB
do some business logic
write some data to DB
some more business logic
if som...
A typical transaction script
get data from DB
do some business logic
write some data to DB
some more business logic
if som...
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 piec...
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?...
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: AppleVariet...
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 in...
interface IPaymentMethod
{..}
class Cash() : IPaymentMethod
{..}
class PayPal(string emailAddress): IPaymentMethod
{..}
cl...
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
...
type EmailAddress = ...
type CardNumber = ...
type CardType = ...
type CreditCardInfo = ...
type PaymentMethod =
| Cash
| ...
type EmailAddress = ...
type CardNumber = ...
type CardType = ...
type CreditCardInfo = ...
type PaymentMethod =
| Cash
| ...
type EmailAddress = ...
type CardNumber = ...
type CardType = ...
type CreditCardInfo = ...
type PaymentMethod =
| Cash
| ...
type EmailAddress = ...
type CardNumber = ...
type CardType = ...
type CreditCardInfo = ...
type PaymentMethod =
| Cash
| ...
Applying FP principles to
Transaction Scripts
Introducing "Workflows"
A.k.a. "Transaction", "Story" , "Use-case"
Check out "Event Storming" for
understanding business e...
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
– …whic...
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
| ...
module CardGame =
type Suit = Club | Diamond | Spade | Heart
type Rank = Two |Three | Four | Five | Six | Seven | Eight
| ...
Deal
(original)
Deck
(remaining)
Deck
(on table)
Card
Modeling a workflow with a function
type Deal = Deck -> (Deck * Card...
Pickup Card
(updated)
Hand
(original)
Hand
(on table)
Card
Modeling a workflow with a function
type PickupCard = (Hand * C...
module CardGame =
type Suit = Club | Diamond | Spade | Heart
type Rank = Two |Three | Four | Five | Six | Seven | Eight
| ...
module CardGame =
type Suit = Club | Diamond | Spade | Heart
type Rank = Two |Three | Four | Five | Six | Seven | Eight
| ...
module CardGame =
type Suit = Club | Diamond | Spade | Heart
type Rank = Two |Three | Four | Five | Six | Seven | Eight
| ...
module CardGame =
type Suit = Club | Diamond | Spade | Heart
type Rank = Two |Three | Four | Five | Six | Seven | Eight | ...
module CardGame =
type Suit = Club | Diamond | Spade | Heart
type Rank = Two |Three | Four | Five | Six | Seven | Eight | ...
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
D...
module CardGame =
type Suit = Club | Diamond | Spade | Heart
type Rank = Two |Three | Four | Five | Six | Seven | Eight | ...
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 confu...
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 Modelin...
Pros and cons of Transaction Scripts
Pros
• Easy to understand
• Focused: All code is
relevant.
Cons
• Hard to modify/evol...
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
Co...
FP workflow
Transaction script style functions
only contain what they need.
Every part is relevant.
You get the ISP for fr...
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 th...
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 indep...
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 workf...
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 c...
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
• Fo...
In conclusion:
The ReinventedTransaction Script
The ReinventedTransaction Script
• Most business applications can be thought of
as a series of transactions.
• A "Transact...
In conclusion…
Transaction scripts should be more popular
• Business-focused not technology-focused
• Great for agile:
– "...
In conclusion…
Problems are solved by
• FP composability
• Separation of I/O
New, improved transaction scripts!
• Have a r...
"Reinventing theTransaction Script"
– Slides and video will be posted at
• fsharpforfunandprofit.com/transactionscript
Rel...
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)
Reinventing the Transaction Script (NDC London 2020)
Upcoming SlideShare
Loading in …5
×
Upcoming SlideShare
What to Upload to SlideShare
Next
Download to read offline and view in fullscreen.

6

Share

Download to read offline

Reinventing the Transaction Script (NDC London 2020)

Download to read offline

The Transaction Script pattern organizes business logic as a single procedure. It has always been considered less sophisticated and flexible than a layered architecture with a rich domain model. But is that really true?

In this talk, we'll reinvent the Transaction Script using functional programming principles. We'll see that we can still do domain-driven design, and still have code which is decoupled and reusable, all while preserving the simplicity and productivity of the original one-script-per-workflow approach.

Related Books

Free with a 30 day trial from Scribd

See all

Related Audiobooks

Free with a 30 day trial from Scribd

See all

Reinventing the Transaction Script (NDC London 2020)

  1. 1. Reinventing the Transaction Script (NDC London 2020) @ScottWlaschin fsharpforfunandprofit.com
  2. 2. Are transaction scripts a Bad Thing?
  3. 3. Are transaction scripts a Bad Thing? No!
  4. 4. Part I What is a "Transaction Script"?
  5. 5. What is a "Transaction Script"?
  6. 6. Question: How should you organize your domain logic?
  7. 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. 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. 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!
  10. 10. The developer's curse Simple Complex
  11. 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. 12. The pros and cons of Transaction Scripts
  13. 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. 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. 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. 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. 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. 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. 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. 20. The fix: Use Functional Programming & Domain Driven Design High coolness score
  21. 21. Part II Intro to Functional Programming Function
  22. 22. The Tunnel of Transformation Function apple -> banana A function is a thing which transforms inputs to outputs
  23. 23. A function is a standalone thing, not attached to a class It can be used for inputs and outputs of other functions
  24. 24. input A function can be an output A function is a standalone thing
  25. 25. output A function can be an input A function is a standalone thing
  26. 26. input output A function can be a parameter A function is a standalone thing
  27. 27. Core FP principle: Composition everywhere
  28. 28. What is Composition?
  29. 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. 30. All pieces are designed to be connected
  31. 31. The pieces are reusable in different contexts
  32. 32. Connect two pieces together and get another "piece" that can still be connected
  33. 33. Make big things from small things in the same way
  34. 34. Function Composition
  35. 35. Function composition Function 1 apple -> banana Function 2 banana -> cherry
  36. 36. Function composition >> Function 1 apple -> banana Function 2 banana -> cherry
  37. 37. Function composition New Function apple -> cherry Can't tell it was built from smaller functions! Where did the banana go? (abstraction)
  38. 38. Building big things from functions It's compositions all the way up
  39. 39. Low-level operation ToUpper stringstring
  40. 40. Low-level operation Service AddressValidator Validation Result Address Low-level operation Low-level operation
  41. 41. Service Use-case UpdateProfileData ChangeProfile Result ChangeProfile Request Service Service
  42. 42. Use-case Web application Http Response Http Request Use-case Use-case
  43. 43. Http Response Http Request Check out my "Power of Composition" talk for more details.
  44. 44. Composition everywhere: Types can be composed too
  45. 45. Algebraic type system
  46. 46. New types are built from smaller types by: Composing with “AND” Composing with “OR”
  47. 47. Example: pairs, tuples, records FruitSalad = One each of and and Compose with “AND” type FruitSalad = { Apple: AppleVariety Banana: BananaVariety Cherry: CherryVariety }
  48. 48. Snack = or or Compose with “OR” type Snack = | Apple of AppleVariety | Banana of BananaVariety | Cherry of CherryVariety
  49. 49. Real world example of type composition
  50. 50. 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
  51. 51. 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:
  52. 52. type EmailAddress = string type CardNumber = string In FP you would probably implement by composing types, like this:
  53. 53. type EmailAddress = ... type CardNumber = … type CardType = Visa | Mastercard type CreditCardInfo = { CardType : CardType CardNumber : CardNumber }
  54. 54. type EmailAddress = ... type CardNumber = ... type CardType = ... type CreditCardInfo = ... type PaymentMethod = | Cash | PayPal of EmailAddress | Card of CreditCardInfo
  55. 55. type EmailAddress = ... type CardNumber = ... type CardType = ... type CreditCardInfo = ... type PaymentMethod = | Cash | PayPal of EmailAddress | Card of CreditCardInfo type PaymentAmount = decimal type Currency = EUR | USD
  56. 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 type Payment = { Amount : PaymentAmount Currency: Currency Method: PaymentMethod }
  57. 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. 58. Applying FP principles to Transaction Scripts
  59. 59. Introducing "Workflows" A.k.a. "Transaction", "Story" , "Use-case" Check out "Event Storming" for understanding business events
  60. 60. Implementing workflows A workflow will be implemented by a function!
  61. 61. Composable Type Composable Type Implementing workflows Inputs and outputs are defined by composable types
  62. 62. Implementing workflows We will compose a workflow from smaller components Each component is a standalone function
  63. 63. Part III Intro to Domain-Driven Design
  64. 64. The DDD book came out just after PEAA in 2003 "Focus on the domain and domain logic rather than technology" -- Eric Evans
  65. 65. Agile
  66. 66. Agile
  67. 67. Domain-Driven Design
  68. 68. Domain-Driven Design
  69. 69. • 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?
  70. 70. Key DDD principle: Communicate the design in the code
  71. 71. Can you really make code represent the domain?
  72. 72. What some source code looks like
  73. 73. 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#)
  74. 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 * means a pair. Choose one from each type list type is built in
  75. 75. Deal (original) Deck (remaining) Deck (on table) Card Modeling a workflow with a function type Deal = Deck -> (Deck * Card) Input Output
  76. 76. Pickup Card (updated) Hand (original) Hand (on table) Card Modeling a workflow with a function type PickupCard = (Hand * Card) –> Hand Input Output
  77. 77. 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
  78. 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. 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 Can non-programmers provide useful feedback?
  80. 80. 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
  81. 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. 82. In the real world Suit Rank Card Hand Deck Player Deal In the code Suit Rank Card Hand Deck Player Deal
  83. 83. In the real world Suit Rank Card Hand Deck Player Deal In the code Suit Rank Card Hand Deck Player Deal PlayerController DeckBase AbstractCardProxyFactoryBean 
  84. 84. 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
  85. 85. Key DDD principle: Communicate the design in the code 
  86. 86. Introducing "bounded contexts"
  87. 87. Grouping functionality in the domain A bounded context
  88. 88. 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!
  89. 89. Bounded context
  90. 90. Bounded context with workflows A bounded context contains a set of related workflows
  91. 91. Bounded context with workflows A bounded context contains a set of related workflows/functions
  92. 92. Part IV Reinventing the Transaction Script
  93. 93. • 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
  94. 94. 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
  95. 95. Claim: FP-style transaction scripts are easier to comprehend than OO domain models.
  96. 96. FP workflow All arrows go left to right
  97. 97. Example: a web backend One directional flow, even with branching
  98. 98. Object Oriented workflow Arrows go in all directions We don't design microservices this way!
  99. 99. Real-world OO dependency graph Multiple cyclic dependencies 
  100. 100. Real-world FP dependency graph All arrows go left to right  Same functionality as the OO example
  101. 101. Claim: FP-style transaction scripts are resistant to bloat
  102. 102. 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?
  103. 103. FP workflow Transaction script style functions only contain what they need. Every part is relevant. You get the ISP for free.
  104. 104. Claim: FP-style transaction scripts can be modified with confidence
  105. 105. Modifying a workflow Replace a component Static type checking ensures that sub-components are used correctly Minimizing the amount of code that I touch
  106. 106. Add features to a workflow Insert new logic Minimizing the amount of code that I touch
  107. 107. Add branching to a workflow Add conditional logic
  108. 108. Parameterizing a workflow for reuse Swap out parameters for reuse as long as input and output types match
  109. 109. Claim: FP-style transaction scripts can have a rich domain model
  110. 110. 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
  111. 111. Sharing rich domain components Shared component Yes, complex domain logic *is* compatible with transaction scripts
  112. 112. Claim: FP-style transaction scripts are the natural evolution of Onion/Clean/Hexagonal Architecture
  113. 113. Traditional layered model A change to the way that a workflow works means that you need to touch every layer.
  114. 114. 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.
  115. 115. Vertical slices stretched out Confusing! 
  116. 116. The "onion" architecture Core domain is pure, and all I/O is at the edges  See "Functional Core/Imperative Shell"
  117. 117. Claim: FP-style transaction scripts are easy to test
  118. 118. 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!
  119. 119. In a functional design, all I/O is at the edges. A FP-style transaction script
  120. 120. Database Database Load data Process it Save it
  121. 121. DeterministicNon-deterministic Non-deterministic
  122. 122. This makes testing easy!
  123. 123. I/O in the middle of a workflow Keep them separate
  124. 124. FP style transactions work on the front end too! event-driven!
  125. 125. MVU is a FP style approach As seen in Elm, Redux, etc
  126. 126. MVU is a FP style approach Deterministic function Deterministic function Non-deterministic actions ("I/O")
  127. 127. PartV Deployment options for FP-style transaction scripts
  128. 128. 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
  129. 129. In conclusion: The ReinventedTransaction Script
  130. 130. 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
  131. 131. 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!
  132. 132. 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!
  133. 133. "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
  • 123mama

    Jun. 15, 2021
  • kmwr

    Jun. 22, 2020
  • trondhr

    Feb. 19, 2020
  • powerirs

    Feb. 16, 2020
  • DionColman

    Feb. 9, 2020
  • GiovanniPezzino

    Feb. 6, 2020

The Transaction Script pattern organizes business logic as a single procedure. It has always been considered less sophisticated and flexible than a layered architecture with a rich domain model. But is that really true? In this talk, we'll reinvent the Transaction Script using functional programming principles. We'll see that we can still do domain-driven design, and still have code which is decoupled and reusable, all while preserving the simplicity and productivity of the original one-script-per-workflow approach.

Views

Total views

1,020

On Slideshare

0

From embeds

0

Number of embeds

123

Actions

Downloads

37

Shares

0

Comments

0

Likes

6

×