Video and slides synchronized, mp3 and slide download available at URL http://bit.ly/2YXwv4Z.
Will Jones talks about how Habito, the leading digital mortgage broker, benefited from using Haskell, some of the wins and trade-offs that have brought it to where it is today and where it's going next. He also talks about why functional programming is beneficial for large projects, and how it helps especially with migrating the data store. Filmed at qconlondon.com.
Will Jones is a polyglot software engineer and passionate teacher with over eight years' experience building applications, creating products and educating other developers and computer scientists. His passions are deeply embedded in the technologies he is using in his current role as VP Engineering at Habito, such as Haskell, PureScript and event sourcing/CQRS.
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
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
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