Utilisation du modèle Factory pour gérer différents canaux de notification dans un produit SaaS

Introduction : Le défi de la notification à SaaS

Les produits SaaS modernes comptent sur des notifications personnalisées et opportunes pour engager les utilisateurs, les garder en mémoire et communiquer des événements critiques du système. Les utilisateurs s'attendent à recevoir des alertes par l'intermédiaire de leurs canaux préférés – email, SMS, notifications push, messages in-app, ou même des webhooks vers des services tiers.

Directus, une plateforme de CMS et de backend sans tête open source, fournit une base flexible pour la construction d'applications SaaS. Son modèle de données, son moteur Flows et ses crochets extensibles en font un environnement idéal pour mettre en place un système de notification robuste. En appliquant un modèle de création classique – le modèle Factory – vous pouvez encapsuler la logique de création spécifique à un canal, découpler votre code d'affaires de base des détails de livraison, et ajouter sans effort de nouveaux canaux à mesure que votre produit mûrit.

Comprendre le modèle d'usine

Le modèle Factory est un modèle de conception créative qui fournit une interface pour créer des objets dans une super-classe, mais permet aux sous-classes de modifier le type d'objets qui seront créés. Il favorise le couplage lâche et adhère aux énoncés Open/Fermé Principe: les entités logicielles devraient être ouvertes pour l'extension mais fermées pour la modification.

