SlideShare ist ein Scribd-Unternehmen logo
1 von 44
Deck title, edit in View > Master
Habito:
The Purely Functional
Mortgage Broker
Will Jones, VP Engineering
1
InfoQ.com: News & Community Site
Watch the video with slide
synchronization on InfoQ.com!
https://www.infoq.com/presentations/
habito-mortgage-broker/
• Over 1,000,000 software developers, architects and CTOs read the site world-
wide every month
• 250,000 senior developers subscribe to our weekly newsletter
• Published in 4 languages (English, Chinese, Japanese and Brazilian
Portuguese)
• Post content from our QCon conferences
• 2 dedicated podcast channels: The InfoQ Podcast, with a focus on
Architecture and The Engineering Culture Podcast, with a focus on building
• 96 deep dives on innovative topics packed as downloadable emags and
minibooks
• Over 40 new content items per week
Purpose of QCon
- to empower software development by facilitating the spread of
knowledge and innovation
Strategy
- practitioner-driven conference designed for YOU: influencers of
change and innovation in your teams
- speakers and topics driving the evolution and innovation
- connecting and catalyzing the influencers and innovators
Highlights
- attended by more than 12,000 delegates since 2007
- held in 9 cities worldwide
Presented at QCon London
www.qconlondon.com
Habito: The Purely Functional Mortgage Broker 2
● Founded in early 2015, live since early 2016
● Completely free service to take the pain out of mortgages
● Brokered over £1bn in applications to date
● ~140 people total, ~40 engineers
● Operate in small, cross-functional teams (~7 at present)
Facts and figures
Habito: The Purely Functional Mortgage Broker
● No clear universal language
● Coupled inheritance hierarchies
● Complex runtime state
● Boilerplate
3
Old wounds
Habito: The Purely Functional Mortgage Broker
● No clear universal language
Rich, data-driven domain model
● Coupled inheritance hierarchies
Compose simpler building blocks
● Complex runtime state
Immutability by default
● Boilerplate
Code generation from specifications
4
New beginnings
Habito: The Purely Functional Mortgage Broker 5
Haskell
● Purely functional programming language
● Strong static typing
● Non-strict evaluation model
● Deploy binaries in Docker containers (for example)
Habito: The Purely Functional Mortgage Broker
● “A transaction is either a purchase or a remortgage. A purchase involves a deposit and a property
value. A remortgage involves a remaining balance, current monthly repayment and a property value.”
6
Domain modelling
Habito: The Purely Functional Mortgage Broker
● “A transaction is either a purchase or a remortgage. A purchase involves a deposit and a property
value. A remortgage involves a remaining balance, current monthly repayment and a property value.”
data Txn
= Purchase PurchaseTxn
| Remo RemoTxn
7
Domain modelling
Habito: The Purely Functional Mortgage Broker
● “A transaction is either a purchase or a remortgage. A purchase involves a deposit and a property
value. A remortgage involves a remaining balance, current monthly repayment and a property value.”
data Txn
= Purchase PurchaseTxn
| Remo RemoTxn
data PurchaseTxn
= PurchaseTxn
{ deposit :: GBP
, propVal :: GBP
}
8
Domain modelling
Habito: The Purely Functional Mortgage Broker
● “A transaction is either a purchase or a remortgage. A purchase involves a deposit and a property
value. A remortgage involves a remaining balance, current monthly repayment and a property value.”
data Txn
= Purchase PurchaseTxn
| Remo RemoTxn
data PurchaseTxn data RemoTxn
= PurchaseTxn = RemoTxn
{ deposit :: GBP { balance :: GBP
, propVal :: GBP , currMonthly :: GBP
} , propVal :: GBP
}
9
Domain modelling
Habito: The Purely Functional Mortgage Broker
● “A transaction is either a purchase or a remortgage. A purchase involves a deposit and a property
value. A remortgage involves a remaining balance, current monthly repayment and a property value.”
data Txn
= Purchase PurchaseTxn
| Remo RemoTxn
txn1 :: Txn
data PurchaseTxn txn1
= PurchaseTxn = Purchase (PurchaseTxn
{ deposit :: GBP { deposit = 30000
, propVal :: GBP , propVal = 100000
} })
10
Domain modelling
Habito: The Purely Functional Mortgage Broker
● “Applicant credit policy rule: buy-to-let customers are not eligible for a mortgage if
they are retired or will enter retirement before the end of the mortgage term.”
11
Domain modelling
Habito: The Purely Functional Mortgage Broker
● “Applicant credit policy rule: buy-to-let customers are not eligible for a mortgage if
they are retired or will enter retirement before the end of the mortgage term.”
rPD4
:: (HasToday, HasApplicant)
=> RuleBuilder "R-PD-4"
12
Domain modelling
Habito: The Purely Functional Mortgage Broker
● “Applicant credit policy rule: buy-to-let customers are not eligible for a mortgage if
they are retired or will enter retirement before the end of the mortgage term.”
rPD4
:: (HasToday, HasApplicant)
=> RuleBuilder "R-PD-4"
rPD4 _
= given (txnParam @"txnScenario" .== buyToLet) $
rejectIf $
13
Domain modelling
Habito: The Purely Functional Mortgage Broker
● “Applicant credit policy rule: buy-to-let customers are not eligible for a mortgage if
they are retired or will enter retirement before the end of the mortgage term.”
rPD4
:: (HasToday, HasApplicant)
=> RuleBuilder "R-PD-4"
rPD4 _
= given (txnParam @"txnScenario" .== buyToLet) $
rejectIf $
empType .== retired .||
derive ageAtEndOfTerm .> retirementAge
14
Domain modelling
Habito: The Purely Functional Mortgage Broker 15
Simpler building blocks
rPD4
:: (HasToday, HasApplicant)
=> RuleBuilder "R-PD-4"
rPD4 _
= given (txnParam @"txnScenario" .== buyToLet) $
rejectIf $
empType .== retired .||
derive ageAtEndOfTerm .> retirementAge
● Domain-specific language
Habito: The Purely Functional Mortgage Broker 16
Simpler building blocks
rPD4
:: (HasToday, HasApplicant)
=> RuleBuilder "R-PD-4"
rPD4 _
= given (txnParam @"txnScenario" .== buyToLet) $
rejectIf $
empType .== retired .||
derive ageAtEndOfTerm .> retirementAge
● Domain-specific language
● Just a big function composition
Habito: The Purely Functional Mortgage Broker 17
Simpler building blocks
rPD4
:: (HasToday, HasApplicant)
=> RuleBuilder "R-PD-4"
rPD4 _
= given (txnParam @"txnScenario" .== buyToLet) $
rejectIf $
empType .== retired .||
derive ageAtEndOfTerm .> retirementAge
● Domain-specific language
● Just a big function composition
● Some power tools: overloading, types
Habito: The Purely Functional Mortgage Broker 18
Simpler building blocks
rPD4
:: (HasToday, HasApplicant)
=> RuleBuilder "R-PD-4"
rPD4 _
= given (txnParam @"txnScenario" .== buyToLet) $
rejectIf $
empType .== retired .||
derive ageAtEndOfTerm .> retirementAge
● Domain-specific language
● Just a big function composition
● Some power tools: overloading, types
{
"ruleId": "R-PD-4",
"log": [
{
"name": "txnScenario",
"value": "BuyToLet",
"entryType": { "type": "TxnParam" }
},
{
"name": "Applicants/Primary/DoB",
"value": "Just 1945-10-21",
"entryType": { "type": "DataKey" }
},
...
],
"result": { "type": "Reject" }
}
Habito: The Purely Functional Mortgage Broker 19
Immutability everywhere
● Verify once, trust elsewhere
● Useful for parallelism/concurrency
● In general: easier to reason about
● Why stop with our language?
Habito: The Purely Functional Mortgage Broker 20
Data
account_id email password created verified
05d1100a-... will@example <hash> 2018-11-22T.. t
dbc85161-... dev@example <hash> 2018-11-21T.. f
account
profile_id account_id first_name
3df81575-... 05d1100a-... William
profile
Habito: The Purely Functional Mortgage Broker 21
Data
account_id email password created verified
05d1100a-... will@example <hash> 2018-11-22T.. t
dbc85161-... dev@example <hash> 2018-11-21T.. t
account
profile_id account_id first_name
3df81575-... 05d1100a-... William
profile
Habito: The Purely Functional Mortgage Broker 22
Event sourcing
2018-11-21T... 05d1100a-... 1 Account {
“type”: “AccountCreated”,
“value”: {
“email”: “will@example”,
“password”: “<hash>”
}
}
2018-11-21T... 05d1100a-... 2 Account {
“type”: “PasswordChanged”,
“value”: {
“newPassword”: “<hash>”
}
}
2018-11-22T... 05d1100a-... 3 Account {
“type”: “EmailVerified”,
“value”: {}
}
?
Aggregate ID
Aggregate version
Aggregate type
Event data/payload
Habito: The Purely Functional Mortgage Broker
● “An account is created. Thereafter the password may be changed, the email may be verified, ...”
data Account
= Account
{ id :: AccId
, ...
}
data AccEvent
= Created { id :: AccId }
| PassChanged { hashedPass :: HashedPass }
| EmailVerified
| ...
23
Event sourcing
Habito: The Purely Functional Mortgage Broker
data Maybe a = Nothing | Just a
updateAcc :: Maybe Account -> AccEvent -> Maybe Account
updateAcc (Just acc) (PassChanged pwd) =
acc { password = pwd }
...
buildAcc
:: [AccEvent]
-> Maybe Account
buildAcc =
foldl updateAcc Nothing
24
Event sourcing
Habito: The Purely Functional Mortgage Broker
data Maybe a = Nothing | Just a
updateAcc :: Maybe Account -> AccEvent -> Maybe Account
updateAcc (Just acc) (PassChanged pwd) =
acc { password = pwd }
...
buildAcc
:: [AccEvent]
-> Maybe Account
buildAcc =
foldl updateAcc Nothing
25
Event sourcing
foldl f z [x1, x2, x3]
== f (f (f z x1) x2) x3
foldl updateAcc Nothing [e1, e2, e3]
== uA (uA (uA Nothing e1) e2) e3
Habito: The Purely Functional Mortgage Broker 26
Asking questions
05d1100a-... 1 Account {
“type”: “AccountCreated”,
“value”: {
“email”: “will@example”,
“password”: “<hash>”
}
}
05d1100a-... 2 Account {
“type”: “PasswordChanged”,
“value”: {
“newPassword”: “<hash>”
}
}
05d1100a-... 3 Account {
“type”: “EmailVerified”,
“value”: {}
}
account_id email password created verified
05d1100a-... will@example <hash> 2018-11-22T.. t
dbc85161-... dev@example <hash> 2018-11-21T.. f
Habito: The Purely Functional Mortgage Broker 27
Asking questions
05d1100a-... 1 Account {
“type”: “AccountCreated”,
“value”: {
“email”: “will@example”,
“password”: “<hash>”
}
}
05d1100a-... 2 Account {
“type”: “PasswordChanged”,
“value”: {
“newPassword”: “<hash>”
}
}
05d1100a-... 3 Account {
“type”: “EmailVerified”,
“value”: {}
}
{
“id”: “05d1100a-...”,
“email”: “will@example”,
“created”: “2018-11-22T..”,
“verified”: true,
...
}
Habito: The Purely Functional Mortgage Broker 28
Asking questions
05d1100a-... 1 Account {
“type”: “AccountCreated”,
“value”: {
“email”: “will@example”,
“password”: “<hash>”
}
}
05d1100a-... 2 Account {
“type”: “PasswordChanged”,
“value”: {
“newPassword”: “<hash>”
}
}
05d1100a-... 3 Account {
“type”: “EmailVerified”,
“value”: {}
}
{
“id”: “05d1100a-...”,
“email”: “will@example”,
“created”: “2018-11-22T..”,
“verified”: true,
...
}
runProjection “Accounts”
$ allEvents @AccountEvent
.| ...
.| ...
.| ...
.| sinkToPostgreSQL “tbl_acc”
Habito: The Purely Functional Mortgage Broker 29
Asking questions
05d1100a-... 1 Account {
“type”: “AccountCreated”,
“value”: {
“email”: “will@example”,
“password”: “<hash>”
}
}
05d1100a-... 2 Account {
“type”: “PasswordChanged”,
“value”: {
“newPassword”: “<hash>”
}
}
05d1100a-... 3 Account {
“type”: “EmailVerified”,
“value”: {}
}
{
“id”: “05d1100a-...”,
“email”: “will@example”,
“created”: “2018-11-22T..”,
“verified”: true,
...
}
runProjection “Accounts”
$ allEvents @AccountEvent
.| ...
.| ...
.| ...
.| sinkToElastic “idx_acc”
Habito: The Purely Functional Mortgage Broker 30
Asking questions
05d1100a-... 1 Account {
“type”: “AccountCreated”,
“value”: {
“email”: “will@example”,
“password”: “<hash>”
}
}
05d1100a-... 2 Account {
“type”: “PasswordChanged”,
“value”: {
“newPassword”: “<hash>”
}
}
05d1100a-... 3 Account {
“type”: “EmailVerified”,
“value”: {}
}
{
“id”: “05d1100a-...”,
“email”: “will@example”,
“created”: “2018-11-22T..”,
“verified”: true,
...
}
runProjection “Accounts”
$ allEvents @AccountEvent
.| loggedToGrafana
.| concurrently
.| batched
.| sinkToElastic “idx_acc”
Habito: The Purely Functional Mortgage Broker
data Txn
= Purchase PurchaseTxn
| Remo RemoTxn
data PurchaseTxn data RemoTxn
= PurchaseTxn = RemoTxn
{ deposit :: GBP { balance :: GBP
, propVal :: GBP , currMonthly :: GBP
} , propVal :: GBP
}
31
Boilerplate
Habito: The Purely Functional Mortgage Broker
data Txn
= Purchase PurchaseTxn
| Remo RemoTxn
deriving (Generic)
data PurchaseTxn data RemoTxn
= PurchaseTxn = RemoTxn
{ deposit :: GBP { balance :: GBP
, propVal :: GBP , currMonthly :: GBP
} , propVal :: GBP
deriving (Generic) }
deriving (Generic)
32
Boilerplate
Habito: The Purely Functional Mortgage Broker
data Txn
= Purchase PurchaseTxn
| Remo RemoTxn
deriving (Generic)
deriving (FromJSON, ToJSON) via (Generically Txn)
data PurchaseTxn data RemoTxn
= PurchaseTxn = RemoTxn
{ deposit :: GBP { balance :: GBP
, propVal :: GBP , currMonthly :: GBP
} , propVal :: GBP
deriving (Generic) }
deriving (Generic)
33
Boilerplate
Habito: The Purely Functional Mortgage Broker
updateTxnPropVal :: GBP -> Txn -> Txn
updateTxnPropVal x txn =
data PurchaseTxn data RemoTxn
= PurchaseTxn = RemoTxn
{ deposit :: GBP { balance :: GBP
, propVal :: GBP , currMonthly :: GBP
} , propVal :: GBP
deriving (Generic) }
deriving (Generic)
34
Boilerplate
Habito: The Purely Functional Mortgage Broker
updateTxnPropVal :: GBP -> Txn -> Txn
updateTxnPropVal x txn =
case txn of
PurchaseTxn pTxn -> ...
RemoTxn rTxn -> ...
data PurchaseTxn data RemoTxn
= PurchaseTxn = RemoTxn
{ deposit :: GBP { balance :: GBP
, propVal :: GBP , currMonthly :: GBP
} , propVal :: GBP
deriving (Generic) }
deriving (Generic)
35
Boilerplate
Habito: The Purely Functional Mortgage Broker
updateTxnPropVal :: GBP -> Txn -> Txn
updateTxnPropVal x txn =
set (nestedField @“propVal”) x txn
data PurchaseTxn data RemoTxn
= PurchaseTxn = RemoTxn
{ deposit :: GBP { balance :: GBP
, propVal :: GBP , currMonthly :: GBP
} , propVal :: GBP
deriving (Generic) }
deriving (Generic)
36
Boilerplate
Habito: The Purely Functional Mortgage Broker
Compiling domains
37
rPD4
:: (HasToday, HasApplicant)
=> RuleBuilder "R-PD-4"
rPD4 _
= given (txnParam @"txnScenario" .== buyToLet) $ ...
{
"ruleId": "R-PD-4",
"log": [
{
"name": "txnScenario",
"value": "BuyToLet",
"entryType": { "type": "TxnParam" }
},
...
],
"result": { "type": "Reject" }
}
Habito: The Purely Functional Mortgage Broker
Compiling domains
38
rPD4
:: (HasToday, HasApplicant)
=> RuleBuilder "R-PD-4"
rPD4 _
= given (txnParam @"txnScenario" .== buyToLet) $ ...
{
"ruleId": "R-PD-4",
"log": [
{
"name": "txnScenario",
"value": "BuyToLet",
"entryType": { "type": "TxnParam" }
},
...
],
"result": { "type": "Reject" }
}
Habito: The Purely Functional Mortgage Broker 39
It can’t all be good news
● Type-checking and compilation times
● Laziness and reasoning about performance
● Language ecosystem -- tooling and libraries
● Recruitment and hiring
● Event sourcing has its own challenges -- reprojection
Habito: The Purely Functional Mortgage Broker
● No clear universal language
Rich, data-driven domain model
● Coupled inheritance hierarchies
Compose simpler building blocks
● Complex runtime state
Immutability by default
● Boilerplate
Code generation from specifications
40
Useful underpinnings
Deck title, edit in View > Master
Thank you
41
Watch the video with slide
synchronization on InfoQ.com!
https://www.infoq.com/presentations/
habito-mortgage-broker/

