Skracanie kodu a czytelność.

0

Witam, chciałbym spytać co sądzicie o skracaniu kodu np. z 100 linijek do 15 ale tracąć przy tym czytelność kodu? Tj. ktoś inny może nie zjarzyć o co chodzi itd. Wiadomo co mam na myśli.

0

To zależy o jakiej przeróbce mówimy. Jeżeli zamiast 5 pętli można umieścić jedną z jakąś funkcją, to jest to nawet wskazane. Jednak jeżeli mówimy ogólnie o ściskaniu kodu na siłę, to nie powinno się tak robić. Nawet wymyślili na to regułę - KISS

0

Witam, chciałbym spytać co sądzicie o skracaniu kodu np. z 100 linijek do 15 ale tracąć przy tym czytelność kodu?

Ja bym po prostu zadał pytanie: "którą wersję łatwiej przeczytać i zrozumieć?" - możliwe, że najlepsze rozwiązanie będzie pośrodku.

0

Jeżeli chcesz skrócić 100 linijkową funkcję, która realizuje konkretne zadania i której zadanie jest na tyle jasno określone, że wiadomo, że nigdy nie trzeba będzie zmieniać jej działania - i funkcja ma mieć 15 linijek - to spoko. Jeżeli nie ma jednak Twoje skrócenie wpływu na wydajność - to odpuść, bo sensu to nie ma - poświęcony czas, a celowości brak (mniejsza ilość linijek szybciej się nie wykona, szczególnie, jeżeli program jest kompilowany, kod źródłowy będzie całe 1-2KB mniej (ależ oszczędność miejsca na dysku), a przydługawe funkcje i tak każde IDE pozwoli "zwinąć").

4

Funkcja na 100 linijek to niemal w każdej sytuacji za dużo. Jeszcze nie widziałem funkcji o takiej długości aby łatwo się taką funkcję analizowało. I raczej też nie widziałem sytuacji, aby taka długa funkcja była uzasadniona.

0

A ja dodam coś od siebie.

Po 1.) funkcja mająca 100 linijek kodu, jest zwyczajnie WTF-em. Ja wiem w firmach co druga funkcja tak wygląda, ale jeśli mówimy tu o dążeniu do profesjonalnego programowania i dbania o kod, nie wolno dopuszczać do zbyt długich funkcji.
Ja osobiście dążę do nie dłuższych funkcji jak 10 linijek kodu, ale nie poprzez absurdalne pisanie w stylu:

while(warunek) rob cos; rob cos; rob cos;

tylko w sposób cywilizowany :)
Szczerze mówiąc nie spotkałęm się jeszcze z funkcją w moim życiu, która musiałaby być dłuższa niż 20 linijek kodu. (serio). Każdą funkcję większą niż 20 linijek kodu można zwinąć kilkakrotnie do kilku mniejszych funkcji zachowując przy tym większy sens niż pierwotnie.

Po 2.)
Krótsza funkcja jest ZAWSZE czytelniejsza niż funkcja dłuższa, biorąc oczywiście pod uwagę, iż funkcje te nie są zwyczajnie skrócone absurdalnie. Np stosując operacje bitowe (które są mało czytelne dla przeciętnego programisty), albo umieszczając kilka instrukcji w jednej linii.

W sumie nie wiem czy autor podał tylko przykład ze 100 linijkową funkcją, ale dla mnie 100 linijek to totalna masakra. Co prawda w firmie kilkakrotnie pracowałem z funkcjami... 1000 linijkowymi -_-. Nie oznacza jednak to, że można dawać przyzwolenie na tego typu ekscesy.

Konkluzja:
Skracaj funkcję zawsze, jeśli tylko to możliwe. Weryfikuj jednocześnie jednak, czy skrócenie funkcji nie spowoduje totalnego spadku jej czytelności. Biorąc pod uwagę 100 linijek kontra 15 to na pewno skrócenie NIE spowoduje braku czytelności. Wręcz przeciwnie.
Jeśli jednak miałbyś przykład 15linijek kontra 10, to już gra niekoniecznie musi być warta świeczki.

Nie zgodzę się również z przedmówcą:

że wiadomo, że nigdy nie trzeba będzie zmieniać jej działania

