All Projects → Sofka-XT → ddd-generic-java

Sofka-XT / ddd-generic-java

Licence: other
Domain-Driven Design - Subdominio Generico en JAVA

Programming Languages

java
68154 projects - #9 most used programming language

Projects that are alternatives of or similar to ddd-generic-java

Event Sourcing Jambo
An Hexagonal Architecture with DDD + Aggregates + Event Sourcing using .NET Core, Kafka e MongoDB (Blog Engine)
Stars: ✭ 159 (+329.73%)
Mutual labels:  ddd-architecture, cqrs-es
Jivejdon
Jivejdon is a Domain Driven Design appication with CQRS/ES/Clean/Hexagonal architecture
Stars: ✭ 287 (+675.68%)
Mutual labels:  ddd-architecture, cqrs-es
Dermayon
Dermayon is Library for supporting build large application,distributed application, scalable, microservices, cqrs, event sourcing, including generic ef repository pattern with unit of work, generic mongo repository pattern with unit of work, kafka, etc
Stars: ✭ 66 (+78.38%)
Mutual labels:  ddd-architecture, cqrs-es
Pos
Sample Application DDD, Reactive Microservices, CQRS Event Sourcing Powered by DERMAYON LIBRARY
Stars: ✭ 207 (+459.46%)
Mutual labels:  ddd-architecture, cqrs-es
fee-office
A DDD, CQRS, ES demo application
Stars: ✭ 35 (-5.41%)
Mutual labels:  cqrs-es
Mpx
Mpx,一款具有优秀开发体验和深度性能优化的增强型跨端小程序框架
Stars: ✭ 2,913 (+7772.97%)
Mutual labels:  reactive-programming
React Easy State
Simple React state management. Made with ❤️ and ES6 Proxies.
Stars: ✭ 2,459 (+6545.95%)
Mutual labels:  reactive-programming
Vlingo Actors
The VLINGO/PLATFORM type-safe Actor Model toolkit for reactive concurrency and resiliency using Java and other JVM languages.
Stars: ✭ 196 (+429.73%)
Mutual labels:  reactive-programming
hodux
🚀Simple reactive React Hooks state management.
Stars: ✭ 29 (-21.62%)
Mutual labels:  reactive-programming
kendo-vue
Issue tracker - Kendo UI for Vue http://www.telerik.com/kendo-vue-ui/
Stars: ✭ 49 (+32.43%)
Mutual labels:  reactive-programming
flutter-form-with-validation-BLOC
This form and validation functions are created by using the BLOC pattern with RxDart instead of using StatefulWidget
Stars: ✭ 63 (+70.27%)
Mutual labels:  reactive-programming
Reactivelists
React-like API for UITableView & UICollectionView
Stars: ✭ 250 (+575.68%)
Mutual labels:  reactive-programming
dddpy
Python DDD Example and Techniques
Stars: ✭ 369 (+897.3%)
Mutual labels:  ddd-architecture
Camelotia
Cross-platform .NET sample GUI app for cloud file management. Built with ReactiveUI, AvaloniaUI, Universal Windows Platform, Xamarin Forms, and WPF, runs on Windows, Linux, Mac and Android.
Stars: ✭ 221 (+497.3%)
Mutual labels:  reactive-programming
RxjavaSamples
This repo is a container for some samples using RXJAVA2 samples
Stars: ✭ 12 (-67.57%)
Mutual labels:  reactive-programming
Slick
A Reactive MVP Framework which is Slick to use
Stars: ✭ 201 (+443.24%)
Mutual labels:  reactive-programming
ms-fastapi-template
This project was built as a result of a deepening of the studies discussed on the blog farlley.com with a greater focus on Domain Driven Design (DDD) architecture. In this work you will find a simple template for creating microservices, as well as a use case (which will still be implemented according to the Roadmap found in this same document) a…
Stars: ✭ 31 (-16.22%)
Mutual labels:  ddd-architecture
nodejs-hexagonal-architecture-and-unit-test
This is a project to explain hexagonal architecture and unit tests in node.js
Stars: ✭ 99 (+167.57%)
Mutual labels:  ddd-architecture
dddplus-archetype-demo
♨️ Using dddplus-archetype build a WMS in 5 minutes. 5分钟搭建一个仓储中台WMS!
Stars: ✭ 56 (+51.35%)
Mutual labels:  ddd-architecture
awesome-software-architecture
A curated list of awesome articles, videos, and other resources to learn and practice software architecture, patterns, and principles.
Stars: ✭ 1,594 (+4208.11%)
Mutual labels:  ddd-architecture

