SkillAgentSearch skills...

Ddd Generic Java

Domain-Driven Design - Subdominio Generico en JAVA

Install / Use

npx skills add Sofka-XT/ddd-generic-java

Installs into whichever agent you are using.

About this skill

Quality Score

0/100

Category

Design

Supported Platforms

Universal

README

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 || g

Related Skills

View on GitHub
GitHub Stars40
CategoryDesign
Updated3mo ago
Forks15

Languages

Java

Security Score

77/100

Audited on Apr 20, 2026

No findings