To zdanie zdradza doświadczenie kolegi. Funkcja NIGDY nie wiadomo czy będzie musiała przejść modyfikację. Można jedynie przewidywać, że tak się nie stanie, ale pewności nie ma się nigdy.

0

Jaki typ skrócenia masz na myśli? Wyrzucenie kodu z tej funkcji do kilku innych? Skrócenie przez ficzery języka np. zastąpienie if przez operator ?:, pętle przez lambdy itd? A może poprawki w składni polegającym na wywaleniu zbędnych nawiasów, zmiennych tymczasowych i ogólnie bardziej zwięzły zapis typu chwała Bogu za 24" monitory panoramiczne?
Funkcja na 100 linii faktycznie trochę śmierdzi, ale nie takie rzeczy się już widziało. Pierwsze 2 metody można stosować, ale wiadomo - z umiarem. Ostatnią odpuść. Ja osobiście wierzę bardziej w inteligencje kompilatora niż swoją, czy osób które będą później kod analizować ;)

2

Witam, chciałbym spytać co sądzicie o skracaniu kodu np. z 100 linijek do 15 ale tracąć przy tym czytelność kodu?
Jeśli uda ci się skrócić funkcję ze 100 linijek do 15, to znaczy że kod był WTF i skrócenie było słuszne.

Ale to rzadkość. Częściej "skrócenie" polega na zamianie 100-linijkowej funkcji na 5 funkcyj po 25 linijek. To jest wydłużenie kodu, a nie skrócenie. Jednak zazwyczaj mimo wszystko warto, kod podzielony na funkcje będzie zazwyczaj czytelniejszy od jednej długiej funkcji.

Nawet dzisiaj "rozbiłem" funkcję (którą sam napisałem z miesiąc temu...) mającą "tylko" 28 linii. Wynikowy kod po rozbiciu ma 47 linii, a i tak uważam że teraz jest lepiej.

Przy czym 100 linijek to jeszcze nie tak wiele. Zdarzają się funkcje bliżej tysiąca :D

4

Raz miałem do czynienia z funkcją ~500 linijek której za cholere nie mogłem rozbić. Rozbicie wymagało by przekazywania masy parametrów do podfunkcji, lub przekazywanie parametrów "bocznymi kanałami" jak na przykład zmienne w klasie co było by jeszcze gorsze. Ale taki przypadek to rzadkość.

0
dzek69 napisał(a)

Generalnie - mózg - tego trzeba używać tylko nie do liczenia linijek tylko zastanawiania się czy to, co piszę - ma sens.

Dokładnie. Podany przeze mnie przykład skrócenia z 28 do 47 wyglądał tak:

// pseudokod, oryginał był w C++/WinAPI/COM, i nie bardzo się nadaje do celów demonstracyjnych.

Surface ConvertBitmapToSurface(Bitmap bmp);

Surface LoadSurfaceFromFile(string file)
{
    Bitmap bmp;

    // cała reszta

    return ConvertBitmapToSurface(bmp);
}

Funkcja (ta druga) robi "jedną rzecz", oznaczoną w nazwie. Ale co to jest "cała reszta"? Czy można ją nazwać? A może LoadBitmapFromFile?

Surface ConvertBitmapToSurface(Bitmap bmp);

Bitmap LoadBitmapFromFile(string file)
{
    // cała reszta
}

Surface LoadSurfaceFromFile(string file)
{
    Bitmap bmp = LoadBitmapFromFile(file);

    return ConvertBitmapToSurface(bmp);
}

Kod jest teraz dłuższy, ale więcej jego fragmentów ma swoją nazwę i "robi jedną rzecz".

0

Raz miałem do czynienia z funkcją ~500 linijek której za cholere nie mogłem rozbić. Rozbicie wymagało by przekazywania masy parametrów do podfunkcji, lub przekazywanie parametrów "bocznymi kanałami" jak na przykład zmienne w klasie co było by jeszcze gorsze. Ale taki przypadek to rzadkość.

Ooo właśnie. Takie cuda miałem w firmie z funkcją 1000 linijek. Toż to totalna mas(karada)akra.
Funkcja była już tak fatalnie napisana (oraz cały zamysł na daną dll-kę), że właściwie skrócenie tego kodu było niemożliwe, bo wszytko się sypało.
To są oczywiście przypadki skrajne i często wynikają po prostu z braku kompetencji tych, którzy planują aplikację. (np zamiast dziedziczenia, tworzą setki tych samych klas, bo "To robi automat i jest wygodne" - a ch**a wygodne...)

3

Zdarzają się funkcje bliżej tysiąca

Nawet mi nie przypominaj. CMS, w którym po przeparsowaniu zmiennych był ładowany plik obsługujący dany moduł... Ale w nim była tylko ładowana klasa do obsługi danego modułu, tworzony był obiekt tej klasy (nie mający większego sensu jako obiekt), w każdej klasie była metoda "pokaz" (bez parametrów), w tej metodzie dopiero były używane zmienne GET/POST żeby ogarnąć akcję do wykonania, następnie w tych funkcjach było robione WSZYSTKO - od tworzenia kilku niepotrzebnych/nieużywanych zmiennych, poprzez zagmatwane kawałki kodu, wybieranie/zmiana danych w bazie, używane były zmienne globalne, było plucie echo (no bo to PHP oczywiście) w tym wszystkim, w tym kawałki HTML/JS, a i niektóre funkcje potrafiły wykonywać się rekursywnie, co było jeszcze zabawniejsze zważywszy na zmienne globalne, które się nadpisywały. Takich potworków było w klasie na np. 10k linijek w sumie, metody krótszej niż 100 linii nie było (no, może ta "pokaz" była czasem krótsza).

funkcja mająca 100 linijek kodu, jest zwyczajnie WTF-em

Dla mnie zapatrywanie się w ilość linii zamiast jakość i czytelność kodu OGÓŁEM jest WTF-em.

Szczerze mówiąc nie spotkałęm się jeszcze z funkcją w moim życiu, która musiałaby być dłuższa niż 20 linijek kodu. (serio). Każdą funkcję większą niż 20 linijek kodu można zwinąć kilkakrotnie do kilku mniejszych funkcji zachowując przy tym większy sens niż pierwotnie.

Jeżeli ma to logiczne uzasadnienie to ok, ale rozbijanie 25 linijkowej funkcji na dwie, z której jedna służy tylko skróceniu drugiej, a sama w sobie nie stanowi wartości (bo przyjmuje parametry, które są zmiennymi potrzebnymi tylko w trakcie wykonywania pierwszej metody) no to coś nie bardzo. Tak samo jeżeli mielibyśmy większą klasę i większe metody - jeżeli potem byłoby w niej kilkanaście/kilkadziesiąt metod, których jako tako samoistnie użyć się nie da, bo są powiązane z konkretnymi innymi metodami - dla mnie taka klasa na pierwszy rzut oka byłaby WTF-em.

To zdanie zdradza doświadczenie kolegi. Funkcja NIGDY nie wiadomo czy będzie musiała przejść modyfikację. Można jedynie przewidywać, że tak się nie stanie, ale pewności nie ma się nigdy.

Jeżeli jest naprawdę prosta, np. wyszukuje czy w podanym folderze jest plik o podanej nazwie, a następnie próbuje dopasować wolną nazwę z cyferką na końcu i taką nazwę zwraca - to nie widzę zasadności jej ruszania (jeżeli tylko funkcjonuje poprawnie).

0

@dzek69 moim zdaniem absolutne maksimum dla długości funkcji to jest jeden ekran. Jeśli jest jakaś funkcja która nie mieści się na ekranie to trzeba ja podzielić, bo jeśli nie widać jej w całości to jest nieczytelna i już.

2

jak masz dwie funkcje to dalej się nie mieszczą na ekranie ;)
już nie wspominając o tym, że są różne rozdzielczości, a nawet na tej samej rozdzielczości w różnych IDE (toolbary), przy różnych ustawieniach (czcionki) to może być trochę linii różnicy :>

takie trochę nie do końca regułki - ja wciąż zostaję przy rozliczaniu tego na zwykły rozsądek, bez sztywnych reguł, nie na zasady n-linijek, n-ekranów, n-znaków, n-...

0
0x200x20 napisał(a):

Raz miałem do czynienia z funkcją ~500 linijek której za cholere nie mogłem rozbić. Rozbicie wymagało by przekazywania masy parametrów do podfunkcji, lub przekazywanie parametrów "bocznymi kanałami" jak na przykład zmienne w klasie co było by jeszcze gorsze. Ale taki przypadek to rzadkość.

