Release Notes
3.6.0
Artifacts are available on Maven Central
- https://search.maven.org/artifact/com.fraktalio.fmodel/domain/3.6.0/jar
- https://search.maven.org/artifact/com.fraktalio.fmodel/application-vanilla/3.6.0/jar
- https://search.maven.org/artifact/com.fraktalio.fmodel/application-arrow/3.6.0/jar
What's changed
In this release, we have introduced a new component on the application layer EphemeralView
:
A view that is built "on the fly" and not maintained/materialized. Potential use cases include:
- Lightweight aggregation for ad-hoc analysis
- Development and prototyping read models
- Building strongly consistent read models
- Supporting the "read your own rights" guarantee
The main algorithm is as follows:
suspend fun <S, E, Q, EV> EV.handle(query: Q): S where EV : ViewStateComputation<S, E>, EV : EphemeralViewRepository<E, Q> =
query.fetchEvents().fold(initialState) { s, e -> evolve(s, e) }
Events of type E
are fetched based on a query Q
, which are then used to build the respective view IView<S, E>
. The result of that computation S
is returned to the caller.
Thank you @DomenicDev for your contribution! You show that we can extend fmodel
to better fit our specific requirements, by composing domain
components in a different way. EphemeralView
is a common use case, so we include it in the library. Looking forward to what is next? :)
Also, Kotlin and Arrow are updated to v2
, respectively!
Full Changelog: https://github.com/fraktalio/fmodel/compare/v3.5.1...v3.6.0
Include the dependencies
- Gradle (Kotlin)
- Gradle (Groovy)
- Maven
dependencies {
implementation("com.fraktalio.fmodel:domain:3.6.0")
implementation("com.fraktalio.fmodel:application-vanilla:3.6.0")
implementation("com.fraktalio.fmodel:application-arrow:3.6.0")
}
dependencies {
implementation 'com.fraktalio.fmodel:domain:3.6.0'
implementation 'com.fraktalio.fmodel:application-vanilla:3.6.0'
implementation 'com.fraktalio.fmodel:application-arrow:3.6.0'
}
<dependency>
<groupId>com.fraktalio.fmodel</groupId>
<artifactId>domain</artifactId>
<version>3.6.0</version>
</dependency>
<dependency>
<groupId>com.fraktalio.fmodel</groupId>
<artifactId>application-vanilla</artifactId>
<version>3.6.0</version>
</dependency>
<dependency>
<groupId>com.fraktalio.fmodel</groupId>
<artifactId>application-arrow</artifactId>
<version>3.6.0</version>
</dependency>
3.5.1
Artifacts are available on Maven Central
- https://search.maven.org/artifact/com.fraktalio.fmodel/domain/3.5.1/jar
- https://search.maven.org/artifact/com.fraktalio.fmodel/application-vanilla/3.5.1/jar
- https://search.maven.org/artifact/com.fraktalio.fmodel/application-arrow/3.5.1/jar
What's changed
In this patch
release, we have fixed the bug on the Event Sourced aggregate within the application
module - https://github.com/fraktalio/fmodel/pull/291.
It is reproducible only in the orchestrating scenarios where you communicate two deciders back and forth, a couple of times.
Full Changelog: https://github.com/fraktalio/fmodel/compare/v3.5.0...v3.5.1
Include the dependencies
- Gradle (Kotlin)
- Gradle (Groovy)
- Maven
dependencies {
implementation("com.fraktalio.fmodel:domain:3.5.1")
implementation("com.fraktalio.fmodel:application-vanilla:3.5.1")
implementation("com.fraktalio.fmodel:application-arrow:3.5.1")
}
dependencies {
implementation 'com.fraktalio.fmodel:domain:3.5.1'
implementation 'com.fraktalio.fmodel:application-vanilla:3.5.1'
implementation 'com.fraktalio.fmodel:application-arrow:3.5.1'
}
<dependency>
<groupId>com.fraktalio.fmodel</groupId>
<artifactId>domain</artifactId>
<version>3.5.1</version>
</dependency>
<dependency>
<groupId>com.fraktalio.fmodel</groupId>
<artifactId>application-vanilla</artifactId>
<version>3.5.1</version>
</dependency>
<dependency>
<groupId>com.fraktalio.fmodel</groupId>
<artifactId>application-arrow</artifactId>
<version>3.5.1</version>
</dependency>
3.5.0
Artifacts are available on Maven Central
- https://search.maven.org/artifact/com.fraktalio.fmodel/domain/3.5.0/jar
- https://search.maven.org/artifact/com.fraktalio.fmodel/application-vanilla/3.5.0/jar
- https://search.maven.org/artifact/com.fraktalio.fmodel/application-arrow/3.5.0/jar
What's changed
In this release, we have upgraded the Kotlin Arrow library to 1.2.0. It is a breaking change for the application-arrow
module/extension.
We have introduced and configured a binary compatibility validator into our build process.
The tool allows dumping binary API of a JVM part of a Kotlin library that is public in the sense of Kotlin visibilities and ensures that the public binary API wasn't changed in a way that makes this change binary incompatible.
We extended the case of using actor
functions to parallelize the message handling processes. (available on JVM target only)
/**
* Extension function - Handles the flow of command messages of type [C] by concurrently distributing the load across finite number of actors/handlers
*
* @param commands [Flow] of Command messages of type [C]
* @param numberOfActors total number of actors/workers available for distributing the load. Minimum one.
* @param actorsCapacity capacity of the actors channel's buffer
* @param actorsStart actors coroutine start option
* @param actorsContext additional to [CoroutineScope.coroutineContext] context of the actor coroutines.
* @param partitionKey a function that calculates the partition key/routing key of command - commands with the same partition key will be handled with the same 'actor' to keep the ordering
* @return [Flow] of stored Events of type [E]
*
*/
fun <C, S, E> EventSourcingAggregate<C, S, E>.handleConcurrently(
commands: Flow<C>,
numberOfActors: Int = 100,
actorsCapacity: Int = Channel.BUFFERED,
actorsStart: CoroutineStart = CoroutineStart.LAZY,
actorsContext: CoroutineContext = EmptyCoroutineContext,
partitionKey: (C) -> Int
): Flow<E>
Deprecating factory functions in favor of constructor-like functions.
@Deprecated(
message = "Use EventSourcingLockingAggregate constructor-like function instead",
replaceWith = ReplaceWith("EventSourcingLockingAggregate(decider, eventRepository)")
)
fun <C, S, E, V> eventSourcingLockingAggregate(
decider: IDecider<C, S, E>,
eventRepository: EventLockingRepository<C, E, V>
): EventSourcingLockingAggregate<C, S, E, V> =
object : EventSourcingLockingAggregate<C, S, E, V>,
EventLockingRepository<C, E, V> by eventRepository,
IDecider<C, S, E> by decider {}
Full Changelog: https://github.com/fraktalio/fmodel/compare/v3.4.0...v3.5.0
Include the dependencies
- Gradle (Kotlin)
- Gradle (Groovy)
- Maven
dependencies {
implementation("com.fraktalio.fmodel:domain:3.5.0")
implementation("com.fraktalio.fmodel:application-vanilla:3.5.0")
implementation("com.fraktalio.fmodel:application-arrow:3.5.0")
}
dependencies {
implementation 'com.fraktalio.fmodel:domain:3.5.0'
implementation 'com.fraktalio.fmodel:application-vanilla:3.5.0'
implementation 'com.fraktalio.fmodel:application-arrow:3.5.0'
}
<dependency>
<groupId>com.fraktalio.fmodel</groupId>
<artifactId>domain</artifactId>
<version>3.5.0</version>
</dependency>
<dependency>
<groupId>com.fraktalio.fmodel</groupId>
<artifactId>application-vanilla</artifactId>
<version>3.5.0</version>
</dependency>
<dependency>
<groupId>com.fraktalio.fmodel</groupId>
<artifactId>application-arrow</artifactId>
<version>3.5.0</version>
</dependency>
3.4.0
Artifacts are available on Maven Central
- https://search.maven.org/artifact/com.fraktalio.fmodel/domain/3.4.0/jar
- https://search.maven.org/artifact/com.fraktalio.fmodel/application-vanilla/3.4.0/jar
- https://search.maven.org/artifact/com.fraktalio.fmodel/application-arrow/3.4.0/jar
What's changed
New native targets are available: linuxX64(), mingwX64(), macosX64(), macosArm64(), tvos(), tvosSimulatorArm64(), watchosArm32(), watchosArm64(), watchosX86(), watchosX64(), watchosSimulatorArm64(), iosX64(), iosArm64(), iosArm32(), iosSimulatorArm64()
Full Changelog: https://github.com/fraktalio/fmodel/compare/v3.3.0...v3.4.0
Include the dependencies
- Gradle (Kotlin)
- Gradle (Groovy)
- Maven
dependencies {
implementation("com.fraktalio.fmodel:domain:3.4.0")
implementation("com.fraktalio.fmodel:application-vanilla:3.4.0")
implementation("com.fraktalio.fmodel:application-arrow:3.4.0")
}
dependencies {
implementation 'com.fraktalio.fmodel:domain:3.4.0'
implementation 'com.fraktalio.fmodel:application-vanilla:3.4.0'
implementation 'com.fraktalio.fmodel:application-arrow:3.4.0'
}
<dependency>
<groupId>com.fraktalio.fmodel</groupId>
<artifactId>domain</artifactId>
<version>3.4.0</version>
</dependency>
<dependency>
<groupId>com.fraktalio.fmodel</groupId>
<artifactId>application-vanilla</artifactId>
<version>3.4.0</version>
</dependency>
<dependency>
<groupId>com.fraktalio.fmodel</groupId>
<artifactId>application-arrow</artifactId>
<version>3.4.0</version>
</dependency>
3.3.0
Artifacts are available on Maven Central
- https://search.maven.org/artifact/com.fraktalio.fmodel/domain/3.3.0/jar
- https://search.maven.org/artifact/com.fraktalio.fmodel/application-vanilla/3.3.0/jar
- https://search.maven.org/artifact/com.fraktalio.fmodel/application-arrow/3.3.0/jar
What's changed
A convenient DSL (builder) for the domain components
fun evenNumberDecider(): Decider<EvenNumberCommand?, EvenNumberState, EvenNumberEvent?> =
decider {
initialState {
evenNumberState {
descriptionString { "Initial state" }
valueInt { 0 }
}
}
decide { c, s ->
when (c) {
is AddEvenNumber -> flowOf(
evenNumberAdded {
description { c.description }
value { s.value + c.value }
}
)
is SubtractEvenNumber -> flowOf(
evenNumberSubtracted {
description { c.description }
value { s.value - c.value }
}
)
null -> emptyFlow()
}
}
evolve { s, e ->
when (e) {
is EvenNumberAdded ->
evenNumberState {
description { s.description + e.description }
value { e.value }
}
is EvenNumberSubtracted ->
evenNumberState {
description { s.description - e.description }
value { e.value }
}
null -> s
}
}
}
Minimizing the API
_Decider<C, Si, So, Ei, Eo>
is internal now_View<Si, So, E>
is internal now
There was no true usage of this API, so we have decided to make it internal, in favor of Decider<C, S, E>
and View<S, E>
.
Previously, Decider
was just a type alias of _Decider
, but these are different types actually, and we want to
promote that.
We hope to minimize the complexity of the API, and make the right thing to do the easy thing to do.
Full Changelog: https://github.com/fraktalio/fmodel/compare/v3.2.0...v3.3.0
Include the dependencies
- Gradle (Kotlin)
- Gradle (Groovy)
- Maven
dependencies {
implementation("com.fraktalio.fmodel:domain:3.3.0")
implementation("com.fraktalio.fmodel:application-vanilla:3.3.0")
implementation("com.fraktalio.fmodel:application-arrow:3.3.0")
}
dependencies {
implementation 'com.fraktalio.fmodel:domain:3.3.0'
implementation 'com.fraktalio.fmodel:application-vanilla:3.3.0'
implementation 'com.fraktalio.fmodel:application-arrow:3.3.0'
}
<dependency>
<groupId>com.fraktalio.fmodel</groupId>
<artifactId>domain</artifactId>
<version>3.3.0</version>
</dependency>
<dependency>
<groupId>com.fraktalio.fmodel</groupId>
<artifactId>application-vanilla</artifactId>
<version>3.3.0</version>
</dependency>
<dependency>
<groupId>com.fraktalio.fmodel</groupId>
<artifactId>application-arrow</artifactId>
<version>3.3.0</version>
</dependency>
3.2.0
Artifacts are available on Maven Central
- https://search.maven.org/artifact/com.fraktalio.fmodel/domain/3.2.0/jar
- https://search.maven.org/artifact/com.fraktalio.fmodel/application-vanilla/3.2.0/jar
- https://search.maven.org/artifact/com.fraktalio.fmodel/application-arrow/3.2.0/jar
What's changed
Optimistic Locking
Optimistic locking, also referred to as optimistic concurrency control, allows multiple concurrent users to attempt to update the same resource.
There are two common ways to implement optimistic locking: version number and timestamp. The version number is generally considered to be a better option because the server clock can be inaccurate over time, but we do not want to restrict it to only one option, so we have the generic parameter V acting as a Version.
The optimistic locking mechanism is not leaking into the core Domain layer.
Application modules provide more interfaces and extensions, giving you additional options to compose your unique Domain components with Optimistic Locking formally in place, without changing the Domain components whatsoever.
example (state-stored aggregate / traditional):
stateStoredLockingAggregate(
decider = myDecider,
stateRepository = myLockingRepository
).handleOptimistically(myCommand)
where myDecider
is of type IDecider<C, S, E>
, myLockingRepository
is of type StateLockingRepository<C, S, V>
and myCommand
is of type C
example (event-sourced aggregate / event-driven):
eventSourcingLockingAggregate(
decider = myDecider,
stateRepository = myLockingRepository
).handleOptimistically(myCommand)
where myDecider
is of type IDecider<C, S, E>
, myLockingRepository
is of type EventLockingRepository<C, E, V>
and myCommand
is of type C
Full Changelog: https://github.com/fraktalio/fmodel/compare/v3.1.0...v3.2.0
Include the dependencies
- Gradle (Kotlin)
- Gradle (Groovy)
- Maven
dependencies {
implementation("com.fraktalio.fmodel:domain:3.2.0")
implementation("com.fraktalio.fmodel:application-vanilla:3.2.0")
implementation("com.fraktalio.fmodel:application-arrow:3.2.0")
}
dependencies {
implementation 'com.fraktalio.fmodel:domain:3.2.0'
implementation 'com.fraktalio.fmodel:application-vanilla:3.2.0'
implementation 'com.fraktalio.fmodel:application-arrow:3.2.0'
}
<dependency>
<groupId>com.fraktalio.fmodel</groupId>
<artifactId>domain</artifactId>
<version>3.2.0</version>
</dependency>
<dependency>
<groupId>com.fraktalio.fmodel</groupId>
<artifactId>application-vanilla</artifactId>
<version>3.2.0</version>
</dependency>
<dependency>
<groupId>com.fraktalio.fmodel</groupId>
<artifactId>application-arrow</artifactId>
<version>3.2.0</version>
</dependency>
3.1.0
Artifacts are available on Maven Central
- https://search.maven.org/artifact/com.fraktalio.fmodel/domain/3.1.0/jar
- https://search.maven.org/artifact/com.fraktalio.fmodel/application-vanilla/3.1.0/jar
- https://search.maven.org/artifact/com.fraktalio.fmodel/application-arrow/3.1.0/jar
What's changed
Experimental Actors (JVM only)
- Kotlin Actors (experimental) - concurrently handling messages by
idugalic
in https://github.com/fraktalio/fmodel/pull/70
@ExperimentalContracts
@FlowPreview
fun <C, S, E> EventSourcingAggregate<C, S, E>.handleConcurrently(
commands: Flow<C>,
numberOfActors: Int = 100,
actorsCapacity: Int = Channel.BUFFERED,
actorsStart: CoroutineStart = CoroutineStart.LAZY,
actorsContext: CoroutineContext = EmptyCoroutineContext,
partitionKey: (C) -> Int
): Flow<E> = channelFlow {
val actors: List<SendChannel<C>> = (1..numberOfActors).map {
commandActor(channel, actorsCapacity, actorsStart, actorsContext) { handle(it) }
}
commands
.onCompletion {
actors.forEach {
it.close()
}
}
.collect {
val partition = partitionKey(it).absoluteValue % numberOfActors.coerceAtLeast(1)
actors[partition].send(it)
}
}
Full Changelog: https://github.com/fraktalio/fmodel/compare/v3.0.0...v3.1.0
Include the dependencies
- Gradle (Kotlin)
- Gradle (Groovy)
- Maven
dependencies {
implementation("com.fraktalio.fmodel:domain:3.1.0")
implementation("com.fraktalio.fmodel:application-vanilla:3.1.0")
implementation("com.fraktalio.fmodel:application-arrow:3.1.0")
}
dependencies {
implementation 'com.fraktalio.fmodel:domain:3.1.0'
implementation 'com.fraktalio.fmodel:application-vanilla:3.1.0'
implementation 'com.fraktalio.fmodel:application-arrow:3.1.0'
}
<dependency>
<groupId>com.fraktalio.fmodel</groupId>
<artifactId>domain</artifactId>
<version>3.1.0</version>
</dependency>
<dependency>
<groupId>com.fraktalio.fmodel</groupId>
<artifactId>application-vanilla</artifactId>
<version>3.1.0</version>
</dependency>
<dependency>
<groupId>com.fraktalio.fmodel</groupId>
<artifactId>application-arrow</artifactId>
<version>3.1.0</version>
</dependency>
3.0.0
Artifacts are available on Maven Central
- https://search.maven.org/artifact/com.fraktalio.fmodel/domain/3.0.0/jar
- https://search.maven.org/artifact/com.fraktalio.fmodel/application-vanilla/3.0.0/jar
- https://search.maven.org/artifact/com.fraktalio.fmodel/application-arrow/3.0.0/jar
What's changed
- A multiplatform support (jvm, js, native) included
- Switched from Spek to Kotest test framework
- Switched from Maven to Gradle
Tests example
class DeciderTest : FunSpec({
val evenDecider = evenNumberDecider()
val oddDecider = oddNumberDecider()
test("Event-sourced Decider - add even number") {
with(evenDecider) {
givenEvents(emptyList()) {
whenCommand(AddEvenNumber(Description("2"), NumberValue(2)))
} thenEvents listOf(EvenNumberAdded(Description("2"), NumberValue(2)))
}
}
test("Event-sourced Decider - given previous state, add even number") {
with(evenDecider) {
givenEvents(listOf(EvenNumberAdded(Description("2"), NumberValue(2)))) {
whenCommand(AddEvenNumber(Description("4"), NumberValue(4)))
} thenEvents listOf(EvenNumberAdded(Description("4"), NumberValue(4)))
}
}
})
Full Changelog: https://github.com/fraktalio/fmodel/compare/v3.0.0...v3.1.0
Include the dependencies
- Gradle (Kotlin)
- Gradle (Groovy)
- Maven
dependencies {
implementation("com.fraktalio.fmodel:domain:3.0.0")
implementation("com.fraktalio.fmodel:application-vanilla:3.0.0")
implementation("com.fraktalio.fmodel:application-arrow:3.0.0")
}
dependencies {
implementation 'com.fraktalio.fmodel:domain:3.0.0'
implementation 'com.fraktalio.fmodel:application-vanilla:3.0.0'
implementation 'com.fraktalio.fmodel:application-arrow:3.0.0'
}
<dependency>
<groupId>com.fraktalio.fmodel</groupId>
<artifactId>domain</artifactId>
<version>3.0.0</version>
</dependency>
<dependency>
<groupId>com.fraktalio.fmodel</groupId>
<artifactId>application-vanilla</artifactId>
<version>3.0.0</version>
</dependency>
<dependency>
<groupId>com.fraktalio.fmodel</groupId>
<artifactId>application-arrow</artifactId>
<version>3.0.0</version>
</dependency>