DEV Community

Concevoir une application évolutif avec des Interfaces en C#

Le serveur web PandApache3 est basé sur une architecture modulaire. Mais qu'est-ce que cela signifie concrètement ?


Les modules d'un serveur web

Si l’on considère le service PandApache3 comme une "boîte noire," on peut néanmoins le diviser en trois modules principaux :

  • Module Web : Il permet de traiter les requêtes HTTP sur le port 80, donnant accès au site hébergé par PandApache3.

  • Module Admin : Il offre une interface web pour administrer le service PandApache.

  • Module Télémetrie : Il est utilisé pour collecter et analyser des données sur le fonctionnement du service.

Ces modules fonctionnent en synergie, mais peuvent également être exécutés indépendamment, ce qui est très pratique lors du développement. Par exemple, on peut activer uniquement le module de télémétrie pour le tester, sans être gêné par les autres modules. Cette flexibilité simplifie les tests et accélère les cycles de développement.

Adopter cette architecture facilite aussi grandement les améliorations futures. Par exemple, si je souhaite ajouter une nouvelle fonctionnalité au serveur, je n’ai qu’à écrire un nouveau module. Grâce à cette approche, le nouveau module peut facilement s’intégrer dans le reste du code sans perturber les modules existants.


Intégration facilitée avec les interfaces

Pour standardiser le comportement de chaque module, PandApache3 utilise une interface C# appelée IModule. Voyons ce qu’une interface apporte en pratique.

Une interface en C# est un contrat qui définit une série de méthodes sans les implémenter. En imposant un cadre commun, elle garantit que tous les modules possèdent les mêmes fonctionnalités de base, tout en permettant à chaque module de personnaliser son comportement.

Voici l’interface IModule utilisée dans PandApache3 :


public interface IModule 

{ 

    Task StartAsync(); 

    Task RunAsync(); 

    Task StopAsync(); 

    bool isEnable(); 

} 

Enter fullscreen mode Exit fullscreen mode

Chaque module doit être capable de démarrer, fonctionner et s'arrêter. La méthode isEnable() sert a vérifier, si le module est activé selon la configuration du service. En implémentant cette interface, chaque module s’assure de respecter cette structure.

Exemple d'implémentation pour le module de télémétrie :


public class TelemetryModule : IModule 

{ 

    public async Task StartAsync() 

    { 

        // Initialiser la collecte de données 

    } 



    public async Task RunAsync() 

    { 

        // Collecte en continue des métriques de télémétrie 

    } 



    public async Task StopAsync() 

    { 

        // Arrêter la collecte de données 

    } 



    public bool isEnable() 

    { 

        // Vérifier si le module est activé 

        return ModuleInfo.isEnable; 

    } 

} 

Enter fullscreen mode Exit fullscreen mode

Le module de télémétrie, comme le module web ou admin, utilise cette interface pour implémenter ses propres fonctionnalités.


Utilisation du polymorphisme

Maintenant que nous avons défini une interface et des classes qui l’implémentente, comment les gérer de manière uniforme ? C'est ici que le polymorphisme intervient.

Le polymorphisme est un concept de programmation qui permet d'utiliser différentes classes de manière identique. En utilisant l’interface IModule, PandApache3 peut traiter tous les modules de manière uniforme, indépendamment de leur type réel.

Dans la classe principale du serveur, les modules sont initialisés puis stockés dans un dictionnaire de type IModule :


public Dictionary<ModuleType, IModule> Modules = new Dictionary<ModuleType, IModule>(); 



// Initialisation des modules 

TelemetryModule telemetryModule = new TelemetryModule(telemetryTaskScheduler); 

ConnectionManagerModule webModule = new ConnectionManagerModule(ModuleType.Web, Pipelines["web"], webTaskScheduler); 

ConnectionManagerModule adminModule = new ConnectionManagerModule(ModuleType.Admin, Pipelines["admin"], adminTaskScheduler); 



Modules.Add(ModuleType.Telemetry, telemetryModule); 

Modules.Add(ModuleType.Web, webModule); 

Modules.Add(ModuleType.Admin, adminModule); 



// Garder seulement les modules activés dans la configuration 

foreach (var moduleKey in Modules.Keys.ToList()) 

{ 

    if (!Modules[moduleKey].isEnable()) 

    { 

        ExecutionContext.Current.Logger.LogWarning($"Module {moduleKey} désactivé"); 

        Modules.Remove(moduleKey); 

    } 

} 

Enter fullscreen mode Exit fullscreen mode

Les modules, bien que créés sous forme d'objets TelemetryModule ou ConnectionManagerModule, sont stockés sous forme de IModule. Ainsi, nous pouvons les gérer de manière uniforme, sans avoir à connaître leur type spécifique.


Démarrage et exécution des modules

Le serveur utilise une boucle pour démarrer tous les modules activés, grâce au polymorphisme. Voici à quoi cela ressemble :


foreach (var moduleName in Modules.Keys) 

{ 

    await Modules[moduleName].StartAsync(); 

} 

Enter fullscreen mode Exit fullscreen mode

L’utilisation de IModule permet de démarrer, exécuter et arrêter chaque module dans une même boucle, sans se soucier du type de chaque module. Par exemple, pour exécuter tous les modules :


List<Task> tasks = new List<Task>(); 

foreach (var moduleName in Modules.Keys) 

{ 

    tasks.Add(Task.Run(() => Modules[moduleName].RunAsync())); 

} 



await Task.WhenAll(tasks); 

Enter fullscreen mode Exit fullscreen mode

Et pour les arrêter :


foreach (var moduleName in Modules.Keys) 

{ 

    await Modules[moduleName].StopAsync(); 

} 

Enter fullscreen mode Exit fullscreen mode

Ajouter un nouveau module

Grâce à cette architecture modulaire, ajouter un nouveau module à PandApache3 est simple : il suffit d’écrire une nouvelle classe qui implémente IModule. L'interface impose le cadre, ce qui garantit une intégration facile et cohérente.

Les interfaces jouent un rôle essentiel dans tout PandApache3. Par exemple, tous les middlewares suivent l’interface IMiddleware, ce qui permet de les exécuter en chaîne. Des composants comme le socket, le logger, le gestionnaire de fichier et même le gestionnaire de configuration utilisent également des interfaces, rendant le code plus flexible et facile à tester.

Avec cette approche modulaire et l'utilisation intelligente des interfaces, PandApache3 devient un serveur web extensible et maintenable, prêt à évoluer avec de nouvelles fonctionnalités sans nécessiter de changements importants dans la base de code existante.


J’espère que cet article vous aura aidé à mieux comprendre le rôle concret et essentiel des interfaces en C#. Si ce langage vous intéresse, sachez que le code de PandApache3 est disponible sur GitHub et en live sur Twitch. N’hésitez pas à suivre l’aventure !

Top comments (0)