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.
Last year:
TechDays 2016
• Event-Driven Applications in F#
• Programming Quantum Computers in F# using
LIQUi|>
• Functional-first programming
language
• Perceived as being only for
math/science/fintech
• Has its own vocabulary and
de...
• Take a boring business domain
• Use familiar approaches
• Use F# constructs to solve known problems
• Fit nicely in Azur...
Our Business
Domain:
Issue Tracker
• Types
• Functions
• Pipelines
Scenario 1:
Create an Issue
// Our first F# type
type IssueCreatedEvent = {
Id: string
Title: string
Description: string
}
type IssueId = Id of string
type IssueCreatedEvent = {
Id: IssueId
Title: string
Description: string
}
type CreateIssueCommand = {
Title: string
Description: string
}
let createIssue (command: CreateIssueCommand) = {
Id = generateId command
Title = command.Title
Description = command.Desc...
module Domain =
type IssueId = Id of string
type IssueCreatedEvent = {
Id: IssueId
Title: string
Description: string
}
typ...
[<DataContract>]
type NewIssueDTO = {
[<DataMember>] title: string
[<DataMember>] description: string
}
[<DataContract>]
t...
module SerDe =
let parseNewCommand (command: NewIssueDTO) = {
Title = command.title
Description = command.description
}
le...
module API =
let create (dto: NewIssueDTO) =
let command = SerDe.parseNewCommand dto
let event = Domain.createIssue comman...
module API =
let create =
SerDe.parseNewCommand
>> Domain.createIssue
>> SerDe.initializeHistory
type public IssuesApp() =
[<FunctionName("CreateIssue")>]
static member CreateIssue (
[<HttpTrigger("post")>]
request : Ne...
• 5 types
• 3 functions
• 1 pipeline
• 0 explicit I/O operations
Scenario 2:
Change an Issue
type User = User of string
type IssueAssignedToUserEvent = {
User: User
}
type IssueCommentedEvent = {
User: User
Comment:...
type AssignIssueCommand = {
User: User
}
let assignIssue (command: AssignIssueCommand) = {
User = command.User
}
You shouldn’t assign an issue if it’s Done
type IssueStatus =
| New
| Done
type Result<TSuccess, TError> =
| Ok of TSuccess
| Error of TError
// Function type is:
// IssueStatus -> AssignIssueCommand -> Result<IssueAssignedEvent,string>
let assignIssue (status: Is...
let closeIssue (status: IssueStatus) command =
match status with
| New -> Ok ()
| Done -> Error "Issue is already closed"
...
type ChangeIssueCommand =
| Assign of AssignIssueCommand
| AddComment of AddCommentCommand
| Close
| Reopen
type IssueChan...
module Domain =
// let createIssue ...
let changeIssue (command: ChangeIssueCommand) status =
match command with
| Assign ...
type IssueEvents = {
Created: IssueCreatedEvent
Changes: IssueChangedEvent list
}
let apply status event =
match event with
| Closed -> Done
| Reopened -> New
| _ -> status
let replay (events: IssueEvents...
Full Flow of Change
module Domain =
// let createIssue ...
let changeIssue (command: Command) (events: IssueEvents) =
let status = replay even...
Service & Deployment Diagram
module API =
// let create = …
let change (req: IssueCommandDTO) (log: IssueEventLogDTO) =
let command = SerDe.parseComman...
let httpResponse result =
match result with
| Ok _ ->
new HttpResponseMessage(HttpStatusCode.OK)
| Error e ->
new HttpResp...
type public IssuesApp() =
[<FunctionName("ChangeIssue")>]
static member ChangeIssue (
[<HttpTrigger("put")>]
request : Iss...
• Concise types
• Choice types (discriminated union)
• Immutability by default
• Explicit concepts
• No nulls, no exceptio...
• Pure Functions
• Determinism
• Totality
• Testability
• Composability
• Functional Architecture
• No circular dependencies
• 10 years of open source
• Community contributions to Compiler, Tooling,
Libraries, Documentation
http://fsharp.org will ...
Event Driven Applications in F#
Event Driven Applications in F#
Event Driven Applications in F#
Event Driven Applications in F#
Event Driven Applications in F#
Event Driven Applications in F#
Event Driven Applications in F#
Event Driven Applications in F#
Event Driven Applications in F#
Event Driven Applications in F#
Event Driven Applications in F#
Event Driven Applications in F#
Event Driven Applications in F#
Event Driven Applications in F#
Event Driven Applications in F#
Event Driven Applications in F#
Event Driven Applications in F#
Event Driven Applications in F#
Event Driven Applications in F#
Upcoming SlideShare
Loading in …5
×

Event Driven Applications in F#

1,117 views

Published on

Event Driven Applications in F# session on Tech Days Netherlands 2017

Published in: Software
  • Be the first to comment

Event Driven Applications in F#

  1. 1. Last year: TechDays 2016
  2. 2. • Event-Driven Applications in F# • Programming Quantum Computers in F# using LIQUi|>
  3. 3. • Functional-first programming language • Perceived as being only for math/science/fintech • Has its own vocabulary and design patterns
  4. 4. • Take a boring business domain • Use familiar approaches • Use F# constructs to solve known problems • Fit nicely in Azure • Show the benefits
  5. 5. Our Business Domain: Issue Tracker
  6. 6. • Types • Functions • Pipelines
  7. 7. Scenario 1: Create an Issue
  8. 8. // Our first F# type type IssueCreatedEvent = { Id: string Title: string Description: string }
  9. 9. type IssueId = Id of string type IssueCreatedEvent = { Id: IssueId Title: string Description: string }
  10. 10. type CreateIssueCommand = { Title: string Description: string }
  11. 11. let createIssue (command: CreateIssueCommand) = { Id = generateId command Title = command.Title Description = command.Description } // createIssue: CreateIssueCommand -> IssueCreatedEvent
  12. 12. module Domain = type IssueId = Id of string type IssueCreatedEvent = { Id: IssueId Title: string Description: string } type CreateIssueCommand = { Title: string Description: string } let createIssue (command: CreateIssueCommand) = { Id = generateId command Title = command.Title Description = command.Description }
  13. 13. [<DataContract>] type NewIssueDTO = { [<DataMember>] title: string [<DataMember>] description: string } [<DataContract>] type IssueEventLogDTO = { [<DataMember>] id: string [<DataMember>] created: NewIssueDTO }
  14. 14. module SerDe = let parseNewCommand (command: NewIssueDTO) = { Title = command.title Description = command.description } let initializeHistory (event: IssueCreatedEvent) = let (Id idString) = event.Id { id = idString created = { title = event.Title description = event.Description } }
  15. 15. module API = let create (dto: NewIssueDTO) = let command = SerDe.parseNewCommand dto let event = Domain.createIssue command let eventLogDTO = SerDe.initializeHistory event eventLogDTO
  16. 16. module API = let create = SerDe.parseNewCommand >> Domain.createIssue >> SerDe.initializeHistory
  17. 17. type public IssuesApp() = [<FunctionName("CreateIssue")>] static member CreateIssue ( [<HttpTrigger("post")>] request : NewIssueDTO, [<DocumentDB("IssuesDB", "Issues")>] documents: ICollector<IssueEventLogDTO>) = let eventLogDTO = API.create request documents.Add eventLogDTO eventLogDTO.id
  18. 18. • 5 types • 3 functions • 1 pipeline • 0 explicit I/O operations
  19. 19. Scenario 2: Change an Issue
  20. 20. type User = User of string type IssueAssignedToUserEvent = { User: User } type IssueCommentedEvent = { User: User Comment: string } //type IssueClosedEvent = { } //type IssueReopenedEvent = { }
  21. 21. type AssignIssueCommand = { User: User } let assignIssue (command: AssignIssueCommand) = { User = command.User }
  22. 22. You shouldn’t assign an issue if it’s Done
  23. 23. type IssueStatus = | New | Done
  24. 24. type Result<TSuccess, TError> = | Ok of TSuccess | Error of TError
  25. 25. // Function type is: // IssueStatus -> AssignIssueCommand -> Result<IssueAssignedEvent,string> let assignIssue (status: IssueStatus) (command: AssignIssueCommand) = match status with | New -> Ok { User = command.User } | Done -> Error "Can't assign closed issue"
  26. 26. let closeIssue (status: IssueStatus) command = match status with | New -> Ok () | Done -> Error "Issue is already closed" let reopenIssue (status: IssueStatus) command = match status with | Done -> Ok () | New -> Error "Can't reopen open issue"
  27. 27. type ChangeIssueCommand = | Assign of AssignIssueCommand | AddComment of AddCommentCommand | Close | Reopen type IssueChangedEvent = | Assigned of IssueAssignedToUserEvent | Commented of IssueCommentedEvent | Closed | Reopened
  28. 28. module Domain = // let createIssue ... let changeIssue (command: ChangeIssueCommand) status = match command with | Assign a -> assignIssue status a | Comment c -> commentIssue status c | Close -> closeIssue status | Reopen -> reopenIssue status
  29. 29. type IssueEvents = { Created: IssueCreatedEvent Changes: IssueChangedEvent list }
  30. 30. let apply status event = match event with | Closed -> Done | Reopened -> New | _ -> status let replay (events: IssueEvents): IssueStatus = List.fold apply New events.Changes
  31. 31. Full Flow of Change
  32. 32. module Domain = // let createIssue ... let changeIssue (command: Command) (events: IssueEvents) = let status = replay events match command with | Assign a -> assignIssue status a | Comment c -> commentIssue status c | Close -> closeIssue status | Reopen -> reopenIssue status
  33. 33. Service & Deployment Diagram
  34. 34. module API = // let create = … let change (req: IssueCommandDTO) (log: IssueEventLogDTO) = let command = SerDe.parseCommand req let eventLog = SerDe.parseHistory log let result = Domain.change command eventLog append log result httpResponse result
  35. 35. let httpResponse result = match result with | Ok _ -> new HttpResponseMessage(HttpStatusCode.OK) | Error e -> new HttpResponseMessage( HttpStatusCode.BadRequest, Content = new StringContent(e)) // httpResponse: Result<T, string> -> HttpResponseMessage
  36. 36. type public IssuesApp() = [<FunctionName("ChangeIssue")>] static member ChangeIssue ( [<HttpTrigger("put")>] request : IssueCommandDTO, [<DocumentDB("IssuesDB", "Issues", Id = "{id}")>] state: IssueEventLogDTO) = API.change request state
  37. 37. • Concise types • Choice types (discriminated union) • Immutability by default • Explicit concepts • No nulls, no exceptions • Make invalid state unrepresentable • Type as documentation • Types as guard
  38. 38. • Pure Functions • Determinism • Totality • Testability • Composability
  39. 39. • Functional Architecture • No circular dependencies
  40. 40. • 10 years of open source • Community contributions to Compiler, Tooling, Libraries, Documentation http://fsharp.org will get you started

×