Scoping zmiennych był odpowiedni, argumenty nie powinny być połączone w nową klasę?

1

@dzek69 mylisz się. Bo po podziale wszystko się na ekranie mieści. Jeśli patrzę na metodę "główną" to widzę na odpowiednim poziomie abstrakcji ze robi ona:
X()
Y()
I na tym poziomie abstrakcji nic więcej mi nie potrzeba. Jeśli interesuje mnie coś niżej to mogę spokojnie osobno analizować X oraz Y. Oczywiście mówię tutaj o podziale tej funkcji niejako "z głową". Nie o przecięciu jej "na pałę" na pół bo to nie ma sensu.

0

Trochę z innej beczki: Jeśli tak często rozdzielać kod, to... jak to robić poprawnie? Klasa? Funkcje? Jakaś fikuśna nazwa? Namespace? Może lambda?

1

@spartanPAGE
Wszystko ma swoje zastosowanie. Trzeba po prostu myslec przy kodzeniu, czeste overviewy i bedzie dobrze.

1

Jak na razie nie widziałem problemu w funkcji mającej ~200 linii kodu, bo zostawiałem komentarze. Ale skoro ~100 linii jest czymś złym, to chcę wiedzieć jak robić to poprawnie, zarazem nie sprawiając, że kod zaczyna przypominać kupę. przykładowo: namespace KLASA_METODA{ CZYNNOSC_1(); CZYNNOSC_2(); } i już jest odruch wymiotny.

Jeżeli potrzebujesz komentarzy, to prawdopodobnie już masz problem... Zamiast:
// wyświetlanie wyniku
... 30 linii kodu

Możesz zrobić nową metodę z samokomentującą się nazwą WyswietlWynik. I metoda jaką przedstawiłeś jest bardzo dobra - składasz metodę z mniejszych które są bardzo proste i nazwa sama mówi co robią, więc nawet nie musisz wchodzić do ich kodu.

1

Dokładnie.
Komentarze same w sobie ą złe. Dokładniej zostało to opisane w książce "Czysty kod" do której odsyłam autora.

Natomiast ogólnie co do rozumienia kodu i pewnego rodzaju dokumentacji to dwie sprawy:

  • Czytelne nazwy, klas, funkcji, zmiennych. Czytelne, poprawne i jeśli trzeba - długie. Lepsza długa dobra nazwa, niż zła krótka.
  • Pisanie testów. testy same w sobie są świetną dokumentacją kodu. Nie dość, że testują kod, to jeszcze przedstawiają w sposób praktyczny jak należy korzystać z danych funkcjonalności.
1

A jak mam zdarzenie kliknięcia przycisku a w nim np.

void MainWindow::on_btnAdd_clicked()
{
    GetItemValue();
    CheckAddingEmptyItem();
    AddItemToTable();
    SuggestPrinting();
}

Szlag mnie trafia chodzić po tych funkcjach w kodzie. Skoro program ma dodawać pozycje do tabeli, a potem msgboxem proponowac drukowanie to niech robi to w tym zdarzeniu po kolei normalnie.

0

Raz zaimplementowana metode, powinno sie wpisac do dokumentacji i zostawic. Metoda musi miec opisowa nazwe, zeby nie trzeba bylo zerkac do wewnetrznej implementacji.
To zachacza o "software entities (classes, modules, functions, etc.) should be open for extension, but closed for modification", w skrocie OCP

1
mcoder napisał(a):

A jak mam zdarzenie kliknięcia przycisku a w nim np.

void MainWindow::on_btnAdd_clicked()
{
    GetItemValue();
    CheckAddingEmptyItem();
    AddItemToTable();
    SuggestPrinting();
}

Szlag mnie trafia chodzić po tych funkcjach w kodzie. Skoro program ma dodawać pozycje do tabeli, a potem msgboxem proponowac drukowanie to niech robi to w tym zdarzeniu po kolei normalnie.

Dla mnie ten kod nie jest ok, bo GetItemValue() sugeruje, że coś zwraca a z tego nie korzystamy.

if (! IsEmptyItem() )
   AddItemToTable()
if ( ShouldPrint() )
   Print()

