# F#: Domain Driven Design (Decoupling)

# Intro

In my last article, I discussed my attempt of practicing Domain Driven Design via F#. As proud as I was of my progress in learning F# in combination with Domain Driven Design, there were some refactoring opportunities that I wanted to take.

# Decoupling Data from Behavior

In the last article, I had created two literals. One literal was for the target number of points that players would play up to. The other literal was the maximum number of allowed foul shots.

**The literals were implemented as follows:**

[<Literal>] let Objective = 33 [<Literal>] let MaxFoulShots = 3

**I used these literals in the active pattern function:**

let (|Underway|AlmostGame|Game|) (score,shot) = let shotValue = match shot with | FoulShot -> 1 | TwoPointer | TwoFoulShots -> 2 | ThreePointer | ThreeFoulShots -> 3 match score, shotValue with | Underway s,v -> if (s + v) <= (Objective - MaxFoulShots) then Underway (s + v) else AlmostGame (s + v) | AlmostGame s,v -> if ( (s+v) < Objective ) then AlmostGame (s + v) else Game Objective | GameTime s,v -> Game s

**Specifically, in this block here:**

match score, shotValue with | Underway s,v -> if (s + v) <= (Objective - MaxFoulShots) then Underway (s + v) else AlmostGame (s + v) | AlmostGame s,v -> if ( (s+v) < Objective ) then AlmostGame (s + v) else Game Objective | GameTime s,v -> Game s

What I don’t like about the above function, is that I feel like the function depends on an external power in order to deliver a result. Hence, my function relies on the hardcoded data “33” and “3” for the total number of points (i.e. “Objective”) and the maximum foul shots allowed (i.e. 3) respectively. Again, I feel as if this data was just planted into my function inorganically.

To remedy this code smell, I decided to practice the art of decoupling data from behavior. Thus, I replaced the literals in my code with a record type called Rules. Thus, this record type would be leveraged as a parameter for my active pattern function. Hence, my active pattern function determines the stage of a game based on a shooter’s score.

**The following record type was created:**

Rules = { Target:int MaxFoulShots:int }

**The active pattern was modified to the following:**

let (|Underway|AlmostGame|Game|) (score, shot, rules) = let shotValue = match shot with | FoulShot -> 1 | TwoPointer | TwoFoulShots -> 2 | ThreePointer | ThreeFoulShots -> 3 match score, shotValue with | Underway s,v -> if (s + v) <= (rules.Target - rules.MaxFoulShots) then Underway (s + v) else AlmostGame (s + v) | AlmostGame s,v -> if ( (s+v) < rules.Target ) then AlmostGame (s + v) else Game rules.Target | Game s,v -> Game s

Pattern matching can leverage Active Patterns for enhanced readability. Thus, my function, makeShot, was updated to call the active pattern.

**The makeShot function was the following:**

let makeShot shot (shooter, defender) = match (shooter.Score, shot) with | Underway p -> { shooter with Score=Underway p }, defender | AlmostGame p -> { shooter with Score=AlmostGame p }, defender | Game p -> { shooter with Score=GameTime p }, defender

**To incorporate the rules, I refactored makeShot to the following:**

let makeShot shot (players, rules) = let shooter = players.Shooter let defender = players.Defender let game = shooter.Score, shot, rules match game with | Underway p -> { Shooter = { shooter with Score=Underway p } Defender = defender }, rules | AlmostGame p -> { Shooter = { shooter with Score=AlmostGame p } Defender = defender }, rules | Game p -> { Shooter = { shooter with Score=Game p } Defender = defender }, rules

If you’ve noticed in the above code, I replaced the shooter and defender tuple with a record type called players. This decision was made because I found myself using this tuple of players in a number of places without any metadata about the order of the players within the tuple. That’s when I decided to create a type to define player roles.

**The Players record type is the following:**

type Players = { Shooter:PlayerScore Defender:PlayerScore }

**I then wrote a function to establish a change of role for the players:**

let changePossession players = { Shooter= players.Defender Defender= players.Shooter }

# Refactoring the Client

Based on the alterations that I’ve made to the domain model, I had to refactor the client code in order for my program to compile.

**The client for the game is the following:**

// ************************************************************ (*Client*) // ************************************************************ let players = startGame let rules = { Target=33; MaxFoulShots=3 } let firstPossession, _ = (players, rules) |> makeShot TwoPointer let turnOver = firstPossession |> changePossession, rules let final = turnOver |> makeShot ThreePointer |> makeShot FoulShot |> makeShot ThreePointer |> makeShot TwoFoulShots |> makeShot ThreePointer |> makeShot ThreeFoulShots |> makeShot ThreePointer |> makeShot ThreePointer |> makeShot ThreePointer |> makeShot ThreePointer |> makeShot ThreePointer |> makeShot FoulShot |> makeShot FoulShot |> makeShot ThreeFoulShots

**The entire domain model is this:**

module Game // ************************************************************ (*Types*) // ************************************************************ type Player = | Player1 | Player2 type Players = { Shooter:PlayerScore Defender:PlayerScore } and PlayerScore = { Player:Player Score:Game } and Rules = { Target:int MaxFoulShots:int } and Shot = | TwoPointer| ThreePointer | FoulShot | TwoFoulShots | ThreeFoulShots and Game = | Underway of int | AlmostGame of int | Game of int // ************************************************************ (*Functions*) // ************************************************************ let (|Underway|AlmostGame|Game|) (score, shot, rules) = let shotValue = match shot with | FoulShot -> 1 | TwoPointer | TwoFoulShots -> 2 | ThreePointer | ThreeFoulShots -> 3 match score, shotValue with | Underway s,v -> if (s + v) <= (rules.Target - rules.MaxFoulShots) then Underway (s + v) else AlmostGame (s + v) | AlmostGame s,v -> if ( (s+v) < rules.Target ) then AlmostGame (s + v) else Game rules.Target | Game s,v -> Game s let makeShot shot (players, rules) = let shooter = players.Shooter let defender = players.Defender let game = shooter.Score, shot, rules match game with | Underway p -> { Shooter = { shooter with Score=Underway p } Defender = defender }, rules | AlmostGame p -> { Shooter = { shooter with Score=AlmostGame p } Defender = defender }, rules | Game p -> { Shooter = { shooter with Score=Game p } Defender = defender }, rules let startGame = { Shooter= { Player=Player1; Score=Underway 0 } Defender= { Player=Player2; Score=Underway 0 } } let changePossession players = { Shooter= players.Defender Defender= players.Shooter } // ************************************************************ (*Client*) // ************************************************************ let players = startGame let rules = { Target=33; MaxFoulShots=3 } let firstPossession, _ = (players, rules) |> makeShot TwoPointer let turnOver = firstPossession |> changePossession, rules let final = turnOver |> makeShot ThreePointer |> makeShot FoulShot |> makeShot ThreePointer |> makeShot TwoFoulShots |> makeShot ThreePointer |> makeShot ThreeFoulShots |> makeShot ThreePointer |> makeShot ThreePointer |> makeShot ThreePointer |> makeShot ThreePointer |> makeShot ThreePointer |> makeShot FoulShot |> makeShot FoulShot |> makeShot ThreeFoulShots