Weitere ähnliche Inhalte

Mehr von C4Media

Shifting Left with Cloud Native CI/CD
Shifting Left with Cloud Native CI/CDShifting Left with Cloud Native CI/CD
Shifting Left with Cloud Native CI/CDC4Media
 
CI/CD for Machine Learning
CI/CD for Machine LearningCI/CD for Machine Learning
CI/CD for Machine LearningC4Media
 
Fault Tolerance at Speed
Fault Tolerance at SpeedFault Tolerance at Speed
Fault Tolerance at SpeedC4Media
 
Architectures That Scale Deep - Regaining Control in Deep Systems
Architectures That Scale Deep - Regaining Control in Deep SystemsArchitectures That Scale Deep - Regaining Control in Deep Systems
Architectures That Scale Deep - Regaining Control in Deep SystemsC4Media
 
ML in the Browser: Interactive Experiences with Tensorflow.js
ML in the Browser: Interactive Experiences with Tensorflow.jsML in the Browser: Interactive Experiences with Tensorflow.js
ML in the Browser: Interactive Experiences with Tensorflow.jsC4Media
 
Build Your Own WebAssembly Compiler
Build Your Own WebAssembly CompilerBuild Your Own WebAssembly Compiler
Build Your Own WebAssembly CompilerC4Media
 
User & Device Identity for Microservices @ Netflix Scale
User & Device Identity for Microservices @ Netflix ScaleUser & Device Identity for Microservices @ Netflix Scale
User & Device Identity for Microservices @ Netflix ScaleC4Media
 
Scaling Patterns for Netflix's Edge
Scaling Patterns for Netflix's EdgeScaling Patterns for Netflix's Edge
Scaling Patterns for Netflix's EdgeC4Media
 
Make Your Electron App Feel at Home Everywhere
Make Your Electron App Feel at Home EverywhereMake Your Electron App Feel at Home Everywhere
Make Your Electron App Feel at Home EverywhereC4Media
 
The Talk You've Been Await-ing For
The Talk You've Been Await-ing ForThe Talk You've Been Await-ing For
The Talk You've Been Await-ing ForC4Media
 
Future of Data Engineering
Future of Data EngineeringFuture of Data Engineering
Future of Data EngineeringC4Media
 
Automated Testing for Terraform, Docker, Packer, Kubernetes, and More
Automated Testing for Terraform, Docker, Packer, Kubernetes, and MoreAutomated Testing for Terraform, Docker, Packer, Kubernetes, and More
Automated Testing for Terraform, Docker, Packer, Kubernetes, and MoreC4Media
 
Navigating Complexity: High-performance Delivery and Discovery Teams
Navigating Complexity: High-performance Delivery and Discovery TeamsNavigating Complexity: High-performance Delivery and Discovery Teams
Navigating Complexity: High-performance Delivery and Discovery TeamsC4Media
 