Codacy Badge Build Status

Sofka Domain-Driven Design

Sofka introduce una librería a la comunidad open source para diseñar aplicaciones orientadas al dominio. Esta librería proporciona abstracciones que permiten adoptar el concepto de forma correcta, el estilo que se propone es totalmente discutible para ser mejorado, se espera que al momento de aplicar esta librería se tenga claro los conceptos tácticos de DDD.

¿Qué es DDD?

DDD (Domain-Driven Desing) es un método de diseño para descubrir el negocio de dominio de forma clara, apoyado de patrones de diseño y estilos de arquitectura centrados en el dominio.

¿Porqué DDD?

DDD es necesario cuando hablamos de modelamiento del negocio para grandes organizaciones, con el objetivo de diseñar software al rededor del dominio y no en solucionar un problema en particular. Ahora bien DDD no se aplica bien para el caso de un CRUD, dado que no estaría orientado al dominio organizacional, sino a resolver un problema en particular.

¿Qué resuelve la librería?

Desde el punto de vista táctico, se requiere aplicar algunos conceptos fundamentales, para poder aplicar DDD. Todo esos conceptos se tiene en la librería para interfaces o abstracciones, y además de proporcional algunos patrones de diseño que se adaptan a estilos de arquitecturas deferentes.

Patrones

  • Commands y Events
  • Use Case (Request y Response)
  • Handlers
  • Publisher y Subscriber
  • Repository
  • Aggregate
  • Event Sourcing

Adoptar las arquitecturas

  • Por eventos (EDA)
  • Por commands, events y queries (CQRS)
  • Por capas

Motivation

A domain-oriented designer, clean architecture, and clear business domain specs are used.

The CQRS pattern will be used with Event Sourcing + EDA. It is segregated into two Queries and Commands applications. Commands are executed with a single instruction or entrypoint. Los Queries also has two unique entrypoints (one for lists and one for the unique model). The databases are managed as collections.

Executor Command

domain model

Queries Handle

domain model

Domain model

domain model

Instalación

Generic dependency for ddd Java - https://mvnrepository.com/artifact/co.com.sofka/domain-driven-design

    <dependency>
       <groupId>co.com.sofka</groupId>
       <artifactId>domain-driven-design</artifactId>
        <version>1.0.0</version>
       <type>pom</type>
     </dependency>

Si se require dividir los conceptos se puede usar de forma independeiente de la siguiente manera:

    <dependency>
       <groupId>co.com.sofka</groupId>
       <artifactId>domain</artifactId>
        <version>1.5.0</version>
     </dependency>
    <dependency>
       <groupId>co.com.sofka</groupId>
       <artifactId>business</artifactId>
        <version>1.5.0</version>
     </dependency>
    <dependency>
       <groupId>co.com.sofka</groupId>
       <artifactId>infrastructure</artifactId>
        <version>1.5.0</version>
     </dependency>
    <dependency>
       <groupId>co.com.sofka</groupId>
       <artifactId>application</artifactId>
        <version>1.5.0</version>
     </dependency>

Conceptos e implementación

Entidades

Una entidad tiene comportamientos, pero no lanza eventos como son los agregados, si tenemos una entidad suelta sin relación con el agregado entonces solo se aplica para cambiar los estados de la misma. Toda entidad depende de una ID, tal cual como el Agregado Root.

public class Student extends Entity<StudentIdentity> {

    protected Name name;
    protected Gender gender;
    protected DateOfBirth dateOfBirth;
    protected Score score;

    protected Student(StudentIdentity studentIdentity, Name name, Gender gender, DateOfBirth dateOfBirth) {
        super(studentIdentity);
        this.name = name;
        this.gender =gender;
        this.dateOfBirth = dateOfBirth;
        this.score = new Score(0);
    }

    private Student(StudentIdentity studentIdentity){
        super(studentIdentity);
    }

    public static Student form(StudentIdentity studentIdentity, Name name, Gender gender, DateOfBirth dateOfBirth){
        var student = new Student(studentIdentity);
        student.name = name;
        student.gender = gender;
        student.dateOfBirth = dateOfBirth;
        return student;
    }

    public String name() {
        return name.value();
    }

    public String gender() {
        return gender.value();
    }

    public String dateOfBirth() {
        return dateOfBirth.value();
    }

    public Score.Values score() {
        return score.value();
    }

    public void updateScore(Score score){
        this.score = score;
    }

    public void updateName(Name name){
        this.name = name;
    }

    public void updateDateOfBirth(DateOfBirth dateOfBirth){
        this.dateOfBirth = dateOfBirth;
    }

    public void updateGender(Gender gender){
        this.gender = gender;
    }

    @Override
    public boolean equals(Object o) {
       return super.equals(o);
    }

    @Override
    public int hashCode() {
        return super.hashCode();
    }
}

Mas adelante estaríamos realizando un tutorial para aplicarlo en una arquitectura distribuida y con CQRS+ES con una arquitectura EDA.

Agregado orientado a Eventos

public class Team extends AggregateEvent<TeamIdentity> {
    protected Name name;
    protected Set<Student> students;
    public Team(TeamIdentity identity, Name name) {
        this(identity);
        appendChange(new CreatedTeam(name)).apply();
    }

    private Team(TeamIdentity identity) {
        super(identity);
        subscribe(new TeamBehavior(this));
    }

    public static Team from(TeamIdentity aggregateId, List<DomainEvent> list) {
        Team team = new Team(aggregateId);
        list.forEach(team::applyEvent);
        return team;
    }


    public void addNewStudent(Name name, Gender gender, DateOfBirth dateOfBirth) {
        StudentIdentity studentIdentity = new StudentIdentity();
        appendChange(new AddedStudent(studentIdentity, name, gender, dateOfBirth)).apply();
    }

    public void removeStudent(StudentIdentity studentIdentity) {
        appendChange(new RemovedStudent(studentIdentity)).apply();
    }

    public void updateName(Name newName) {
        appendChange(new UpdatedName(newName)).apply();
    }

    public void updateStudentName(StudentIdentity studentIdentity, Name name) {
        appendChange(new UpdatedStudent(studentIdentity, name)).apply();
    }

    public void applyScoreToStudent(StudentIdentity studentIdentity, Score score) {
        appendChange(new UpdateScoreOfStudent(studentIdentity, score)).apply();
    }

    public Set<Student> students() {
        return students;
    }

    public String name() {
        return name.value();
    }
}

Comportamientos orientado a Eventos

 public class TeamBehavior extends EventChange {
        protected TeamBehavior(Team entity) {
            apply((CreatedTeam event) -> {
                entity.students = new HashSet<>();
                entity.name = event.getName();
            });

            apply((AddedStudent event) -> {
                var student = new Student(
                        event.getStudentIdentity(),
                        event.getName(),
                        event.getGender(),
                        event.getDateOfBirth()
                );
                entity.students.add(student);
            });

            apply((RemovedStudent event) -> entity.students
                    .removeIf(e -> e.identity().equals(event.getIdentity())));

            apply((UpdatedName event) -> entity.name = event.getNewName());

            apply((UpdatedStudent event) -> {
                var studentUpdate = getStudentByIdentity(entity, event.getStudentIdentity());
                studentUpdate.updateName(event.getName());
            });

            apply((UpdateScoreOfStudent event) -> {
                var studentUpdate = getStudentByIdentity(entity, event.getStudentIdentity());
                studentUpdate.updateScore(event.getScore());
            });
        }

        private Student getStudentByIdentity(Team entity, Identity identity) {
            return entity.students.stream()
                    .filter(e -> e.identity().equals(identity))
                    .findFirst()
                    .orElseThrow();
        }
   }

Objetos de valor

Un objeto de valor es un objeto inmutable que representa un valor de la entidad. A diferencia de la entidad es que el VO (Value Object) no tiene un identidad que la represente.

public class DateOfBirth  implements ValueObject<String> {
    private final LocalDate date;
    private final String format;

    public DateOfBirth(int day, int month, int year) {
        try {
            date = LocalDate.of(year, month, day);
            if(date.isAfter(LocalDate.now())){
                throw new IllegalArgumentException("No valid the date of birth");
            }
        } catch (DateTimeException e){
            throw new IllegalArgumentException(e.getMessage());
        }
        format = generateFormat();
    }

    private String generateFormat(){
        return date.format(DateTimeFormatter.ofPattern("dd-MM-yyyy"));
    }

    @Override
    public String value() {
        return format;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        DateOfBirth that = (DateOfBirth) o;
        return Objects.equals(format, that.format);
    }

    @Override
    public int hashCode() {
        return Objects.hash(format);
    }
}

Evento de Dominio

Un evento de dominio esta relacionado con un Agregado Id (que es un VO), este evento es la consecuencia de un comando que ejecuta un comportamiento de un Agregado un Entidad.

public class AddedStudent extends DomainEvent  {

    private final StudentIdentity studentIdentity;
    private final Name name;
    private final Gender gender;
    private final DateOfBirth dateOfBirth;

