F#: Bank Account Kata (Refactoring)

In the Bank Account Kata (vol. 1 & 2) video, I expressed disappointment on how I implemented my handlers.

The handlers were the following:

let handleWithdraw =  function
    | Withdraw (account , amount) ->
      if canWithdraw account amount then
           Some (Withdrawal(BeforeWithdrawal (account ,     amount),
                            AfterWithdrawal  (debit account amount)))
      else Some (WithdrawalFailed (account, amount) )
    | _ -> None

let handleDeposit =   function
    | Deposit   (account , amount) ->
      if amount > 0m then
           Some (Deposited((BeforeDeposit (account , amount),
                            AfterDeposit  (credit account amount) )))
      else Some (DepositFailed (account , amount))
    | _ -> None

let handleTransfer =  function
    | Transfer (fromAccount, toAccount, amount) ->
      if canWithdraw fromAccount amount then
          Some (Transferred ({ FromBalanceBefore=fromAccount
                               ToBalanceBefore=  toAccount

                               FromBalanceAfter= debit  fromAccount amount
                               ToBalanceAfter=   credit toAccount   amount } ,

                             amount))
          else Some (TransferFailed (fromAccount, toAccount, amount))
    | _ -> None

Let’s look at the first function:

let handleWithdraw =  function
    | Withdraw (account , amount) ->
      if canWithdraw account amount then
           Some (Withdrawal(BeforeWithdrawal (account ,     amount),
                            AfterWithdrawal  (debit account amount)))
      else Some (WithdrawalFailed (account, amount) )
    | _ -> None

The function above did not read as well as I would like. As a result I refactored the function to fully embrace pattern matching:

let handleWithdraw =  function
    | Withdraw (account , amount) when canWithdraw account amount ->
           Some (Withdrawal(BeforeWithdrawal (account ,     amount),
                            AfterWithdrawal  (debit account amount)))
    | Withdraw (account , amount) when not (canWithdraw account amount) ->
           Some (WithdrawalFailed (account, amount) )
    | _ -> None

Here’s the refactoring of all three functions:

let handleWithdraw =  function
    | Withdraw (account , amount) when canWithdraw account amount ->
           Some (Withdrawal(BeforeWithdrawal (account ,     amount),
                            AfterWithdrawal  (debit account amount)))
    | Withdraw (account , amount) when not (canWithdraw account amount) ->
           Some (WithdrawalFailed (account, amount) )
    | _ -> None

let handleDeposit =   function
    | Deposit (account , amount) when amount > 0m ->
            Some (Deposited((BeforeDeposit (account , amount),
                             AfterDeposit  (credit account amount) )))
    | Deposit (account , amount) when amount <= 0m ->
            Some (DepositFailed (account , amount))
    | _ -> None

let handleTransfer =  function
    | Transfer (fromAccount, toAccount, amount) when canWithdraw fromAccount amount ->
           Some (Transferred ({ FromBalanceBefore=fromAccount
                                ToBalanceBefore=  toAccount
                                FromBalanceAfter= debit  fromAccount amount
                                ToBalanceAfter=   credit toAccount   amount } ,
                                amount))

    | Transfer (fromAccount, toAccount, amount) when not (canWithdraw fromAccount amount) ->
           Some (TransferFailed (fromAccount, toAccount, amount))
    | _ -> None
Advertisements

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 )

Google+ photo

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

Connecting to %s

%d bloggers like this: