Skip to content

Latest commit

 

History

History
73 lines (51 loc) · 3.41 KB

README.md

File metadata and controls

73 lines (51 loc) · 3.41 KB

ddmf-scala

Scala Steward badge

Sample code in scala, using ZIO, using the examples of the book Domain modeling made functional from Scott Wlaschin.

Features

  • Scala 3
  • Hexagonal Architecture
  • ZIO 2
  • New (refined) types: Application demonstrates the use of ZIO Prelude New Types as a way to implement refined types for DDD value objects.
  • Validation: Application uses Validation[E,A] to back the validations of input models.
  • Combining non-effectful & side-effecting validations: Validation[E,A] is a datastructure representing either a sucessful validation or some errors. In the application we demonstrate a way to combine this with ZIO[R,E,A].

DDD Value objects

Project demonstrates the use of new types to enhance the type safety and clarity of simple DDD value objects. Three approaches have been used:

The DDD Value object simple or composite can be found in domain

An example of a simple DDD VO using new types

 type ZipCode       = ZipCode.Type
 object ZipCode extends Newtype[String]:
    override inline def assertion: Assertion[String] = matches("^\\d{5}$".r)

An example of a simple DDD VO that uses opaque types is the Money which is implemented using Joda Money.

import org.joda.money.Money as JodaMoney
import org.joda.money.CurrencyUnit as JodaCurrencyUnit

opaque type Money = JodaMoney
object Money:

  def apply(amount: BigDecimal): Money = JodaMoney.of(JodaCurrencyUnit.EUR, amount.bigDecimal)

  def make(amount: BigDecimal): Validation[String, Money] =
    Validation
      .fromTry(Try(Money(amount)))
      .mapError(t => s"$amount is not a valid amount. ${t.getMessage}")
      

Finally, an example that uses both methods is BillingAmount which is based on Money which is constraint to a specific max value

import zio.prelude.{ Assertion, Identity, Subtype, Validation }
import Assertion.*
import zio.prelude.newtypes.Sum

object BillingAmount extends Subtype[Money]:

  override inline def assertion: Assertion[Money] = between(Money(0), Money(10000))

  def total(prices: Iterable[Price]): Validation[String, BillingAmount] =
    make(Money.total(prices))