Skip to Content

Comunicación entre Módulos

La comunicación entre módulos en Creative Minds se realiza principalmente a través de servicios, utilizando un patrón de inyección de dependencias para mantener un acoplamiento bajo y una alta cohesión.

Principios Fundamentales

  1. Inyección de Dependencias: Los servicios reciben sus dependencias a través del constructor
  2. Acoplamiento a Interfaces: Se depende de interfaces/tipos, no de implementaciones
  3. Singleton Services: Los servicios se instancian una única vez y se comparten
  4. Inversión de Control: Las dependencias se configuran en la composición raíz

Estructura de un Servicio

Los servicios extienden una clase base Service que proporciona funcionalidades comunes:

// shared/utils/service.ts export class Service { protected logger: Logger; constructor() { this.logger = new Logger(this.constructor.name); } protected async withErrorHandling<T>( operation: () => Promise<T>, errorMessage: string ): Promise<T> { try { return await operation(); } catch (error) { this.logger.error(errorMessage, { error }); throw error; } } }

Ejemplo de Comunicación entre Módulos

1. Definición del Servicio

// modules/onboarding/services/onboarding.service.ts class OnboardingService extends Service { constructor( private authService: AuthService, private dataBase: SupabaseProvider ) { super(); } async setUserOnboarding( onboardingData: CreateOnboardingData ): Promise<{ data: OnboardingResponse | null; error: Error | null }> { try { // Usa authService para obtener el usuario actual const currentUser = await this.authService.getCurrentUser(); // Usa el provider de base de datos para operaciones const { data, error } = await (await this.dataBase.access()) .from("onboardings") .insert({ ...onboardingData, user_id: currentUser?.sub, created_at: new Date(), updated_at: new Date(), }); // Manejo de errores y logging if (error) { this.logger.error("Error creating user onboarding", { origin: "OnboardingService.createUserOnboarding", metadata: { error: error.message, userId: currentUser?.sub, }, }); } return { data, error }; } catch (error) { // Logging centralizado de errores this.logger.error("Unexpected error", { origin: "OnboardingService.createUserOnboarding", metadata: { error: error instanceof Error ? error.message : String(error), }, }); throw error; } } }

2. Composición de Servicios

// Instanciación con inyección de dependencias export const onboardingService = new OnboardingService( authService, // Servicio de autenticación supabaseProvider // Provider de base de datos );

Patrones de Comunicación

Beneficios del Patrón

  1. Desacoplamiento

    • Los módulos no conocen las implementaciones concretas
    • Fácil reemplazo de dependencias
    • Testing simplificado con mocks
  2. Mantenibilidad

    • Responsabilidades claras
    • Cambios localizados
    • Código más legible
  3. Testabilidad

    // Ejemplo de test con mocks describe('OnboardingService', () => { const mockAuthService = { getCurrentUser: jest.fn() }; const mockDatabase = { access: jest.fn() }; const service = new OnboardingService( mockAuthService, mockDatabase ); it('should create onboarding', async () => { // Test con dependencias mockeadas }); });
  4. Reusabilidad

    • Servicios compartibles entre módulos
    • Lógica centralizada
    • Evita duplicación de código

Mejores Prácticas

  1. Tipado Fuerte

    import { type AuthService } from '@/modules/auth/services/auth.service'; import { type SupabaseProvider } from '@/providers/database/database.provider';
  2. Logging Consistente

    this.logger.info("Operación completada", { origin: "ServiceName.methodName", metadata: { /* datos relevantes */ } });
  3. Manejo de Errores

    try { // Operación } catch (error) { this.logger.error("Mensaje descriptivo", { origin: "ServiceName.methodName", metadata: { error } }); throw error; }
  4. Documentación de Interfaces

    interface ServiceDependencies { authService: AuthService; database: SupabaseProvider; }

Patrones de Uso Común

  1. Composición de Servicios

    // Módulo A usa servicios de Módulos B y C class ServiceA extends Service { constructor( private serviceB: ServiceB, private serviceC: ServiceC ) { super(); } }
  2. Cadena de Servicios

    // onboarding -> auth -> database const result = await this.onboardingService .setUserOnboarding(data); // Usa authService internamente
  3. Providers Compartidos

    // Múltiples servicios usando el mismo provider const databaseProvider = new DatabaseProvider(); const serviceA = new ServiceA(databaseProvider); const serviceB = new ServiceB(databaseProvider);
Last updated on