Este artículo se tradujo automáticamente con la API de Google Cloud Translation.
Algunas páginas pueden leerse mejor que el original.
Command Query Responsibility Segregation (CQRS) es un patrón arquitectónico que separa la responsabilidad de manejar comandos (solicitudes que cambian el estado del sistema) de la responsabilidad de manejar consultas (solicitudes que devuelven información del sistema).
Esta separación de preocupaciones puede ofrecer varios beneficios, como un mejor rendimiento, escalabilidad y mantenibilidad.
En una arquitectura CQRS, los comandos generalmente los maneja un servicio separado del que maneja las consultas. Esta separación se puede implementar de diferentes maneras, pero un enfoque común es usar diferentes tablas de base de datos para almacenar datos a los que se accede mediante comandos y datos a los que se accede mediante consultas.
Spring Boot es un marco Java popular para crear aplicaciones web. Ofrece una forma conveniente de crear aplicaciones basadas en Spring independientes y de grado de producción que se pueden "simplemente ejecutar".
En este artículo, veremos cómo implementar una arquitectura CQRS en una aplicación Spring Boot. Comenzaremos observando los diferentes componentes que están involucrados en dicha aplicación. Luego, implementaremos una aplicación de ejemplo simple que usa CQRS.
Una aplicación CQRS normalmente tiene los siguientes componentes:
Ahora que hemos visto los diferentes componentes de una aplicación CQRS, implementemos una aplicación de ejemplo simple que usa CQRS.
Nuestra aplicación de ejemplo será un administrador de tareas. Los usuarios podrán crear tareas y asignárselas a sí mismos oa otros usuarios. También podrán marcar las tareas como completadas.
Comenzaremos implementando el servicio de comando. Este servicio será el encargado de validar y ejecutar comandos.
El servicio de comando tendrá los siguientes métodos:
Implementaremos estos métodos en una clase llamada TaskCommandService. Esta clase se anotará con @Service, que es una anotación de Spring que marca una clase como un componente de servicio.
@Service
public class TaskCommandService {
public void createTask(Task task) {
// validate the task
// save the task
}
public void updateTask(Task task) {
// validate the task
// save the task
}
public void markTaskAsComplete(String taskId) {
// validate the task
// mark the task as complete
// save the task
}
}
Como puede ver, los métodos createTask y updateTask aceptan un objeto Task como parámetro. Este objeto se utilizará para almacenar los datos de la tarea que se está creando o actualizando.
El método markTaskAsComplete acepta una ID de tarea como parámetro. Este ID de tarea se usará para buscar la tarea que se marcará como completa.
Cada uno de estos métodos comienza con una llamada a un método validar. Este método de validación será responsable de validar los datos que se pasan. Implementaremos este método en la siguiente sección.
El método validar será responsable de validar los datos que se pasan a los métodos del servicio de comando. Implementaremos este método en una clase llamada TaskCommandValidator. Esta clase se anotará con @Component, que es una anotación de Spring que marca una clase como componente.
@Component
public class TaskCommandValidator {
public void validate(Task task) {
// validate the task
}
public void validate(String taskId) {
// validate the task ID
}
}
Como puede ver, esta clase tiene dos métodos de validación. Uno de estos métodos acepta un objeto Tarea como parámetro. Este método se utilizará para validar los datos para crear y actualizar tareas.
El otro método de validación acepta un ID de tarea como parámetro. Este método se usará para validar la identificación de la tarea para marcar tareas como completas.
En una aplicación real, estos métodos de validación contendrían lógica para validar los datos. A los efectos de este ejemplo, los dejaremos vacíos.
El servicio de consulta tendrá los siguientes métodos:
Implementaremos estos métodos en una clase llamada TaskQueryService. Esta clase se anotará con @Service.
@Service
public class TaskQueryService {
public List<Task> getAllTasks() {
// execute query
// return results
}
public Task getTaskById(String taskId) {
// execute query
// return results
}
}
Como puede ver, el método getAllTasks devuelve una lista de objetos de Tarea. Esta lista contendrá los datos de todas las tareas del sistema.
El método getTaskById devuelve un único objeto Tarea. Este objeto contendrá los datos de la tarea con el ID especificado.
El repositorio es una capa de acceso a datos que proporciona una interfaz para acceder al almacén de datos. En nuestra aplicación de ejemplo, usaremos un repositorio para acceder a los datos de las tareas.
Implementaremos el repositorio en una clase llamada TaskRepository. Esta clase se anotará con @Repository, que es una anotación de Spring que marca una clase como un componente del repositorio.
@Repository
public class TaskRepository {
public void save(Task task) {
// save the task
}
public Task findById(String id) {
// find the task
// return the task
}
public List<Task> findAll() {
// find all tasks
// return the tasks
}
}
Como puede ver, este repositorio tiene métodos para guardar, buscar y eliminar tareas.
El modelo es el modelo de dominio para la aplicación. En nuestra aplicación de ejemplo, la tarea será el único objeto modelo.
Implementaremos el modelo de tarea en una clase llamada Tarea. Esta clase se anotará con @Entity, que es una anotación JPA que marca una clase como entidad.
@Entity
public class Task {
@Id
private String id;
private String name;
private String description;
private boolean complete;
// getters and setters
}
Como puede ver, este modelo de tarea tiene cuatro campos: id, nombre, descripción y completo. El campo id se anota con @Id, que es una anotación JPA que marca un campo como la clave principal de una entidad.
Ahora que hemos implementado los diferentes componentes de nuestra aplicación CQRS, juntemos todo y veamos cómo funciona.
Comenzaremos creando una tarea. Para hacer esto, primero crearemos un objeto Tarea y lo completaremos con los datos de la tarea. Luego, pasaremos este objeto al método createTask del TaskCommandService.
Task task = new Task();
task.setName("Write example");
task.setDescription("Write an example of the CQRS pattern");
taskCommandService.createTask(task);
Esto creará una nueva tarea en el sistema.
Ahora, digamos que queremos obtener una lista de todas las tareas. Para hacer esto, llamaremos al método getAllTasks del TaskQueryService.
List<Task> tasks = taskQueryService.getAllTasks();
Esto devolverá una lista de todas las tareas en el sistema.
Finalmente, digamos que queremos marcar una tarea como completa. Para hacer esto, primero obtendremos la tarea por ID. Luego, llamaremos al método markTaskAsComplete del TaskCommandService.
Task task = taskQueryService.getTaskById("1");
taskCommandService.markTaskAsComplete(task.getId());
Esto marcará la tarea con ID "1" como completa.
En este artículo, analizamos el patrón Command Query Responsibility Segregation (CQRS) y cómo se puede implementar en una aplicación Spring Boot.
También hemos visto cómo este patrón puede ofrecer varios beneficios, como un mejor rendimiento, escalabilidad y facilidad de mantenimiento.
Si está interesado en obtener más información sobre CQRS, le recomiendo los siguientes recursos: