#26 – debugowanie aplikacji

By 21 maja 2015Kurs Javy

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:

Klikamy prawym przyciskiem myszy na szare pole obok edytora kodu i z menu wybieramy 'Toggle breakpoint'

Klikamy prawym przyciskiem myszy na szare pole obok edytora kodu i z menu wybieramy ‚Toggle breakpoint’


Dwukrotnie klikamy obok linii, na którą chcemy ustawić breakpoint

Dwukrotnie klikamy obok linii, na którą chcemy ustawić breakpoint

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

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:

Widok Eclipse w perspektywie 'Debug'

Widok Eclipse w perspektywie ‚Debug’

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

Screenshot_5

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

Screenshot_6

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!

Licencja Creative Commons

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!

  •  
  •  
  •  
  •  
  •  
  • Damian Skórka

    Hej :)

    Na wstępie chciałbym pozdrowić autorów tego bloga, kawał dobrej roboty :)
    Miło czytać blog który żyje.

    Czy opiszecie może kiedyś jak debugować aplikacje webowe ?
    Dość często używam debugera do zwykłych aplikacji dekstopowych. Teraz uczę się Spring MVC i nie mogę się odnaleźć jak tu się używa debugera ;/

    pozdrawiam,
    Damian

    • Cześć,

      zasada jest identyczna – możesz używać tego samego debuggera. Jak skonfigurować zależy od tego, jak uruchamiasz aplikacje. Jeśli robisz to lokalnie, z poziomu Eclipse, uruchomienie serwera jako Debug (tak jak normalnej aplikacji) zadziała identycznie jak z aplikacją desktopową.

      Możliwe jest też debugowanie zdalne – tutaj konfiguracja zależy przede wszystkim od tego, z jakiego IDE, z jakiego serwera korzystasz i jak go uruchamiasz. Na pewno potrzebujesz bezpośredniego dostępu do serwera, na których chcesz debugować. Przykład konfiguracji (musisz ją wykonać po obu stronach – w Eclipse i na serwerze osobno) znajdziesz np tutaj: http://wiki.apache.org/tomcat/FAQ/Developing#Debugging

      Jeśli chodzi o metodykę to jest tutaj trochę więcej zabawy – musisz za pomocą zapytania HTTP (albo czekając, itp – w zależności od elementu, który chcesz debugować) wywołać odpowiedni fragment, reszta jest prawie identyczna (inny będzie tylko stos – znajdziesz tam na początku sporo Springowych obiektów, ale zorientowanie się nie powinno zająć dużo czasu)

      Gdybyś miał problemy z konfiguracją czy podejściem daj znać, spróbujemy pomóc.

  • jumpinJackFlash

    Cześć,
    Nie chcę wyjść na czepialską osobę, ale Grace Hopper była kobietą, dlatego w zdaniu „…przypisuje się admirał Grace Hopper, pracującemu w latach 40-tych ubiegłego wieku przy komputerze Mark II” może warto zmienić na „pracującej”? ;)
    Pozdrawiam ^^