Architecting a web application in a functional style
Chris Birchall
Agenda
- Hand waving
 - Write some code
 - Summarise
 

http://lambdale.org/
@lambd_ale
1st September 2018
Functional style?
Obstacles to writing in functional style
- Disconnect between theory and practice
 - Decision paralysis
 - Nagging doubts
 
Disconnect between theory and practice
Disconnect between theory and practice
theory
practice
Kan
extensions
corepresentable functors
Monads
Yoneda lemma
Type classes
Kleisli
StateT
"build a working, well-tested, maintainable piece of software to deliver business value"
Decision paralysis
Somebody told me to use free monads,
but somebody else told they were passé
Should this thing be a class or an object?
Is it ok to use traits?
I don't even know what my package structure
should look like
Nagging doubt #1
Am I doing it right?

Nagging doubt #2
Is FP actually better than the alternatives?
Benefits of FP
- Local reasoning
 - Abstraction
 - Composition
 
Nagging doubt #3
Don't FP and OOP boil down to the same thing anyway?
Yes!
But one or the other might still be
a better tool for the job
Worked example
Photo storage service
Requirements
User can upload a photo and get back a unique ID
User can retrieve a photo by ID
Detailed requirements: upload photo
- Check that uploaded data is a valid photo
	
- If validation fails, log it and return a 400 error
 
 
- Store to a durable filestore service
	
- If this fails, log a warning and return a 500 error
 
 - Also store to a remote cache
	
- If this fails, just log a warning
 
 - Send a "photo uploaded" Kafka event
 - Return a 201 response containing the photo ID
 
Detailed requirements: retrieve photo
- First lookup the file in the cache
- If this fails, log a warning and treat as cache miss
 
 - On cache hit, return a 200 response
 - On cache miss:
- Retrieve file from filestore
- If file exists:
- Write it to the cache
- If this fails, just log a warning
 
 - Return a 200 response
 
 - Write it to the cache
 - Else, return a 404 response
 
 - If file exists:
 
 - Retrieve file from filestore
 
Non-functional requirements
- Request ID should be extracted from request header (or generated if not present)
	
- Should be propagated to all backend requests
 - Should be included in all logs
 
 - We expect a lot of concurrent requests, so all I/O must be asynchronous
 
Domain-driven design
Domain
Translation
External world
Functional design
Pure
Impure
External world
Functional design
Abstract
Concrete
External world
"DDD-inspired" package structure
api
application
domain
infrastructure
HTTP controllers
Concrete effects, interpreters
Domain models and algebras
HTTP clients, config loading, ...
Functional domain modelling
Data Behaviour = Domain
ADTs Algebras = Domain
+
+
Errors
- 
	
Expected errors
- Part of the domain
 - Model with Either
 
 - 
Unexpected errors
	
- Network errors, cosmic rays, ...
 - Handle with Try, IO, Task, ...
 
 - In general you need to handle both
	
- EitherT can be handy
 
 
def validate(input: Foo): IO[Either[ValidationError, Bar]]Enough talk!
Let's write some code
Summary
✓ Local reasoning
✓ Abstraction
✓ Composition
Architecting a web application in a functional style
By Chris Birchall
Architecting a web application in a functional style
- 3,086