Ce modèle brille lorsque vous avez une famille d'objets liés et le type exact à l'instantané est déterminé à l'exécution en fonction de l'entrée dynamique – comme les préférences de notification d'un utilisateur ou l'événement déclenché. Dans un contexte de notification, chaque canal est un produit différent, - mais ils partagent tous une interface commune (par exemple, une méthode .

Voies de notification dans un produit SaaS

Les voies de notification communes comprennent:

Sans modèle, votre code pourrait ressembler à ceci :

function sendNotification(channel, message, recipient) {
 if (channel === 'email') {
 // Email logic here
 } else if (channel === 'sms') {
 // SMS logic here
 } else if (channel === 'push') {
 // Push logic here
 } else {
 throw new Error('Unknown channel');
 }
}

Cette approche fonctionne pour quelques canaux, mais chaque nouveau canal vous force à modifier votre fonction d'envoi et de retest toute la logique existante. Le modèle d'usine élimine cette fragilité.

Mise en œuvre du modèle d'usine pour les notifications

Ci-dessous, nous traversons une implémentation TypeScript qui peut être adaptée pour une SaaS basée sur Directus. TypeScript est naturel pour Directus parce que la plate-forme elle-même est construite avec elle et fournit un système de type riche.

1. Définir l'interface de notification

interface Notification {
 send(message: string, recipient: string): Promise<void>
}

2. Classes de notification de béton

class EmailNotification implements Notification {
 async send(message: string, recipient: string): Promise<void> {
 // Use Directus’s internal mailer or an external SDK
 console.log(`Sending email to ${recipient}: ${message}`);
 }
}

class SMSNotification implements Notification {
 async send(message: string, recipient: string): Promise<void> {
 // Call Twilio API
 console.log(`Sending SMS to ${recipient}: ${message}`);
 }
}

class PushNotification implements Notification {
 async send(message: string, recipient: string): Promise<void> {
 // Use Firebase or OneSignal SDK
 console.log(`Sending push to ${recipient}: ${message}`);
 }
}

3. L ' usine de notification

type ChannelType = 'email' | 'sms' | 'push';

class NotificationFactory {
 static createNotification(channel: ChannelType): Notification {
 switch (channel) {
 case 'email':
 return new EmailNotification();
 case 'sms':
 return new SMSNotification();
 case 'push':
 return new PushNotification();
 default:
 throw new Error(`Unknown notification channel: ${channel}`);
 }
 }
}

4. Utilisation de l'usine dans votre application

async function notifyUser(event: string, userId: string, channel: ChannelType) {
 const notification = NotificationFactory.createNotification(channel);
 await notification.send(event, userId);
}

Le code client n'a jamais besoin de connaître le type de béton. Cela dépend uniquement de l'interface . Ce découplage rend les tests unitaires simples – vous pouvez vous moquer de l'objet de notification sans toucher l'usine ou les classes de béton.

Intégrer le modèle d'usine avec Directus

Directus offre plusieurs points d'entrée pour déclencher les notifications:

Dans un projet Directus, vous pouvez installer votre service de notification comme service à l'intérieur d'un module personnalisé ou d'une extension. Par exemple, à l'intérieur d'un Flow vous pouvez appeler un paramètre interne d'API qui permet d'instantaner le bon canal en fonction des préférences stockées par un utilisateur. Vous pouvez aussi envelopper l'usine dans un hook qui s'allume après un nouvel utilisateur et envoie un courriel de bienvenue, une confirmation SMS et une notification de poussée à l'application mobile.

Parce que l'usine vit en un seul endroit, vous pouvez mettre à jour ses mappings sans toucher chaque crochet ou flux. Et puisque Directus Flows peut passer des données JSON arbitraires, vous pouvez facilement alimenter l'usine avec des identifiants de canal de votre base de données.

Avantages de l'approche de l'usine

Échelle

Ajouter un nouveau canal signifie écrire une nouvelle classe qui implémente et ajouter une ligne à la déclaration de commutation de l'usine. Aucun changement de code client n'est nécessaire. Ceci est particulièrement utile dans les produits SaaS multi-tenus où différents locataires peuvent activer différents ensembles de canaux.

Maintenabilité

La logique de la notification est isolée de la logique d'affaires. Chaque classe concrète peut être maintenue indépendamment. Si le fournisseur de SMS change son API, vous ne modifiez que . L'usine et tous les consommateurs restent inchangés.

Testabilité

Vous pouvez tester chaque classe de notification séparément et vous pouvez vous moquer de l'interface lors des tests de fonctions de niveau supérieur. L'usine elle-même peut être vérifiée par un simple test qui vérifie qu'elle renvoie des instances du type correct pour chaque canal.

Flexibilité

L'usine peut être étendue pour construire des objets complexes. Par exemple, vous pouvez passer la configuration (clés API, politiques de réessayer) au moment de la création. Vous pouvez surcharger la méthode d'usine ou utiliser un Builder modèle à l'intérieur de l'usine pour assembler des objets de notification entièrement configurés.

Inconvénients et considérations potentiels

Bien que le modèle d'usine soit un outil puissant, ce n'est pas une balle d'argent:

Dans une extension Directus, vous pouvez utiliser la plateforme d'injection intégrée (la fonction et les services ) pour passer des instances partagées comme le enregistreur ou l'accès à la base de données à l'usine.

Exemple réel-mondial : Notifications multicanaux dans un B2B SaaS

Considérez un outil de gestion de projet construit sur Directus. Lorsqu'une tâche est assignée, le système doit aviser :

En utilisant l'usine, le code sous un crochet Directus devient :

import { NotificationFactory } from './services/NotificationFactory';

async function onTaskCreate(payload, { accountability }) {
 const { assigneeId } = payload;
 const userPreferences = await getUserNotificationPreferences(assigneeId);
 for (const channel of userPreferences.channels) {
 const notifier = NotificationFactory.createNotification(channel);
 await notifier.send(`You have a new task!`, assigneeId);
 }
}

Chaque classe de notification gère sa propre livraison idiomatique. L'usine reste la seule source de vérité pour la cartographie des canaux.

Pour une mise en œuvre complète d'un tel système, reportez-vous à la documentation officielle Directus sur la création de crochets et de services personnalisés. Pour une compréhension plus approfondie du modèle d'usine lui-même, la page du Guru de la méthode d'usine est une excellente ressource.

Conclusion

Le Factory Pattern fournit une façon propre et durable de gérer plusieurs canaux de notification dans un produit SaaS. En encapsulant la création d'objets, vous découplez votre logique d'application de base des spécifications de livraison, ce qui facilite l'ajout, la suppression ou la modification de canaux sans effets d'entraînement sur la base de code.

Que vous construisiez un simple notificateur de courriel ou un moteur multicanaux complexe, à commencer par le modèle d'usine tôt paie au fur et à mesure que votre jeu de fonctionnalités s'étend. L'investissement dans une petite quantité d'abstraction aujourd'hui permet d'économiser des jours de refactoring demain.