Principes SOLID en Go : théorie et pratique de A à Z
\n\nSOLID est l'acronyme de cinq principes fondamentaux de la programmation orientée objet qui aident à créer un code flexible, maintenable et évolutif. Bien que Go ne soit pas un langage OOP classique (il n'a pas de classes ni d'héritage au sens traditionnel), ces principes sont applicables et extrêmement utiles lors du développement en Go. Dans cet article, nous analyserons chaque principe avec des exemples concrets, montrerons comment les appliquer en Go et expliquerons pourquoi c'est important.
\n\n1. Single Responsibility Principle (SRP) — Principe de responsabilité unique
\n\nEssence : Chaque module, classe ou fonction ne doit avoir qu'une seule raison de changer. En d'autres termes, une entité doit être responsable d'une seule partie de la fonctionnalité.
\n\nEn Go, cela est souvent violé lorsqu'une structure (struct) effectue trop de tâches : travailler avec la base de données, envoyer des e-mails, générer des rapports.
\n\nMauvais exemple (violation du SRP) :
\ntype User struct {\n Name string\n Email string\n}\n\nfunc (u *User) Save() error {\n // logique de sauvegarde en BD\n return nil\n}\n\nfunc (u *User) SendWelcomeEmail() error {\n // logique d'envoi d'e-mail\n return nil\n}\n\nfunc (u *User) GenerateReport() string {\n // logique de génération de rapport\n return "report"\n}\n\n\nBon exemple (respect du SRP) :
\ntype User struct {\n Name string\n Email string\n}\n\ntype UserRepository struct{}\n\nfunc (r *UserRepository) Save(u *User) error {\n // seulement la sauvegarde\n return nil\n}\n\ntype EmailService struct{}\n\nfunc (s *EmailService) SendWelcome(u *User) error {\n // seulement l'envoi d'e-mail\n return nil\n}\n\ntype ReportGenerator struct{}\n\nfunc (g *ReportGenerator) Generate(u *User) string {\n // seulement la génération de rapport\n return "report"\n}\n\n\nConclusion : Chaque structure est responsable de sa propre tâche. Modifier la logique de sauvegarde n'affectera pas l'envoi d'e-mails.
\n\n2. Open-Closed Principle (OCP) — Principe d'ouverture/fermeture
\n\nEssence : Les entités logicielles (classes, modules, fonctions) doivent être ouvertes à l'extension, mais fermées à la modification. C'est-à-dire que vous devez pouvoir ajouter de nouvelles fonctionnalités sans modifier le code existant.
\n\nEn Go, cela se réalise parfaitement via les interfaces.
\n\nMauvais exemple (violation de l'OCP) :
\ntype PaymentProcessor struct{}\n\nfunc (p *PaymentProcessor) Process(paymentType string, amount float64) {\n if paymentType == "credit_card" {\n // logique pour carte de crédit\n } else if paymentType == "paypal" {\n // logique pour PayPal\n }\n // lors de l'ajout d'un nouveau type, il faudra modifier cette méthode\n}\n\n\nBon exemple (respect de l'OCP) :
\ntype PaymentMethod interface {\n Pay(amount float64) error\n}\n\ntype CreditCard struct{}\n\nfunc (c *CreditCard) Pay(amount float64) error {\n // logique pour carte de crédit\n return nil\n}\n\ntype PayPal struct{}\n\nfunc (p *PayPal) Pay(amount float64) error {\n // logique pour PayPal\n return nil\n}\n\nfunc ProcessPayment(method PaymentMethod, amount float64) error {\n return method.Pay(amount)\n}\n\n\nConclusion : Maintenant, pour ajouter un nouveau moyen de paiement (par exemple, ApplePay), il suffit de créer une nouvelle structure avec la méthode Pay(), sans toucher au code existant.
3. Liskov Substitution Principle (LSP) — Principe de substitution de Barbara Liskov
\n\nEssence : Les objets d'un programme doivent être remplaçables par des instances de leurs sous-types sans altérer la correction du programme. En Go, cela signifie que si une fonction accepte une interface, toute implémentation de cette interface doit fonctionner correctement, sans violer les attentes.
\n\nMauvais exemple (violation du LSP) :
\ntype Bird interface {\n Fly() error\n}\n\nt