DRY (DON'T REPEAT YOURSELF), czyli: NIE POWTARZAJ SIĘ
Chodzi tu po prostu o powtórzenia kodu. KAŻDE powtórzenie prowadzi do tego, iż cały system coraz trudniej się konserwuje. Wyobraźmy sobie sytuację: mamy metodę, która wylicza składkę ubezpieczenia. Do tego zaraz tworzymy identyczną metodę (w tym samym miejscu lub gdzieś w innej klasie). Musimy pamiętać o tym, że posiadamy dwie takie same metody i jeśli chcemy coś zmienić to musimy to zrobić tu i tu. Przeważnie wystarczy usunąć 1 metodę i korzystać z jednej. To oczywiście najprostszy przypadek. W części drugiej dotyczącej DRY zajmiemy się usuwaniem powielonych części kodu przez stosowanie: metody szablonowej, zastąpieniem algorytmu, przemieszczenie pola w górę etc.
Krótka historyjka wyjaśni nam jak mogą powstawać DRY.
1. Złe zarządzanie projektem
Agnieszka: Kasia, przeglądałam wczoraj Twój kod i natchnęłam się na niemal identyczną klasę, którą w zeszłym miesiącu zrobił Tomek.
Kasia: Co? Ech, gdybym wiedziała, to użyłabym jego klasy a nie traciła czasu na coś co istnieje.
Mogło dojść do tej sytuacji, ze względu:
-na zły podział zadań w projekcie. Widocznie Kasia dostała do zrobienia coś podobnego co już robił Tomek
-nieznajomości struktury aplikacji Kasi (gdyby np. kod był tworzony w parach, to raczej by nie doszło do takiej sytuacji)
-pewność Kasi, że taka klasa nie istniała w systemie i przez to nie zapytała się członków zespołu czy już coś takiego zostało stworzone
-brak (dobrze) rozrysowanej struktury aplikacji, z której można byłoby wyczytać z jakich klas oraz relacji składa się system
2. Głupota (czy jak kto woli brak doświadczenia ;))
Kasia: Tomek, potrzebuje klasy, która służy do obliczania wynagrodzenia na koniec roku, muszę trochę zmienić jej funkcjonalność pod siebie.
Tomek: Okey, tylko nic nie zepsuj. Znajduje się ona w Wyliczenie.Wynagrodzen.
Kasia: Dzięki.
[Kasia bierze całą klasę i kopiuje ją do swojego modułu nad którym pracuje.]
Mogło dojść do tej sytuacji, ze względu:
-brak doświadczenia/zdrowego rozsądku ;)
-obawa przed wprowadzeniem błędu do klasy, co spowodowałoby katastroficzne skutki w całym systemie
To są tylko oczywiście takie dwa przypadki, które powinny Was uczulić na to co robią członkowie zespołu, w którym pracujemy. Sprawdzajmy i pilnujmy się nawzajem ;)
wzorce projektowe, programowanie ruby on rails, c#, nowości, nowinki ze świata programistów
Pokazywanie postów oznaczonych etykietą brzydkie zapachy kodu. Pokaż wszystkie posty
Pokazywanie postów oznaczonych etykietą brzydkie zapachy kodu. Pokaż wszystkie posty
czwartek, 1 maja 2008
[brzydkie zapachy kodu] Długa metoda
Jak nie trudno się domyśleć zapach - długa metoda, polega na tym, iż metoda jest bardzo ... długa ;) Ale co to oznacza w praktyce? Otóż to, iż np. w takiej metodzie znajdziemy pętle, różnego rodzaju obliczenia, wyświetlenia treści etc. Przykład takiej metody:
Rozwiązanie tego problemu jest banalne. Wystarczy stosować "wydzielenie metody". Czyli tą długa metodę dzielimy na mniejsze:
Gdzie mamy zysk?
-wprowadzanie zmian w takiej metodzie jest łatwiejsze
-ciało metody jest CZYTELNIEJSZE
-jesteśmy w stanie objąć całą metodę wzrokiem
-jeśli dobrze nazwiemy te inne metody powstałe przy "wydzieleniu", to nie będziemy musieli zaglądać do ich kodu, gdyż ich nazwa określi nam co robią
class Przyklad
{
public void DlugaMetoda()
{
Console.WriteLine("Naglowek");
Console.WriteLine("---------------------------");
int wynik = 3 * 5;
int a = 0;
for (int i = 0; i < wynik; i++)
{
a += wynik;
}
if (wynik < a)
{
wynik = 123 + 123;
}
else
{
a = wynik;
}
Console.WriteLine("Wyniki:");
Console.WriteLine("a: " + a);
Console.WriteLine("wynik: " + wynik);
Console.WriteLine("---------------------------");
Console.WriteLine("Stopka");
}
}
Rozwiązanie tego problemu jest banalne. Wystarczy stosować "wydzielenie metody". Czyli tą długa metodę dzielimy na mniejsze:
class Przyklad
{
public void DlugaMetoda()
{
DrawNaglowek();
int wynik = ObliczWynik(3, 5);
int a = 0;
a = ZrobCos(wynik, a);
ZrobCosInnego(ref wynik, ref a);
DrawWyniki(wynik, a);
DrawStopka();
}
private static void ZrobCosInnego(ref int wynik, ref int a)
{
if (wynik < a)
{
wynik = 123 + 123;
}
else
{
a = wynik;
}
}
private static int ZrobCos(int wynik, int a)
{
for (int i = 0; i < wynik; i++)
{
a += wynik;
}
return a;
}
private static void DrawStopka()
{
Console.WriteLine("---------------------------");
Console.WriteLine("Stopka");
}
private static void DrawWyniki(int wynik, int a)
{
Console.WriteLine("Wyniki:");
Console.WriteLine("a: " + a);
Console.WriteLine("wynik: " + wynik);
}
private static void DrawNaglowek()
{
Console.WriteLine("Naglowek");
Console.WriteLine("---------------------------");
}
private static int ObliczWynik(int a, int b)
{
return a * b;
}
}
Gdzie mamy zysk?
-wprowadzanie zmian w takiej metodzie jest łatwiejsze
-ciało metody jest CZYTELNIEJSZE
-jesteśmy w stanie objąć całą metodę wzrokiem
-jeśli dobrze nazwiemy te inne metody powstałe przy "wydzieleniu", to nie będziemy musieli zaglądać do ich kodu, gdyż ich nazwa określi nam co robią