W walce o jakość kodu

post_img

Wielu programistów, zwłaszcza początkujących, nie zwraca uwagi na jakość kodu, który tworzą. Czasami brak nam czasu lub wiedzy na wytworzenie kodu, który – poza tym że działa – jest czytelny, zrozumiały i wydajny. Jakość kodu to nie tylko sławne „do not repeat yourself” (swoją drogą często zapomniane…), ale także całe zestawy reguł dbające o prostotę utrzymania, łatwość zrozumienia, wydajność itd. Na szczęście nie musimy znać ich wszystkich, bo istnieją narzędzia które mogą nas wspierać w pisaniu kodu wysokiej jakości. Jedno z nich chciałbym przedstawić w tym artykule – jest to Sonar.

Sonar to opensource’owy projekt, który wykorzystuje najpopularniejsze zewnętrzne narzędzia do sprawdzania jakości kodu – pmd, findbugs czy checkstyle. Wyniki prezentowane są na stronie WWW. Ponieważ najlepiej temat poznawać na przykładzie, zainstalujmy Sonara i sprawdźmy jak to wygląda w praktyce.

Przede wszystkim potrzebujemy Sonara – można pobrać go z http://sonar.codehaus.org/downloads/ . Na potrzeby tego artykułu pobrałem wersję 2.1.2.

Dostarczany jest jako paczka zip/tar,  po rozpakowaniu aplikacja jest gotowa do pracy. Żadne wyrafinowane mechanizmy instalacji czy konfiguracji nie są wymagane – wystarczy wejść do folderu Sonara i uruchomić

bin\windows-x86-32\StartSonar.bat

w przypadku systemu operacyjnego Windows lub wybrać odpowiedni skrypt dla swojej wersji OS (dostępna jest spora ilość skryptów na systemy Linux, UNIX czy Mac OS). Po bardziej zaawansowaną konfigurację odsyłam do dokumentacji

W wyniku działania powinniśmy dostać nowe okienko powłoki. Nie należy się martwić, jeżeli jest puste – zależnie od wersji Sonara którą pobraliśmy, czasami będziemy widzieć w nim log aplikacji, a w innych wersjach log domyślnie zapisywany jest do pliku. Aplikacja Sonar dostępna jest pod adresem http://localhost:9000/

Jeżeli wszystko poszło dobrze, powinniśmy otrzymać stronę główną Sonara

Po kliknięciu odnośnika ‘Configuration’ zostaniemy przeniesieni na stronę z listą profili jakościowych domyślnie zdefiniowanych w Sonarze. Oczywiście nic nie stoi na przeszkodzie, aby zdefiniować własny styl – każda reguła posiada dokładny opis, czego dotyczy. A reguł jest aż 706. Jest więc z czego wybierać, tworząc własne profile jakości. Ja pozostanę przy domyślnym „Sonar way” – zbiera najczęstsze błędy i naruszenia.

Jeżeli zechcecie zmienić domyślny profil dla testów, najpierw należy się zalogować jako ‘admin’, domyślne hasło to również ‘admin’.

Aby wykonać analizę projektu, należy wykonać z linii komend polecenie

mvn sonar:sonar

Jeżeli nie masz zainstalowanego Mavena to najwyższa pora, by to zrobić – http://maven.apache.org/download.html Ponieważ nie jest to artykuł o Mavenie, pomijam opis instalacji i konfiguracji. Na stronie projektu są dostępne materiały dobrze opisujące te zagadnienia.

Prawdopodobnie po przeczytaniu powyższego akapitu pomyślałeś, że Sonar nie nadaje się do twoich projektów, bo nie korzystasz z Mavena. Nic bardziej mylnego. Sonar może przeanalizować każdy projekt w Javie. Wystarczy, że dodasz do niego plik pom.xml z następującą treścią

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
<project xmlns="http ://maven.apache.org/POM/4.0.0"
   xmlns:xsi="http ://www.w3.org/2001/XMLSchema-instance"
   xsi:schemaLocation="http ://maven.apache.org/POM/4.0.0 http ://maven.apache.org/xsd/maven-4.0.0.xsd">

   <modelVersion>4.0.0</modelVersion>
   <groupId>pl.atena</groupId>
   <artifactId>test2</artifactId>
   <name>Test2</name>
   <version>1.0</version>

   <build>
      <sourceDirectory>C:\projekt\zrodla</sourceDirectory>
      <plugins>
         <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-compiler-plugin</artifactId>
            <configuration>
               <source>1.5</source>
               <target>1.5</target>
               <excludes>
                  <exclude>**/*.*</exclude>
               </excludes>
            </configuration>
         </plugin>
      </plugins>
   </build>
   <properties>
      <sonar.dynamicAnalysis>false</sonar.dynamicAnalysis>
   </properties>
</project>

W pliku definiujemy nazwę projektu, którego dotyczy analiza oraz ścieżkę do katalogu z plikami źródłowymi projektu. W katalogu, w którym jest nasz plik wywołujemy z listy poleceń

mvn sonar:sonar

W efekcie powinnien pojawić się taki trace:

C:\Documents and Settings\adama\workspace\SonarTest\src>mvn sonar:sonar
[INFO] Scanning for projects...
[INFO] Searching repository for plugin with prefix: 'sonar'.
[INFO] ------------------------------------------------------------------------
[INFO] Building SonarTest
[INFO]    task-segment: [sonar:sonar] (aggregator-style)
[INFO] ------------------------------------------------------------------------
[INFO] [sonar:sonar]
[INFO] Sonar host: http://localhost:9000
[INFO] Sonar version: 2.1.2
[INFO] [sonar-core:internal]
[INFO]  Database dialect class org.sonar.api.database.dialect.Derby
[INFO]  -------------  Analyzing SonarTest
[INFO]  Selected quality profile : Sonar way, language=java
[INFO]  Configure maven plugins...
[INFO]  Sensor SquidSensor...
[INFO]  Java AST scan...
[INFO]  Java AST scan done: 265 ms
[INFO]  Squid extraction...
[INFO]  Squid extraction done: 906 ms
[INFO]  Sensor SquidSensor done: 1250 ms
[INFO]  Sensor JavaSourceImporter...
[INFO]  Sensor JavaSourceImporter done: 3188 ms
[INFO]  Sensor AsynchronousMeasuresSensor...
[INFO]  Sensor AsynchronousMeasuresSensor done: 625 ms
[INFO]  Execute maven plugin maven-pmd-plugin...
[INFO] ------------------------------------------------------------------------
[INFO] Building SonarTest
[INFO]    task-segment: [org.apache.maven.plugins:maven-pmd-plugin:2.4:pmd]
[INFO] ------------------------------------------------------------------------
[INFO] [pmd:pmd]
[WARNING] Unable to locate Source XRef to link to - DISABLED
[WARNING] File encoding has not been set, using platform encoding Cp1250, i.e. b
uild is platform dependent!
[INFO]  Execute maven plugin maven-pmd-plugin done: 5265 ms
[INFO]  Sensor PmdSensor...
[INFO]  Sensor PmdSensor done: 3375 ms
[INFO]  Sensor ProfileSensor...
[INFO]  Sensor ProfileSensor done: 16 ms
[INFO]  Sensor ProjectLinksSensor...
[INFO]  Sensor ProjectLinksSensor done: 94 ms
[INFO]  Sensor VersionEventsSensor...
[INFO]  Sensor VersionEventsSensor done: 156 ms
[INFO]  Execute maven plugin maven-checkstyle-plugin...
[INFO] ------------------------------------------------------------------------
[INFO] Building SonarTest
[INFO]    task-segment: [org.apache.maven.plugins:maven-checkstyle-plugin:2.4:ch
eckstyle]
[INFO] ------------------------------------------------------------------------
[INFO] [checkstyle:checkstyle]
[WARNING] File encoding has not been set, using platform encoding Cp1250, i.e. b
uild is platform dependent!
[WARNING] Unable to locate Source XRef to link to - DISABLED
[INFO]  Execute maven plugin maven-checkstyle-plugin done: 8984 ms
[INFO]  Sensor CheckstyleSensor...
[INFO]  Sensor CheckstyleSensor done: 172 ms
[INFO]  Sensor CpdSensor...
[INFO]  Sensor CpdSensor done: 94 ms
[INFO]  Sensor Maven dependencies...
[INFO]  Sensor Maven dependencies done: 15 ms
[INFO]  Execute decorators...
[INFO]  ANALYSIS SUCCESSFUL, you can browse http://localhost:9000
[INFO]  Database optimization...
[INFO]  Database optimization done: 453 ms
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESSFUL
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 1 minute 5 seconds
[INFO] Finished at: Thu Jun 17 09:22:21 CEST 2010
[INFO] Final Memory: 22M/40M
[INFO] ------------------------------------------------------------------------

Po odświeżeniu strony głównej Sonara powinny pojawić się informacje o przeanalizowanym projekcie

Klikając w nazwę projektu zagłębiamy się w szczegóły:

Z tego miejsca możemy jeszcze głębiej zajrzeć, np. w konkretny typ błędów:

Wybierając konkretny błąd, możemy podejrzeć, w którym miejscu w kodzie wystąpiło naruszenie.

Po takiej analizie jak na dłoni widać gdzie i jakie naruszenia popełniliśmy.

Dodatkową istotną funkcjonalnością jest możliwość integracji bezpośrednio z IDE.
W tej chwili Sonar posiada wtyczki do Eclipse i IntelliJ IDEA. W fazie budowy jest też wtyczka do NetBeans. W tym przykładzie skupię się na Eclipse.

Wtyczkę do Eclipse pobieramy z update site http://dist.sonar-ide.codehaus.org/eclipse/
Po instalacji przechodzimy do Window -> Preferences -> Sonar. Możemy zdefiniować nową instancję Sonara, ale domyślnie powinniśmy mieć dodaną już lokalną wersję. Po kliknięciu przycisku  ‘Edit’ możemy sprawdzić czy połączenie z Sonarem działa.


Następnie klikamy prawym na naszym projekcie, wybieramy ‘Properties i w zakładce Sonar upewniamy się, że jesteśmy podpięci do poprawnej instancji Sonara

Jeżeli wszystko się zgadza, ponownie klikamy prawym na projekt, wybieramy Sonar -> Associate Project with Sonar, a potem jeszcze prawy -> Sonar -> Refresh Violations.

Po tych zabiegach nasz kod zostanie zbadany przez Sonara i wszelkie naruszenia zostaną podświetlone oraz dodany stosowny komentarz:

Niestety Eclipse pobiera tylko listę naruszeń z serwera Sonara, więc istnieje możliwość że otrzymamy zgłoszenia dotyczące linii kodu, które nie są błędne, a nawet nie istnieją lub są puste. Jeżeli chcemy otrzymać świeżą listę naruszeń, dokładnie odpowiadającą naszej wersji kodu musimy z linii poleceń wywołać

mvn sonar:sonar

w katalogu z plikiem pom.xml naszego projektu.

A to jeszcze nie wszystko – przecież rozwój prawdziwych aplikacji to nie tylko development i budowa projektów w IDE. Często większe projekty wykorzystują środowiska Continues Integration do budowy i weryfikacji poprawności kodu. Jednym z takich narzędzi jest Hudson. Sonar wpasowuje się w trend CI dostarczając wtyczkę do Hudsona umożliwiającą weryfikację jakości kodu po każdej budowie projektu. Wtyczka do pobrania jest na stronie http://wiki.hudson-ci.org/display/HUDSON/Sonar+plugin. Dokładne informacje o mechanizmach Hudsona dostępne są na stronie projektu, ja skupię się tylko na konfiguracji połączenia z Sonarem.

Po uruchomieniu Hudsona przechodzimy do „Manage Hudson” -> „Manage Plugins” -> „Advanced”. Tam ładujemy pobrany plik z wtyczką Sonara i restartujemy Hudsona.
Następnie przechodzimy do „Manage Hudson”->”Configure System” i na samym dole dokonujemy konfiguracji instancji Sonara – jeżeli wszystko instalowaliśmy z domyślnymi wartościami nasza konfiguracja ogranicza się jedynie do podania nazwy identyfikacyjnej daną instancję Sonara

Po dokonaniu konfiguracji przechodzimy do utworzenia zadania kompilującego i wykonującego weryfikację jakościową. Wybieramy „New Job” -> „Build a free-style software Project”. Dokonujemy standardowej konfiguracji zadania podając namiary na SCM i metody budowania (maven, ant itp.) – po szczegóły odsyłam do dokumentacji.
Dla nas najistotniejsza jest sekcja „Post-build Actions”. Zaznaczamy opcję „Sonar” i wypełniamy interesujące nas pola. Co ciekawe, z poziomu Hudsona nie potrzebujemy pliku pom.xml, możemy dodać odpowiednie parametry w definicji akcji

Po zapisaniu i wykonaniu builda powinien pojawić się taki trace

…
[SonarTest] $ D:\apache-maven-2.1.0\bin\mvn.bat -e -B -f sonar-pom.xml sonar:sonar
+ Error stacktraces are turned on.
[INFO] Scanning for projects...
[INFO] Searching repository for plugin with prefix: 'sonar'.
[INFO] ------------------------------------------------------------------------
[INFO] Building SonarTest
[INFO]    task-segment: [sonar:sonar] (aggregator-style)
[INFO] ------------------------------------------------------------------------
[INFO] [sonar:sonar]
[INFO] Sonar host: http://localhost:9000
[INFO] Sonar version: 2.1.2
[INFO] [sonar-core:internal]
[INFO]  Database dialect class org.sonar.api.database.dialect.Derby
[INFO]  -------------  Analyzing SonarTest
[INFO]  Selected quality profile : Sonar way, language=java
[INFO]  Configure maven plugins...
[INFO]  Sensor SquidSensor...
[INFO]  Java AST scan...
[INFO]  Java AST scan done: 312 ms
[INFO]  Squid extraction...
[INFO]  Squid extraction done: 344 ms
[INFO]  Sensor SquidSensor done: 719 ms
[INFO]  Sensor JavaSourceImporter...
[INFO]  Sensor JavaSourceImporter done: 78 ms
[INFO]  Sensor AsynchronousMeasuresSensor...
[INFO]  Sensor AsynchronousMeasuresSensor done: 47 ms
[INFO]  Execute maven plugin maven-pmd-plugin...
[INFO] ------------------------------------------------------------------------
[INFO] Building SonarTest
[INFO]    task-segment: [org.apache.maven.plugins:maven-pmd-plugin:2.4:pmd]
[INFO] ------------------------------------------------------------------------
[INFO] [pmd:pmd]
[WARNING] Unable to locate Source XRef to link to - DISABLED
[WARNING] File encoding has not been set, using platform encoding Cp1250, i.e. build is platform dependent!
[INFO]  Execute maven plugin maven-pmd-plugin done: 5265 ms
[INFO]  Sensor PmdSensor...
[INFO]  Sensor PmdSensor done: 859 ms
[INFO]  Sensor ProfileSensor...
[INFO]  Sensor ProfileSensor done: 0 ms
[INFO]  Sensor ProjectLinksSensor...
[INFO]  Sensor ProjectLinksSensor done: 16 ms
[INFO]  Sensor VersionEventsSensor...
[INFO]  Sensor VersionEventsSensor done: 31 ms
[INFO]  Execute maven plugin maven-checkstyle-plugin...
[INFO] ------------------------------------------------------------------------
[INFO] Building SonarTest
[INFO]    task-segment: [org.apache.maven.plugins:maven-checkstyle-plugin:2.4:checkstyle]
[INFO] ------------------------------------------------------------------------
[INFO] [checkstyle:checkstyle]
[WARNING] File encoding has not been set, using platform encoding Cp1250, i.e. build is platform dependent!
[WARNING] Unable to locate Source XRef to link to - DISABLED
[INFO]  Execute maven plugin maven-checkstyle-plugin done: 9219 ms
[INFO]  Sensor CheckstyleSensor...
[INFO]  Sensor CheckstyleSensor done: 187 ms
[INFO]  Sensor CpdSensor...
[INFO]  Sensor CpdSensor done: 157 ms
[INFO]  Sensor Maven dependencies...
[INFO]  Sensor Maven dependencies done: 15 ms
[INFO]  Execute decorators...
[INFO]  ANALYSIS SUCCESSFUL, you can browse http://localhost:9000
[INFO]  Database optimization...
[INFO]  Database optimization done: 219 ms
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESSFUL
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 27 seconds
[INFO] Finished at: Thu Jun 17 11:12:20 CEST 2010
[INFO] Final Memory: 22M/40M
[INFO] ------------------------------------------------------------------------
Finished: SUCCESS

W tym momencie możemy przejść na stronę główną aplikacji Sonara żeby sprawdzić wyniki weryfikacji.

Łącząc razem te trzy narzędzia otrzymujemy prawdziwy kombajn do weryfikacji poprawności i jakości tworzonych aplikacji. Korzyści są ogromne:
1. developerzy tworząc kod danych modułów na bieżąco widzą naruszenia jakościowe
2. kod oddany do SCM jest pobierany przed Hudsona i regularnie raz na dobę uruchamiana jest procedura budowy całej aplikacji, która sprawdza, czy całość aplikacji się kompiluje i buduje, a następnie jest poddawana weryfikacji przez Sonara
3. weryfikacje jakości wywoływane przez Hudsona są zapisywane w bazie danych Sonara, a zatem możemy obserwować trendy w jakości kodu oraz korzystać ze wszystkich dobrodziejstw Sonara nie obciążając go nadmierną ilością weryfikacji wywoływanych przez developerów.

Podsumowując – Sonar jest kompleksowym narzędziem do weryfikacji jakości kodu. Może być wykorzystywany zarówno do szybkiej lokalnej weryfikacji jak i przy budowie bardziej złożonych aplikacji w systemach CI. Jest to narzędzie, które zdecydowanie warto posiadać i wykorzystywać by budować dobrej jakości aplikacje.

Źródła:
http://docs.codehaus.org/display/SONAR/Documentation
http://wiki.hudson-ci.org/display/HUDSON/
http://maven.apache.org


Dodaj komentarz

Twój adres email nie zostanie opublikowany. Pola, których wypełnienie jest wymagane, są oznaczone symbolem *

2 komentarzy do “W walce o jakość kodu

  • Tomek N.

    Witam,

    ostatnimi czasy przeforsowałem instalację Sonara w mojej firmie i od kilku tygodni blisko 20 projektów cieszy moje oczy każdego ranka. Muszę przyznać, że oglądanie takich statystyk potrafi być wciągające. I tu nadmienię bodaj najciekawszą cechę Sonara: każda metryka (ilość linii, naruszone reguły, pokrycie kodu, etc.) jest wersjonowana i można oglądać jej zmiany w czasie na ekranie Time Machine. Widok jak zmieniało się pokrycie kodu testami vs. ilość LOC na przestrzeni wielu miesięcy i wersji jest bardzo ciekawy.

  • devlab

    Przy analizie dużych projektów piętą achillesową Sonara jest jego wydajności – potrafi ostro przycisnąć maszynę. Druga rzecz to trzeba poświęcić trochę czasu, aby przystosować analizatory kodu (pmd/findbugs/checkstyle) do reguł panujących w danej organizacji – bez tego zostaniemy zarzuceni mnóstwem mało istotnych informacji z których ciężko będzie wyciągnąć coś godnego uwagi.