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] Jeden z Twoich najwiekszych wrogów: DRY! cz. 1

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 ;)

[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:


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ą