Skip to content

DomingoAlvarez99/ddd-example

Repository files navigation

The repository is under develop

Hexagonal Architecture and DDD in Java

Example of a Java application using the Ports and Adapters Architecture (Hexagonal Architecture) with Domain Driven Design (DDD) to keep the code as simple as possible.

0. Table of contents

1. Libraries and examples of implementation

Feature Library Example of implementation
Build tool Maven Dependencies, configuration and build
Style formatting EditorConf Rules
Extract metadata at runtime Reflections DomainEventSuscribersInfo
HTTP server Spring Boot Starter Web Article POST controller
Database integration Spring Data JPA + Hibernate + Postgresql driver Article repository
Domain events publishing & consuming Spring Kafka Publisher integration, Publisher integration
Document storer MinIO TO DO
Infrastructure management Docker Docker compose
Logging Logback + Logstash encoder Logback configuration, Logger implementation
Code report Jacoco + Sonar Scanner Instructions
Unit tests Spring Boot Starter Test (Mainly JUnit 5 and Mockito) Unit test case
Integration tests Spring Boot Starter Test (Mainly JUnit 5 and Spring Test) Integration test case
Acceptance tests Spring Boot Starter Test (Mainly JUnit 4 + Spring Test) + Cucumber Health check feature, Health check test case
Code generation Open Api generator Instructions
Api documentation Swagger Open Api 3 Article POST controller

2. Use cases and examples of implementation

Use cases and patterns Example of implementation
Adapter pattern & infrastructure Service Logger implementation
Repository pattern Repository implementation
Specification pattern Criteria implementation
Domain Service CategoryFinder
Value Object Identifier Value Object
Rich Domain models (Tell don't ask, Avoid anemic domain models) Article model
Some clean code patterns (Guard clauses, Named constructors, Self encapsulation) Identifier
Application Service ArticleEraser
Composition over inheritance ArticleCreator
Dependency container (unique instantiation point) ArticleDependencyContainer
SRP of SOLID ArticlePostController
OCP of SOLID ArticleCreator
ISP of SOLID ArticleRepository
DIP of SOLID ArticleByCriteriaFinder (Interface, implementation and instantiation point)

3. Environment setup

Install the needed tools

  1. Clone this repository: > git clone https://github.com/DomingoAlvarez99/ddd-example.git
  2. Download and install: Docker Java Maven

Prepare the application environment

  1. Copy the Docker environment variables config file and tune it with your desired values: > cp .env.dist .env
  2. Start Docker and bring up the database container docker-compose up -d postgres
  3. Configure the users and databases of the backend and Sonarqube containers.
  • Common script to generate a database, an user and a schema:
      CREATE ROLE ${username} LOGIN PASSWORD '${password}';
      CREATE DATABASE ${db};
      GRANT CREATE ON DATABASE ${db} TO ${username};
      CREATE SCHEMA ${schema};
      ALTER ROLE ${username} IN DATABASE ${db} SET search_path TO ${schema};
  • Backend
    • Create the user, the database and the schema:
      • Access to the root db replacing the variables: > docker exec -it postgres -U ${root_username} ${root_db}
      • Run the common script replacing the variables.
    • Create the database tables:
      • Find the tables: > find . -path '*/migration/*' -type f
      • Access to the database: > docker exec -it postgres -U ${username} ${db}
      • Copy and paste the definition of the tables.
  • SonarQube
    • Create the user, the database and the schema:
      • Access to the root db replacing the variables: > docker exec -it postgres -U ${root_username} ${root_db}
        • Run the above script replacing the variables.
  1. Bring up the other containers: > make infrastructure
  2. Create the topics to publish and consume domain events: > bash ./kafka_scripts/create-topics.sh domain_events,dead_letter-domain_events
  3. Add the index pattern logstash* in the kibana config.

Run the tests

  • Unit: (The name must follow the following pattern *TestCase):
  • Integration (The name must follow the following pattern *ItTestCase)
  • Acceptance: Must have a .feature file linked with a .java file

Before all install the dependencies: > make deps

  • Execute the unit tests: > make unit-test
  • Execute all the tests: > make test

Start the app

Backend: > make start

4. Entrypoint

Endpoints

Swagger ui

Cli

TO DO

5. Logs

The logging mechanism uses Logback and logstash-logback-encoder in order to:

  • Output the log records through the standard output channel (STDOUT, your terminal).
  • Append the log records in JSON format into Logstash.

After that we can:

  • Send the log records to an Elasticsearch index.
  • And finally visualize them centrally in Kibana.

6. Code coverage

Jacoco is a Java library that generates reports like code coverage.

SonarQube inspects and evaluates everything that affects our codebase, from minor styling details to critical design errors finding code duplications, bugs, and other issues in the code. It also defines a quality gate, which is a set of measure-based boolean conditions.

SonarQube and JaCoCo are two tools that can be used together:

  • Generate the metrics: > make test
  • Send metrics to SonarQube:
      mvn sonar:sonar \
        -Dsonar.projectKey=${key} \
        -Dsonar.host.url=${host} \
        -Dsonar.login=${token}
    
  • Do all:
      mvn verify sonar:sonar \
        -Dsonar.projectKey=${key} \
        -Dsonar.host.url=${host} \
        -Dsonar.login=${token}
    

7. Code generation

Open Api code generation allows generating a REST API client from a specification (controller definition):

  1. Download the spec: > wget -P /generated/swagger-api http://localhost:8080/api-docs -O api-docs.json
  2. Generate the client:
  > mvn clean install -P code-gen
  > cd /target/generated-sources-swagger-api
  > mvn clean install

After that you can import the client:

<dependency>
  <groupId>org.dalvarez.shop</groupId>
  <artifactId>${project.artifactId}-api-client</artifactId>
  <version>${project.version}</version>
</dependency>

8. Deploy

The project uses Maven in order to package the app in a single Jar file that you can execute.

To do this > make deploy.

Releases

No releases published

Packages

No packages published

Languages