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
- Inyección de Dependencias: Los servicios reciben sus dependencias a través del constructor
- Acoplamiento a Interfaces: Se depende de interfaces/tipos, no de implementaciones
- Singleton Services: Los servicios se instancian una única vez y se comparten
- 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
-
Desacoplamiento
- Los módulos no conocen las implementaciones concretas
- Fácil reemplazo de dependencias
- Testing simplificado con mocks
-
Mantenibilidad
- Responsabilidades claras
- Cambios localizados
- Código más legible
-
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 }); }); -
Reusabilidad
- Servicios compartibles entre módulos
- Lógica centralizada
- Evita duplicación de código
Mejores Prácticas
-
Tipado Fuerte
import { type AuthService } from '@/modules/auth/services/auth.service'; import { type SupabaseProvider } from '@/providers/database/database.provider'; -
Logging Consistente
this.logger.info("Operación completada", { origin: "ServiceName.methodName", metadata: { /* datos relevantes */ } }); -
Manejo de Errores
try { // Operación } catch (error) { this.logger.error("Mensaje descriptivo", { origin: "ServiceName.methodName", metadata: { error } }); throw error; } -
Documentación de Interfaces
interface ServiceDependencies { authService: AuthService; database: SupabaseProvider; }
Patrones de Uso Común
-
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(); } } -
Cadena de Servicios
// onboarding -> auth -> database const result = await this.onboardingService .setUserOnboarding(data); // Usa authService internamente -
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