Skip to content

Commit

Permalink
feat(tutorial): enhance the tutorial by adding a section on scenario
Browse files Browse the repository at this point in the history
  • Loading branch information
tmorin committed Feb 18, 2024
1 parent bf97ca9 commit a9a04d3
Show file tree
Hide file tree
Showing 9 changed files with 189 additions and 23 deletions.
10 changes: 5 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,10 @@
[![Continuous Integration - Build](https://github.com/tmorin/faggregate/actions/workflows/ci-build.yaml/badge.svg)](https://github.com/tmorin/faggregate/actions/workflows/ci-build.yaml)
[![Quality Gate Status](https://sonarcloud.io/api/project_badges/measure?project=tmorin_faggregate&metric=alert_status)](https://sonarcloud.io/summary/new_code?id=tmorin_faggregate)

> Unlock the Power of DDD Aggregates and Functional Programming with `faggregate`!
> This Java Library simplifies the implementation of complex business systems by offering a set of tools and abstractions that make it easy to build robust and scalable software.
> Whether you're a seasoned developer or just getting started, our library provides a powerful solution for leveraging the full potential of Domain Driven Design Aggregates and functional programming concepts.
> Don't miss out on this opportunity to streamline your development process and build high-quality software - try our library today!
> Enhance DDD and Functional Programming with `faggregate`.
> It offers Java developers tools and abstractions to streamline building scalable, robust software.
> Ideal for any developer level, it maximizes Domain Driven Design Aggregates and functional programming.
> Elevate your software quality by integrating `faggregate` into your workflow.
The Value Stream is barely simple:

Expand All @@ -29,7 +29,7 @@ The [todo-infra-quarkus](examples/todo-infra-quarkus) example demonstrates the u

The library is designed to be integrated directly into a [Native Image](https://www.graalvm.org/latest/reference-manual/native-image/basics/).

The [todo-infra-quarkus](examples/todo-infra-quarkus) example provides an E2E exemple leveraging on [Quarkus](https://quarkus.io).
The [todo-infra-quarkus](examples/todo-infra-quarkus) example provides an E2E example leveraging on [Quarkus](https://quarkus.io).

### Functional

Expand Down
2 changes: 1 addition & 1 deletion examples/tutorial/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,4 @@

> Elevate your DDD implementation with this [Tutorial](https://tmorin.github.io/faggregate) on a Java library that blends Aggregates & functional programming. Gain hands-on expertise now!
The tutorial is publish on [tmorin.github.io/faggregate](https://tmorin.github.io/faggregate).
The tutorial is published on [tmorin.github.io/faggregate](https://tmorin.github.io/faggregate).
7 changes: 6 additions & 1 deletion examples/tutorial/pom.example.xml
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,12 @@
<dependency>
<artifactId>faggregate-core-simple</artifactId>
<groupId>io.morin.faggregate</groupId>
<version>1.4.0-SNAPSHOT</version>
<version>1.5.0-SNAPSHOT</version>
</dependency>
<dependency>
<artifactId>faggregate-core-scenario</artifactId>
<groupId>io.morin.faggregate</groupId>
<version>1.5.0-SNAPSHOT</version>
</dependency>
<!-- TEST -->
<dependency>
Expand Down
5 changes: 5 additions & 0 deletions examples/tutorial/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,11 @@
<groupId>io.morin.faggregate</groupId>
<version>1.5.0-SNAPSHOT</version>
</dependency>
<dependency>
<artifactId>faggregate-core-scenario</artifactId>
<groupId>io.morin.faggregate</groupId>
<version>1.5.0-SNAPSHOT</version>
</dependency>
<!-- TEST -->
<dependency>
<groupId>org.junit.jupiter</groupId>
Expand Down
68 changes: 54 additions & 14 deletions examples/tutorial/src/asciidoc/index.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -10,19 +10,25 @@
[abstract]
== Abstract

Unlock the full potential of Domain Driven Design implementation with this step-by-step tutorial focusing on `faggregate` that blends Aggregates and functional programming.
This library provides developers with a powerful tool to simplify complex development tasks, and this tutorial will give you the hands-on experience and insights you need to effectively utilize its capabilities.
Whether you're a seasoned Java developer or just starting out, this tutorial is the perfect resource for anyone looking to take their DDD implementation to the next level.
[Abstract]

This document presents a comprehensive guide aimed at facilitating the implementation of Domain Driven Design (DDD) by integrating the `faggregate` library, which harmoniously combines the concepts of Aggregates with functional programming paradigms.
The library is designed to offer developers an efficient means to navigate and simplify intricate development challenges.
Through practical exercises and detailed explanations, this tutorial aims to equip readers with the necessary skills and knowledge to adeptly apply the library's functionalities.

== Introduction

`faggregate` is a Java library helping to define Aggregate according to the _Domain Driven Design_ approach with a touch of _Functional Programming_. The source code of `faggregate` is available on link:https://github.com/tmorin/faggregate[github.com/tmorin/faggregate].

By combining the strengths of Domain Driven Design Aggregates and functional programming, developers can achieve a powerful and streamlined development process.
Domain Driven Design Aggregates provide a clear structure for managing complex business entities and enforcing transactional consistency, while functional programming promotes a declarative style of programming, making code easier to understand and maintain.
Together, these approaches lead to more predictable and reliable code, with a reduced likelihood of bugs and easier maintenance.
Additionally, the functional programming paradigm supports code modularity and easy refactoring, making it a great fit for large-scale software development projects.
Put simply, developers can build maintainable and scalable systems that effectively meet the demands of their business domain.
`faggregate` synthesizes the robust methodologies of DDD Aggregates and functional programming to streamline the software development process.

DDD Aggregates offer a structured approach to managing complex domain entities and ensuring transactional consistency.
In parallel, functional programming emphasizes a declarative coding style, enhancing code clarity and simplifying maintenance efforts.
The amalgamation of these methodologies not only fosters more stable and reliable software but also minimizes the incidence of defects.

Furthermore, the emphasis on functional programming augments code modularity and facilitates straightforward refactoring, attributes highly beneficial in the context of extensive software development endeavors.

In essence, `faggregate` empowers developers to create systems that are both scalable and maintainable, adeptly addressing the needs of their specific business domains.

== The scope

Expand All @@ -49,15 +55,17 @@ We will then delve into defining the Counter aggregate, a core component of our
Following this, we'll tackle implementing the command handler for the IncrementCounter command, allowing us to interact with our aggregate.
We'll also implement the mutator for the CounterIncremented domain event to handle state changes.
The creation of the repository for the Counter aggregate will be our next step, ensuring we have a solid persistence mechanism.
Finally, we'll conclude with implementing the configurer of the Counter aggregate, tying all components together for a cohesive application configuration.
We'll continue with implementing the configurer of the Counter aggregate, tying all components together for a cohesive application configuration.
Finally, we'll explore the validation of the Counter aggregate, ensuring that our implementation meets the requirements of our business domain.

The source code of the tutorial is available on link:https://github.com/tmorin/faggregate/tree/main/examples/tutorial[github.com/tmorin/faggregate].

== The Maven module

The Maven module brings four dependencies.
The first one, `faggregate-core-simple`, brings the `faggregate` library.
The second one, link:https://junit.org/junit5/docs/current/user-guide/[`junit-jupiter`], provides a test framework.
The second one, `faggregate-core-scenario`, brings an extension of `faggregate` library to implement acceptance tests.
The third one, link:https://junit.org/junit5/docs/current/user-guide/[`junit-jupiter`], provides a test framework.
Finally, link:https://projectlombok.org/[`lombok`], _spices_ up java helping to save lines of codes.

[source,xml,title=./pom.xml]
Expand Down Expand Up @@ -307,11 +315,43 @@ The Configurer is covered by the following unit test.
include::../../src/test/java/faggregate/tutorial/CounterConfigurerTest.java[]
----

== The validation

The building blocks offered by `faggregate` facilitate the separation of the API, core, and side effects layers.
This architecture allows the core to define acceptance scenarios with commands, events, and states, essential for validating the implementations of side effects.
Consequently, side effects are testable from the core's perspective, which is crucial for ensuring that business rules are correctly implemented and accepted.
This design principle underpins the framework's approach to robust, domain-driven application development.

In this tutorial, we explore two key scenarios using `faggregate`: the creation and the incrementation of a counter, both of which are organized within the same suite. In the context of `faggregate`, a suite refers to a collection of acceptance scenarios.

A scenario follows the _Given-When-Then_ pattern, which is a widely used format for writing acceptance tests. It consists of three parts:

- *Given*: the initial state of the system
- *When*: the action that triggers the change in the system
- *Then*: the expected outcome of the action

The acceptance suite of the Counter aggregate is provided by the following factory.

[source,java,title=src/main/java/faggregate/tutorial/CounterSuiteFactory.java]
----
include::../../src/main/java/faggregate/tutorial/CounterSuiteFactory.java[]
----

The execution of the acceptance suite is handled by a usual JUnit test.

[source,java,title=src/main/java/faggregate/tutorial/CounterSuiteFactory.java]
----
include::../../src/test/java/faggregate/tutorial/CounterSuiteTest.java[]
----

== Conclusion

In conclusion, the tutorial provides an overview of the Java library that helps developers implement Domain Driven Design Aggregates and functional programming concepts.
The library offers a set of tools and abstractions that make it easier to build complex software systems in a maintainable and scalable way.
In conclusion, this tutorial offers a comprehensive exploration of the `faggregate` Java library, a potent resource for developers aiming to integrate Domain Driven Design Aggregates with functional programming principles.
Through the meticulous construction of the Counter aggregate example, it showcases how `faggregate` simplifies the development of complex, domain-centric software systems, promoting maintainability and scalability.

By following the guidelines and best practices outlined in the tutorial, developers can leverage the full potential of this library to build high-quality software that effectively meets the demands of their business domain.
The step-by-step guidance provided throughout the tutorial, from setting up a Maven project to implementing domain-specific logic and persistence mechanisms, equips developers with the tools and knowledge needed to fully harness the capabilities of `faggregate`.
This approach not only facilitates the building of high-quality software that aligns with business requirements but also enhances the overall development experience by leveraging functional programming's strengths in clarity, modularity, and immutability.

Overall, the tutorial serves as a valuable resource for those looking to gain a deeper understanding of DDD Aggregates and functional programming, and for those looking to build robust and scalable software systems.
As a valuable educational resource, the tutorial underscores the significance of adopting DDD Aggregates and functional programming in modern software development.
It empowers developers to create software systems that are not only robust and scalable but also aligned with the strategic goals of their business domains.
Thus, for those seeking to deepen their understanding of DDD and functional programming or to elevate the quality of their software projects, this tutorial proves to be an indispensable guide.
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
*/
@Value
@RequiredArgsConstructor(access = AccessLevel.PRIVATE)
class Counter {
public class Counter {

/**
* The default value.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,16 +4,27 @@
import io.morin.faggregate.api.Configurer;
import io.morin.faggregate.api.Loader;
import io.morin.faggregate.api.Persister;
import lombok.NonNull;
import lombok.RequiredArgsConstructor;

/**
* The configurer binds the handlers, mutator as well as side effects.
*/
@RequiredArgsConstructor
class CounterConfigurer implements Configurer<String, Counter> {
public class CounterConfigurer implements Configurer<String, Counter> {

private final CounterRepository repository;

/**
* Create a new instance of the configurer.
*
* @param repository the repository to use
* @return the configurer
*/
public static CounterConfigurer create(@NonNull CounterRepository repository) {
return new CounterConfigurer(repository);
}

@Override
public void configure(AggregateManagerBuilder<String, Counter> builder) {
// set the loader
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
package faggregate.tutorial;

import io.morin.faggregate.core.validation.Scenario;
import io.morin.faggregate.core.validation.Suite;
import lombok.experimental.UtilityClass;
import lombok.val;

/**
* The {@link CounterSuiteFactory} class is a factory class that creates a suite of scenarios to validate the
* behavior of the {@link Counter} Aggregate.
*/
@UtilityClass
public class CounterSuiteFactory {

/**
* Creates a suite of scenarios to validate the behavior of the {@link Counter} Aggregate.
*
* @return the suite of scenarios
*/
public Suite create() {
// Define a scenario validating the creation of a counter
val scenarioAId = "counter#a";
val scenarioA = Scenario
.builder()
.name("Counter Creation")
// no state initialization is required for the Counter Creation scenario
.given(Scenario.Given.builder().identifier(scenarioAId).build())
// trigger the increment of the counter
.when(Scenario.When.builder().command(new IncrementCounter(scenarioAId)).build())
.then(
Scenario.Then
.builder()
// validate the state of the aggregate has been incremented
.state(Counter.create(scenarioAId).updateValue(1))
// validate the right event has been published
.event(new CounterChanged(scenarioAId, 0, 1))
.build()
)
.build();

// Define a scenario validating the increment of a counter
val scenarioBId = "counter#b";
val scenarioB = Scenario
.builder()
.name("Counter Creation")
// initialize the state of the aggregate with a value of 1 for the Counter Increment scenario
.given(Scenario.Given.builder().identifier(scenarioBId).command(new IncrementCounter(scenarioBId)).build())
// trigger the increment of the counter
.when(Scenario.When.builder().command(new IncrementCounter(scenarioBId)).build())
.then(
Scenario.Then
.builder()
// validate the state of the aggregate has been incremented
.state(Counter.create(scenarioBId).updateValue(2))
// validate the right event has been published
.event(new CounterChanged(scenarioBId, 1, 2))
.build()
)
.build();

// Create and return a suite containing the two scenarios
return Suite.builder().scenario(scenarioA).scenario(scenarioB).build();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
package faggregate.tutorial;

import io.morin.faggregate.simple.core.SimpleAggregateManagerBuilder;
import java.util.concurrent.CompletableFuture;
import lombok.val;
import org.junit.jupiter.api.Test;

/**
* This JUnit test validates the side effect implementation executing the CounterSuite.
*/
class CounterSuiteTest {

@Test
void shouldValidateSideEffects() {
// create the repository
val counterRepository = CounterRepository.create();

// create the builder for the aggregate manager
val counterManagerBuilder = SimpleAggregateManagerBuilder.<String, Counter>get();

// create the configurer and configure the aggregate manager
// i.e. register the handlers, mutators and side effects
CounterConfigurer.create(counterRepository).configure(counterManagerBuilder);

// build the aggregate manager
val counterManager = counterManagerBuilder.build();

// execute the suite providing the aggregate manager
CounterSuiteFactory
.create()
.execute(
// the aggregate manager to test
counterManager,
// an optional lambda to store the initialize state of the aggregate before the _Given_ phase
// this functionality is not required for the CounterSuite, so the implementation is null
null,
// an optional lambda to load the state of the aggregate before the _Then_ phase
identifier -> CompletableFuture.completedFuture(counterRepository.statesByIdentifier.get(identifier))
);
}
}

0 comments on commit a9a04d3

Please sign in to comment.