Last active
March 7, 2025 12:47
-
-
Save programaker/09de2a15cfa587cdbe78fb724d33e6c2 to your computer and use it in GitHub Desktop.
Revisions
-
programaker revised this gist
Oct 21, 2021 . 1 changed file with 3 additions and 16 deletions.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -15,20 +15,12 @@ import io.circe.syntax.* import java.util.UUID // the pure domain concept/entity // the base data is declared here, and only here case class Frunfles(a: String, b: Int, c: Boolean) object Frunfles: given Encoder[Frunfles] = deriveEncoder // persisted entity containing an id // no need to make the id optional // no need to duplicate Frunfles fields @@ -40,20 +32,15 @@ object PersistedFrunfles: // type-safe operations // explictly stating which operations require an entity with id def insert(f: Frunfles): PersistedFrunfles = ??? def update(f: PersistedFrunfles): PersistedFrunfles = ??? def delete(f: PersistedFrunfles): Unit = ??? // composition over inheritance, more FP-ish val f = Frunfles("Meh", 42, true) val pf = PersistedFrunfles(id = UUID.randomUUID().nn, data = f) // exported fields available without calling `.data`. Happy demeter! val id = pf.id val a2 = pf.a val b2 = pf.b -
programaker revised this gist
Sep 14, 2021 . 1 changed file with 1 addition and 1 deletion.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -1,6 +1,6 @@ /* * The good practices say we shouldn't use the same type for everything (domain, json, persistence, ...), but * most of the time those types are very similar - if not exactly identical - creating a lot of duplication. * * Inheritance to the rescue? Nah... not very FP and even the OOP folks are aware that we should * prefer composition over it. But composition has it's own challenges (Law of Demeter for instance). -
programaker created this gist
Sep 13, 2021 .There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -0,0 +1,60 @@ /* * The good practices say we shouldn't use the same type for everything (domain, json, persistence, ...), but * most of the time those types are very similar - if not exactly identical - creating a lot of dupliation. * * Inheritance to the rescue? Nah... not very FP and even the OOP folks are aware that we should * prefer composition over it. But composition has it's own challenges (Law of Demeter for instance). * * Let's see how the new `Export Clauses` in Scala 3 can help with that: * https://docs.scala-lang.org/scala3/reference/other-new-features/export.html * */ import io.circe.Encoder import io.circe.generic.semiauto.* import io.circe.syntax.* import java.util.UUID // the pure domain concept // the base data is declared here, and only here case class Frunfles(a: String, b: Int, c: Boolean) object Frunfles: given Encoder[Frunfles] = deriveEncoder // new entity to be persisted without id // no need to make the id optional // no need to duplicate Frunfles fields case class NewFrunfles(data: Frunfles): export data.* // super-powered delegation! object NewFrunfles: given Encoder[NewFrunfles] = Encoder.instance(_.data.asJson) // persisted entity containing an id // no need to make the id optional // no need to duplicate Frunfles fields case class PersistedFrunfles(id: UUID, data: Frunfles): export data.* object PersistedFrunfles: // easy to avoid exposing the id in Json given Encoder[PersistedFrunfles] = Encoder.instance(_.data.asJson) // type-safe operations // explictly stating which operations require an entity with id def insert(f: NewFrunfles): PersistedFrunfles = ??? def update(f: PersistedFrunfles): PersistedFrunfles = ??? def delete(f: PersistedFrunfles): Unit = ??? // composition over inheritance, more FP-ish val f = Frunfles("Meh", 42, true) val nf = NewFrunfles(data = f) val pf = PersistedFrunfles(id = UUID.randomUUID().nn, data = f) // exported fields available without calling `.data` val a1 = nf.a val b1 = nf.b val c1 = nf.c /// val id = pf.id val a2 = pf.a val b2 = pf.b val c2 = pf.c