Difference between revisions of "Real World Applications/Event Driven Applications"

From HaskellWiki
Jump to navigation Jump to search
Line 102: Line 102:
 
The Domain API is ''Value'' based not ''API'' based.
 
The Domain API is ''Value'' based not ''API'' based.
 
Events can be queued, recorded, distributed and replayed.
 
Events can be queued, recorded, distributed and replayed.
  +
  +
And by the way, this is ''NOT'' MVC (more like Mediator) :-)
   
 
== Growing the Application ==
 
== Growing the Application ==

Revision as of 13:57, 2 July 2014

Introduction

An event driven application is an application that reacts to external events.

Examples of events are:

  • A Loan Application has been accepted/rejected (commercial business).
  • A new Rostering Schedule is ready for distribution to all crew (Airline Management System).
  • An Illegal Trade Pattern has been detected (Trading Fraud Detection System).
  • A simulated car has hits another simulated car (Commercial Racing Game).
  • A robot has reached its destination (Real Time Warehouse Management System).
  • A HTML message has been received (Web Server).
  • A key has been pressed (Text Editor).

The examples demonstrate that events can be anything from high level business events ("A loan application accepted/rejected") to low level events ("User pressed key").

In the following, I will show a way to architecture a Haskell system so that it can scale from small "toy" applications (dealing with low level IO events) to large scale, high volume, distributed, fault tolerant "Enterprise" scale applications.

Please note that the following is not the only way to attack the problem. So please contribute your (clearly superior of course) alternative way to do it here: Real World Applications

Events in Haskell

In the following, I define an "Event" to be a value describing something that has happened in the past. And yes this should really be called an "Event Notification" but life is too short :-)

Here is a straightforward way to define Events in Haskell:

data Event =
    EventUserExit            -- User wants to exit
  | EventUserSave            -- User wants to save
  | EventUserSaveAs String
  | EventUserUndo            -- User wants to undo
  | EventUserRedo            -- User wants to redo
  deriving(Eq,Show)

Events can be high level or low level depending on how "low level" in the system you are operating. Within a UI sub-system the events are typically low level (key pressed, window closed). In a large scale distributed system the events are typically high level business events (EventCustomerCreated <details>).

A Tiny Event Driven Haskell Application

Let's begin with a tiny event driven Haskell application:

module Main where

import Control.Monad (when)

import Domain   -- The (pure) "domain model" is defined here
import Event    -- The (pure) events
import UI       -- A (non-pure) UI (User Interface) is defined here

I am here using the term "Domain" to abstract away from the actual application domain. Fell free to use "Shipping" instead of Domain if your application area is shipping containers and "Game" if your domain is a game application. More info here: Domain Model

The Event module defines the events that both the Domain module and the UI module need to agree on.

The UI module contains some sort of User Interface. For now it doesn't really matter how the UI is implemented. All that matters is that it can somehow present the Domain to a user and get user events back. More on this later.

main :: IO ()
main = run newDomain []

The main function simply starts the event loop (run):

run :: Domain -> [Event] -> IO ()

run dm [] = do
  events <- uiUpdate dm
  run dm events

run dm (EventExit:_) =
  return ()

run dm (e:es) =
  run (domainUpdate dm e) es

"run" is what is traditionally called the "Event Loop". This is the beating heart of the application. The UI updates itself and returns one or more events. While there are still events to be processed, the domain will be updated one event at a time.

Consequences

The tiny application above is simple. However a number of key choices have been made that will profoundly shape how the application scales from this tiny application to "Enterprise" level:

UI depends on Domain - Domain does not depend on UI. This is the complete opposite of how most applications are (wrongly) developed.

UI can be swapped without changing Domain. Try that with your average application.

Domain is pure. All the goodness of functional programming.

Domain can be tested without the UI. No need to setup Database to test.

The Domain API is Value based not API based. Events can be queued, recorded, distributed and replayed.

And by the way, this is NOT MVC (more like Mediator) :-)

Growing the Application

So how do we grow this tiny application to "Enterprise" scale? Read on:

  • Simple File Storage
  • Logging
  • Testing
  • Crash Recovery
  • Undo/Redo
  • Time
  • UI
  • Performance Monitoring (Dashboard)
  • Automatic Server Scaling
  • Complex Event Processing
  • (Multiple) Databases (Separating Online and Reporting)
  • Client/Server
  • Humble "File in Directory" Events
  • Reporting
  • Business Workflow
  • Remove Control
  • Event Sourcing
  • Event Bus
  • Security (Event Pattern Based)
  • Interop with non-Haskell applications

Questions and feedback

If you have any questions or suggestions, feel free to mail me.