I'm attempting to use Railway Oriented Programming principals http://fsharpforfunandprofit.com/rop/ and this http://indiedevspot.azurewebsites.net/2015/01/20/two-track-coding-rop-for-dummies-part-2/ for reference
I have successfully implemented this for most of the codebase, except now we are getting to putting items into SQL and wish to use ROP for validation of those types. The typical pattern is
Figure 1:
let createSomething a b c = {A = a; B = b; C = c}
let createValidSomething so =
createSomething
<!> validateFunction1 so.param1
<*> validateFunction2 so.param2
<*> ...so forth and so on
You will notice that createSomething is a function that returns a record type instantiation a -> b -> c -> a' -> b' -> c' The SQL Type providers return a mutable type (non record). Lets look at my attempt to build a similar createSomething function
Figure 2:
let createSQS(a, b, c, d, e, f, g) =
let sqs = context.``[dbo].[Something]``.Create(a, b, c, d, e, f, g)
sqs
At this point, we know this already will not work, we have a->b->c->d->e->f->g->context.[dbo].[Something]
.Entity
I know I can have an intermediary record type and follow ROP principals, match on success/failure and then create my object off of the already validated. But does that not seem like too many steps?
Does anybody know of a good pattern for this? Ideally we could have a function similar to Figure1 that generates a Record Type that is compatible with the Type Providers.
I'm open to trying things and hanging out on Skype :).
So we came up with an answer at our dev meeting, and decided that we in fact WANT to execute each part in its own function. For the inner binds we invented our own operator; similar to plus (&&&) (which I will blog about on my site www.indiedevspot.com) and at the top level we ran with a normal bind.
Our top level code looks like this:
[<HttpPost>]
x.member Add(sa:Something) =
sa|>ValidateSomething
>>= converttoSSA
>>= persistSSA
We decided to separate the concerns due to independent testability of validation, conversion and persistence. The theory is that functional composition if made up of functions that are guaranteed to work, is itself inherently guaranteed to work (or have a much better chance).
If we went with the proposed method (which we have not yet solved), we would be mixing concerns of creation, validation and conversion. That would also end up creating an additional record type which was un-necessary.