Mercury: A Functional Review

18
Mercury: A Functional Review Retrospective on a first commercial F# project Mark Cheeseman [email protected] http://hombredequeso.id.au /

Transcript of Mercury: A Functional Review

Mercury:A Functional Review

Retrospective on a first commercial F# project

Mark Cheeseman

[email protected]

http://hombredequeso.id.au/

Why Use F# ?

• Less Code

• Easier to reason about the code

• Easier to multi-thread.

• You get to say “monad”

Why Did We Use F# : Immutability

By default, F# Record Types are immutable

type Point = {X: intY: int

}

class Point{

Point(int x, int y){

X = x;Y = y;

}public int X { get; private set; }public int Y { get; private set; }

}

Why Did We Use F#: Value Equality

F# records have structural (value) equality.

Classes have reference equality by default, but can implement value equality.type Point = {

X: intY: int

}

public class Point : IEquatable<Point>{

public Point(int x, int y){

X = x;Y = y;

}

public int X { get; private set; }public int Y { get; private set; }

public bool Equals(Point other){…

public class Point : IEquatable<Point>{

public Point(int x, int y){

X = x;Y = y;

}

public int X { get; private set; }public int Y { get; private set; }

public bool Equals(Point other){

if (ReferenceEquals(null, other)) return false;if (ReferenceEquals(this, other)) return true;return X == other.X && Y == other.Y;

}

public override bool Equals(object obj){

if (ReferenceEquals(null, obj)) return false;if (ReferenceEquals(this, obj)) return true;if (obj.GetType() != this.GetType()) return false;return Equals((Point) obj);

}

public override int GetHashCode(){

unchecked{

return (X*397) ^ Y;}

}

public static bool operator ==(Point left, Point right){

return Equals(left, right);}

public static bool operator !=(Point left, Point right){

return !Equals(left, right);}

}

Why Did We Use F#:Functional is the New SOLID

(or the end/goal of SI at least)

public interface IWidgetFactory

{

Widget Create(T1 t1, T2 t2);

}

http://blog.ploeh.dk/2014/03/10/solid-the-next-step-is-functional/

Base

Type1 Type2

Base

Type1 Type2

BaseA

Type1 Type2

BaseB

Inheritance Composition

Refactored Composition

Why Did We Use F#:Emergence of Functional Style with

Composition over Inheritance

Major Challenges

• Libraries/Frameworks to use

• Getting the most out of F# (idiomatic F#)

• How to put together a project

Local Server

Po

lling

(WC

F)

Shipment Polling

Endpoint

(C#)

External Shipping

System

Azure Web

Website

WebJob

Shipment

Processing

Endpoint

Bus

Shipment Polling DB

Shipment DB

(SQL Azure)

Mercury System Overview

Putting the Pieces Together

Requirement Technological Solution

Distributed Communication between company server and Azure

NServiceBus

Db Access (SQL Azure) F# (Sql) Dbml Type Provider

Website (Azure) Nancy

Unit Testing FsUnit, FsCheck

Browser Aurelia

Website Security BrockAllen.MembershipReboot, IdentityServer3

class Shipment{

public void Depart(T1 d){

// mutate _state}

public void Arrive(T2 a){

// mutate _state}

private State _state}

type Shipment {// state of shipment: record type

}

type Operation =Depart of T1Arrive of T2

let depart (d: T1) (s: Shipment) : Shipment =// departs shipment s, and returns a new// instance of Shipment in departed state

let arrive (a: T2) (s: Shipment) : Shipment =// arrives shipment s, and returns a new// instance of Shipmente in arrived state

let apply (operation: Operation) (shipment: Shipment): Shipment =

match operation with| Depart(d) -> depart d shipment| Arrive(a) -> arrive a shipment

Domain Code: C# and F#

Domain

Shipment DB (SQL Azure)

DAL

Composition Root

Bus (NSB)

NServiceBus Handlers

Nsb to Domain Transforms

Domain

Shipment DB (SQL Azure)

DAL

Composition Root

type Shipment

type Operation

apply:

Shipment -> Operation -> Shipment

… other entities

Bus (NSB)

NServiceBus Handlers

(ICmd -> unit)

Nsb to Domain Transforms

ICmd -> ShipmentEntity.Operation

Sql Type Provider

type dbContext.Shipment

type Dal.Shipment

dbContext.Shipment -> Dal.Shipment ->

Domain.Shipment

C# syntaxint GetHashCode(string s){

...}

F# syntaxlet GetHashCode (s: string) : int =

...or justlet GetHashCode s =

...

F# function signatureGetHashCode: string -> int

Domain

Shipment DB (SQL Azure)

DAL

Composition Root

type Shipment

type Operation

apply:

Shipment -> Operation -> Shipment

(ShipmentEntity.fs)

… other entities

Bus (NSB)

NServiceBus Handlers

(ICmd -> unit)

NsbHandlers.fs

Nsb to Domain Transforms

ICmd -> ShipmentEntity.Operation

(NsbToDomainTransform.fs)

Sql Type Provider

type dbContext.Shipment

type Dal.Shipment

dbContext.Shipment -> Dal.Shipment ->

Domain.Shipment

ShipmentViewModelDal.fs

Pattern Hints

• Making illegal states unrepresentable with single case unions.

http://fsharpforfunandprofit.com/posts/designing-with-types-making-illegal-states-unrepresentable/

• Do not throw exceptions.

http://fsharpforfunandprofit.com/rop/

Was it worth it?

Er, it depends…

On what?

Resources

http://fsharpforfunandprofit.com

One of the best, practically oriented F# resources.

http://blog.ploeh.dk/

Mark Seeman’s blog. Regularly blogs on F#.

https://www.youtube.com/watch?v=MHvr71T_LZw

Domain-Driven Design, Event Sourcing and CQRS with F# and EventStore

Syme et. al., Expert F# 4.0

Petricek, Real-World Functional Programming With Examples in F# and C#