High Performance Cooperative Distributed Systems in Adtech
High Performance Cooperative Distributed Systems in AdtechHigh Performance Cooperative Distributed Systems in Adtech
High Performance Cooperative Distributed Systems in AdtechC4Media
 
Rust's Journey to Async/await
Rust's Journey to Async/awaitRust's Journey to Async/await
Rust's Journey to Async/awaitC4Media
 
Opportunities and Pitfalls of Event-Driven Utopia
Opportunities and Pitfalls of Event-Driven UtopiaOpportunities and Pitfalls of Event-Driven Utopia
Opportunities and Pitfalls of Event-Driven UtopiaC4Media
 
Datadog: a Real-Time Metrics Database for One Quadrillion Points/Day
Datadog: a Real-Time Metrics Database for One Quadrillion Points/DayDatadog: a Real-Time Metrics Database for One Quadrillion Points/Day
Datadog: a Real-Time Metrics Database for One Quadrillion Points/DayC4Media
 
Are We Really Cloud-Native?
Are We Really Cloud-Native?Are We Really Cloud-Native?
Are We Really Cloud-Native?C4Media
 
CockroachDB: Architecture of a Geo-Distributed SQL Database
CockroachDB: Architecture of a Geo-Distributed SQL DatabaseCockroachDB: Architecture of a Geo-Distributed SQL Database
CockroachDB: Architecture of a Geo-Distributed SQL DatabaseC4Media
 
A Dive into Streams @LinkedIn with Brooklin
A Dive into Streams @LinkedIn with BrooklinA Dive into Streams @LinkedIn with Brooklin
A Dive into Streams @LinkedIn with BrooklinC4Media
 

Mehr von C4Media (20)

Shifting Left with Cloud Native CI/CD
Shifting Left with Cloud Native CI/CDShifting Left with Cloud Native CI/CD
Shifting Left with Cloud Native CI/CD
 
CI/CD for Machine Learning
CI/CD for Machine LearningCI/CD for Machine Learning
CI/CD for Machine Learning
 
Fault Tolerance at Speed
Fault Tolerance at SpeedFault Tolerance at Speed
Fault Tolerance at Speed
 
Architectures That Scale Deep - Regaining Control in Deep Systems
Architectures That Scale Deep - Regaining Control in Deep SystemsArchitectures That Scale Deep - Regaining Control in Deep Systems
Architectures That Scale Deep - Regaining Control in Deep Systems
 
ML in the Browser: Interactive Experiences with Tensorflow.js
ML in the Browser: Interactive Experiences with Tensorflow.jsML in the Browser: Interactive Experiences with Tensorflow.js
ML in the Browser: Interactive Experiences with Tensorflow.js
 
Build Your Own WebAssembly Compiler
Build Your Own WebAssembly CompilerBuild Your Own WebAssembly Compiler
Build Your Own WebAssembly Compiler
 
User & Device Identity for Microservices @ Netflix Scale
User & Device Identity for Microservices @ Netflix ScaleUser & Device Identity for Microservices @ Netflix Scale
User & Device Identity for Microservices @ Netflix Scale
 
Scaling Patterns for Netflix's Edge
Scaling Patterns for Netflix's EdgeScaling Patterns for Netflix's Edge
Scaling Patterns for Netflix's Edge
 
Make Your Electron App Feel at Home Everywhere
Make Your Electron App Feel at Home EverywhereMake Your Electron App Feel at Home Everywhere
Make Your Electron App Feel at Home Everywhere
 
The Talk You've Been Await-ing For
The Talk You've Been Await-ing ForThe Talk You've Been Await-ing For
The Talk You've Been Await-ing For
 
Future of Data Engineering
Future of Data EngineeringFuture of Data Engineering
Future of Data Engineering
 
Automated Testing for Terraform, Docker, Packer, Kubernetes, and More
Automated Testing for Terraform, Docker, Packer, Kubernetes, and MoreAutomated Testing for Terraform, Docker, Packer, Kubernetes, and More
Automated Testing for Terraform, Docker, Packer, Kubernetes, and More
 
Navigating Complexity: High-performance Delivery and Discovery Teams
Navigating Complexity: High-performance Delivery and Discovery TeamsNavigating Complexity: High-performance Delivery and Discovery Teams
Navigating Complexity: High-performance Delivery and Discovery Teams
 
High Performance Cooperative Distributed Systems in Adtech
High Performance Cooperative Distributed Systems in AdtechHigh Performance Cooperative Distributed Systems in Adtech
High Performance Cooperative Distributed Systems in Adtech
 
Rust's Journey to Async/await
Rust's Journey to Async/awaitRust's Journey to Async/await
Rust's Journey to Async/await
 
Opportunities and Pitfalls of Event-Driven Utopia
Opportunities and Pitfalls of Event-Driven UtopiaOpportunities and Pitfalls of Event-Driven Utopia
Opportunities and Pitfalls of Event-Driven Utopia
 
Datadog: a Real-Time Metrics Database for One Quadrillion Points/Day
Datadog: a Real-Time Metrics Database for One Quadrillion Points/DayDatadog: a Real-Time Metrics Database for One Quadrillion Points/Day
Datadog: a Real-Time Metrics Database for One Quadrillion Points/Day
 
Are We Really Cloud-Native?
Are We Really Cloud-Native?Are We Really Cloud-Native?
Are We Really Cloud-Native?
 
CockroachDB: Architecture of a Geo-Distributed SQL Database
CockroachDB: Architecture of a Geo-Distributed SQL DatabaseCockroachDB: Architecture of a Geo-Distributed SQL Database
CockroachDB: Architecture of a Geo-Distributed SQL Database
 
A Dive into Streams @LinkedIn with Brooklin
A Dive into Streams @LinkedIn with BrooklinA Dive into Streams @LinkedIn with Brooklin
A Dive into Streams @LinkedIn with Brooklin
 

Kürzlich hochgeladen

A Domino Admins Adventures (Engage 2024)
A Domino Admins Adventures (Engage 2024)A Domino Admins Adventures (Engage 2024)
A Domino Admins Adventures (Engage 2024)Gabriella Davis
 
From Event to Action: Accelerate Your Decision Making with Real-Time Automation
From Event to Action: Accelerate Your Decision Making with Real-Time AutomationFrom Event to Action: Accelerate Your Decision Making with Real-Time Automation
From Event to Action: Accelerate Your Decision Making with Real-Time AutomationSafe Software
 
GenCyber Cyber Security Day Presentation
GenCyber Cyber Security Day PresentationGenCyber Cyber Security Day Presentation
GenCyber Cyber Security Day PresentationMichael W. Hawkins
 
