Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Functional Programming + Domain-Driven Design

Functional programming promotes immutable classes and referential transparency.

Domain-driven design is composed of Value Object (immutable) and Entities (mutable).

Should we create immutable Entities instead of mutable ones?

Let's assume, project uses Scala as main language, how could we write Entities as case classes (immutable so) without risking stale status if we're dealing with concurrency?

What is a good practice? Keeping Entities mutable (var fields etc...) and avoiding great syntax of case classes?

like image 802
Mik378 Avatar asked Feb 11 '13 13:02

Mik378


People also ask

What is functional programming design?

In computer science, functional programming is a programming paradigm where programs are constructed by applying and composing functions.

What is domain driven programming?

Domain-Driven Design(DDD) is a collection of principles and patterns that help developers craft elegant object systems. Properly applied it can lead to software abstractions called domain models. These models encapsulate complex business logic, closing the gap between business reality and code.

Is domain-driven design still relevant?

If you're developing a large system that has complexity at the heart, then yes, I recommend looking at some of the strategic (and tactical) patterns from Domain Driven Design.

What is the function of design domain?

5. Design domain is important because it helps us to create products or systems that are both functional and aesthetically pleasing. Design domain is important because it helps us to create products or systems that are both functional and aesthetically pleasing.


1 Answers

You can effectively use immutable Entities in Scala and avoid the horror of mutable fields and all the bugs that derives from mutable state. Using Immutable entities help you with concurrency, doesn't make things worse. Your previous mutable state will become a set of transformation which will create a new reference at each change.

At a certain level of your application, however, you will need to have a mutable state, or your application would be useless. The idea is to push it as up as you can in your program logic. Let's take an example of a Bank Account, which can change because of interest rate and ATM withdrawal or deposit.

You have two valid approaches:

  • You expose methods that can modify an internal property and you manage concurrency on those methods (very few, in fact)

  • You make all the class immutable and you surround it with a "manager" that can change the account.

Since the first is pretty straightforward, I will detail the first.

case class BankAccount(val balance:Double, val code:Int)

class BankAccountRef(private var bankAccount:BankAccount){
   def withdraw(withdrawal) = {
       bankAccount = bankAccount.copy(balance = bankAccount.balance - withdrawal)
       bankAccount.balance
   }
}

This is nice, but gosh, you are still stuck with managing concurrency. Well, Scala offers you a solution for that. The problem here is that if you share your reference to BankAccountRef to your Background job, then you will have to synchronize the call. The problem is that you are doing concurrency in a suboptimal way.

The optimal way of doing concurrency: message passing

What if on the other side, the different jobs cannot invoke methods directly on the BankAccount or a BankAccountRef, but just notify them that some operations needs to be performed? Well, then you have an Actor, the favourite way of doing concurrency in Scala.

class BankAccountActor(private var bankAccount:BankAccount) extends Actor {

    def receive {
        case BalanceRequest => sender ! Balance(bankAccount.balance)
        case Withdraw(amount) => {
            this.bankAccount = bankAccount.copy(balance = bankAccount.balance - amount)
        }
        case Deposit(amount) => {
            this.bankAccount = bankAccount.copy(balance = bankAccount.balance + amount)

        }

    }
}

This solution is extensively described in Akka documentation: http://doc.akka.io/docs/akka/2.1.0/scala/actors.html . The idea is that you communicate with an Actor by sending messages to its mailbox, and those messages are processed in order of receival. As such, you will never have concurrency flaws if using this model.

like image 188
Edmondo1984 Avatar answered Sep 26 '22 00:09

Edmondo1984