Interfaces et inversion de dépendances
Publié le par

Lors de la refonte d'une application existante, il n’est pas rare de tomber sur l'utilisation directe d'un service externe dans le code. Le problème c’est que si on souhaite changer de service, ou que le fournisseur du dit service modifie son SDK ou son API, on doit réécrire une partie importante du code.
Pour éviter de se retrouver dans cette situation à l'avenir, on peut adopter une approche plus modulaire et évolutive.
Voici une solution possible pour un service d’envoi de mail :
- Création d'une interface commune : Créer une interface appelée MailerInterface, par exemple, qui définit une méthode send (au minimum). Cette interface sert de contrat que tous les services de messagerie doivent respecter.
- Implémentation de services spécifiques : Ensuite, il suffit d’implémenter cette interface dans les classes utilisant un service d’envoi de mail : MailjetMailer et SendgridMailer par exemple. Chaque classe implémente MailerInterface et utilise un fournisseur de services d'email distinct. Elles possèdent toutes deux une méthode send, ce qui permet de les utiliser et de les interchanger facilement dans le code.
// Définition de l'interface
interface MailerInterface {
public function send($recipient, $subject, $body);
}
// Implémentation pour Mailjet
class MailjetMailer implements MailerInterface {
public function send($recipient, $subject, $body) {
// Code pour envoyer un email via Mailjet
}
}
// Implémentation pour Sendgrid
class SendgridMailer implements MailerInterface {
public function send($recipient, $subject, $body) {
// Code pour envoyer un email via Sendgrid
}
}
// Exemple d'implem très simpliste
class ResetPasswordCommandHandler {
private $mailer;
// On peut utiliser le mailer de notre choix
public function __construct(MailerInterface $mailer) {
$this->mailer = $mailer;
}
public function __invoke(ResetPasswordCommand $resetPasswordCommand ): void {
// Génération du token de réinitialisation de mot de passe (par exemple)
$resetToken = //random;
// Envoi de l'email, quel que soit le mailer on appelle la méthode send
$this->mailer->send(
$resetPasswordCommand->email,
'Réinitialisation de votre mot de passe',
"Utilisez ce token pour réinitialiser votre mot de passe : $resetToken"
);
}
}
Avec cette architecture, il suffit de changer l'implémentation de MailerInterface utilisée pour basculer entre les services externes sans modifier le reste du code.
En appliquant cette méthode, nous avons non seulement simplifié la gestion des services dans notre application, mais nous avons également adopté une meilleure pratique pour le développement logiciel.
Les avantages de cette approche sont clairs :
- Flexibilité : Nous pouvons facilement changer de fournisseur ou de service sans toucher à la logique principale de notre application.
- Maintenance facilitée : Les modifications sont localisées et ne nécessitent pas de refactorisation massive.
- Extensibilité : Ajouter un nouveau service ou fournisseur ne demande que la création d'une nouvelle classe implémentant l'interface définie.
Cette méthode nous a permis de gagner en agilité et en réactivité face aux évolutions technologiques et aux besoins changeants de notre application. C'est une meilleure pratique que je recommande vivement à tous les développeurs.