Czy coś w tym stylu. Jeżeli warunki są trywialne (ShouldPrint to np. Dialog.Result == ok), to można je użyć inline, ale ogólnie wolę taki kod który czytam po angielsku. Nie wiem co rozumiem przez "normalne", mam wpisać kod odpowiadający za drukowanie dokumentu (np. 5 linii kodu) - a co jeżeli mam opcję drukowania w 10 miejscach? Don't repeat yourself. No i zazwyczaj chcąc zmienić/dodać funkcjonalność nie potrzebuję zagłębiać się w stary kod. Jeśli potrzebuję wejść do metody, to od tego mam IDE żeby nawigowało poprawnie.

4
Cleaner napisał(a):

Komentarze same w sobie ą złe.

właśnie wywróciłeś do góry nogami wszystko, czego uczą o programowaniu :D

wiadomo, że czytelny kod wyjaśnia wszystko bez komentarzy, ale zdarzają się sytuacje, kiedy komentarz jest zasadny (i nie mowię tu o komentarzach do dokumentacji oczywiście) - np. robisz import danych z jakiegoś pokomplikowanego formatu - mieszasz ze sobą wiele tablic, robisz jakieś bliżej nieokreślone porównania (bo nie wiadomo co w tych zmiennych siedzi, bo to jakiś plik zewnętrzny, zakodowany) i operacje - warto wtedy krótko opisać co w którym miejscu się dzieje, bo nawet jak w momencie pisania kodu będziesz to wiedział, to ty sam za 3 tygodnie, albo osoba po Tobie - już nie. Rzadko też produkuje się jakiś projekt od A-Z samemu, albo w grupach, albo się rozwija/poprawia całkiem obcy kod - i choćbyś produkował najlepszy kod na świecie - czasem warto będzie w takim obcym kodzie wyjaśnić pewien WTF komentarzem.

Ogólnie widzę, że sporo osób naczytało się gdzieś NIE RÓB TAK!!!!!11oneone i trzyma się sztywno tych reguł. Nie można tego, nie można tamtego i żadne przypadki nie pozwalają złamać tej reguły.

5

Komentarze same w sobie ą złe.

Nie wszystkie komentarze są złe.

Takie komentarze są złe:

int l; // 牛郎念劉娘
2

Nie wszystkie?
No ok, czasami zdarzy się przypadek, gdy komentarz się przyda. Jednak każdy komentarz da się zastąpić nieco inaczej, a nawet lepiej.

Do głowy jedynie wpadł mi teraz pomysł, podczas pisania aplikacji mocno nastawionej na wydajność.
W takiej sytuacji często kod może stać się nie czytelny, gdyż nacisk jest na wydajność.
Dobrze może w takiej sytuacji dać w komentarzu odpowiednik do istniejącego kodu.

Z drugiej strony to też nie do końca dobry pomysł. Może się zdarzyć, że funkcja ulegnie zmianie a o komentarzu się zapomni.

Według mnie często stosowanie komentarzy wynika z kilku rzeczy:

  • Złych praktyk programistycznych.
  • Niezrozumienia co tak naprawdę chcemy zrobić.
  • Nierozumienia kodu.
  • Złego zaprojektowania aplikacji. (komentarze w stylu: "czemu to jest napisane tak, zamiast tak")

Jeśli zaprojektowana aplikacja jest poprawna, jeśli mam dostęp do UML, jeśli piszemy ładny kod, to komentarze są zbędne. W takim projekcie ilość komentarzy jest ograniczona do minimum.

W mojej starej firmie programista kładł nacisk na pisanie wielu komentarzy. Taki z niego był programista jak z koziej.... nie wiedział nawet co to UML (serio nie wiedział co to jest), pisał wszystkie funkcje statyczne (sic!) i wiele innych kwiatków.

W mojej aktualnej firmie, komentarzy wielu nie ma. Fakt zdarzają się czasami akie, które mi się nie podobają (np. komentarz po wywołaniu jakiejś funkcji, który to komentarz opisuje działanie funkcji. Zamiast komentarza trzeba było zadbać o dobrą nazwę dla funkcji).
Ale są też takie, których istnienie rozumiem:
Mamy pewne funkcje w dll-kach, które są public. Są one wywoływane w nieznanych nam miejscach, więc warto wyjaśnić potencjalnemu programiście, który wykorzysta tę dll-kę co dana funkcja robi w dwóch - trzech zdaniach. Taki komentarz mnie nie drażni.