WhatsApp 9892124323 ✓Call Girls In Kalyan ( Mumbai ) secure service
WhatsApp 9892124323 ✓Call Girls In Kalyan ( Mumbai ) secure serviceWhatsApp 9892124323 ✓Call Girls In Kalyan ( Mumbai ) secure service
WhatsApp 9892124323 ✓Call Girls In Kalyan ( Mumbai ) secure servicePooja Nehwal
 
Kotlin Multiplatform & Compose Multiplatform - Starter kit for pragmatics
Kotlin Multiplatform & Compose Multiplatform - Starter kit for pragmaticsKotlin Multiplatform & Compose Multiplatform - Starter kit for pragmatics
Kotlin Multiplatform & Compose Multiplatform - Starter kit for pragmaticscarlostorres15106
 
Beyond Boundaries: Leveraging No-Code Solutions for Industry Innovation
Beyond Boundaries: Leveraging No-Code Solutions for Industry InnovationBeyond Boundaries: Leveraging No-Code Solutions for Industry Innovation
Beyond Boundaries: Leveraging No-Code Solutions for Industry InnovationSafe Software
 
SQL Database Design For Developers at php[tek] 2024
SQL Database Design For Developers at php[tek] 2024SQL Database Design For Developers at php[tek] 2024
SQL Database Design For Developers at php[tek] 2024Scott Keck-Warren
 
08448380779 Call Girls In Greater Kailash - I Women Seeking Men
08448380779 Call Girls In Greater Kailash - I Women Seeking Men08448380779 Call Girls In Greater Kailash - I Women Seeking Men
08448380779 Call Girls In Greater Kailash - I Women Seeking MenDelhi Call girls
 
Tech-Forward - Achieving Business Readiness For Copilot in Microsoft 365
Tech-Forward - Achieving Business Readiness For Copilot in Microsoft 365Tech-Forward - Achieving Business Readiness For Copilot in Microsoft 365
Tech-Forward - Achieving Business Readiness For Copilot in Microsoft 3652toLead Limited
 
08448380779 Call Girls In Civil Lines Women Seeking Men
08448380779 Call Girls In Civil Lines Women Seeking Men08448380779 Call Girls In Civil Lines Women Seeking Men
08448380779 Call Girls In Civil Lines Women Seeking MenDelhi Call girls
 
Understanding the Laravel MVC Architecture
Understanding the Laravel MVC ArchitectureUnderstanding the Laravel MVC Architecture
Understanding the Laravel MVC ArchitecturePixlogix Infotech
 
Pigging Solutions Piggable Sweeping Elbows
Pigging Solutions Piggable Sweeping ElbowsPigging Solutions Piggable Sweeping Elbows
Pigging Solutions Piggable Sweeping ElbowsPigging Solutions
 
Breaking the Kubernetes Kill Chain: Host Path Mount
Breaking the Kubernetes Kill Chain: Host Path MountBreaking the Kubernetes Kill Chain: Host Path Mount
Breaking the Kubernetes Kill Chain: Host Path MountPuma Security, LLC
 
Key Features Of Token Development (1).pptx
Key  Features Of Token  Development (1).pptxKey  Features Of Token  Development (1).pptx
Key Features Of Token Development (1).pptxLBM Solutions
 
08448380779 Call Girls In Friends Colony Women Seeking Men
08448380779 Call Girls In Friends Colony Women Seeking Men08448380779 Call Girls In Friends Colony Women Seeking Men
08448380779 Call Girls In Friends Colony Women Seeking MenDelhi Call girls
 
Unblocking The Main Thread Solving ANRs and Frozen Frames
Unblocking The Main Thread Solving ANRs and Frozen FramesUnblocking The Main Thread Solving ANRs and Frozen Frames
Unblocking The Main Thread Solving ANRs and Frozen FramesSinan KOZAK
 
08448380779 Call Girls In Diplomatic Enclave Women Seeking Men
08448380779 Call Girls In Diplomatic Enclave Women Seeking Men08448380779 Call Girls In Diplomatic Enclave Women Seeking Men
08448380779 Call Girls In Diplomatic Enclave Women Seeking MenDelhi Call girls
 
Injustice - Developers Among Us (SciFiDevCon 2024)
Injustice - Developers Among Us (SciFiDevCon 2024)Injustice - Developers Among Us (SciFiDevCon 2024)
Injustice - Developers Among Us (SciFiDevCon 2024)Allon Mureinik
 
How to convert PDF to text with Nanonets
How to convert PDF to text with NanonetsHow to convert PDF to text with Nanonets
How to convert PDF to text with Nanonetsnaman860154
 
Swan(sea) Song – personal research during my six years at Swansea ... and bey...
Swan(sea) Song – personal research during my six years at Swansea ... and bey...Swan(sea) Song – personal research during my six years at Swansea ... and bey...
Swan(sea) Song – personal research during my six years at Swansea ... and bey...Alan Dix
 

Kürzlich hochgeladen (20)

A Domino Admins Adventures (Engage 2024)
A Domino Admins Adventures (Engage 2024)A Domino Admins Adventures (Engage 2024)
A Domino Admins Adventures (Engage 2024)
 
From Event to Action: Accelerate Your Decision Making with Real-Time Automation
From Event to Action: Accelerate Your Decision Making with Real-Time AutomationFrom Event to Action: Accelerate Your Decision Making with Real-Time Automation
From Event to Action: Accelerate Your Decision Making with Real-Time Automation
 
GenCyber Cyber Security Day Presentation
GenCyber Cyber Security Day PresentationGenCyber Cyber Security Day Presentation
GenCyber Cyber Security Day Presentation
 
WhatsApp 9892124323 ✓Call Girls In Kalyan ( Mumbai ) secure service
WhatsApp 9892124323 ✓Call Girls In Kalyan ( Mumbai ) secure serviceWhatsApp 9892124323 ✓Call Girls In Kalyan ( Mumbai ) secure service
WhatsApp 9892124323 ✓Call Girls In Kalyan ( Mumbai ) secure service
 
Kotlin Multiplatform & Compose Multiplatform - Starter kit for pragmatics
Kotlin Multiplatform & Compose Multiplatform - Starter kit for pragmaticsKotlin Multiplatform & Compose Multiplatform - Starter kit for pragmatics
Kotlin Multiplatform & Compose Multiplatform - Starter kit for pragmatics
 
Beyond Boundaries: Leveraging No-Code Solutions for Industry Innovation
Beyond Boundaries: Leveraging No-Code Solutions for Industry InnovationBeyond Boundaries: Leveraging No-Code Solutions for Industry Innovation
Beyond Boundaries: Leveraging No-Code Solutions for Industry Innovation
 
SQL Database Design For Developers at php[tek] 2024
SQL Database Design For Developers at php[tek] 2024SQL Database Design For Developers at php[tek] 2024
SQL Database Design For Developers at php[tek] 2024
 
08448380779 Call Girls In Greater Kailash - I Women Seeking Men
08448380779 Call Girls In Greater Kailash - I Women Seeking Men08448380779 Call Girls In Greater Kailash - I Women Seeking Men
08448380779 Call Girls In Greater Kailash - I Women Seeking Men
 
