Zasada DRY w C#: Dlaczego duplikacja kodu szkodzi twojej bazie kodowej – Wyjaśnione przez Dereka Comartina
Kiedy mówimy o pisaniu kodu w języku C#, który można łatwo utrzymywać, często pojawia się jedna podstawowa koncepcja — zasada DRY (Don't Repeat Yourself — nie powtarzaj się). Jest to filar tworzenia oprogramowania, którego celem jest wyeliminowanie nadmiarowości, ograniczenie powielania kodu oraz poprawa jego łatwości utrzymania.
Jednak, podobnie jak wiele zasad projektowania, zasada DRY może być źle rozumiana, a nawet niewłaściwie stosowana. W swoim filmie "DRY principle is why your codebase sucks?" Derek Comartin z CodeOpinion.com przedstawia szczere i pragmatyczne spojrzenie na to, jak należy i jak nie należy stosować zasadę DRY — zwłaszcza podczas programowania w .NET Core lub podobnych ekosystemach.
W tym artykułe zagłębimy się w wyjaśnienia Dereka, omawiając jego przykłady i komentarze z filmu. Niezależnie od tego, czy rozpoczynasz nowy projekt w Visual Studio, utrzymujesz istniejącą bazę kodu, czy po prostu refaktoryzujesz w celu lepszego ponownego wykorzystania kodu, spostrzeżenia Dereka są praktyczne i trafne.
Definicja zasady DRY
Na początku filmu Derek przedstawia sytuację, z jaką boryka się wielu programistów: mają do czynienia z systemem, który trudno zmodyfikować — plątaniną powtarzającego się kodu i zbędnej logiki.
Autor przedstawia zasadę DRY w języku C# jako strategię mającą na celu ograniczenie powtarzania kodu, ale ostrzega, że jest ona często błędnie interpretowana. Jak wyjaśnia Derek w 0:28:
"Gdy zasada DRY jest stosowana skutecznie, modyfikacja dowolnego pojedynczego elementu systemu nie wymaga zmiany żadnych elementów, które nie są z nim logicznie powiązane."
To rozróżnienie ma kluczowe znaczenie. Zasada DRY ma na celu nie tylko uniknięcie powielania kodu, ale także promowanie rozdzielenia zagadnień i właściwego ponownego wykorzystania kodu — co prowadzi do powstania łatwego w utrzymaniu, suchego kodu, który jest łatwiejszy do testowania i refaktoryzacji.
Praktyczny przykład: przeliczanie odległości
Aby uczynić to bardziej namacalnym, Derek podaje prosty przykład w języku C#. Autor opisuje dwie metody:
-
ShipDistance
- TollDistance
Każda z nich oblicza odległości w milach, a następnie przelicza je na kilometry — stosując tę samą logikę w obu metodach. To klasyczny przykład powielania kodu.
Zamiast umieszczać ten sam fragment kodu w wielu miejscach, Derek pokazuje, jak można wyodrębnić logikę konwersji do prywatnej metody — MilesToKilometers() — co jest prostym, ale skutecznym sposobem refaktoryzacji kodu w celu ponownego wykorzystania.
Ilustruje to na przykładzie typowej struktury aplikacji konsolowej: klasy Program ze statyczną metodą void Main. Jest to rodzaj struktury, z której korzysta wielu programistów podczas testowania logiki lub eksperymentowania z nowym scenariuszem wprowadzania danych przez użytkownika, takim jak public int age, string username, string password itp.
DRY a nadmierne sprzężenie
Chociaż abstrakcyjne ujęcie logiki w postaci metody wielokrotnego użytku lub oddzielnej klasy brzmi idealnie, Derek zaleca ostrożność. Nadmierne stosowanie zasady DRY, zwłaszcza w całej aplikacji, może prowadzić do niebezpiecznego poziomu sprzężenia.
Na przykład, jeśli umieścisz logikę konwersji we wspólnym narzędziu używanym przez wiele projektów, a później zmienisz jego zachowanie w zakresie zaokrąglania lub precyzji dziesiętnej, zmiana ta może nieoczekiwanie wpłynąć na wiele obszarów. Jak ujął to Derek w 2:31:
"Czy klienci oczekują dwóch miejsc po przecinku? Co się stanie, jeśli zmienimy to na zero?"
Jest to problem przekrojowy — logika ponownie wykorzystywana w wielu częściach systemu — i ilustruje ryzyko zbyt wczesnej centralizacji lub centralizacji bez jasnych granic.
Rada Dereka nawiązuje tutaj do zasady pojedynczej odpowiedziąlności (Single Responsibility Principle) oraz zasady odwrócenia zależności (Dependency Inversion Principle) – dwóch innych zasad SOLID, które mają kluczowe znaczenie dla zachowania elastyczności i modułowości kodu.
Nadmierna rozbudowa kodu wynikająca z nieprawidłowego zastosowania zasady DRY
Kolejnym problemem związanym z niewłaściwym stosowaniem zasady DRY jest nadmierne rozbudowanie kodu — sytuacja, w której próba abstrakcyjnego ujęcia wszystkiego prowadzi do rozbudowanych klas użytkowych lub zbyt ogólnych metod. Derek ostrzega, że nadmierne stosowanie zasady DRY w logice może przynieść więcej szkody niż pożytku, zwłaszcza w dużych systemach, gdzie poprawki błędów w jednym obszarze mogą spowodować awarie w innych obszarach z powodu wspólnych zależności.
Według Dereka kluczem jest wiedza o tym, kiedy nie należy udostępniać kodu — zwłaszcza jeśli skutkuje to ściśle powiązanymi modułami. DRY nie jest regułą; To wytyczna, którą trzeba stosować w kontekście.
Zasada DRY zastosowana do encji: przepis na złożoność
Derek wskazuje na powszechną tendencję wśród programistów: organizowanie systemów w całości wokół encji takich jak Truck, Order, Driver i Shipment. Chociaż kuszące jest ponowne wykorzystanie tej samej klasy lub obiektu w różnych metodach, często prowadzi to do powtarzania koncepcji i niepożądanego sprzężenia.
Twierdzi on, że to możliwości biznesowe — a nie tylko struktury danych — powinny determinować architekturę. Na przykład "wysyłanie zamówienia" to coś innego niż "odłączanie przyczepy", nawet jeśli dotyczą one tych samych podmiotów.
O godz. 4:45 Derek wyjaśnia:
"Pojedynczy element w systemie nie musi reprezentować wielu pojęć."
Podkreśla to głębszy wgląd w architekturę: jednostki o tej samej nazwie (Pojazd, Przyczepa) mogą reprezentować różne zadania w różnych przepływach pracy. Używanie ich zamiennie powoduje zamieszanie i ściśle wiąże niepowiązaną logikę biznesową.
DRY i możliwości biznesowe
Aby rozwiązać ten problem, Derek wprowadza architekturę Vertical Slice Architecture (VSA) — wzorzec, który organizuje aplikacje wokół funkcji biznesowych zamiast warstw. Każdy "segment" zawiera wszystko, co jest potrzebne do konkretnej akcji lub przypadku użycia — od żądania do bazy danych — w postaci zamkniętej i samowystarczalnej.
Podkreśla on, że kod DRY jest dobry w obrębie jednego fragmentu — w jednej lokalizacji — ale stosowanie DRY w wielu fragmentach może prowadzić do splątanych zależności. O godz. 6:44 dodaje:
"Chodzi po prostu o zmniejszenie sprzężenia, zwiększenie spójności... a jednym ze sposobów na to jest: nie powtarzaj pojęć w obrębie jednego fragmentu tekstu."
Takie myślenie oparte na granicach zapewnia elastyczność. W jednym fragmencie możesz mieć pełny model domeny, a w innym tylko lekki model danych. Wszystko zależy od potrzeb danego fragmentu — to pragmatyczne podejście zgodne z filozofią "The Pragmatic Programmer".
Podsumowanie
Derek kończy, przedstawiając DRY jako narzędzie, a nie prawo. Jak sam to ujął o godz. 7:00:
"Chodzi po prostu o zrozumieniuiuiuiuie, w jaki sposób się to stosuje. Jeśli stosujesz to intensywnie, potencjalnie masz większe sprzężenie.
Zanim więc wyodrębnisz logikę walidacji, ciąg połączenia lub przekształcisz powtarzający się kod w oddzielną metodę, zastanów się, czy rzeczywiście sprawi to, że cała baza kodu będzie łatwiejsza w utrzymaniu — czy też po prostu trudniejsza do zmiany.
Wnioski
Analiza zasady DRY w języku C# przeprowadzona przez Dereka Comartina pokazuje, jak pozornie prosta zasada może przynieść odwrotny skutek, jeśli zostanie zastosowana bez uwzględnienia niuansów. Przechodząc przez przykłady kodu, omawiając praktyczne scenariusze i podkreślając zasady projektowania oprogramowania, autor ujawnia równowagę niezbędną między ponownym wykorzystaniem a modułowością.
Aby znacznie usprawnić proces programowania, pamiętaj:
-
Użyj zasady DRY, aby zrefaktoryzować zbędny kod w jasno określonych granicach.
-
Nie należy ujednolicać elementów, które służą różnym celom biznesowym.
-
Należy uwzględniać kontekst podczas centralizacji logiki — zwłaszcza w wielu miejscach lub projektach.
- Weź pod uwagę testy jednostkowe oraz to, jak wstrzykiwanie zależności może wpłynąć na kod współdzielony.
Stosując te wskazówki, będziesz pisać bardziej wydajny, modułowy i łatwiejszy w utrzymaniu kod w języku C# — i unikniesz przekształcenia swojego kodu w gąszcz zduplikówanej logiki i splątanych zależności.
Aby uzyskać więcej informacji, obejrzyj pełną wersję filmu Dereka Martina na kanale YouTube CodeOpinion.