2
Azarien napisał(a):

Ale to rzadkość. Częściej "skrócenie" polega na zamianie 100-linijkowej funkcji na 5 funkcyj po 25 linijek. To jest wydłużenie kodu, a nie skrócenie.

Bo tu właśnie chodzi o skrócenie długości funkcji, a nie całości kodu. ;)

0x200x20 napisał(a):

Raz miałem do czynienia z funkcją ~500 linijek której za cholere nie mogłem rozbić. Rozbicie wymagało by przekazywania masy parametrów do podfunkcji, lub przekazywanie parametrów "bocznymi kanałami" jak na przykład zmienne w klasie co było by jeszcze gorsze. Ale taki przypadek to rzadkość.

Właśnie o czymś takim chciałem wspomnieć, bo mnie takie coś dopadło w pracy mgr. Co prawda nie 500 tylko jakieś 120 linii, ale to i tak za dużo.
Rozwiązaniem, jakie widzę w takich przypadkach, to:

  1. wydzielenie całej takiej operacji do nowej klasy;
  2. w konstruktorze przekazanie argumentów wejściowych pierwotnej funkcji;
  3. podział kodu na podfunkcje;
  4. te podfunkcje zamiast argumentów operują na polach klasy;
  5. dużo testów, bo jest spore ryzyko błędów związanych ze skutkami ubocznymi.
dzek69 napisał(a):
Cleaner napisał(a):

Komentarze same w sobie ą złe.

właśnie wywróciłeś do góry nogami wszystko, czego uczą o programowaniu :D

Chyba to, czego teoretycy uczą o programowaniu na uczelniach. I takie bzdety jak "komentarze są potrzebne" jak najbardziej trzeba wywracać do góry nogami.

Trzy sensowne zastosowania komentarzy:

  1. Odesłanie do źródeł (literatury/linka, itd.), które opisują zaimplementowany algorytm.
  2. Przykład zewnętrznego formatu danych (np. kolumn w pliku CSV), na którym dana funkcja operuje.
  3. Opisanie kodu, który zwiera jakieś skomplikowane hacki na wydajność.
  4. Opisanie obejścia na błędne działanie zewnętrznej biblioteki, funkcji systemu operacyjnego, przeglądarki internetowej, itp.
    Komentarze na ogół mają tendencję do dezaktualizacji, bo mało kto je aktualizuje po zmianach w kodzie. Skutkiem tego po pewnym czasie stają się bardzo mylące. Nic nie zastąpi sensownego nazewnictwa zmiennych, metod i sensownego podziału na metody.

A podział na metody jest prosty - jedna metoda robi jedną rzecz. A zatem:

  • Jeśli wczytuje dane z pliku, to nie pobiera od użytkownika nazwy tego pliku, ani nie wyświetla ich na ekranie;
  • Jeśli oblicza pole figury geometrycznej, to nie rysuje jej na ekranie.
  • Jeśli przetwarza bitmapę na skalę szarości, to nie wczytuje jej z dysku.
  • Jeśli liczy rabat dla zakupów, to nie generuje faktury;
  • Jeśli wyznacza układ własny, to nie oblicza macierzy korelacji;
  • Itd., itp.
0

@dzek69 ale przecież wszędzie uczą ze komentarze są złe! Czemu?

  • Bo są nieaktualne. Kod zmienia się często, komentarze prawie nigdy. W efekcie za pół roku masz w kodzie komentarz który tylko utrudnia zrozumienie kodu, bo jest nieaktualny
  • Bo jeśli musisz dać w kodzie komentarz to na 95% mogłeś z tego kawałka zrobić po prostu osobną funkcję
    Pozostaje oczywiście te 5% gdzie komentarz postawić warto - na przykład robimy jakiegoś hacka na buga w języku / bibliotece i takie coś wart opatrzyć odpowiednim komentarzem. Tak samo jeśli robimy jakąś chorą operację optymalizacyjną, wtedy warto napisać co się tam dzieje (zamiast przysłowiowego //magic, do not touch!)

@mcoder nie bądź śmieszny. Normalne IDE pozwala ci trawersować te funkcje bez żadnych problemów. Zresztą po co w ogóle chcesz "po nich chodzić"? Przecież od razu widzisz co się dzieje po wciśnięciu przycisku! A jeśli coś nie działa to możesz spokojnie analizować poszczególne fragmenty operacji. Człowiek ma to do siebie że nie jest w stanie ogarniać kilku poziomów abstrakcji w kodzie jednocześnie i jeśli je mieszasz to szansa że znajdziesz bląd znacząco spada. Dużo łatwiej stwierdzyć czy metoda GetItemValue(); robi to co powinna, niż stwierdzić że 200 linijkowy klocek coś robi ;)

0

Najczęściej spotykane przeze mnie komentarze których być nie powinno...

// Lista figur
private List<Figura> _figury = new List<Figura>();

// liczy Pole Prostokąta
public static int PP(int a, int b) 
{
	// Sprawdzanie czy boki są okej
	// Bug: "nie działa dla a=0, b=10"
	if ( !( a > 0 && b > 0 )) // Mietek 18.08.2010 tu był
		throw new ArgumentException();

// Console.Writeline("{0} {1} = {2}", a, b, a*b);
	return a*b; 
}

/// <summary>liczy Pole Kwadratu
/// <para name="a"></para>
/// </summary>
public static int PK(int a )
{
	return a*a;
}

// public static int PoleKola(int r)
// {
//		return r*r*Math.PI;
// }

Właśnie o czymś takim chciałem wspomnieć, bo mnie takie coś dopadło w pracy mgr. Co prawda nie 500 tylko jakieś 120 linii, ale to i tak za dużo.
Rozwiązaniem, jakie widzę w takich przypadkach, to:

Dla mnie pierwszą rzeczą którą sprawdzam jest scoping zmiennych.

public void PoliczIWyswietlPole(Figura rodzajFigury, int[] boki)
{
	string message = "";
	Color fontColor = Color.Red;
	
	if ( rodzajFigury == Kwadrat )
	{
		message = string.Format("Pole kwadratu wynosi: {0}.", boki[0] * boki[0] );
		fontColor = Color.Green;
	}
	else if ( rodzajFigruy == Prostokat )
	{
		message =  String.Format("Pole prostokata wynosi: {0}.", boki[0]*boki[1] ); 
		fontColor = Color.Yellow;
	}
	else
	{
		message = "Nieznana figura.";
	}
	
	Console.ForegroundColor = fontColor;
	Console.WriteLine(messaage)
}

Jeżeli z powyższego kodu spróbujemy wyizolować PoliczIWyswietlPoleKwadratu(), PoliczIWyswietlPoleProstokata(), WyswietlBlad(), to będziemy mieć paskudne metody, bo dwie pierwsze zwracają 2 informację (message, fontColor), a gdy zmienimy kod na...

public void PoliczIWyswietlPole(Figura rodzajFigury, int[] boki)
{
	if ( rodzajFigury == Kwadrat )
	{
		message = string.Format("Pole kwadratu wynosi: {0}.", boki[0] * boki[0] );
		fontColor = Color.Green;
	
		Console.ForegroundColor = fontColor;
		Console.WriteLine(messaage)
	}
	else if ( rodzajFigruy == Prostokat )
	{
		message =  String.Format("Pole prostokata wynosi: {0}.", boki[0] * boki[1] ); 
		fontColor = Color.Yellow;
	
		Console.ForegroundColor = fontColor;
		Console.WriteLine(messaage)
	}
	else
	{
		message = "Nieznana figura.";
	
		Console.ForegroundColor = fontColor;
		Console.WriteLine(messaage)
	}
}

Po tych zmianach bez bólu możemy wyciąć poszczególne przypadki do nowych metod. Drugim częstym problemem jest nadużywanie prymitywnych typów.

public bool Contains(int areaX, int areaY, int width, int height, int pX, int pY);
public bool Contains(Rectangle area, Point point);
0

Aha, jeszcze jedna rzecz - oczywiście po wycięciu metod zauważam, że są zbyt skomplikowane (dwa zadania), a poza tym że powinniśmy użyć polimorfizmu.

1 użytkowników online, w tym zalogowanych: 0, gości: 1