Tech-Forward - Achieving Business Readiness For Copilot in Microsoft 365
Tech-Forward - Achieving Business Readiness For Copilot in Microsoft 365Tech-Forward - Achieving Business Readiness For Copilot in Microsoft 365
Tech-Forward - Achieving Business Readiness For Copilot in Microsoft 365
 
08448380779 Call Girls In Civil Lines Women Seeking Men
08448380779 Call Girls In Civil Lines Women Seeking Men08448380779 Call Girls In Civil Lines Women Seeking Men
08448380779 Call Girls In Civil Lines Women Seeking Men
 
Understanding the Laravel MVC Architecture
Understanding the Laravel MVC ArchitectureUnderstanding the Laravel MVC Architecture
Understanding the Laravel MVC Architecture
 
Pigging Solutions Piggable Sweeping Elbows
Pigging Solutions Piggable Sweeping ElbowsPigging Solutions Piggable Sweeping Elbows
Pigging Solutions Piggable Sweeping Elbows
 
Breaking the Kubernetes Kill Chain: Host Path Mount
Breaking the Kubernetes Kill Chain: Host Path MountBreaking the Kubernetes Kill Chain: Host Path Mount
Breaking the Kubernetes Kill Chain: Host Path Mount
 
Key Features Of Token Development (1).pptx
Key  Features Of Token  Development (1).pptxKey  Features Of Token  Development (1).pptx
Key Features Of Token Development (1).pptx
 
08448380779 Call Girls In Friends Colony Women Seeking Men
08448380779 Call Girls In Friends Colony Women Seeking Men08448380779 Call Girls In Friends Colony Women Seeking Men
08448380779 Call Girls In Friends Colony Women Seeking Men
 
Unblocking The Main Thread Solving ANRs and Frozen Frames
Unblocking The Main Thread Solving ANRs and Frozen FramesUnblocking The Main Thread Solving ANRs and Frozen Frames
Unblocking The Main Thread Solving ANRs and Frozen Frames
 
08448380779 Call Girls In Diplomatic Enclave Women Seeking Men
08448380779 Call Girls In Diplomatic Enclave Women Seeking Men08448380779 Call Girls In Diplomatic Enclave Women Seeking Men
08448380779 Call Girls In Diplomatic Enclave Women Seeking Men
 
Injustice - Developers Among Us (SciFiDevCon 2024)
Injustice - Developers Among Us (SciFiDevCon 2024)Injustice - Developers Among Us (SciFiDevCon 2024)
Injustice - Developers Among Us (SciFiDevCon 2024)
 
How to convert PDF to text with Nanonets
How to convert PDF to text with NanonetsHow to convert PDF to text with Nanonets
How to convert PDF to text with Nanonets
 
Swan(sea) Song – personal research during my six years at Swansea ... and bey...
Swan(sea) Song – personal research during my six years at Swansea ... and bey...Swan(sea) Song – personal research during my six years at Swansea ... and bey...
Swan(sea) Song – personal research during my six years at Swansea ... and bey...
 

Habito: The Purely Functional Mortgage Broker

  • 1. Deck title, edit in View > Master Habito: The Purely Functional Mortgage Broker Will Jones, VP Engineering 1
  • 2. InfoQ.com: News & Community Site Watch the video with slide synchronization on InfoQ.com! https://www.infoq.com/presentations/ habito-mortgage-broker/ • Over 1,000,000 software developers, architects and CTOs read the site world- wide every month • 250,000 senior developers subscribe to our weekly newsletter • Published in 4 languages (English, Chinese, Japanese and Brazilian Portuguese) • Post content from our QCon conferences • 2 dedicated podcast channels: The InfoQ Podcast, with a focus on Architecture and The Engineering Culture Podcast, with a focus on building • 96 deep dives on innovative topics packed as downloadable emags and minibooks • Over 40 new content items per week
  • 3. Purpose of QCon - to empower software development by facilitating the spread of knowledge and innovation Strategy - practitioner-driven conference designed for YOU: influencers of change and innovation in your teams - speakers and topics driving the evolution and innovation - connecting and catalyzing the influencers and innovators Highlights - attended by more than 12,000 delegates since 2007 - held in 9 cities worldwide Presented at QCon London www.qconlondon.com
  • 4. Habito: The Purely Functional Mortgage Broker 2 ● Founded in early 2015, live since early 2016 ● Completely free service to take the pain out of mortgages ● Brokered over £1bn in applications to date ● ~140 people total, ~40 engineers ● Operate in small, cross-functional teams (~7 at present) Facts and figures
  • 5. Habito: The Purely Functional Mortgage Broker ● No clear universal language ● Coupled inheritance hierarchies ● Complex runtime state ● Boilerplate 3 Old wounds
  • 6. Habito: The Purely Functional Mortgage Broker ● No clear universal language Rich, data-driven domain model ● Coupled inheritance hierarchies Compose simpler building blocks ● Complex runtime state Immutability by default ● Boilerplate Code generation from specifications 4 New beginnings
  • 7. Habito: The Purely Functional Mortgage Broker 5 Haskell ● Purely functional programming language ● Strong static typing ● Non-strict evaluation model ● Deploy binaries in Docker containers (for example)
  • 8. Habito: The Purely Functional Mortgage Broker ● “A transaction is either a purchase or a remortgage. A purchase involves a deposit and a property value. A remortgage involves a remaining balance, current monthly repayment and a property value.” 6 Domain modelling
  • 9. Habito: The Purely Functional Mortgage Broker ● “A transaction is either a purchase or a remortgage. A purchase involves a deposit and a property value. A remortgage involves a remaining balance, current monthly repayment and a property value.” data Txn = Purchase PurchaseTxn | Remo RemoTxn 7 Domain modelling
  • 10. Habito: The Purely Functional Mortgage Broker ● “A transaction is either a purchase or a remortgage. A purchase involves a deposit and a property value. A remortgage involves a remaining balance, current monthly repayment and a property value.” data Txn = Purchase PurchaseTxn | Remo RemoTxn data PurchaseTxn = PurchaseTxn { deposit :: GBP , propVal :: GBP } 8 Domain modelling
  • 11. Habito: The Purely Functional Mortgage Broker ● “A transaction is either a purchase or a remortgage. A purchase involves a deposit and a property value. A remortgage involves a remaining balance, current monthly repayment and a property value.” data Txn = Purchase PurchaseTxn | Remo RemoTxn data PurchaseTxn data RemoTxn = PurchaseTxn = RemoTxn { deposit :: GBP { balance :: GBP , propVal :: GBP , currMonthly :: GBP } , propVal :: GBP } 9 Domain modelling
  • 12. Habito: The Purely Functional Mortgage Broker ● “A transaction is either a purchase or a remortgage. A purchase involves a deposit and a property value. A remortgage involves a remaining balance, current monthly repayment and a property value.” data Txn = Purchase PurchaseTxn | Remo RemoTxn txn1 :: Txn data PurchaseTxn txn1 = PurchaseTxn = Purchase (PurchaseTxn { deposit :: GBP { deposit = 30000 , propVal :: GBP , propVal = 100000 } }) 10 Domain modelling
  • 13. Habito: The Purely Functional Mortgage Broker ● “Applicant credit policy rule: buy-to-let customers are not eligible for a mortgage if they are retired or will enter retirement before the end of the mortgage term.” 11 Domain modelling
  • 14. Habito: The Purely Functional Mortgage Broker ● “Applicant credit policy rule: buy-to-let customers are not eligible for a mortgage if they are retired or will enter retirement before the end of the mortgage term.” rPD4 :: (HasToday, HasApplicant) => RuleBuilder "R-PD-4" 12 Domain modelling
  • 15. Habito: The Purely Functional Mortgage Broker ● “Applicant credit policy rule: buy-to-let customers are not eligible for a mortgage if they are retired or will enter retirement before the end of the mortgage term.” rPD4 :: (HasToday, HasApplicant) => RuleBuilder "R-PD-4" rPD4 _ = given (txnParam @"txnScenario" .== buyToLet) $ rejectIf $ 13 Domain modelling
  • 16. Habito: The Purely Functional Mortgage Broker ● “Applicant credit policy rule: buy-to-let customers are not eligible for a mortgage if they are retired or will enter retirement before the end of the mortgage term.” rPD4 :: (HasToday, HasApplicant) => RuleBuilder "R-PD-4" rPD4 _ = given (txnParam @"txnScenario" .== buyToLet) $ rejectIf $ empType .== retired .|| derive ageAtEndOfTerm .> retirementAge 14 Domain modelling
  • 17. Habito: The Purely Functional Mortgage Broker 15 Simpler building blocks rPD4 :: (HasToday, HasApplicant) => RuleBuilder "R-PD-4" rPD4 _ = given (txnParam @"txnScenario" .== buyToLet) $ rejectIf $ empType .== retired .|| derive ageAtEndOfTerm .> retirementAge ● Domain-specific language
  • 18. Habito: The Purely Functional Mortgage Broker 16 Simpler building blocks rPD4 :: (HasToday, HasApplicant) => RuleBuilder "R-PD-4" rPD4 _ = given (txnParam @"txnScenario" .== buyToLet) $ rejectIf $ empType .== retired .|| derive ageAtEndOfTerm .> retirementAge ● Domain-specific language ● Just a big function composition
  • 19. Habito: The Purely Functional Mortgage Broker 17 Simpler building blocks rPD4 :: (HasToday, HasApplicant) => RuleBuilder "R-PD-4" rPD4 _ = given (txnParam @"txnScenario" .== buyToLet) $ rejectIf $ empType .== retired .|| derive ageAtEndOfTerm .> retirementAge ● Domain-specific language ● Just a big function composition ● Some power tools: overloading, types
  • 20. Habito: The Purely Functional Mortgage Broker 18 Simpler building blocks rPD4 :: (HasToday, HasApplicant) => RuleBuilder "R-PD-4" rPD4 _ = given (txnParam @"txnScenario" .== buyToLet) $ rejectIf $ empType .== retired .|| derive ageAtEndOfTerm .> retirementAge ● Domain-specific language ● Just a big function composition ● Some power tools: overloading, types { "ruleId": "R-PD-4", "log": [ { "name": "txnScenario", "value": "BuyToLet", "entryType": { "type": "TxnParam" } }, { "name": "Applicants/Primary/DoB", "value": "Just 1945-10-21", "entryType": { "type": "DataKey" } }, ... ], "result": { "type": "Reject" } }
  • 21. Habito: The Purely Functional Mortgage Broker 19 Immutability everywhere ● Verify once, trust elsewhere ● Useful for parallelism/concurrency ● In general: easier to reason about ● Why stop with our language?
  • 22. Habito: The Purely Functional Mortgage Broker 20 Data account_id email password created verified 05d1100a-... will@example <hash> 2018-11-22T.. t dbc85161-... dev@example <hash> 2018-11-21T.. f account profile_id account_id first_name 3df81575-... 05d1100a-... William profile
  • 23. Habito: The Purely Functional Mortgage Broker 21 Data account_id email password created verified 05d1100a-... will@example <hash> 2018-11-22T.. t dbc85161-... dev@example <hash> 2018-11-21T.. t account profile_id account_id first_name 3df81575-... 05d1100a-... William profile
  • 24. Habito: The Purely Functional Mortgage Broker 22 Event sourcing 2018-11-21T... 05d1100a-... 1 Account { “type”: “AccountCreated”, “value”: { “email”: “will@example”, “password”: “<hash>” } } 2018-11-21T... 05d1100a-... 2 Account { “type”: “PasswordChanged”, “value”: { “newPassword”: “<hash>” } } 2018-11-22T... 05d1100a-... 3 Account { “type”: “EmailVerified”, “value”: {} } ? Aggregate ID Aggregate version Aggregate type Event data/payload
  • 25. Habito: The Purely Functional Mortgage Broker ● “An account is created. Thereafter the password may be changed, the email may be verified, ...” data Account = Account { id :: AccId , ... } data AccEvent = Created { id :: AccId } | PassChanged { hashedPass :: HashedPass } | EmailVerified | ... 23 Event sourcing
  • 26. Habito: The Purely Functional Mortgage Broker data Maybe a = Nothing | Just a updateAcc :: Maybe Account -> AccEvent -> Maybe Account updateAcc (Just acc) (PassChanged pwd) = acc { password = pwd } ... buildAcc :: [AccEvent] -> Maybe Account buildAcc = foldl updateAcc Nothing 24 Event sourcing
  • 27. Habito: The Purely Functional Mortgage Broker data Maybe a = Nothing | Just a updateAcc :: Maybe Account -> AccEvent -> Maybe Account updateAcc (Just acc) (PassChanged pwd) = acc { password = pwd } ... buildAcc :: [AccEvent] -> Maybe Account buildAcc = foldl updateAcc Nothing 25 Event sourcing foldl f z [x1, x2, x3] == f (f (f z x1) x2) x3 foldl updateAcc Nothing [e1, e2, e3] == uA (uA (uA Nothing e1) e2) e3
  • 28. Habito: The Purely Functional Mortgage Broker 26 Asking questions 05d1100a-... 1 Account { “type”: “AccountCreated”, “value”: { “email”: “will@example”, “password”: “<hash>” } } 05d1100a-... 2 Account { “type”: “PasswordChanged”, “value”: { “newPassword”: “<hash>” } } 05d1100a-... 3 Account { “type”: “EmailVerified”, “value”: {} } account_id email password created verified 05d1100a-... will@example <hash> 2018-11-22T.. t dbc85161-... dev@example <hash> 2018-11-21T.. f
  • 29. Habito: The Purely Functional Mortgage Broker 27 Asking questions 05d1100a-... 1 Account { “type”: “AccountCreated”, “value”: { “email”: “will@example”, “password”: “<hash>” } } 05d1100a-... 2 Account { “type”: “PasswordChanged”, “value”: { “newPassword”: “<hash>” } } 05d1100a-... 3 Account { “type”: “EmailVerified”, “value”: {} } { “id”: “05d1100a-...”, “email”: “will@example”, “created”: “2018-11-22T..”, “verified”: true, ... }
  • 30. Habito: The Purely Functional Mortgage Broker 28 Asking questions 05d1100a-... 1 Account { “type”: “AccountCreated”, “value”: { “email”: “will@example”, “password”: “<hash>” } } 05d1100a-... 2 Account { “type”: “PasswordChanged”, “value”: { “newPassword”: “<hash>” } } 05d1100a-... 3 Account { “type”: “EmailVerified”, “value”: {} } { “id”: “05d1100a-...”, “email”: “will@example”, “created”: “2018-11-22T..”, “verified”: true, ... } runProjection “Accounts” $ allEvents @AccountEvent .| ... .| ... .| ... .| sinkToPostgreSQL “tbl_acc”
  • 31. Habito: The Purely Functional Mortgage Broker 29 Asking questions 05d1100a-... 1 Account { “type”: “AccountCreated”, “value”: { “email”: “will@example”, “password”: “<hash>” } } 05d1100a-... 2 Account { “type”: “PasswordChanged”, “value”: { “newPassword”: “<hash>” } } 05d1100a-... 3 Account { “type”: “EmailVerified”, “value”: {} } { “id”: “05d1100a-...”, “email”: “will@example”, “created”: “2018-11-22T..”, “verified”: true, ... } runProjection “Accounts” $ allEvents @AccountEvent .| ... .| ... .| ... .| sinkToElastic “idx_acc”
  • 32. Habito: The Purely Functional Mortgage Broker 30 Asking questions 05d1100a-... 1 Account { “type”: “AccountCreated”, “value”: { “email”: “will@example”, “password”: “<hash>” } } 05d1100a-... 2 Account { “type”: “PasswordChanged”, “value”: { “newPassword”: “<hash>” } } 05d1100a-... 3 Account { “type”: “EmailVerified”, “value”: {} } { “id”: “05d1100a-...”, “email”: “will@example”, “created”: “2018-11-22T..”, “verified”: true, ... } runProjection “Accounts” $ allEvents @AccountEvent .| loggedToGrafana .| concurrently .| batched .| sinkToElastic “idx_acc”
  • 33. Habito: The Purely Functional Mortgage Broker data Txn = Purchase PurchaseTxn | Remo RemoTxn data PurchaseTxn data RemoTxn = PurchaseTxn = RemoTxn { deposit :: GBP { balance :: GBP , propVal :: GBP , currMonthly :: GBP } , propVal :: GBP } 31 Boilerplate
  • 34. Habito: The Purely Functional Mortgage Broker data Txn = Purchase PurchaseTxn | Remo RemoTxn deriving (Generic) data PurchaseTxn data RemoTxn = PurchaseTxn = RemoTxn { deposit :: GBP { balance :: GBP , propVal :: GBP , currMonthly :: GBP } , propVal :: GBP deriving (Generic) } deriving (Generic) 32 Boilerplate
  • 35. Habito: The Purely Functional Mortgage Broker data Txn = Purchase PurchaseTxn | Remo RemoTxn deriving (Generic) deriving (FromJSON, ToJSON) via (Generically Txn) data PurchaseTxn data RemoTxn = PurchaseTxn = RemoTxn { deposit :: GBP { balance :: GBP , propVal :: GBP , currMonthly :: GBP } , propVal :: GBP deriving (Generic) } deriving (Generic) 33 Boilerplate
  • 36. Habito: The Purely Functional Mortgage Broker updateTxnPropVal :: GBP -> Txn -> Txn updateTxnPropVal x txn = data PurchaseTxn data RemoTxn = PurchaseTxn = RemoTxn { deposit :: GBP { balance :: GBP , propVal :: GBP , currMonthly :: GBP } , propVal :: GBP deriving (Generic) } deriving (Generic) 34 Boilerplate
  • 37. Habito: The Purely Functional Mortgage Broker updateTxnPropVal :: GBP -> Txn -> Txn updateTxnPropVal x txn = case txn of PurchaseTxn pTxn -> ... RemoTxn rTxn -> ... data PurchaseTxn data RemoTxn = PurchaseTxn = RemoTxn { deposit :: GBP { balance :: GBP , propVal :: GBP , currMonthly :: GBP } , propVal :: GBP deriving (Generic) } deriving (Generic) 35 Boilerplate
  • 38. Habito: The Purely Functional Mortgage Broker updateTxnPropVal :: GBP -> Txn -> Txn updateTxnPropVal x txn = set (nestedField @“propVal”) x txn data PurchaseTxn data RemoTxn = PurchaseTxn = RemoTxn { deposit :: GBP { balance :: GBP , propVal :: GBP , currMonthly :: GBP } , propVal :: GBP deriving (Generic) } deriving (Generic) 36 Boilerplate
  • 39. Habito: The Purely Functional Mortgage Broker Compiling domains 37 rPD4 :: (HasToday, HasApplicant) => RuleBuilder "R-PD-4" rPD4 _ = given (txnParam @"txnScenario" .== buyToLet) $ ... { "ruleId": "R-PD-4", "log": [ { "name": "txnScenario", "value": "BuyToLet", "entryType": { "type": "TxnParam" } }, ... ], "result": { "type": "Reject" } }
  • 40. Habito: The Purely Functional Mortgage Broker Compiling domains 38 rPD4 :: (HasToday, HasApplicant) => RuleBuilder "R-PD-4" rPD4 _ = given (txnParam @"txnScenario" .== buyToLet) $ ... { "ruleId": "R-PD-4", "log": [ { "name": "txnScenario", "value": "BuyToLet", "entryType": { "type": "TxnParam" } }, ... ], "result": { "type": "Reject" } }
  • 41. Habito: The Purely Functional Mortgage Broker 39 It can’t all be good news ● Type-checking and compilation times ● Laziness and reasoning about performance ● Language ecosystem -- tooling and libraries ● Recruitment and hiring ● Event sourcing has its own challenges -- reprojection
  • 42. Habito: The Purely Functional Mortgage Broker ● No clear universal language Rich, data-driven domain model ● Coupled inheritance hierarchies Compose simpler building blocks ● Complex runtime state Immutability by default ● Boilerplate Code generation from specifications 40 Useful underpinnings
  • 43. Deck title, edit in View > Master Thank you 41
  • 44. Watch the video with slide synchronization on InfoQ.com! https://www.infoq.com/presentations/ habito-mortgage-broker/