# Domain Modeling made Functional / Domain Modeling with Types / Modeling Workflows with Functions ###### tags: `ddd` If we have a workflow step that validates an order form, we might document it like this: ```ts type ValidateOrder = UnvalidatedOrder-> ValidatedOrder ``` It’s clear from this code that the ValidateOrder process transforms an unvalidated order into a validated one. ## Working with Complex Inputs and Outputs Every function has only one input and one output, but some workflows might have multiple inputs and outputs. We saw this with the order-placing workflow: the output needs to be three different events, so let’s create a compound type to store them as one record: ``` type PlaceOrderEvents = { AcknowledgmentSent : AcknowledgmentSent OrderPlaced : OrderPlaced BillableOrderPlaced : BillableOrderPlaced } ``` Using this approach, the order-placing workflow can be written as a function type, starting with the raw UnvalidatedOrder as input and returning the PlaceOrderEvents record: ``` type PlaceOrder = UnvalidatedOrder -> PlaceOrderEvents ``` On the other hand, if a workflow has an outputA or an outputB, then we can create a choice type to store them both. ``` workflow "Categorize Inbound Mail" = input: Envelope contents output: QuoteForm (put on appropriate pile) OR OrderForm (put on appropriate pile) OR ... ``` ``` type EnvelopeContents = EnvelopeContents of string type CategorizedMail = | Quote of QuoteForm | Order of OrderForm // etc type CategorizeInboundMail = EnvelopeContents -> CategorizedMail ``` If a workflow has a choice of different inputs (OR), then we can create a choice type. But if a process has multiple inputs that are all required (AND), such as “Calculate Prices” (below), we can choose between two possible approaches. ``` "Calculate Prices" = input: OrderForm, ProductCatalog output: PricedOrder ``` ``` type CalculatePrices = OrderForm -> ProductCatalog -> PricedOrder ``` Alternatively, we could create a new record type to contain them both. ``` type CalculatePricesInput = { OrderForm : OrderForm ProductCatalog : ProductCatalog } ``` ``` type CalculatePrices = CalculatePricesInput -> PricedOrder ``` Which approach is better? In the cases above, where the ProductCatalog is a dependency rather than a “real” input, we want to use the separate parameter approach. This lets us use the functional equivalent of dependency injection. On the other hand, if both inputs are always required and are strongly connected with each other, then a record type will make that clear. ## Documenting Effects in the Function Signature ``` type ValidateOrder = UnvalidatedOrder -> ValidatedOrder ``` But that assumes that the validation always works and a ValidatedOrder is always returned. In practice, of course, this would not be true, so it would better to indicate this situation by returning a Result type (introduced) in the function signature: ``` type ValidateOrder = UnvalidatedOrder -> Result<ValidatedOrder,ValidationError list> and ValidationError = { FieldName : string ErrorDescription : string } ``` Functional programming people use the term effects to describe things that a function does in addition to its primary output. By using Result here, we’ve now documented that ValidateOrder might have “error effects.” This makes it clear in the type signature that we can’t assume the function will always succeed and that we should be prepared to handle errors. In F#, we use the Async type to show that a function will have “asynchronous effects.” So if ValidateOrder had async effects as well as error effects, then we would write the function type like this: ``` type ValidateOrder = UnvalidatedOrder -> Async<Result<ValidatedOrder,ValidationError list>> ``` Listing all the effects explicitly like this is useful, but it does make the type signature ugly and complicated, so we would typically create a type alias for this to make it look nicer. ``` type ValidationResponse<'a> = Async<Result<'a,ValidationError list>> ``` ``` type ValidateOrder = UnvalidatedOrder -> ValidationResponse<ValidatedOrder> ```