Friday, December 09, 2016

Build Yourself a Robo-Advisor in F#. Part I : Domain Modelling


This article is part of the F# Advent Calendar 2016

It is based on the first part of the ‘Build yourself a Robo-Advisor in F#’ workshop, as presented at the 2016 F# Progressive F# Tutorials conference in London.

Introduction


Most of us aren’t saving enough for our future. This isn’t something that’s going to go away - we’re living longer and many of us are underestimating how much money we need for a comfortable retirement. How can you solve this problem? By harnessing the power of F# to deliver clear and easy-to-understand advice and recommendations that takes you on a journey from confused to confident.

Over the last couple of years, robo-advisors have emerged as a platform for automating this advice as one part of the Fintech revolution. In this short series of posts we will build a web-based robo advisor that will show you how much money you might have in retirement.

Along the way you will discover how to:

  • Understand a domain and model it with the F# type system
  • Leverage F#’s data capabilities and make a first program that can chart our projected savings
  • Take it to the next level by building a web-based robo-advisor using one of F#’s fantastic open-source web app frameworks

Part 1 - Domain modelling


A good first step towards building a new piece of software is to model the domain: what exactly is it we’re getting the software to do? What are the real-life equivalents of the code we want to write?

What is our domain?


We boil our domain down to one example question:

How much money will I have when I retire?

More generally, we want to take someone and calculate how much their pension pot will be worth when they retire.

The bold sections give us our basic domain:

  • People
  • Money
  • Time


How can F# help us model it?


Algebraic Data Types


Discriminated Unions allow us to express real-world concepts almost directly in code

Let’s take a really simple one with only two options, the boolean. How to we write this in F#?

type Bool = True | False

What if we want to say that something can either have a value or not?

type Option<'a> = 
| Some of 'a
None

What about if something can fail?

type Result<'TSuccess, 'TFailure> = 
| Succcess of 'TSuccess
| Failure of 'TFailure

And what if we want to distinguish one type of string from another?

type EmailAddress = EmailAddress of string

That’s all pretty useful! We can combin them with Records. Immutable records have a concise syntax and structural equality which make them really powerful for modelling. Here’s an example:

type Car = {
  Engine : Engine
  Wheels : Wheel list
  Seats : ... }


Pattern matching


Once we have our unions, we have a type-safe switch alternative in the form of pattern matching. These give us a one-step match & decompose workflow, and for extra benefit the compiler catches non-exhaustive match so that we are warned if we’ve added a case and not properly handled it.

Here’s an example using a Result:

let handleResult = function
| Success result -> "Woop! It all worked, the answer is: " + result
| Failure error -> "Uh-oh. Something bad happened: " + error


Units of measure


The question we want to answer here is:

How do you represent a currency in code?

One way to do so is with Units of Measure. With these we can make sure something has the right unit, as well as creating derives measures ( e.g kg m / s^2)

We can also reduce errors in conversions & calculations. How bad can this really be? Take a look here!


What did we come up with?


Using what we’ve just discussed, here’s a minimal domain model for figuring out how much money someone is likely to have in retirement.

module Domain =
  open System 

  type Gender = Male | Female

  type EmailAddress = EmailAddress of string

  type Person = { 
      Name : string
      Gender : Gender
      DateOfBirth : DateTime
      EmailAddress : EmailAddress option }

  type ContributionFrequency = Monthly | Annual

  type ContributionSchedule<[<Measure>] 'ccy> = {
      Amount : decimal<'ccy>
      Frequency : ContributionFrequency }

  type PensionPot<[<Measure>] 'ccy> = { 
      Value : decimal<'ccy>; 
      ValuationDate : DateTime; 
      ContributionSchedule: ContributionSchedule<'ccy> }

  [<Measure>] type GBP
  [<Measure>] type USD
  [<Measure>] type EUR

  let valuePensionPot<[<Measure>] 'ccy> (pensionPot : PensionPot<'ccy>) (valuationDate: DateTime) = 
     match pensionPot.ContributionSchedule.Frequency with 
     | Monthly ->
        let monthsInFuture = (valuationDate.Year - pensionPot.ValuationDate.Year) * 12 + valuationDate.Month - pensionPot.ValuationDate.Month
        pensionPot.Value + decimal monthsInFuture * pensionPot.ContributionSchedule.Amount
     | Annual ->
        let yearsInFuture = valuationDate.Year - pensionPot.ValuationDate.Year
        pensionPot.Value + decimal yearsInFuture * pensionPot.ContributionSchedule.Amount

I think this code is pretty short and easy to understand given the complexity of the domain. We’ve used a wide variety of features that helped us along the way.



Talks


Scott Wlaschin NDC: https://vimeo.com/97507575

Tomas Petricek Channel 9: https://www.youtube.com/watch?v=Sa6bntNslvY

Mark Seeman NDC: https://vimeo.com/131631483


Blogs


http://fsharpforfunandprofit.com/ddd/

http://tomasp.net/blog/type-first-development.aspx/

http://gorodinski.com/blog/2013/02/17/domain-driven-design-with-fsharp-and-eventstore/


Wrapping up


In this part you’ve seen how we take take a real-life domain and come up with a concise and accurate model for it using F#.

We’ve got some great language features to model domains in F#! If you are thinking about how to represent things in code, the ideas in this post are a great starting point.


Next time


Charts and data! You’ll see how to take the domain we’ve just created and chart it in a Desktop app with FSharp.Charting. We’ll also look at accessing data via type providers.

No comments:

Post a comment