In definitiva, questa è una questione di incapsulamento. Da dove viene la dichiarazione di if
sull'invio o meno di email live?
Opzione 1 (a) - Utilizza un URI diverso
In questa opzione, ci sono almeno due distinti software: l'applicazione chiamante e il servizio. Inoltre, l'istruzione if
sull'invio o meno dell'email risiede nell'applicazione chiamante, che indica al servizio quale ramo prendere chiamando diversi endpoint.
Opzione 1 (b): utilizza un parametro
Come sopra, ci sono gli stessi due software, ma l'istruzione if
risiede nel servizio, più vicino al codice di creazione dell'utente.
Opzione 2 - Servizio di alto livello
Qui ci sono almeno tre pezzi di software: l'applicazione chiamante, il servizio di alto livello e il servizio di creazione degli utenti. Questa opzione si riduce tecnicamente alla stessa domanda dell'opzione 1: se il servizio di alto livello ora possiede l'istruzione if
, come fa a sapere quale ramo eseguire? L'applicazione chiamante chiama un endpoint diverso nel servizio di alto livello? Oppure, passa un parametro ad esso?
Opzione 3: introduce un middleware orientato ai messaggi
Questa opzione suona davvero più come un piuttosto che come cosa. L'introduzione di un MOM riguarda il passaggio di messaggi tramite code e messaggi di passaggio tramite endpoint sui servizi. Pertanto, l'applicazione chiamante dovrebbe sapere se passare diversi tipi di messaggi (utilizzare un diverso endpoint) o se passare un parametro come parte del payload del messaggio (utilizzare un parametro). In altre parole, ti rimangono le stesse due scelte.
Quindi, alla fine, la decisione si riduce a se creare o meno endpoint (o messaggi) separati o passare un parametro (sull'endpoint o nel corpo del messaggio).
Principio di responsabilità singola dice che dovremmo raccogliere insieme le cose che probabilmente cambiano insieme e separano quelle cose che cambieranno per ragioni diverse. Pertanto, dobbiamo decidere se l'istruzione if
appartiene o meno ai casi d'uso nell'applicazione chiamante o al servizio stesso.
Mentre scrivevo questo, andavo letteralmente avanti e indietro su quale raccomandare. Non sono sicuro che ci sia una risposta corretta. Alla fine, mi sto orientando verso un'opzione che non era nell'OP, che va così:
Opzione 4 - Usa design basato sui casi
In questa opzione, ci sono tre parti del software, l'applicazione chiamante, il servizio di creazione degli utenti e un servizio di notifica utente. L'applicazione chiamante ha classi di "use case" differenti, ognuna delle quali sa se notificare o meno l'utente. E i servizi sono responsabili solo per l'unica cosa che sa.
Quindi, in questa opzione, l'istruzione if
risiede nell'applicazione chiamante e vi è un solo endpoint su ciascuno dei servizi sottostanti:
Chiamata all'applicazione (in pseudo rubino)
class RegistrationController
def create
if agent_registration
UseCases::AgentRegistration.register(user_attributes)
else
UseCases::SelfRegistration.register(user_attributes)
end
end
end
class AgentRegistrationUseCase
def register(user_attributes)
UserRegistrationServivce.create(user_attributes)
end
end
class UserRegistrationUseCase
def register(user_attributes)
UserRegistrationService.create(user_attributes)
UserNotificationService.create(user_attributes)
end
end
Si noti che l'istruzione if
risiede nell'applicazione chiamante, vicino all'interfaccia utente, e potrebbe facilmente essere sostituita con un'istruzione case
nel caso in cui si abbiano casi di utilizzo aggiuntivi. Le classi UseCases sono specifiche per uno dei due casi d'uso. E i servizi hanno solo un singolo create
di endpoint su di essi.