Usando o padrão de fábrica para gerenciar diferentes canais de notificação em um produto SaaS
Introdução: O desafio de notificação em SaaS
Os produtos SaaS modernos dependem de notificações oportunas e personalizadas para envolver usuários, gerar retenção e comunicar eventos críticos do sistema. Os usuários esperam receber alertas através de seus canais preferidos – email, SMS, notificações de push, mensagens no aplicativo ou até mesmo webhooks para serviços de terceiros. À medida que o produto evolui, o número de canais cresce e geri-los através de lógica condicional dispersa torna-se um pesadelo de manutenção.
Directus, uma plataforma de CMS sem cabeça e backend de código aberto, oferece uma base flexível para a construção de aplicações SaaS. Seu modelo de dados, motor de fluxo e ganchos extensíveis tornam o ambiente ideal para implementar um sistema de notificação robusto. Aplicando um padrão de design criacional clássico – o Padrão de Fábrica – você pode encapsular a lógica de criação específica de canais, desarticular seu código de negócios principal dos detalhes de entrega e sem esforço adicionar novos canais à medida que seu produto amadurece.
Compreender o padrão de fábrica
O Padrão de Fábrica é um padrão de design criacional que fornece uma interface para criar objetos em uma super-classe, mas permite que as subclasses alterem o tipo de objetos que serão criados. Promove o acoplamento solto e adere às declarações Princípio Aberto/Fechado: as entidades de software devem estar abertas para extensão, mas fechadas para modificação. Em vez de sujar sua aplicação com ] ou ] para decidir qual objeto de notificação deve ser instanciado, você delega essa responsabilidade a uma fábrica dedicada.
Este padrão brilha quando você tem uma família de objetos relacionados e o tipo exato para instanciar é determinado em tempo de execução com base em entradas dinâmicas, como as preferências de notificação de um usuário ou o evento sendo disparado. Em um contexto de notificação, cada canal é um “produto” diferente, mas todos eles compartilham uma interface comum (por exemplo, um método ).
Canais de notificação em um produto SaaS
Os canais comuns de notificação incluem:
- Email – e-mails transacionais e de marketing através de serviços como SendGrid ou Mailgun.
- SMS – mensagens curtas via Twilio ou Vonage.
- Push Notifications – web push, mobile push via Firebase Cloud Messaging ou OneSignal.
- Notificações no aplicativo – brindas de IU ou alertas de painel.
- Webhooks – Solicitações HTTP POST para terminais externos para integrações.
- Slack / Discord – mensagens focadas em equipa.
Sem um padrão, o seu código pode ser assim:
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');
}
}
Esta abordagem funciona para alguns canais, mas cada novo canal obriga- o a modificar a sua função de envio e a testar de novo toda a lógica existente. O padrão de fábrica elimina esta fragilidade.
Implementação do padrão de fábrica para notificações
Abaixo, caminhamos através de uma implementação TypeScript que pode ser adaptada para um SaaS baseado em Directus. TypeScript é natural para Directus porque a plataforma em si é construída com ele e fornece um sistema de tipo rico.
1. Defina a Interface de Notificação
interface Notification {
send(message: string, recipient: string): Promise<void>
}
2. Classes de Notificação de Concreto
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. A Fábrica de Notificação
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. Usando a fábrica em sua aplicação
async function notifyUser(event: string, userId: string, channel: ChannelType) {
const notification = NotificationFactory.createNotification(channel);
await notification.send(event, userId);
}
O código do cliente nunca precisa saber o tipo de concreto. Ele depende apenas da interface . Esta dissociação torna o teste de unidade simples – você pode zombar do objeto de notificação sem tocar na fábrica ou nas classes de concreto.
Integrando o padrão de fábrica com Directus
Directus oferece vários pontos de entrada para acionar notificações:
- Flows – Automação visual que pode chamar operações personalizadas ou webhooks.
- Arremessos – ] ou ganchos que funcionam em eventos CRUD.
- Endpoints personalizados – Rotas expressas injectadas no servidor Directus.
- Webhooks – Transportadores de webhook de saída.
Num projeto Directus, você pode instalar sua fábrica de notificação como um serviço dentro de um módulo personalizado ou uma extensão. Por exemplo, dentro de um Flow você pode chamar um endpoint interno da API que instancia o canal correto com base nas preferências armazenadas de um usuário. Alternativamente, você pode embrulhar a fábrica em um hook que dispara após um novo registro do usuário e envia um e-mail de boas-vindas, uma confirmação de SMS e uma notificação push para o aplicativo móvel.
Como a fábrica vive em um único lugar, você pode atualizar seus mapeamentos sem tocar em cada gancho ou fluxo. E como Directus Flows pode passar dados JSON arbitrários, você pode facilmente alimentar a fábrica com identificadores de canal de seu banco de dados.
Benefícios da abordagem padrão de fábrica
Escalabilidade
Adicionar um novo canal significa escrever uma nova classe que implementa e adicionar uma linha à instrução de switch da fábrica. Não são necessárias alterações de código do cliente. Isto é especialmente valioso em produtos SaaS multi-tenant onde diferentes inquilinos podem permitir diferentes conjuntos de canais.
Manutenção
A lógica de entrega de notificações é isolada da lógica de negócios. Cada classe concreta pode ser mantida independentemente. Se o provedor de SMS alterar sua API, você só modifica . A fábrica e todos os consumidores permanecem inalterados.
Testabilidade
Você pode testar cada classe de notificação isoladamente, e você pode zombar da interface ao testar funções de nível superior. A própria fábrica pode ser verificada com um teste simples que verifica se retorna instâncias do tipo correto para cada canal.
Flexibilidade
A fábrica pode ser estendida para construir objetos complexos. Por exemplo, você pode passar a configuração (chaves API, políticas de repetição) no momento da criação. Você pode sobrecarregar o método de fábrica ou usar um padrão Construtor dentro da fábrica para montar objetos de notificação totalmente configurados. Variáveis de ambiente ou configurações de banco de dados do Directus (por exemplo, uma tabela ) são fontes ideais para tal configuração.
Potenciais retaliações e considerações
Enquanto o padrão de fábrica é uma ferramenta poderosa, não é uma bala de prata:
- Engenharia excessiva: Se você tiver apenas dois canais e nenhum plano para adicionar mais, uma condição simples pode ser boa. O padrão introduz arquivos adicionais e abstrações.
- A lógica de decisão ainda existe: A própria fábrica usa uma instrução de switch. Se você tiver dezenas de canais, considere um padrão de registro onde os canais se auto-registram, ou use um padrão de estratégia ] que troca algoritmos em vez de objetos. Ambos podem complementar a fábrica.
- Injeção de dependência: Se suas classes de notificação dependem de serviços externos (por exemplo, um cliente HTTP ou um registrador), você precisa injetar essas dependências.A fábrica deve aceitar um container DI ou receber as dependências como parâmetros – algo para planejar precocemente.
Em uma extensão Directus, você pode aproveitar a injeção de dependência integrada da plataforma (a função e serviços ]) para passar instâncias compartilhadas como o logger ou o acesso ao banco de dados à fábrica.
Exemplo do mundo real: Notificações multicanais em um B2B SaaS
Considere uma ferramenta de gerenciamento de projeto construída no Directus. Quando uma tarefa é atribuída, o sistema deve notificar:
- o atribuído via e-mail (se preferirem isso)
- o cessionário através de torradas in-app
- o canal do projeto no Slack
Usando a fábrica, o código sob um gancho Directus torna-se:
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);
}
}
Cada classe de notificação lida com sua própria entrega idiomática. A fábrica continua sendo a única fonte de verdade para o mapeamento de canais.
Para ver uma implementação completa de tal sistema, consulte A documentação oficial do Directus sobre a criação de ganchos e serviços personalizados.Para uma compreensão mais profunda do próprio padrão de fábrica, a página Refactoring Guru on Factory Method é um excelente recurso.Você também pode estar interessado em como outras plataformas lidam com a orquestração de notificações –Twilio Notificate[]] mostra um conceito semelhante no nível de infraestrutura.
Conclusão
O padrão de fábrica fornece uma maneira limpa e mantendível de gerenciar vários canais de notificação em um produto SaaS. Ao encapsular a criação de objetos, você desacopla sua lógica de aplicação central a partir de específicos de entrega, tornando fácil adicionar, remover ou modificar canais sem efeitos ondulantes através da base de código. Quando combinado com os ganchos e fluxos flexíveis do Directus, você ganha uma arquitetura de notificação que escala com o crescimento do seu produto.
Se você está construindo um simples notificador de e-mail ou um complexo mecanismo multicanal, começando com o padrão de fábrica cedo compensa à medida que seu conjunto de recursos se expande. O investimento em uma pequena quantidade de abstração hoje economiza dias de refatoração amanhã.