Specification as a Library (Vol.3)


In a previous blog post, I described how to consume a specification as input and in return, output a set of isolated business domains. These business domains will serve as our initial blueprint for constructing the application.

The following are the business domains that were extracted from the specification:

  • Access
  • Profile
  • Subscriptions
  • Portfolio

These domains can serve as the initial foundation for our architecture. Let’s now explore the implementation phase of this application by adding a specification library that our Access domain will interpret.

Identify Domain Operations

We’ll first establish a general design for handling requests inside of our application. These requests will most likely come from the user of the application.


To start off, we need to identify what a user can attempt to do within the Access domain:

  • Submit registration
  • Login to session
  • Logout of session

If you’ve noticed, I used the term “attempt” instead of “command” in regards to the requests that a user may make within the application. So what’s the difference between an attempt and a command?

An attempt is an operation that’s not guaranteed to succeed. Thus, I would like to define a command as simply an order that gets dispatched for observers to respond to.

The following types are the supported commands within the Access domain of our application:

type ValidateCommand = Execute of UnvalidatedForm
type AttachCommand =   Attach  of ValidatedForm

type LoginCommand =  Login  of Credentials
type LogoutCommand = Logout of Provider


The following are attempt types:

module Attempt =
    type Submit = ValidatedForm -> Result
    type Login =  Credentials   -> Result
    type Logout = Provider      -> Result

In order to perform an attempt, a command must be issued. Therefore, we will bundle commands as precursors to attempts.

The following types are interfaces that require a command and an attempt and thus return a Result type.

type SubmitAttempt = Attempt.Submit -> Registration.Attach -> Result
type LoginAttempt =  Attempt.Login  -> LoginCommand        -> Result
type LogoutAttempt = Attempt.Logout -> LogoutCommand       -> Result


Attempt as a Data Structure

If you remember, we defined Submit as an interface (i.e. function type):

module Attempt =
    type Submit = ValidatedForm -> Result


Let’s now expose this Submit type as a member of another type that we’ll call Attempt:

type Attempt = {
        Submit : Submit

Also remember that our Submit type is just an interface. Hence, in functional programming languages, function types are interfaces. This means that we’ll eventually need to provide an implementation for what it means to Submit.

Once our attempt and Submit interfaces get implemented, we could call it inside of a view-model like this:

type ViewModel(dependencies) as x =
    inherit ViewModelBase()
    let submit = dependencies.Attempt.Submit

    let validate() =
        validatedForm |> function 
                         | Some form -> 
                                form |> Attach 
                                     |> attempt submit
                                     |> ResultOf.Submit.Executed
                                     |> Are.Submission.events
                                     |> broadcast
                         | None -> ()



Contrary to an attempt operation, a user can also request an operation that’s completely controlled within the confines of a domain. This form of operation accepts a command as input and emits a list of domain events for further processing. This form of operation can be called a workflow.

Validating a registration form, does not require external systems. Translated, we can validate a registration form internally before submitting the form to an external system for additional processing.

The following is an interface for validating a form:

type ValidateWorkflow = Registration.ValidateCommand -> RegistrationValidationEvent nonempty

Remember, we defined the validate command as the following:

type ValidateCommand = Validate of UnvalidatedForm

Unlike the attempt function type that we declared in the last section, the ValidateWorkflow interface doesn’t return a Result type. Instead, ValidateWorkflow returns a nonempty list of domain events.

Here’s a sneak peak of how the ValidateWorkflow interface will be invoked inside of a view-model:

  Validate ( Unvalidated { Email=    Email    x.Email
                            Password= Password x.Password
                            Confirm=  Password x.Confirm
                            |> In.ValidateRegistration.workflow
                            |> Update.statusOf isValidated

Our Access domain is essentially an interpreter. Hence, like the Access domain, other domains in our system will also rely on interfaces that are exposed by a specification library.

Here’s a sneak peek of the ValidateWorkfow implementation:

module ValidateRegistration =
    open Registration.Validate
    let workflow : ValidateWorkflow = function
                    .Execute form -> 
                             form |> Registration.validate
                                  |> ResultOf.Validate.Executed
                                  |> Are.Validation.events

The specification library can expose the Validate interface as the following:

type ValidateForm = UnvalidatedForm -> Result


Thus, our Access domain provides the following implementation for the ValidateForm interface:

let validate : ValidateForm =
    fun (Unvalidated form) ->
        let  isValidEmail (Email email) = email |> String.length > 3
        let (password,confirm) =
            (form.Password |> function Password p -> p, form.Confirm  |> function Password p -> p)
        if   not (form.Email |> isValidEmail) then
             Unvalidated form |> Error
        elif String.length password < 3 then
             Error <| Unvalidated form
        elif not (password = confirm) then
             Error <| Unvalidated form
        else Ok <| Validated form

Once our validation workflow gets implemented, we could call it inside of a view-model like this:

    let mutable validatedForm = None
    let validate() =
        let isValidated = function
            | FormValidated form -> validatedForm  false
        Unvalidated { Email=    Email    x.Email
                      Password= Password x.Password
                      Confirm=  Password x.Confirm
                      |> Validate
                      |> In.ValidateRegistration.workflow
                      |> Update.statusOf isValidated



As stated earlier, an attempt returns a Result type and a workflow returns a list of domain events. The Result type from an attempt requires further processing and needs to get converted into a list of domain events similar to workflows.

The Submit type under the ResultOf module will assist in converting a Result type into a list of domain events.

module Submit =
        module ResultOf = type Submit = Executed of Result

The following shows how a submit attempt gets converted into domain events:

|> attempt submit
|> ResultOf.Submit.Executed
|> Are.Submission.events


In this blog post, I provided some hints on how we could encode a specification as a library. Thus, I shared how we could leverage function types as interfaces that a specification library can expose for a corresponding domain to implement. In addition, I discussed how a command will either trigger an attempt or a workflow. An attempt will return a Result type. A workflow will return a nonempty list of domain events. In the next blog post, I will explain the processing of what gets returned from an attempt and a workflow.

The saga continues…

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

%d bloggers like this: