Aprenda c贸mo Event Sourcing puede revolucionar su implementaci贸n de pista de auditor铆a, ofreciendo trazabilidad, integridad de datos y resiliencia del sistema sin precedentes. Explore ejemplos pr谩cticos y estrategias de implementaci贸n.
Event Sourcing: Implementaci贸n de Pistas de Auditor铆a para Sistemas Robustos y Trazables
En el panorama digital actual, complejo e interconectado, mantener una pista de auditor铆a robusta y completa es primordial. No solo es a menudo un requisito regulatorio, sino que tambi茅n es crucial para la depuraci贸n, el an谩lisis de seguridad y la comprensi贸n de la evoluci贸n de su sistema. Event Sourcing, un patr贸n arquitect贸nico que captura todos los cambios en el estado de una aplicaci贸n como una secuencia de eventos, ofrece una soluci贸n elegante y poderosa para implementar pistas de auditor铆a que son confiables, auditables y extensibles.
驴Qu茅 es Event Sourcing?
Las aplicaciones tradicionales suelen almacenar solo el estado actual de los datos en una base de datos. Este enfoque dificulta la reconstrucci贸n de estados anteriores o la comprensi贸n de la serie de eventos que llevaron al estado actual. Event Sourcing, por el contrario, se centra en capturar cada cambio significativo en el estado de la aplicaci贸n como un evento inmutable. Estos eventos se almacenan en un almac茅n de eventos de solo anexi贸n, formando un registro completo y cronol贸gico de todas las acciones dentro del sistema.
Piense en ello como un libro mayor de una cuenta bancaria. En lugar de simplemente registrar el saldo actual, cada dep贸sito, retiro y transferencia se registra como un evento separado. Al reproducir estos eventos, puede reconstruir el estado de la cuenta en cualquier momento.
驴Por qu茅 usar Event Sourcing para pistas de auditor铆a?
Event Sourcing ofrece varias ventajas convincentes para la implementaci贸n de pistas de auditor铆a:
- Historial completo e inmutable: Cada cambio se captura como un evento, proporcionando un registro completo e inmutable de la evoluci贸n del sistema. Esto asegura que la pista de auditor铆a sea precisa y a prueba de manipulaciones.
- Consultas temporales: Puede reconstruir f谩cilmente el estado del sistema en cualquier momento reproduciendo los eventos hasta ese punto. Esto permite capacidades de consulta temporal potentes para la auditor铆a y el an谩lisis.
- Auditable y trazable: Cada evento suele incluir metadatos como la marca de tiempo, el ID de usuario y el ID de transacci贸n, lo que facilita el seguimiento del origen y el impacto de cada cambio.
- Desacoplamiento y escalabilidad: Event Sourcing promueve el desacoplamiento entre diferentes partes del sistema. Los eventos pueden ser consumidos por m煤ltiples suscriptores, lo que permite la escalabilidad y la flexibilidad.
- Reproducibilidad para depuraci贸n y recuperaci贸n: Los eventos se pueden reproducir para recrear estados anteriores con fines de depuraci贸n o para recuperarse de errores.
- Soporte para CQRS: Event Sourcing se utiliza a menudo junto con el patr贸n de Segregaci贸n de Responsabilidad de Consulta de Comando (CQRS), que separa las operaciones de lectura y escritura, mejorando a煤n m谩s el rendimiento y la escalabilidad.
Implementaci贸n de Event Sourcing para pistas de auditor铆a: una gu铆a paso a paso
Aqu铆 hay una gu铆a pr谩ctica para implementar Event Sourcing para pistas de auditor铆a:
1. Identificar eventos clave
El primer paso es identificar los eventos clave que desea capturar en su pista de auditor铆a. Estos eventos deben representar cambios significativos en el estado de la aplicaci贸n. Considere acciones como:
- Autenticaci贸n de usuario (inicio de sesi贸n, cierre de sesi贸n)
- Creaci贸n, modificaci贸n y eliminaci贸n de datos
- Inicio y finalizaci贸n de transacciones
- Cambios de configuraci贸n
- Eventos relacionados con la seguridad (por ejemplo, cambios en el control de acceso)
Ejemplo: Para una plataforma de comercio electr贸nico, los eventos clave podr铆an incluir "PedidoCreado", "PagoRecibido", "PedidoEnviado", "ProductoAgregadoAlCarrito" y "PerfilDeUsuarioActualizado".
2. Definir la estructura del evento
Cada evento debe tener una estructura bien definida que incluya la siguiente informaci贸n:
- Tipo de evento: Un identificador 煤nico para el tipo de evento (por ejemplo, "PedidoCreado").
- Datos del evento: Los datos asociados con el evento, como el ID del pedido, el ID del producto, el ID del cliente y el importe del pago.
- Marca de tiempo: La fecha y hora en que ocurri贸 el evento. Considere usar UTC para la coherencia en diferentes zonas horarias.
- ID de usuario: El ID del usuario que inici贸 el evento.
- ID de transacci贸n: Un identificador 煤nico para la transacci贸n a la que pertenece el evento. Esto es crucial para garantizar la atomicidad y la coherencia en m煤ltiples eventos.
- ID de correlaci贸n: Un identificador utilizado para rastrear eventos relacionados en diferentes servicios o componentes. Esto es particularmente 煤til en arquitecturas de microservicios.
- ID de causalidad: (Opcional) El ID del evento que caus贸 este evento. Esto ayuda a rastrear la cadena causal de eventos.
- Metadatos: Informaci贸n contextual adicional, como la direcci贸n IP del usuario, el tipo de navegador o la ubicaci贸n geogr谩fica. Tenga en cuenta las regulaciones de privacidad de datos como el RGPD al recopilar y almacenar metadatos.
Ejemplo: El evento "PedidoCreado" podr铆a tener la siguiente estructura:
{
"eventType": "PedidoCreado",
"eventData": {
"orderId": "12345",
"customerId": "67890",
"orderDate": "2023-10-27T10:00:00Z",
"totalAmount": 100.00,
"currency": "USD",
"shippingAddress": {
"street": "123 Main St",
"city": "Anytown",
"state": "CA",
"zipCode": "91234",
"country": "USA"
}
},
"timestamp": "2023-10-27T10:00:00Z",
"userId": "user123",
"transactionId": "tx12345",
"correlationId": "corr123",
"metadata": {
"ipAddress": "192.168.1.1",
"browser": "Chrome",
"location": {
"latitude": 34.0522,
"longitude": -118.2437
}
}
}
3. Elija un almac茅n de eventos
El almac茅n de eventos es el repositorio central para almacenar eventos. Debe ser una base de datos de solo anexi贸n que est茅 optimizada para escribir y leer secuencias de eventos. Hay varias opciones disponibles:
- Bases de datos dedicadas al almac茅n de eventos: Estas son bases de datos dise帽adas espec铆ficamente para Event Sourcing, como EventStoreDB y AxonDB. Ofrecen caracter铆sticas como flujos de eventos, proyecciones y suscripciones.
- Bases de datos relacionales: Puede utilizar una base de datos relacional como PostgreSQL o MySQL como almac茅n de eventos. Sin embargo, deber谩 implementar la sem谩ntica de solo anexi贸n y la gesti贸n del flujo de eventos usted mismo. Considere usar una tabla dedicada para eventos con columnas para el ID del evento, el tipo de evento, los datos del evento, la marca de tiempo y los metadatos.
- Bases de datos NoSQL: Las bases de datos NoSQL como MongoDB o Cassandra tambi茅n se pueden usar como almacenes de eventos. Ofrecen flexibilidad y escalabilidad, pero pueden requerir m谩s esfuerzo para implementar las funciones requeridas.
- Soluciones basadas en la nube: Los proveedores de la nube como AWS, Azure y Google Cloud ofrecen servicios de transmisi贸n de eventos gestionados como Kafka, Kinesis y Pub/Sub, que se pueden utilizar como almacenes de eventos. Estos servicios brindan escalabilidad, confiabilidad e integraci贸n con otros servicios en la nube.
Al elegir un almac茅n de eventos, considere factores como:
- Escalabilidad: 驴Puede el almac茅n de eventos manejar el volumen esperado de eventos?
- Durabilidad: 驴Qu茅 tan confiable es el almac茅n de eventos en t茅rminos de prevenci贸n de p茅rdida de datos?
- Capacidades de consulta: 驴El almac茅n de eventos admite los tipos de consultas que necesita para la auditor铆a y el an谩lisis?
- Soporte de transacciones: 驴El almac茅n de eventos admite transacciones ACID para garantizar la consistencia de los datos?
- Integraci贸n: 驴El almac茅n de eventos se integra bien con su infraestructura y herramientas existentes?
- Costo: 驴Cu谩l es el costo de usar el almac茅n de eventos, incluidos el almacenamiento, el c谩lculo y los costos de red?
4. Implementar la publicaci贸n de eventos
Cuando ocurre un evento, su aplicaci贸n necesita publicarlo en el almac茅n de eventos. Esto t铆picamente involucra los siguientes pasos:
- Crear un objeto de evento: Cree un objeto de evento que contenga el tipo de evento, los datos del evento, la marca de tiempo, el ID de usuario y otros metadatos relevantes.
- Serializar el evento: Serialice el objeto del evento a un formato que se pueda almacenar en el almac茅n de eventos, como JSON o Avro.
- Anexar el evento al almac茅n de eventos: Anexe el evento serializado al almac茅n de eventos. Aseg煤rese de que esta operaci贸n sea at贸mica para evitar la corrupci贸n de datos.
- Publicar el evento a los suscriptores: (Opcional) Publique el evento a cualquier suscriptor que est茅 interesado en recibirlo. Esto se puede hacer usando una cola de mensajes o un patr贸n de publicaci贸n-suscripci贸n.
Ejemplo (usando un EventStoreService hipot茅tico):
public class OrderService {
private final EventStoreService eventStoreService;
public OrderService(EventStoreService eventStoreService) {
this.eventStoreService = eventStoreService;
}
public void createOrder(Order order, String userId) {
// ... l贸gica de negocio para crear el pedido ...
OrderCreatedEvent event = new OrderCreatedEvent(
order.getOrderId(),
order.getCustomerId(),
order.getOrderDate(),
order.getTotalAmount(),
order.getCurrency(),
order.getShippingAddress()
);
eventStoreService.appendEvent("order", order.getOrderId(), event, userId);
}
}
public class EventStoreService {
public void appendEvent(String streamName, String entityId, Object event, String userId) {
// Crear un objeto de evento
EventRecord eventRecord = new EventRecord(
UUID.randomUUID(), // eventId
streamName, // streamName
entityId, // entityId
event.getClass().getName(), // eventType
toJson(event), // eventData
Instant.now().toString(), // timestamp
userId // userId
);
// Serializar el evento
String serializedEvent = toJson(eventRecord);
// Anexar el evento al almac茅n de eventos (implementaci贸n espec铆fica del almac茅n de eventos elegido)
storeEventInDatabase(serializedEvent);
// Publicar el evento a los suscriptores (opcional)
publishEventToMessageQueue(serializedEvent);
}
// M茅todos de marcador de posici贸n para la interacci贸n con la base de datos y la cola de mensajes
private void storeEventInDatabase(String serializedEvent) {
// Implementaci贸n para almacenar el evento en la base de datos
System.out.println("Almacenando el evento en la base de datos: " + serializedEvent);
}
private void publishEventToMessageQueue(String serializedEvent) {
// Implementaci贸n para publicar el evento en una cola de mensajes
System.out.println("Publicando el evento en la cola de mensajes: " + serializedEvent);
}
private String toJson(Object obj) {
// Implementaci贸n para serializar el evento a JSON
try {
ObjectMapper mapper = new ObjectMapper();
return mapper.writeValueAsString(obj);
} catch (Exception e) {
throw new RuntimeException("Error al serializar el evento a JSON", e);
}
}
}
class EventRecord {
private final UUID eventId;
private final String streamName;
private final String entityId;
private final String eventType;
private final String eventData;
private final String timestamp;
private final String userId;
public EventRecord(UUID eventId, String streamName, String entityId, String eventType, String eventData, String timestamp, String userId) {
this.eventId = eventId;
this.streamName = streamName;
this.entityId = entityId;
this.eventType = eventType;
this.eventData = eventData;
this.timestamp = timestamp;
this.userId = userId;
}
// Getters
@Override
public String toString() {
return "EventRecord{" +
"eventId=" + eventId +
", streamName='" + streamName + '\'' +
", entityId='" + entityId + '\'' +
", eventType='" + eventType + '\'' +
", eventData='" + eventData + '\'' +
", timestamp='" + timestamp + '\'' +
", userId='" + userId + '\'' +
'}';
}
}
class OrderCreatedEvent {
private final String orderId;
private final String customerId;
private final String orderDate;
private final double totalAmount;
private final String currency;
private final String shippingAddress;
public OrderCreatedEvent(String orderId, String customerId, String orderDate, double totalAmount, String currency, String shippingAddress) {
this.orderId = orderId;
this.customerId = customerId;
this.orderDate = orderDate;
this.totalAmount = totalAmount;
this.currency = currency;
this.shippingAddress = shippingAddress;
}
// Getters para todos los campos
public String getOrderId() { return orderId; }
public String getCustomerId() { return customerId; }
public String getOrderDate() { return orderDate; }
public double getTotalAmount() { return totalAmount; }
public String getCurrency() { return currency; }
public String getShippingAddress() { return shippingAddress; }
@Override
public String toString() {
return "OrderCreatedEvent{" +
"orderId='" + orderId + '\'' +
", customerId='" + customerId + '\'' +
", orderDate='" + orderDate + '\'' +
", totalAmount=" + totalAmount +
", currency='" + currency + '\'' +
", shippingAddress='" + shippingAddress + '\'' +
'}';
}
}
class Order {
private final String orderId;
private final String customerId;
private final String orderDate;
private final double totalAmount;
private final String currency;
private final String shippingAddress;
public Order(String orderId, String customerId, String orderDate, double totalAmount, String currency, String shippingAddress) {
this.orderId = orderId;
this.customerId = customerId;
this.orderDate = orderDate;
this.totalAmount = totalAmount;
this.currency = currency;
this.shippingAddress = shippingAddress;
}
// Getters para todos los campos
public String getOrderId() { return orderId; }
public String getCustomerId() { return customerId; }
public String getOrderDate() { return orderDate; }
public double getTotalAmount() { return totalAmount; }
public String getCurrency() { return currency; }
public String getShippingAddress() { return shippingAddress; }
@Override
public String toString() {
return "Order{" +
"orderId='" + orderId + '\'' +
", customerId='" + customerId + '\'' +
", orderDate='" + orderDate + '\'' +
", totalAmount=" + totalAmount +
", currency='" + currency + '\'' +
", shippingAddress='" + shippingAddress + '\'' +
'}';
}
}
5. Construir modelos de lectura (proyecciones)
Si bien el almac茅n de eventos proporciona un historial completo de todos los cambios, a menudo no es eficiente consultarlo directamente para operaciones de lectura. En cambio, puede construir modelos de lectura, tambi茅n conocidos como proyecciones, que est谩n optimizados para patrones de consulta espec铆ficos. Estos modelos de lectura se derivan del flujo de eventos y se actualizan de forma as铆ncrona a medida que se publican nuevos eventos.
Ejemplo: Podr铆a crear un modelo de lectura que contenga una lista de todos los pedidos de un cliente espec铆fico, o un modelo de lectura que resuma los datos de ventas de un producto en particular.
Para construir un modelo de lectura, se suscribe al flujo de eventos y procesa cada evento. Para cada evento, actualiza el modelo de lectura en consecuencia.
Ejemplo:
public class OrderSummaryReadModelUpdater {
private final OrderSummaryRepository orderSummaryRepository;
public OrderSummaryReadModelUpdater(OrderSummaryRepository orderSummaryRepository) {
this.orderSummaryRepository = orderSummaryRepository;
}
public void handle(OrderCreatedEvent event) {
OrderSummary orderSummary = new OrderSummary(
event.getOrderId(),
event.getCustomerId(),
event.getOrderDate(),
event.getTotalAmount(),
event.getCurrency()
);
orderSummaryRepository.save(orderSummary);
}
// Otros controladores de eventos para PaymentReceivedEvent, OrderShippedEvent, etc.
}
interface OrderSummaryRepository {
void save(OrderSummary orderSummary);
}
class OrderSummary {
private final String orderId;
private final String customerId;
private final String orderDate;
private final double totalAmount;
private final String currency;
public OrderSummary(String orderId, String customerId, String orderDate, double totalAmount, String currency) {
this.orderId = orderId;
this.customerId = customerId;
this.orderDate = orderDate;
this.totalAmount = totalAmount;
this.currency = currency;
}
//Getters
}
6. Asegurar el almac茅n de eventos
El almac茅n de eventos contiene datos confidenciales, por lo que es fundamental protegerlo adecuadamente. Considere las siguientes medidas de seguridad:
- Control de acceso: Restrinja el acceso al almac茅n de eventos solo a usuarios y aplicaciones autorizados. Utilice mecanismos de autenticaci贸n y autorizaci贸n s贸lidos.
- Cifrado: Cifre los datos en el almac茅n de eventos en reposo y en tr谩nsito para protegerlos del acceso no autorizado. Considere el uso de claves de cifrado administradas por un M贸dulo de Seguridad de Hardware (HSM) para mayor seguridad.
- Auditor铆a: Audite todo el acceso al almac茅n de eventos para detectar y prevenir actividades no autorizadas.
- Enmascaramiento de datos: Enmascare los datos confidenciales en el almac茅n de eventos para protegerlos de la divulgaci贸n no autorizada. Por ejemplo, podr铆a enmascarar informaci贸n de identificaci贸n personal (PII) como n煤meros de tarjetas de cr茅dito o n煤meros de seguro social.
- Copias de seguridad regulares: Haga copias de seguridad del almac茅n de eventos con regularidad para protegerlo contra la p茅rdida de datos. Almacene las copias de seguridad en una ubicaci贸n segura.
- Recuperaci贸n ante desastres: Implemente un plan de recuperaci贸n ante desastres para garantizar que pueda recuperar el almac茅n de eventos en caso de desastre.
7. Implementar la auditor铆a y los informes
Una vez que haya implementado Event Sourcing, puede usar el flujo de eventos para generar informes de auditor铆a y realizar an谩lisis de seguridad. Puede consultar el almac茅n de eventos para encontrar todos los eventos relacionados con un usuario, transacci贸n o entidad espec铆ficos. Tambi茅n puede usar el flujo de eventos para reconstruir el estado del sistema en cualquier momento.
Ejemplo: Podr铆a generar un informe que muestre todos los cambios realizados en un perfil de usuario espec铆fico durante un per铆odo de tiempo, o un informe que muestre todas las transacciones iniciadas por un usuario en particular.
Considere las siguientes capacidades de generaci贸n de informes:
- Informes de actividad del usuario: Rastree los inicios de sesi贸n, cierres de sesi贸n y otras actividades del usuario.
- Informes de cambio de datos: Supervise los cambios en las entidades de datos cr铆ticas.
- Informes de eventos de seguridad: Alerta sobre actividades sospechosas, como intentos de inicio de sesi贸n fallidos o intentos de acceso no autorizado.
- Informes de cumplimiento: Genere informes requeridos para el cumplimiento normativo (por ejemplo, RGPD, HIPAA).
Desaf铆os de Event Sourcing
Si bien Event Sourcing ofrece muchos beneficios, tambi茅n presenta algunos desaf铆os:
- Complejidad: Event Sourcing agrega complejidad a la arquitectura del sistema. Necesita dise帽ar la estructura del evento, elegir un almac茅n de eventos e implementar la publicaci贸n y el consumo de eventos.
- Consistencia eventual: Los modelos de lectura son eventualmente consistentes con el flujo de eventos. Esto significa que puede haber un retraso entre el momento en que ocurre un evento y el momento en que se actualiza el modelo de lectura. Esto puede generar inconsistencias en la interfaz de usuario.
- Versionado de eventos: A medida que su aplicaci贸n evoluciona, es posible que deba cambiar la estructura de sus eventos. Esto puede ser un desaf铆o, ya que necesita asegurarse de que los eventos existentes a煤n se puedan procesar correctamente. Considere usar t茅cnicas como la conversi贸n ascendente de eventos para manejar diferentes versiones de eventos.
- Consistencia eventual y transacciones distribuidas: La implementaci贸n de transacciones distribuidas con Event Sourcing puede ser compleja. Debe asegurarse de que los eventos se publiquen y consuman de manera consistente en m煤ltiples servicios.
- Gastos generales operativos: La gesti贸n de un almac茅n de eventos y su infraestructura asociada puede agregar gastos generales operativos. Debe supervisar el almac茅n de eventos, hacer una copia de seguridad y asegurarse de que se est茅 ejecutando sin problemas.
Mejores pr谩cticas para Event Sourcing
Para mitigar los desaf铆os de Event Sourcing, siga estas mejores pr谩cticas:
- Empiece poco a poco: Comience implementando Event Sourcing en una peque帽a parte de su aplicaci贸n. Esto le permitir谩 aprender los conceptos y obtener experiencia antes de aplicarlos a 谩reas m谩s complejas.
- Utilice un marco: Utilice un marco como Axon Framework o Spring Cloud Stream para simplificar la implementaci贸n de Event Sourcing. Estos marcos proporcionan abstracciones y herramientas que pueden ayudarle a gestionar eventos, proyecciones y suscripciones.
- Dise帽e eventos cuidadosamente: Dise帽e sus eventos cuidadosamente para asegurarse de que capturen toda la informaci贸n que necesita. Evite incluir demasiada informaci贸n en los eventos, ya que esto puede dificultar su procesamiento.
- Implemente la conversi贸n ascendente de eventos: Implemente la conversi贸n ascendente de eventos para manejar los cambios en la estructura de sus eventos. Esto le permitir谩 procesar eventos existentes incluso despu茅s de que la estructura del evento haya cambiado.
- Supervise el sistema: Supervise el sistema de cerca para detectar y prevenir errores. Supervise el almac茅n de eventos, el proceso de publicaci贸n de eventos y las actualizaciones del modelo de lectura.
- Manejar la idempotencia: Aseg煤rese de que sus controladores de eventos sean idempotentes. Esto significa que pueden procesar el mismo evento varias veces sin causar ning煤n da帽o. Esto es importante porque los eventos pueden entregarse m谩s de una vez en un sistema distribuido.
- Considere las transacciones de compensaci贸n: Si una operaci贸n falla despu茅s de que se haya publicado un evento, es posible que deba ejecutar una transacci贸n de compensaci贸n para deshacer los cambios. Por ejemplo, si se crea un pedido pero el pago falla, es posible que deba cancelar el pedido.
Ejemplos del mundo real de Event Sourcing
Event Sourcing se utiliza en una variedad de industrias y aplicaciones, incluyendo:
- Servicios financieros: Los bancos y las instituciones financieras utilizan Event Sourcing para rastrear transacciones, administrar cuentas y detectar fraudes.
- Comercio electr贸nico: Las empresas de comercio electr贸nico utilizan Event Sourcing para gestionar pedidos, realizar un seguimiento del inventario y personalizar la experiencia del cliente.
- Juegos: Los desarrolladores de juegos utilizan Event Sourcing para rastrear el estado del juego, gestionar el progreso de los jugadores e implementar funciones multijugador.
- Gesti贸n de la cadena de suministro: Las empresas de la cadena de suministro utilizan Event Sourcing para rastrear mercanc铆as, gestionar el inventario y optimizar la log铆stica.
- Atenci贸n m茅dica: Los proveedores de atenci贸n m茅dica utilizan Event Sourcing para rastrear los registros de los pacientes, gestionar citas y mejorar la atenci贸n al paciente.
- Log铆stica global: Empresas como Maersk o DHL pueden usar el abastecimiento de eventos para rastrear env铆os en todo el mundo, capturando eventos como "Env铆oParti贸Puerto", "Env铆oLleg贸Puerto", "DespachoAduaneroIniciado" y "Env铆oEntregado". Esto crea una pista de auditor铆a completa para cada env铆o.
- Banca internacional: Bancos como HSBC o Standard Chartered pueden usar el abastecimiento de eventos para rastrear transferencias de dinero internacionales, capturando eventos como "TransferenciaIniciada", "CambioDeMonedaEjecutado", "FondosEnviadosAlBancoBeneficiario" y "FondosRecibidosPorElBeneficiario". Esto ayuda a garantizar el cumplimiento normativo y facilita la detecci贸n de fraudes.
Conclusi贸n
Event Sourcing es un patr贸n arquitect贸nico poderoso que puede revolucionar su implementaci贸n de pista de auditor铆a. Proporciona una trazabilidad, integridad de datos y resiliencia del sistema sin precedentes. Si bien presenta algunos desaf铆os, los beneficios de Event Sourcing a menudo superan los costos, especialmente para sistemas complejos y cr铆ticos. Siguiendo las mejores pr谩cticas descritas en esta gu铆a, puede implementar con 茅xito Event Sourcing y construir sistemas robustos y auditables.