Dzisiaj ostatnia z lekcji w cyklu o Javie — o debugowaniu aplikacji. Debugowanie to proces wyszukiwania błędów i ich usuwania — Java oraz Eclipse dostarczają nam wielu wygodnych narzędzi, które pozwalają na metodyczne i wygodne podejście.
Ale zanim zaczniemy ciekawostka (o której sam nie wiedziałem, dopiero Ania mi to uświadomiła): termin debugowanie przypisuje się admirał Grace Hopper, pracującej w latach 40-tych ubiegłego wieku przy komputerze Mark II. Problemem w tamtym czasie były ćmy, które blokowały elektromechaniczne mechanizmy komputera powodując błędy — konieczne było więc usuwanie ich z wnętrza komputera, co później przyjęło się jako określenie procedury usuwania błędów w systemach w ogóle. Skoro znamy już historię, zajmijmy się jej wdrożeniem w życie :)
Lekcja
Na początku wyjaśnijmy sobie przede wszystkim na czym polega debugowanie w Javie. Narzędzia, które mamy dostępne pozwalają nam na wstrzymanie wykonywania programu w wybranym miejscu, a następnie możliwość zbadania wartości zmiennych w tym momencie oraz dalszego wykonywania programu ‘krok po kroku’. Dzięki temu możemy dojść do przyczyny problemu sprawdzając, gdzie ‘gubimy’ potrzebną nam informację lub co się z nią dzieje. Nierozerwalnie z debugowaniem powiązane jest pojęcie breakpoint’u — breakpoint to nic innego jak miejsce, w którym działanie naszego programu zostanie ‘wstrzymane’ w celu dalszej analizy.
Należy tutaj podkreślić, że samo włączenie procesu debugowania spowolni działanie naszej aplikacji (oczywiście tylko w czasie debugowania) — maszyna wirtualna Javy wymienia dużo więcej informacji ze środowiskiem niż robiłaby to normalnie, nie przeprowadza też optymalizacji, które mogą mieć miejsce w normalnym działaniu.
System.out.println / logger.debug()
Zanim przejdziemy do nauki debuggowania, parę słów o często stosowanym podejściu — czyli bardzo ‘gęstym’ logowaniu. Oczywiście odradzamy użycie System.out.println na rzecz loggerów, ale idea pozostaje ta sama — po co debugować, skoro mogę używać metod takich jak logger.debug() i w razie potrzeby włączyć wypisywanie tych informacji na konsolę?
Prawidłowa odpowiedź jest jak zwykle pośrodku ;) Stosowanie logger.debug() jest równie ważne co samo debugowanie — w systemach rozproszonych, w których działa wiele komponentów, uruchomienie każdego z nich w trybie debugowania byłoby pracochłonne, a często też niemożliwe z jakichś przyczyn. Wtedy warto włączyć wypisywanie logów na poziomie DEBUG we wszystkich komponentach, z których korzystamy, a debugować tylko komponent, nad którym pracujemy.
Właściwe użycie logerów (takie, które pozwoli nam na podstawie logó dojść do tego, co się stało) jest niełatwe, ale nie zwalnia nas z konieczności umiejętnego posługiwania się debuggerem! Czasem można iść na skróty i skorzystać z loggera, jeśli wiesz, gdzie leży problem i chcesz to tylko potwierdzić, ale w większości przypadków umiejętne posługiwanie się debuggerem oszczędzi Ci wiele czasu i nerwów.
Ustawiamy breakpointy w Eclipse
Pierwszym krokiem w debugowaniu jest ustawienie breakpointów. Można to zrobić na dwa sposoby:
Są one równoważne i działają w taki sam sposób. Aby usunąć breakpoint, postępujemy w analogiczny sposób.
Breakpointy ustawiamy w linijkach, w których jest kod! Tzn. Nie ustawiamy ich na sygnaturze metody, na klamrach itp. Warunkiem zatrzymania się działania programu jest wykonanie linijki oznaczonej breakpointem — jeśli nasz breakpoint znajduje się w bloku if (), który nie zostanie wykonany, to breakpoint także nie zadziała.
Jeśli chodzi o lokalizację breakpointów, to ustawiamy je przed miejscem, w którym podejrzewamy, że może wystąpić problem. Breakpointów możemy mieć wiele w naszej aplikacji, działanie programu będzie wtedy wstrzymywane za każdym razem, kiedy Java natrafi na breakpoint. Po zatrzymaniu działania programu nie można ‘cofnąć’ się, musismy ustawić breakpoint wcześniej i ponownie uruchomić debugowanie. Dlatego w wym przypadku, często więcej == lepiej :)
Co ważne, działanie programu zostanie wstrzymane przed oznaczoną linią — tzn nie zostanie ona jeszcze wykonana w momencie zatrzymania kodu.
Debugowanie aplikacji w Eclipse
Debugowanie aplikacji pod Eclipse sprowadza się do jej uruchomienia w szczególny sposób — zamiast standardowego przycisku, używamy tego, oznaczonego ikoną robaczka:
Aplikacja uruchomi się wtedy (możliwe jest także uruchomienie w ten sposób np. serwera Tomcat) w trybie debugowania, po napotkaniu na pierwszy breakpoint Eclipse zaproponuje zmianę perspektywy na ‘Debug’ , na co się zgadzamy. Zobaczymy wtedy poniższy ekran:
Poza standardowymi oknami znanymi nam już z normalnej perspektywy Java, mamy tutaj dodatkowe: Debug, Variables oraz Breakpoints.
Okno Breakpoints to lista wszystkich breakpointów (możemy się między nimi łatwo przełaczać szukając czegoś w kodzie).
Okno Debug dostarcza nam informacji o wątku, który został wstrzymany, jak wygląda stos wywołań (która funkcja jakiej klasy została użyta, żeby wywołać naszą funkcję — jest to po prostu kontekst, w jakim dany fragment kodu został wywołany).
Trzecie okienko — Variables — jest prawdopodobnie najczęściej używane, a dostarcza nam informację o wszystkich zmiennych, jakie są dostępne w tym miejscu. Warto zrwrócić uwagę na to, co wspominałem wcześniej — w tej linijce zmienna i nie jest jeszcze widoczna. W tym okienku możemy podejrzeć wartość tej zmiennej a także, jesli ma ona jakieś pola, podejrzeć ich wartości. Dzięki temu mamy obraz tego co ‘widzi’ program w danym momencie. Nie możemy jednak zmieniać tych wartości.
W ten sposób możemy uzyskać informację co dzieje się ‘w tym momencie’, przejdźmy zatem do ‘podążania’ za kodem — wykonywania programu krok po kroku.
Sterowanie działaniem programu w trybie debugowanie
Do sterowania działaniem programu służą nam dwie grupy przycisków (Eclipse oferuje znacznie więcej opcji, ale te 6 przycisków jest podstawowa i znajdziesz je w każdym IDE)
Sterowanie procesem debugowania
Te przyciski pozwalają nam na wznowienie działania programu po jego zatrzymaniu przez breakpoint (przycisk po lewej) lub zakończeniu go całkowicie (przycisk po prawej). Środkowy przycisk pozwala ‘wstrzymać’ działanie programu ręcznie.
Sterowanie działaniem
Te przyciski są bardziej interesujące, bo pozwalają nam kontrolować działanie programu ‘krok po kroku’. Przyciski te w kolejności od lewej do prawej to:
- Step into (klawisz skrótu: F5) — wykonuje jedną operację (przechodzi linijkę dalej). Jeśli obecna linijka była wywołaniem funkcji, przechodzi do wnętrza tej funkcji
- Step over (F6) — wykonuje jedną operację (przechodzi linijkę dalej). Jeśli obecna linijka była wywołaniem funkcji, wykonuje ją i wznawia debugowanie po jej wykonaniu
- Step return (F7) — kontynuuje działanie aż do końca bieżącej metody i wraca do trybu debugowania po zrwóceniu wartości z tej metody
Najczęściej będziesz używała środkowej opcji — używanie F5 szybko przeniesie Cie do getterów i setterów oraz metod języka, gdzie łatwo się pogubić (wtedy możesz użyć F7, aby ‘wrócić’ poziom wyżej). Te trzy proste operacja pozwalają wykonywać kod programu linijka po linijce.
Podsumowanie
W tej lekcji nauczyłaś się, jak debugować aplikację — szukać błedów poprzez ręczną analizę jej stanów (porównywanie wartości zmiennych w danym miejscu z oczekiwanymi, sprawdzanie warunków itp). Dzięki temu będziesz w stanie znaleźć źródło problemów szybciej i usunąć problem :)
To także ostatnia lekcja z cyklu kursu Javy — wiedza w nim zawarta jest wystarczająca, abyś samodzielnie zaczęła się rozwijać w programowaniu, ćwiczyła, praktykowała i samodzielnie poszukiwała informacji.
To jednak zdecydowanie nie koniec! Zachęcamy do czytania serii Niezbędnik Juniora oraz Pierwsza praca w IT, gdzie część informacji być może będzie się powtarzać, ale część będzie też nowa. Sam kurs Javy także będzie lekko ewoluował — pojawią się czasem rozszerzenia lekcji, uzupełnimy rozwiązania, będziemy go przeglądać w poszukiwaniu elementów, które moglibyśmy poszerzyć albo uprościć.
Czekamy też na informacje od Was, czytelników, bo to dla Was ten blog istnieje :) Piszcie w komentarzach, co chciałybyście zobaczyć na blogu w przyszłości lub czym chciałybyście, abyśmy się zajęli. Czekamy na informacje od Was, byśmy wspólnie poszerzali naszą wiedzę z Javy!
Jeśli uważasz powyższą lekcję za przydatną, mamy małą prośbę: polub nasz fanpage. Dzięki temu będziesz zawsze na bieżąco z nowymi treściami na blogu ( i oczywiście, z nowymi częściami kursu Javy). Dzięki!