Skip to content

Latest commit

History

44 Commits

Folders and files

NameName
Last commit message
Last commit date

Repository files navigation

Build statuscodecovDependenciesLicenseDownload

Fluent

The seamless translation layer

Context

In DDD (Domain Driven Design) it is recommended to introduce a translation layer (aka anticorruption layer) between different domains. It allows to isolate the domain from each other making sure the can evolve independently.

However writing code for the translation layer isn't really exciting as quite often the domain objects share some similarities. Translating from one domain to the other introduces lots of boilerplate code and doesn't add much business value.

Fluent aims at reducing this boilerplate code. It leverages the similarities between the domains in order to convert case classes from one domain into the other. Under the hood it relies on Shapeless and implicit type class instances.

Setup

In order to use Fluent you need to add the following lines to your build.sbt:

resolvers +=Resolver.bintrayRepo("beyondthelines", "maven")
libraryDependencies +="beyondthelines"%%"fluent"%"0.0.7"

## Dependencies

Fluent has only 2 dependencies: Shapeless and Cats.

Usage

In order to use Fluent you need to import the following:

importcats.intances.all._importfluent._

The cats import is only needed if your case classes contains functors like List, Option, ... Of course you can be more specific and import only the instances you need.

Importing fluent._ adds a new method to your case classes transformTo. You only need to call this method to transform a case class into another one.

Basic Example

Let's take a basic example to illustrate the usage:

objectExternal {
caseclassCircle(x: Double, y: Double, radius: Double, color: Option[String])
}
objectInternal {
caseclassPoint(x: Double, y: Double)
sealedtraitColorobjectColor {
caseobjectBlueextendsColorcaseobjectRedextendsColorcaseobjectYellowextendsColor
}
caseclassCircle(center: Point, radius: Double, color: Option[Color])
}

Let's create an instance of external circle:

valexternalCircle=External.Circle(
x =1.0,
y =2.0,
radius =3.0,
color =Some("Red")
)

and turn it into an internal circle

valinternalCircle= externalCircle.transformTo[Internal.Circle]

In this case it's easy to figure out what Fluent does: External.Circle contains a x and a y of type Double so Fluent can create a Point from an External.Circle. The radius can be taken as it is and color needs to be turned into the correct type (Note that if the colour doesn't exist in the expected values it would fail at runtime).

Using user defined functions

Sometimes Fluent cannot figure out how to convert from one case class to the other. In such cases it's possible to define implicit functions that Fluent can use to achieve the conversion.

Let's take another example:

importjava.time.InstantobjectExternal {
caseclassPost(author: String, body: String, timestamp: Long)
}
objectInternal {
caseclassAuthor(name: String)
caseclassPost(author: Author, body: String, tags: List[String], timestamp: Instant)
}

Let's create an External.Post instance:

valexternalPost=External.Post(
author ="Misty",
body ="#Fluent is a cool library to implement your #DDD #translationLayer seamlessly",
timestamp =1491823712002L
)

In this case it's not possible to transform the External.Post into an Internal.Post because Fluent can't figure out how to extract the tags from the post and how to convert the timestamp of type Long into a timestamp of type Instant.

We can define 2 implicit functions to perform these transformations:

implicitdeftagsExtractor(post: External.Post):List[String] =
post.body.split("\\s").toList.filter(_.startsWith("#"))
implicitdeftoInstant(timestamp: Long):Instant=Instant.ofEpochMilli(timestamp)

With these 2 functions in scope we can now transform the External.Post into an Internal.Post

valinternalPost= externalPost.transformTo[Internal.Post]

More information

More implementation details can be found on this blog post: http://www.beyondthelines.net/programing/fluent-a-deep-dive-into-shapeless-and-implicit-resolution/

About

The seamless translation layer

Resources

Stars

25 stars

Watchers

4 watching

Forks

Releases

Packages

Contributors

Languages