Refactoring C# WinForms — Un regard plus profond avec Tim Corey
La refactorisation est l'un de ces sujets qui sépare le code qui fonctionne simplement du code qui est maintenable, flexible et prêt pour l'avenir. Dans la Leçon 24 de la série " C# App From Start to Finish ", Tim Corey parcourt une session de refactorisation réelle et pratique à l'intérieur d'une application WinForms. Plutôt que la théorie, Tim refactorise un projet existant, expliquant pourquoi des changements sont nécessaires et comment les aborder en toute sécurité.
Dans cet article, nous examinerons de plus près la refactorisation WinForms C#, en suivant strictement les explications de Tim de la vidéo.
Ce que signifie la refactorisation dans cette leçon
À 0:02, Tim présente la Leçon 24 et explique que la refactorisation signifie remanier le code afin qu'il effectue le même travail, mais de manière meilleure. Il souligne que l'application fonctionne déjà, mais qu'elle contient des " déchets " et des zones qui ne sont pas à la hauteur. Selon Tim, c'est le bon moment pour nettoyer avant que le projet ne se développe davantage.
Il souligne que la refactorisation ne consiste pas à ajouter des fonctionnalités, mais à améliorer la structure, la lisibilité, et la maintenabilité à long terme tout en gardant le même comportement.
Nettoyer les valeurs de retour inutiles dans les interfaces
À partir de 0:31, Tim plonge dans le premier remaniement : corriger les signatures des méthodes d'interface. Il explique qu'au début du projet, les méthodes renvoyaient inutilement des modèles. Puisque les objets sont déjà passés par référence, renvoyer à nouveau le même modèle n'a pas de réelle utilité.
Tim montre comment transformer ces méthodes en void, ce qui casse immédiatement les implémentations. Il explique pourquoi cela se produit : lorsqu'une interface change, toutes les classes de l'implémentation doivent correspondre exactement à la nouvelle signature. Il passe en revue la correction du connecteur SQL et du connecteur texte pour s'aligner avec l'interface mise à jour.
À 2:33, Tim fait une pause pour montrer ce qui se passe si vous laissez Visual Studio auto-implémenter l'interface. Il explique pourquoi des noms de méthodes en double se produisent et précise que les seuls types de retour ne suffisent pas à différencier les signatures de méthode.
Correction des erreurs de compilation causées par la refactorisation
À 4:00, Tim bâtit la solution et montre intentionnellement les erreurs qui apparaissent. Il explique que ces erreurs sont attendues et utiles. Par exemple, le code qui attendait auparavant un modèle renvoyé échoue maintenant parce que la méthode retourne void.
Tim corrige cela en supprimant les affectations inutiles et en reconstruisant la solution. Il souligne que la refactorisation provoque souvent des ruptures à court terme, mais que chaque erreur pointe directement vers un code qui a besoin d'améliorations.
Déplacer les constantes de noms de fichiers vers GlobalConfig
À partir de 5:25, Tim remanie la façon dont les noms de fichiers sont gérés dans le connecteur texte. Auparavant, les chemins de fichiers étaient stockés sous forme de constantes string privées dans la classe. Tim explique que ceux-ci ne sont plus nécessaires car les noms de fichiers existent déjà dans GlobalConfig.
Il remplace les constantes locales par GlobalConfig.PeopleFile, GlobalConfig.PrizesFile, et des propriétés similaires. Tim explique que ce changement centralise la configuration et garantit que l'ensemble de l'application utilise des chemins de fichiers cohérents.
Il fait aussi un point important : évitez de refactoriser trop de choses à la fois. Quand il remarque des améliorations supplémentaires qui pourraient être faites, il dit explicitement qu'il y reviendra plus tard.
Refactorisation du processeur de connecteur texte
À 7:44, Tim continue la refactorisation en supprimant les paramètres de nom de fichier de plusieurs méthodes dans le processeur de connecteur texte. Puisque les noms de fichiers résident désormais dans GlobalConfig, les passer est redondant.
Tim met soigneusement à jour les signatures des méthodes, remplace les paramètres par des références GlobalConfig, et s'appuie sur la liste des erreurs de Visual Studio pour le guider. Il explique que voir de nombreuses erreurs à la fois est normal lors de la refactorisation et qu'il ne faut pas s'alarmer.
À 13:16, il note à quel point le suivi des erreurs en temps réel est utile lorsqu'on nettoie systématiquement les appels de méthode à travers le projet.
Identifier la logique de l'interface utilisateur qui en fait trop
À 15:24, Tim souligne un problème majeur de conception : trop de logique à l'intérieur d'un gestionnaire d'événements de l'interface utilisateur. Il parcours un événement de clic de bouton et explique qu'il contient beaucoup plus de code que ne devrait en contenir un événement. En Windows Forms, les actions utilisateur comme les clics de bouton sont gérées par des gestionnaires d'événements, qui définissent l'action spécifique à exécuter lorsque l'événement se produit.
Tim explique que le code de l'interface utilisateur doit se concentrer uniquement sur l'interaction utilisateur. Windows Forms utilise un modèle de programmation basé sur les événements, où les actions de l'utilisateur déclenchent des événements gérés par le code de l'application. La logique métier—telle que le calcul des scores et l'avancement des gagnants—appartient à une librairie de classes. Cette séparation permet de réutiliser la même logique plus tard dans une application web ou WPF.
Extraire la logique de tournoi dans la librairie de classes
À partir de 17:55, Tim déplace la logique de calcul des scores de tournoi dans une nouvelle méthode publique à l'intérieur de la classe de logique de tournoi. Il la nomme UpdateTournamentResults et explique pourquoi elle accepte le modèle de tournoi entier, pas seulement une seule confrontation.
Il copie la logique depuis le formulaire, la colle dans la librairie de classes, et l'ajuste pour fonctionner indépendamment des éléments de l'interface utilisateur. Ce remaniement garantit que les règles de tournoi résident en un seul endroit et peuvent être réutilisées partout.
Attribuer les scores aux confrontations et gérer proprement les exemptions
À 21:37, Tim remanie la façon dont les confrontations sont notées. Au lieu de travailler avec une seule confrontation, il parcourt toutes les manches et toutes les confrontations, construisant une liste de confrontations qui doivent être notées.
Il explique la logique pour détecter les matchs terminés et les semaines d'exemption. Tim souligne que les semaines d'exemption étaient auparavant gérées de façon " bidouilleuse " en attribuant des faux scores. La refactorisation lui permet de gérer les exemptions de manière explicite et propre.
Extraction du Scoring vers des Méthodes Privées
À 28:17, Tim extrait la logique de scoring dans une méthode privée. Il explique que des méthodes plus petites et ciblées rendent le code plus facile à comprendre et à maintenir.
Il renomme également des méthodes pour mieux refléter leur fonction, comme changer la logique de scoring en quelque chose qui indique clairement 'identifie les gagnants dans les affrontements'.
Détermination du Gagnant Configurable
À partir de 29:58, Tim refactorise la logique de détermination du gagnant pour qu'elle puisse gérer à la fois les scénarios où le score le plus élevé gagne et ceux où le score le plus bas gagne. Il introduit un nouveau paramètre d'application et explique pourquoi la configuration est préférable au codage en dur des règles.
Tim discute des conceptions alternatives, y compris le stockage de cette valeur dans le modèle du tournoi, mais explique pourquoi ce changement dépasse le cadre de cette leçon.
Avancer les Gagnants et Sauvegarder les Résultats
À 45:40, Tim passe à l'avancement des gagnants vers le tour suivant. Il explique comment les gagnants sont associés aux affrontements parentaux et pourquoi il est crucial de sauvegarder les données au bon moment.
Plus tard, vers 52:10, il démontre une approche concise de ForEach pour mettre à jour les affrontements, en expliquant comment elle est fonctionnellement équivalente à une boucle traditionnelle mais plus compacte.
Correction des Bugs Introduits par le Refactoring
À 58:33, Tim découvre des données incorrectes dans la base de données et retrace le problème jusqu'à l'appel de logique avant que le tournoi ne soit sauvegardé. Il explique comment le refactoring révèle parfois des bugs cachés plutôt que d'en créer de nouveaux.
En déplaçant la logique de mise à jour à l'emplacement correct—après la persistance—Tim résout le problème et reteste l'application.
Réflexions Finales sur le Refactoring
À 1:09:00, Tim conclut en résumant ce que le refactoring a accompli dans cette leçon. Il explique que le refactoring ne concerne pas seulement un code plus propre—il s'agit également de gérer les cas de bord, de corriger les défauts de conception et de se préparer à des changements futurs.
Il souligne que le refactoring est un processus continu et suggère que la prochaine leçon se concentrera sur la gestion des erreurs.
Note de Clôture
Cette leçon montre le refactoring tel qu'il se produit dans de vrais projets : progressif, parfois désordonné, mais finalement gratifiant. En suivant l'approche étape par étape de Tim Corey, vous obtenez un plan pratique pour améliorer les applications WinForms sans casser la fonctionnalité—et sans deviner ce qu'il faut faire ensuite.
