Skip to content

gabpmcp/minimal-api

Repository files navigation

minimal-api

La solución es una aplicación ASP.NET Core que utiliza una caché de dos niveles para almacenar datos de productos. La caché se puede actualizar automáticamente cada 5 minutos y también manualmente a través de un comando específico. La arquitectura se basa en el uso de un solo endpoint para manejar diferentes tipos de solicitudes HTTP y comandos.

La clase TwoLevelCache implementa una caché de dos niveles utilizando un diccionario concurrente para el caché local y Redis para el caché distribuido. Las funciones de obtención y almacenamiento de datos están desacopladas utilizando funciones de alto orden.

ConcurrentDictionary<TKey, TValue> es una estructura de datos diseñada para permitir el acceso concurrente seguro desde múltiples hilos, manejando internamente la sincronización de datos. Se utiliza para el almacenamiento en caché en memoria, asegurando que las operaciones de lectura y escritura sean seguras en entornos multihilo.

Patrones de Diseño Utilizados

Currificación:

Utilizamos currificación para la función BuildCommand para permitir una invocación secuencial de parámetros en diferentes momentos.

Composición de Funciones:

Se utilizan funciones de alto orden para componer comportamientos específicos de serialización, deserialización y obtención de datos. Esto permite que la lógica de la caché sea flexible y extensible.

Inyección de Dependencias con Funciones de Alto Orden (High-Order Functions):

En lugar de usar constructores o propiedades para la inyección de dependencias, se utilizan funciones de alto orden. Esto mejora la flexibilidad y facilita las pruebas.

Factory Method:

La función PreBuild se utiliza para crear comandos a partir de datos deserializados. Está currificada para permitir la invocación secuencial de parámetros.

Command Pattern:

Se utiliza un único endpoint para despachar diferentes comandos según el método HTTP y otros parámetros de la solicitud. Cada comando encapsula una operación que se debe realizar.

Memoization:

La función BuildCommand está memoizada para optimizar el rendimiento al evitar cálculos repetitivos.

Singleton:

ConcurrentDictionary en TwoLevelCache actúa como una caché local singleton, manteniendo una única instancia de caché en memoria.

Strategy Pattern:

Los validadores (Validator) son implementados como funciones delegadas, lo que permite definir diferentes estrategias de validación para diferentes campos y comandos. Este patrón facilita la adición de nuevos tipos de validadores sin modificar el código existente.

Builder Pattern:

La clase ValidationSchema sigue el patrón Builder, permitiendo la construcción de un esquema de validación mediante la adición de validadores de manera fluida (fluent interface). Este patrón facilita la creación y configuración de objetos complejos paso a paso.

Composite Pattern:

La clase ValidationResult y su método Combine implementan una forma de patrón Composite, donde múltiples resultados de validación se pueden combinar en un solo resultado, acumulando los mensajes de error. Esto permite que las validaciones sean compuestas de manera jerárquica.

Factory Method Pattern:

Los métodos estáticos en Validations como Required, OfType, MinLength y GreaterThan actúan como métodos de fábrica para crear diferentes tipos de validadores. Esto permite crear instancias de validadores sin conocer los detalles específicos de su implementación.

Delegate Pattern:

Utilización de delegados (Validator) para definir la firma de las funciones de validación. Esto permite pasar funciones como parámetros y almacenar colecciones de funciones, facilitando la modularidad y flexibilidad del código.

Proxy:

TwoLevelCache actúa como un proxy para la caché distribuida, controlando el acceso a los datos almacenados en Redis y proporcionando un intermediario que maneja la lógica de caché.

Decorator:

La lógica de actualización de caché en TwoLevelCache puede considerarse una forma de decorator, añadiendo funcionalidad adicional (caché local) a una funcionalidad existente (caché distribuida).

Template Method:

TwoLevelCache implementa métodos con lógica fija (como GetAsync y SetAsync) que utilizan funciones inyectadas para personalizar partes específicas del algoritmo (como deserialize, serialize, factory, etc.).

Principios Aplicados

Single Responsibility Principle (SRP):

Cada clase y función tiene una única responsabilidad, lo que mejora la mantenibilidad y la claridad del código.

Open/Closed Principle (OCP):

El sistema está diseñado para ser extensible sin modificar el código existente, permitiendo agregar nuevos comandos y tipos de caché sin cambios significativos.

Dependency Injection (DI):

Las dependencias se inyectan utilizando funciones de alto orden, lo que desacopla las clases y mejora la testabilidad. Las dependencias como las funciones de serialización y deserialización, y los métodos para obtener y establecer valores en la caché distribuida, se inyectan en TwoLevelCache como parámetros de función. Esto desacopla la implementación de la caché de las dependencias específicas, facilitando la prueba y la modificación.

Separation of Concerns (SoC):

La lógica de caché, la deserialización, la serialización y la creación de comandos están claramente separadas, facilitando la comprensión y el mantenimiento del código.

Highlight Patterns:

FCIS:

El principio FCIS (Functional Core, Imperative Shell) se basa en la separación de la lógica pura (funcional) del código imperativo (efectos secundarios, interacciones con el entorno). En esta solución, aplicamos FCIS y el uso de intérpretes para desacoplar aún más las responsabilidades, mejorando la mantenibilidad y testabilidad del sistema.

Functional Core (Núcleo Funcional)

El núcleo funcional contiene toda la lógica de negocio, escrita de manera pura y sin efectos secundarios. Este núcleo es fácil de probar y razonar porque no depende del estado externo ni produce efectos secundarios.

Imperative Shell (Capa Imperativa)

La capa imperativa se encarga de los efectos secundarios y las interacciones con el entorno, como la I/O, llamadas a bases de datos, etc. Esta capa delega la lógica al núcleo funcional y maneja los resultados.

Aplicación Práctica en la Solución

La función GetAsync en TwoLevelCache aplica el principio FCIS al desacoplar la lógica de la caché de dos niveles en componentes funcionales y partes imperativas. La lógica central de decisión se implementa en la función pura Decide.GetAsync, mientras que la cáscara imperativa en GetAsync maneja las interacciones con la caché y los efectos secundarios.

La función Decide.GetAsync encapsula la lógica de decisión sobre dónde obtener el valor de la caché (local o distribuida) y qué hacer si no se encuentra. Esta función es pura y no tiene efectos secundarios, lo que facilita las pruebas sobre la lógica. Actúa como un intérprete para la lógica de caché. En lugar de realizar las acciones directamente, devuelve una decisión y un valor, permitiendo que la cáscara imperativa (GetAsync) interprete esa decisión y realice las acciones correspondientes.

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages