Praktyczna Java: FindBugs

By 20 December 2017 Praktyczna Java

W więk­szoś­ci pro­jek­tów z cza­sem pojaw­ia­ją się drob­ne prob­le­my i niedo­ciąg­nię­cia — cza­sem wynika­jące z poś­piechu, cza­sem z nieuwa­gi. W przeszłoś­ci opisy­wal­iśmy już Check­style — narzędzie, które pomoże Ci utrzy­mać stan­dardy for­ma­towa­nia na wysokim poziomie, a także Sonar­Qube — paki­et do śledzenia długu tech­nicznego w pro­jek­cie. Dzisi­aj zajmiemy się ostat­nim przed­staw­icielem ‘wielkiej trój­ki’ — Find­Bugs, który szu­ka potenc­jal­nych prob­lemów w kodzie!

Find­Bugs to opro­gramowanie opra­cow­ane na uni­w­er­syte­cie w Mary­land, którego celem jest — podob­nie jak w przy­pad­ku pozostałych wymienionych — staty­cz­na anal­iza kodu. Zasa­da dzi­ała­nia jest jed­nak inna — sprawdza nie tyle zgod­ność z ustalonym wcześniej stylem, co potenc­jalne prob­le­my i błędy w aplikacji (np. mody­fikowanie zmi­en­nych, które są argu­men­ta­mi metody itp). O ile inte­grac­ja z pro­jek­tem rozwi­janym przez lata może przypraw­ić o ból głowy pod kątem iloś­ci zalezionych prob­lemów, częs­to zgłaszane prob­le­my są warte popraw­ienia, a przy­na­jm­niej sprawdzenia.

Użycie FindBugs

Podob­nie jak w przy­pad­ku innych narzędzi, Find­Bugs także może­my uży­wać z poziomu lini komend, środowiska IDE jak i bezpośred­nio w ramach Mave­na, jako część pro­ce­su budowa­nia projektu.

Z użyciem linii komend / GUI

Find­Bugs ofer­u­je graficzny inter­fe­js użytkown­i­ka, za pomocą którego może­my dokon­ać anal­izy wybranych klas czy pro­jek­tu. Aby uru­chomić inter­fe­js graficzny, wystar­czy uru­chomić plik JAR z pro­jek­tem — dwukrot­nie na niego klika­jąc lub uruchami­a­jąc z linii komend, np. polece­niem java ‑jar findbugs.jar ‑gui . Po skon­fig­urowa­niu pro­jek­tu za pomocą GUI możli­we jest uruchami­an­ie sprawdza­nia za pomocą linii komend (co może być przy­datne w przy­pad­ku automatyza­cji). Szczegółowe infor­ma­c­je na tem­at uży­wa­nia graficznego inter­fe­j­su, linii komend oraz dostęp­nych opcji moż­na znaleźć w doku­men­tacji pro­jek­tu.

W prak­tyce ten sposób uży­wa­nia jest najm­niej wygod­ny i o ile jest to możli­we, zachę­camy do korzys­ta­nia z inte­gracji z Maven­em oraz środowiskiem IDE. Możli­wość kon­fig­u­racji z linii komend jest nadal przy­dat­na w starszych pro­jek­tach, które korzys­ta­ją z archaicznych lub nie­s­tandar­d­owych sys­temów budowania.

Wtyczka do Eclipse

W przy­pad­ku Eclipse, wty­cz­ka ta jest dostęp­na w Mar­ket­place. Zwróć uwagę, że dla najnowszych wer­sji Eclipse nazy­wa się ona Spot­Bugs, not Find­Bugs! Insta­lac­ja sprowadza się do kliknię­cia w ‘Install’:

 

Okno Eclipse Mar­ket­place z opcją insta­lacji SpotBugs

Po insta­lacji plu­g­in powinien być gotowy do dzi­ała­nia. Aby uru­chomić anal­izę, z menu kon­tek­stowego (pro­jek­tu, paki­etu lub klasy) wybier­amy opcję ‘Spot­Bugs’:

W efek­cie plu­g­in oznaczy znalezione błędy w następu­ją­cy sposób:

Mark­er znalezionego problemu

Odnośni­ki:

Wtyczka do IntelliJ IDEA

Podob­nie jak w przy­pad­ku Eclipse, także do środowiska Intel­liJ IDEA są dostęp­ne wtyczki:

Jako element buildu Mavenowego

Poza kon­fig­u­racją IDE warto także dodać Find­Bugs do kon­fig­u­racji Mave­na w pro­jek­cie. Dzię­ki temu sprawdze­nie będzie się odby­wało także pod­czas budowa­nia pro­jek­tu — dodatkowy stopień ‘ochrony’ naszego pro­jek­tu przed niepożą­dany­mi problemami.

Kon­fig­u­rac­ja sprowadza się do doda­nia plug­inu do naszego pliku pom.xml — szczegóły opisane są oczy­wiś­cie w doku­men­tacji. Pod­sta­wowa kon­fig­u­rac­ja może wyglą­dać następująco:

<project>
  ...
  <build>
    <plugins>
      <plugin>
        <groupId>org.codehaus.mojo</groupId>
        <artifactId>findbugs-maven-plugin</artifactId>
        <version>3.0.6-SNAPSHOT</version>
        <configuration>
          <effort>Max</effort>
          <threshold>Low</threshold>
          <xmlOutput>true</xmlOutput>
        </configuration>
        <executions>
          <execution>
            <goals>
              <goal>check</goal>
            </goals>
          </execution>
        </executions>
      </plugin>
    </plugins>
  </build>
  ...
</project>

Domyśl­nie sprawdze­nie uru­cho­mi się w fazie ver­i­fy, co może­my oczy­wiś­cie zmienić w kon­fig­u­racji plug­inu. Dostęp­ne opc­je oraz ich znacze­nie stan­dar­d­owo zna­j­du­ją się w doku­men­tacji. W przy­pad­ku znalezienia błędów w pro­jek­cie, Maven zatrzy­ma pro­ces budowa­nia z błę­dem i infor­ma­cją o lokaliza­cji rapor­tu FindBugs.

Znajdywane problemy

Find­Bugs wyszuku­je różnego rodza­ju prob­lemów, które grupu­je w kat­e­gorie. Wszys­tkie prob­le­my, wraz z konkret­nym plikiem i numerem linii, są zawarte w rapor­cie gen­erowanym pod­czas sprawdzenia — raport gen­erowany jest zarówno jako plik HTML (do stan­dar­d­owego wglą­du przez pro­gramistę) — jak i w for­ma­cie XML (możli­wym do wyko­rzys­ta­nia przy automatyzacji).

Listę wyszuki­wanych prob­lemów wraz z opisa­mi moż­na znaleźć na stron­ie pro­jek­tu. Opisy te są także zawarte w rapor­cie gen­erowanym pod­czas sprawdzenia.

Własne (lub po prostu dodatkowe) sprawdzenia

W niek­tórych pro­jek­tach konieczne jest sprawdze­nie specy­ficznych aspek­tów lub kon­wencji, które wynika­ją ze środowiska pro­jek­tu lub prak­tyk przyję­tych w fir­mie. Find­Bugs pozwala nam na to umożli­wia­jąc pisanie włas­nych detek­torów (ang. Detec­tors). Ponieważ stworze­nie włas­nego detek­to­ra jest dość skom­p­likowane i koniecz­na jest wiedza na tem­at staty­cznej anal­izy kodu oraz par­sowa­nia, ograniczymy się jedynie do odesła­nia do zewnętrznych materiałów:

Ignorowanie problemów

Find­Bugs jest jed­nak tylko narzędziem do staty­cznej anal­izy kodu — cza­sem zna­jdy­wane ‘błędy’ nie są fak­ty­czny­mi prob­le­ma­mi, a celowym dzi­ałaniem pro­gramisty. W takiej sytu­acji Find­Bugs pozwala nam ignorować określone prob­le­my (wraz z podaniem uza­sad­nienia). Pier­wot­nie wyma­gało to doda­nia odpowied­niej kon­fig­u­racji w XML (opis moż­na nadal znaleźć w doku­men­tacji), my jed­nak sko­rzys­tamy z wygod­niejszego rozwiąza­nia — adno­tacji. Aby móc je wyko­rzys­tać, przede wszys­tkim konieczne jest dodanie zależnoś­ci do projektu:

<dependency>
  <groupId>net.sourceforge.findbugs</groupId>
  <artifactId>annotations</artifactId>
  <version>3.0.1</version>
  <scope>provided</scope>
</dependency>

Zwróć uwagę na scope — adno­tac­je te potrzeb­ne są tylko pod­czas budowa­nia pro­jek­tu, w przy­pad­ku dzi­ała­jącej aplikacji nie mają znaczenia. Dodanie <scope>provided</scope> powodu­je, że zależność ta nie będzie dołąc­zona do zbu­dowanego pliku jar (lub war). Więcej o różnych wartoś­ci­ach scope zna­jdziesz w doku­men­tacji Mave­na, w tym wpisie poprzes­taniemy na ich użyciu :)

Mając dodaną zależność, kole­jnym krok­iem jest oznacze­nie prob­lematy­cznych miejsc adno­tacją @SupressFBWarning, np:

@SuppressFBWarnings(value="HE_EQUALS_USE_HASHCODE", justification="Ja wiem lepiej!!")
public void someOffensiveMethod() {
  //...
}

W ten sposób określony rodzaj błę­du będzie ignorowany w wybranej metodzie. Pamię­taj jed­nak, że jest to ostate­czność, uży­waj tej możli­woś­ci z dużym umi­arem i tylko kiedy jest abso­lut­nie konieczna!

Podsumowanie

Find­Bugs jest jed­nym z tych pro­jek­tów, które warto zawsze mieć ‘pod ręką’ — jeśli nie zin­te­growane z sys­te­mem budowa­nia, to na pewno ze środowiskiem. Find­Bugs ofer­u­je znacznie bogat­szą i bardziej kon­tek­stową anal­izę kodu niż inne, podob­ne rozwiąza­nia. Pomi­mo dość długiego cyk­lu roz­wo­jowego (kole­jne wer­sje wypuszczane są co kil­ka miesię­cy czy nawet lat — głównie w celu zapewnienia zgod­noś­ci z najnowszą wer­sją Javy), rozwiązanie to nie traci na aktualności.

Nieste­ty prob­le­mem bywa współpra­ca z narzędzi­a­mi typu Lom­bok — częs­to potrzeb­na jest dodatkowa kon­fig­u­rac­ja lub rapor­towane są błędy, które nie są fak­ty­czny­mi błę­da­mi. Mimo wszys­tko jest to narzędzie zde­cy­dowanie warte uwa­gi i doda­nia do swo­jego ‘przy­borni­ka’.

Na pod­staw­ie Find­Bugs pow­sta­je także sporo ciekawych pro­jek­tów pobocznych, np w formie plug­inów. Jed­nym z nich wartym uwa­gi jest find-sec-bugs — plu­g­in, który wyszuku­je błędy w kodzie związane z bez­pieczeńst­wem aplikacji.

Nazwa oraz logo Find­Bugs są włas­noś­cią Uni­w­er­syte­tu w Maryland.

FindBugs vs SpotBugs

W ostat­nim cza­sie moż­na znaleźć infor­ma­c­je na tem­at innego pro­duk­tu — Spot­Bugs. Pro­jekt ten jest forkiem Find­Bugs — inny­mi słowy ktoś wziął dostęp­ny kod i rozwi­ja go nieza­leżnie od pier­wot­nego pro­jek­tu. Powodów było zapewne wiele, na pewno nie poma­gało to, że ‘mar­ka’ Find­Bugs była włas­noś­cią uni­w­er­syte­tu oraz spra­wował on kuratelę nad pro­jek­tem. O ile nam wiado­mo, społeczność zgro­mad­zona wokół Find­Bugs raczej entuz­jasty­cznie odnosi się do zmi­any — moż­na więc mieć nadzieję, że pro­jekt będzie rozwi­jany pod tą marką. Na ten moment sposób dzi­ała­nia, UI i właś­ci­wie wszys­tkie inne ele­men­ty są kom­paty­bilne pomiędzy tymi pro­jek­ta­mi i nie ma za wiele różnic. Częś­ciej spo­tykana jest jed­nak nazwa Find­Bugs, dlat­ego zde­cy­dowal­iśmy się jej uży­wać w tym artykule. Niem­niej, zachę­camy do obser­wowa­nia repozy­to­ri­um Spot­Bugs — najpraw­dopodob­niej to tam będzie się odby­wał dal­szy rozwój projektu.