    public AddedStudent(StudentIdentity studentIdentity, Name name, Gender gender, DateOfBirth dateOfBirth) {
        super("training.team.addedstudent");
        this.studentIdentity = studentIdentity;
        this.name = name;
        this.gender = gender;
        this.dateOfBirth = dateOfBirth;
    }

    public Name getName() {
        return name;
    }

    public Gender getGender() {
        return gender;
    }

    public DateOfBirth getDateOfBirth() {
        return dateOfBirth;
    }

    public StudentIdentity getStudentIdentity() {
        return studentIdentity;
    }

}

Comandos

public class CreateTeam extends Command {
    private final Name name;

    public CreateTeam(Name name) {
        this.name = name;
    }

    public Name getName() {
        return name;
    }

}

Aplicar el agregado

Cuando se crear nuevo objeto se instancia el agregado y se le asigna el identificado que relaciona la entidad. Además de los argumentos de creación. Un agregado puede tener múltiples constructores que permiten crear el agregado.

@CommandHandles
@CommandType(name = "training.team.create",  aggregate = "team")
public class CreateTeamHandle extends UseCaseExecutor<CreateTeam> {
    private static Logger logger = Logger.getLogger(CreateTeamHandle.class.getName());

    private RequestCommand<CreateTeam> request;

    @Override
    public void accept(CreateTeam command) {
        logger.info(" ----- Executor CreateTeamHandle ------");
        request = new RequestCommand<>(command);
    }

    @Override
    public void run() {
        runUseCase(new UseCase<UseCase.RequestValues, ResponseEvents>() {
            @Override
            public void executeUseCase(RequestValues objectInput) {
                var id = new TeamIdentity();
                var command = request.getCommand();
                var team = new Team(id, command.getName());
                emit().onSuccess(new ResponseEvents(team.getUncommittedChanges()));
            }
        }, request);
    }
}

Ya para el caso de Actualizar un agregado se reconstruye el agregado según los eventos persistidos, si se tiene un agregado no orientado a eventos se reconstruye con los valores necesarios. Cuando se reconstruya se aplica el comportamiento de la entidad.

@BusinessLogin
public class CreateStudentUseCase extends UseCase<RequestCommand<AddNewStudent>, ResponseEvents> {
    private final DomainEventRepository repository;
    
    public CreateStudentUseCase(DomainEventRepository repository) {
        this.repository = repository;
    }
    @Override
    protected void executeUseCase(RequestCommand<AddNewStudent> request) {
        Team team = reclaimTeam();

        var students = Optional.ofNullable(team.students())
                .orElseThrow(() -> new NecessaryDependency("the students is need for this use case"));

        if(students.size() > 5){
            emit().onError(new NoMoreStudentAllowed());
        } else {
            emit().onResponse(aNewStudentAddedFor(team));
        }
    }

    private Team reclaimTeam() {
        var aggregateId = request().getCommand().aggregateRootId();
        var events = repository.getEventsBy(aggregateId);
        return Team.from(TeamIdentity.of(aggregateId), events);
    }

    private ResponseEvents aNewStudentAddedFor(Team team) {
        var command = request().getCommand();
        team.addNewStudent(
                command.getName(),
                command.getGender(),
                command.getDateOfBirth()
        );
       return new ResponseEvents(team.getUncommittedChanges());
    }
}

Al final de ejecutar el comportamiento se determina si existe cambios dentro del agregado para emitir los eventos a una capa superior. Después se marca los cambios como confirmados.

Se puede aplicar aquí casos de uso, comandos y eventos para aplicar el agregado.

Queries

@QueryHandles
public class StudentsByTeam extends ViewModelExecutor<ViewModel> {
    @Override
    public ViewModel apply(Map<String, String> params) {
        var query = new ByStudentIdentity();
        query.setAggregateRootId(params.get("teamId"));

        return getDataMapped("teams", StudentViewModel.class)
                .applyAsElement(query);
    }
}

Contribución

  1. Realizar el fork
  2. Crea tu rama de características: git checkout -b feature/my-feat
  3. Confirma tus cambios: git commit -am "Agrega alguna característica"
  4. Empuje a la rama: git push origin feature/my-feat
  5. Presentar una Pull Requests

También pueden colaborar creando issue para dar evolución del proyecto.

License

Sofka Domain-Drive Desing is Open Source software released under the Apache 2.0 license.

Note that the project description data, including the texts, logos, images, and/or trademarks, for each open source project belongs to its rightful owner. If you wish to add or remove any projects, please contact us at [email protected].