Refaktoryzacja WinForms C# — Głębsza Analiza z Timmem Coreym
Refaktoryzacja to jeden z tematów, które oddzielają kod, który po prostu działa, od kodu, który jest łatwy do utrzymania, elastyczny i gotowy na przyszłość. W Lekcji 24 serii "C# App From Start to Finish", Tim Corey przechodzi przez rzeczywistą, praktyczną sesję refaktoryzacji w aplikacji WinForms. Zamiast teorii, Tim refaktoryzuje istniejący projekt, wyjaśniając, dlaczego zmiany są potrzebne i jak podejść do nich bezpiecznie.
W tym artykule przyjrzymy się bliżej refaktoryzacji WinForms C#, ściśle śledząc wyjaśnienia Tima z wideo.
Co oznacza refaktoryzacja w tej lekcji
O godzinie 0:02 Tim przedstawia Lekcję 24 i wyjaśnia, że refaktoryzacja oznacza przerobienie kodu, aby wykonywał te same zadania, ale w lepszy sposób. Wskazuje, że aplikacja już działa, ale zawiera "śmieci" i obszary, które nie spełniają standardów. Według Tima, to jest odpowiedni moment na wyczyszczenie, zanim projekt się bardziej rozrośnie.
Podkreśla, że refaktoryzacja nie polega na dodawaniu funkcji - chodzi o poprawę struktury, czytelności i długoterminowej konserwowalności, zachowując to samo zachowanie.
Sprzątanie niepotrzebnych wartości zwracanych w interfejsach
Zaczynając od 0:31, Tim wchodzi w pierwszy refaktoring: naprawianie sygnatur metod interfejsu. Wyjaśnia, że we wczesnych etapach projektu metody niepotrzebnie zwracały modele. Ponieważ obiekty są już przekazywane przez referencję, ponowne zwracanie tego samego modelu nie ma prawdziwego celu.
Tim demonstruje zmianę tych metod na void, co natychmiast łamie implementacje. Wyjaśnia, dlaczego tak się dzieje: gdy interfejs się zmienia, wszystkie klasy implementujące muszą dokładnie pasować do nowej sygnatury. Przeprowadza naprawę łącznika SQL i łącznika tekstowego, aby dostosować je do zaktualizowanego interfejsu.
O godzinie 2:33 Tim zatrzymuje się, aby pokazać, co się dzieje, jeśli pozwolisz Visual Studio na automatyczne zaimplementowanie interfejsu. Wyjaśnia, dlaczego występują duplikaty nazw metod i wyjaśnia, że same typy zwracane nie wystarczają do odróżnienia sygnatur metod.
Naprawianie błędów budowy spowodowanych refaktoryzacją
O godzinie 4:00 Tim buduje rozwiązanie i celowo pokazuje pojawiające się błędy. Wyjaśnia, że te błędy są oczekiwane i pomocne. Na przykład, kod, który wcześniej oczekiwał zwracanego modelu, teraz zawodzi, ponieważ metoda zwraca void.
Tim naprawia to, usuwając niepotrzebne przypisania i ponownie budując rozwiązanie. Podkreśla, że refaktoryzacja często powoduje krótkotrwałe błędy, ale każdy błąd wskazuje bezpośrednio na kod, który wymaga poprawy.
Przenoszenie stałych nazw plików do GlobalConfig
Zaczynając od 5:25, Tim refaktoryzuje, jak zarządza się nazwami plików w łączniku tekstowym. Wcześniej ścieżki plików były przechowywane jako prywatne stałe łańcuchowe wewnątrz klasy. Tim wyjaśnia, że nie są już potrzebne, ponieważ nazwy plików już istnieją w GlobalConfig.
Zastępuje lokalne stałe za pomocą GlobalConfig.PeopleFile, GlobalConfig.PrizesFile i podobnych właściwości. Tim wyjaśnia, że ta zmiana centralizuje konfigurację i zapewnia, że cała aplikacja używa spójnych ścieżek plików.
Robi również ważny punkt: unikaj refaktoryzacji zbyt wielu rzeczy naraz. Gdy zauważa dodatkowe ulepszenia, które można by wprowadzić, jasno mówi, że wróci do nich później.
Refaktoryzacja procesora łącznika tekstowego
O godzinie 7:44 Tim kontynuuje refaktoryzację, usuwając parametry nazw plików z wielu metod w procesorze łącznika tekstowego. Ponieważ nazwy plików teraz znajdują się w GlobalConfig, przesyłanie ich jest zbędne.
Tim dokładnie aktualizuje sygnatury metod, zastępuje parametry odniesieniami do GlobalConfig i polega na liście błędów w Visual Studio, aby go poprowadziła. Wyjaśnia, że widok wielu błędów naraz jest normalny podczas refaktoryzacji i nie jest to coś, co powinno panikować.
O godzinie 13:16 zauważa, jak pomocne jest śledzenie błędów w czasie rzeczywistym, kiedy systematycznie sprząta wywołania metod w całym projekcie.
Identyfikowanie logiki UI, która robi zbyt dużo
O godzinie 15:24 Tim wskazuje na poważny problem projektowy: zbyt dużo logiki w obsłudze zdarzeń UI. Przewija zdarzenie kliknięcia przycisku i wyjaśnia, że zawiera ono znacznie więcej kodu, niż powinno. W Windows Forms, działania użytkownika, takie jak kliknięcia przycisków, są obsługiwane przez obsługiwacze zdarzeń, które definiują konkretną akcję do wykonania, gdy zdarzenie wystąpi.
Tim wyjaśnia, że kod UI powinien skupiać się wyłącznie na interakcji z użytkownikiem. Windows Forms korzysta z modelu programowania opartego na zdarzeniach, gdzie działania użytkownika wywołują zdarzenia obsługiwane przez kod aplikacji. Logika biznesowa - taka jak punktowanie turniejów i awansowanie zwycięzców - należy do biblioteki klas. To rozdzielenie umożliwia ponowne wykorzystanie tej samej logiki w późniejszej aplikacji webowej lub aplikacji WPF.
Wyodrębnianie logiki turniejowej do biblioteki klas
Zaczynając od 17:55, Tim przenosi logikę punktowania turniejowego do nowej publicznej metody w klasie logiki turniejowej. Nazywa ją UpdateTournamentResults i wyjaśnia, dlaczego przyjmuje cały model turniejowy, a nie tylko jedno sparowanie.
Kopiuje logikę z formularza, wkleja ją do biblioteki klas i dostosowuje do pracy niezależnie od elementów UI. Ten refaktor zapewnia, że zasady turniejowe są zapisane w jednym miejscu i mogą być ponownie wykorzystane wszędzie.
Punktowanie sparowań i prawidłowe obsługiwanie byes
O godzinie 21:37 Tim refaktoryzuje, jak punktowane są sparowania. Zamiast pracować z pojedynczym sparowaniem, zatrudnia wszystkie rundy i wszystkie sparowania, budując listę sparowań wymagających punktacji.
Wyjaśnia logikę wykrywania ukończonych gier i tygodni byes. Tim wskazuje, że tygodnie byes były wcześniej obsługiwane w "hackowym" sposób poprzez przypisywanie fałszywych wyników. Refaktoryzacja umożliwia mu jednoznaczną i czystą obsługę byes.
Wyodrębnianie punktacji do metod prywatnych
O godzinie 28:17 Tim wyodrębnia logikę punktowania do metody prywatnej. Wyjaśnia, że mniejsze, skoncentrowane metody ułatwiają zrozumienie i utrzymanie kodu.
Również zmienia nazwy metod, aby lepiej odzwierciedlały, co robią, na przykład zmieniając logikę punktowania na coś, co jasno "oznacza zwycięzców w sparowaniach".
Konfigurowalna determinacja zwycięzcy
Zaczynając od 29:58, Tim refaktoryzuje logikę determinacji zwycięzcy, aby mogła obsługiwać zarówno przypadku wysokiej, jak i niskiej punktacji. Wprowadza nowe ustawienie aplikacji i wyjaśnia, dlaczego konfiguracja jest lepsza niż kodowanie na stałe zasad.
Tim omawia alternatywne projektowanie, w tym przechowywanie tej wartości w modelu turniejowym, ale wyjaśnia, dlaczego ta zmiana wykracza poza zakres tej lekcji.
Awansowanie zwycięzców i zapisywanie wyników
O godzinie 45:40 Tim przechodzi do awansowania zwycięzców do następnej rundy. Wyjaśnia, jak zwycięzcy są przypisywani do sparowań rodziców i dlaczego zapisanie danych w odpowiednim czasie jest kluczowe.
Później, około 52:10, demonstruje zwięzłe podejście ForEach do aktualizacji sparowań, wyjaśniając, jak funkcjonalnie jest równoważne tradycyjnej pętli, ale bardziej kompaktowe.
Naprawianie błędów wprowadzonych przez refaktoryzację
O godzinie 58:33 Tim odkrywa nieprawidłowe dane w bazie danych i odnajduje problem w wywoływaniu logiki przed zapisaniem turnieju. Wyjaśnia, że refaktoryzacja czasami ujawnia ukryte błędy, a nie tworzy nowe.
Przenosząc logikę aktualizacji w odpowiednie miejsce—po utrwaleniu—Tim rozwiązuje problem i ponownie testuje aplikację.
Ostateczne przemyślenia na temat refaktoryzacji
O godzinie 1:09:00 Tim podsumowuje, co osiągnięto w ramach refaktoryzacji. Wyjaśnia, że refaktoryzacja nie dotyczy tylko czystego kodu—to także radzenie sobie z przypadkami krańcowymi, naprawianie wad projektowych i przygotowanie na przyszłe zmiany.
Podkreśla, że refaktoryzacja jest procesem ciągłym i sugeruje, że następna lekcja skupi się na obsłudze błędów.
Zamknięcie
Ta lekcja pokazuje refaktoryzację dokładnie tak, jak dzieje się w rzeczywistych projektach: inkrementalnie, czasem chaotycznie, ale ostatecznie satysfakcjonująco. Śledząc krok po kroku podejście Tima Corey'a, otrzymujesz praktyczny plan doskonalenia aplikacji WinForms bez łamania funkcjonalności — i bez zgadywania, co robić dalej.
