NDepend4 – co potrafi statyczna analiza kodu.

Dosta艂em NDepend4 w zamian za jego opis 馃檪 Nie musz臋 o nim m贸wi膰 w samych s艂odkich komentarzach, tak偶e mo偶na wpis czyta膰 do ko艅ca.
NDepend s艂u偶y to statycznej analizy kodu napisanego w .NET. Potrafi oceni膰 kod po wieloma wzgl臋dami, np: ze wzgl臋du na skomplikowanie, ilo艣膰 linii kod czy instrukcji IL, ilo艣膰 zmiennych, 艂atwo艣膰 modyfikacji, mo偶e zasugerowa膰 zmian臋 typ贸w z referencyjnych na warto艣ciowe (ref type –> value type).
Sama instalacja jest banalnie prosta, 艣ci膮gamy paczk臋 ze strony, rozpakowujemy oraz wrzucamy plik z licencj膮 :> Chyyyba 偶e jej nie macie, wtedy mo偶na skorzysta膰 z darmowej wersji 14 dniowej. To wszystko, potem wystarczy odpali膰 i za艂adowa膰 plik z solucj膮, kt贸r膮 chcieliby艣my si臋 bli偶ej przyjrze膰.

Do opisu wykorzystam swoj膮 pierwsz膮 aplikacj臋 na Windows Phone. Troch臋 wstyd, ale dla dobra ludzko艣ci trzeba si臋 czasem troch臋 po艣wi臋ci膰. Przy okazji, jest ona dost臋pna na Baazar (nieoficjalny marketplace dla Windows Phone 7) – nazywa si臋 CompactCal

Po uruchominiu NDepend mo偶na za艂adowa膰 plik solucji, kt贸r膮 chcemy podda膰 analizie. Nast臋pnie zostanie wy艣wietlona lista assemblies, kt贸re zostan膮 przeanalizowane:

Jak wida膰 mo偶e si臋 okaza膰, 偶e czego艣 b臋dzie brakowa膰, wtedy mo偶na doda膰 r臋cznie brakuj膮ce pliki (np. u偶ywaj膮c drag’n’drop) waln膮膰 OK. Warto zwr贸ci膰 uwag臋 z kt贸rej konfiguracji b臋d膮 brane: debug czy release.

Czary mary, czekamy chwil臋 i wybieram opcje Close dialog – chce wszystko sam zobaczy膰.
Pierwsze ciary na plecach, bo widz臋 ba艂agan w kodzie. Wszytko przez diagram zale偶no艣ci klas, u mnie wygl膮da on tak:

(Troch臋 si臋 obrazek rozjecha艂)
Ci z nas, kt贸rzy posiadaj膮 Visual Studio wy偶sz膮 ni偶 expres (i chyba pro te偶), mog膮 zna膰 ju偶 taki obrazek. Podobny widok mo偶na utworzy膰 w MVSC z menu Architecture -> Generate Dependency Graph -> By Assembly.
Og贸lnie rzecz ujmuj膮c wida膰 na nim, co od czego zale偶y i jak bardzo, im grubsza kreska tym wi臋cej zale偶no艣ci w kodzie. Mo偶e by膰 taka sytuacja 偶e ju偶 tutaj zauwa偶ymy zale偶no艣ci kt贸rych
nie powinno by膰. Mo偶e z jakiego艣 powodu nasz View si臋ga bezpo艣rednio
do serwis贸w z danymi, a mia艂 to robi膰 tylko ViewModel. Po rozwi膮zaniu takich problem贸w, ja najcz臋艣ciej usuwam  zale偶no艣ci od systemowy plik贸w, tak jest dla mniej przejrzy艣ciej.
Niestety ND (偶eby nie pisa膰 ci膮gle ca艂ej nazwy) nie potrafi sobie poradzi膰 z u艂o偶eniem kwadracik贸w tak, aby linie si臋 nigdzie nie przecina艂y. Nad czytelno艣ci膮 trzeba diagramu trzeba popracowa膰 samodzielnie. Nie wiem czemu, ale lubi臋 w艂a艣nie w ten spos贸b mie膰 u艂o偶one wszelkie diagramy.
Kolejnym innym widokiem zale偶no艣ci jest Matrix view, jest czytelniejszy ni偶 diagram powy偶ej, w przypadkach gdy jest bardzo du偶o obiekt贸w do analizy.

U mnie tego nie wida膰, ale gdy pojawi膮 si臋 cyferki na czarnym tle, oznacza膰 to b臋dzie zale偶no艣ci cykliczne. Cho膰 musz臋 si臋 przyzna膰, 偶e gdy po raz pierwszy uruchomi艂em ND na tym projekcie pewnie znalaz艂o by si臋 kilka czarnych miejsc. Na szcz臋艣cie od tamtego czasu zd膮偶y艂em poprawi膰 kod, a ten wpis powstaje du偶o p贸藕niej. Wida膰 na nim dok艂adnie zale偶no艣ci modu艂贸w, mo偶emy bada膰 zale偶no艣膰 na podstawie ilo艣ci wykorzystywanych metod, p贸l, namespaces, typ贸w zmiennych, i jeszcze kilku innych. ND potrafi tak偶e wykry膰 zale偶no艣ci nie bezpo艣rednie.
Po klikni臋ciu na jedno ze skrzy偶owa艅, zobaczymy jeszcze dok艂adniejszy diagram tego, gdzie i jak s膮 wykorzystywane te zale偶no艣ci, np. ViewModel vs. Helpers:

Do tego mo偶na wygenerowa膰 ciekawszy graph (Export Matrix Code Elements to Graph):

Co w wyniku da co艣 takiego:

W tym przypadku diagram zale偶no艣ci jest czytelny (linie si臋 nigdzie nie przecinaj膮).

To dopiero pocz膮tek, je艣li ju偶 pogodzili艣my si臋 ze skal膮 zale偶no艣ci w naszym kodzie warto przej艣膰 dalej i zobaczy膰 jakie regu艂y z艂amali艣my oraz gdzie. ND dostarcza ponad 80 zdefiniowanych regu艂. Mo偶emy samodzielnie je modyfikowa膰, dodawa膰 nowe oraz usuwa膰 te z nich , kt贸re naszym lub architekta odpowiedzialnego za projekt s膮 z jakiego艣 powodu nie potrzebne.

Tak bardzo 藕le nie jest, brak czerwonych k贸艂eczek.

Jak wida膰 powy偶ej istnieje kilka r贸偶nych grup zasad, z kt贸rych cz臋艣膰 zosta艂a w brzydki spos贸b naruszona, a cz臋艣膰 jest akceptowalna. Zobaczmy co zrobi艂em 藕le, sprawd藕my Code Quality (dwuklik i wida膰 szczeg贸艂y):

Ka偶da grupa sk艂ada si臋 znowu z kilku mniejszych regu艂, tutaj jak wida膰 mam najwyra藕niej problem ze zbyt du偶ymi klasami i metodami. Brakiem komentarzy si臋 nie przejmuje. M贸j kod komentuje si臋 sam – tak go wytresowa艂em.

Wa偶ne jest to 偶e parametry definiuj膮ce te regu艂y mo偶emy samodzielnie zmienia膰. Dla przyk艂adu domy艣lne aby metoda zosta艂a oznaczona za posiadaj膮c膮 zbyt du偶a ilo艣膰 parametr贸w,  musi posiada膰 ich wi臋cej ni偶 pi臋膰:

Metody zbyt du偶e musz膮 mie膰 wi臋cej ni偶 30 linii kodu lub wi臋cej ni偶 200 instrukcji IL.

Gdy ju偶 zdecydujemy si臋 obejrze膰 list臋 przewinie艅 s艂u偶y do tego osobny panel, ja sprawdz臋 kt贸r膮 z metod tak strasznie spas艂em kodem:

Ja mam dwa takie przypadki, gdzie ten drugi jest bliski warto艣ci granicznej. Aby obejrze膰 kod wystarczy dwuklik na wybranym przypadku. W wersji darmowej trzeba niestety r臋cznie znale藕膰 kod w MSVC.

.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: Consolas, „Courier New”, Courier, Monospace;
background-color: #ffffff;
/*white-space: pre;*/
}

.csharpcode pre { margin: 0em; }

.csharpcode .rem { color: #008000; }

.csharpcode .kwrd { color: #0000ff; }

.csharpcode .str { color: #a31515; }

.csharpcode .op { color: #0000c0; }

.csharpcode .preproc { color: #cc6633; }

.csharpcode .asp { background-color: #ffff00; }

.csharpcode .html { color: #800000; }

.csharpcode .attr { color: #ff0000; }

.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}

.csharpcode .lnum { color: #606060; }

   1:  public static WriteableBitmap GenerateBitmapImage(string aHeading, IEnumerable<string> aItems)
   2:  {
   3:      WriteableBitmap wbm = null;
   4:      StackPanel sp = new StackPanel();
   5:      sp.Margin = new Thickness { Left = 6, Bottom = 0, Right = 6, Top = 0 };
   6:      sp.Height = 173;
   7:      sp.Width = 173;
   8:      sp.Background = new SolidColorBrush(Colors.Transparent);
   9:   
  10:      if (!string.IsNullOrEmpty(aHeading))
  11:      {
  12:          TextBlock heading = new TextBlock();
  13:          heading.Style = (Style)Application.Current.Resources["PhoneTextTitle3Style"];
  14:   
  15:          heading.Text = aHeading;
  16:          heading.Height = 35;
  17:          heading.Width = 173;
  18:   
  19:          sp.Children.Add(heading);
  20:      }
  21:   
  22:      int maxitems = (string.IsNullOrEmpty(aHeading)) ? 5 : 6;
  23:      int c = 0;
  24:   
  25:      foreach (var item in aItems)
  26:      {
  27:          TextBlock tbAction = new TextBlock();
  28:          tbAction.Foreground = (SolidColorBrush)Application.Current.Resources["PhoneAccentBrush"];
  29:          tbAction.Text = item;
  30:          tbAction.Style = (Style)Application.Current.Resources["PhoneTextNormalStyle"];
  31:          tbAction.Margin = new Thickness(4, 0, 0, 0);
  32:          tbAction.Height = 27;
  33:          tbAction.Width = 173;
  34:          sp.Children.Add(tbAction);
  35:          if (c++ > maxitems)
  36:          {
  37:              break;
  38:          }
  39:      }
  40:   
  41:      //call measure, arrange and updatelayout to prepare for rendering
  42:      sp.Measure(new Size(173, 173));
  43:      sp.Arrange(new Rect(0, 0, 173, 173));
  44:      sp.UpdateLayout();
  45:   
  46:      wbm = new WriteableBitmap(173, 173);
  47:      wbm.Render(sp, null);
  48:      wbm.Invalidate();
  49:      return wbm;
  50:  }

Rzeczywi艣cie ca艂kiem sporo, kod z blok贸w IF oraz FOREACH mo偶na wyrzuci膰 do osobnych metod, tak samo ostatnie linijki z kodem kt贸ry wymusza render na bitmapie. Poprawi臋 to p贸藕niej 馃槈
To tylko jeden z wielu przypadk贸w, kt贸ry jest mo偶liwy do przeanalizowania w kodzie. Jak ju偶 napisa艂em ND domy艣lnie ma ich ponad 80. Na stronie domowej s膮 przyk艂ady jak pisa膰 w艂asne CQL (code query language) i analizowa膰 kod na inny spos贸b, np:

  • Ostrzegaj gdy code coverage poni偶ej n%
  • Nazwy interfejs贸w nie zaczynaj膮ce si臋 od litery I
  • Wykorzystanie w膮tk贸w inaczej ni偶 przez ThreadPool
  • Zmiany warto艣ci zmiennych, bez wykorzystania mechanizm贸w synchronizacji
  • Zbyt d艂uga lista typ贸w dziedzicz膮cych po X

Opr贸cz tego co wymieni艂em powy偶ej, generowany jest tak偶e dodatkowy raport podsumowuj膮cy ca艂y projekt, wykresy, liczby, inne pierd贸艂ki, co艣 co menad偶erowie i klienci lubi膮 najbardziej.
Skupmy si臋 na najwa偶niejszej grupie, na programistach.S膮 tam tak偶e informacje, kt贸re nam tak偶e si臋 przydadz膮.
Dodatkowy wykres wy艣wietlaj膮cy stopie艅 abstrakcji oraz stabilno艣膰 waszego kodu. Gdzie stabilno艣膰 nie oznacza dobrego kodu, a raczej wsp贸艂prac臋 z innymi typami (wsparcie dla polimorfizmu). W zasadzie ci臋偶ko wyt艂umaczy膰 ten parametr. Scott Hanselman ma podobny wpis o ND, tam t艂umaczy troch臋 lepiej ten wykres: post Scotta.
Teraz b臋dzie siara, bo o ile jestem zwolennikiem abstrakcji, to w tym projekcie pojecha艂em bez niej:

Warto trzyma膰 si臋 zielonej strefy.
I tak Service oraz GeocodeService by艂 ju偶 tworzony z my艣l膮 o testach czy zastosowaniem innego 藕r贸d艂a danych, dlatego znajduje si臋 wy偶ej je艣li chodzi o o艣 Y (abstrakcj臋), natomiast Model, Extension (tam s膮 metody rozszerzaj膮ce), Helpery, etc jest p艂askie jak deska. Po艂o偶enie na osi X dzia艂a w taki spos贸b: je艣li assembly jest nie rozszerzalne, brakuje mu/jej jakiejkolwiek wirtualno艣ci, a dodatkowo wiele innych typ贸w od niej zale偶y tym bli偶ej strefy b贸lu (na lewo) b臋dzie si臋 znajdowa膰. U mnie wygl膮da to tak, 偶e kod nie jest abstrakcyjny (s膮 momenty), jednak nie posiadam klas kt贸re s膮 wykorzystywane przez wszystkie inne. Brak tutaj typowych „utils贸w” czy klas statycznych, do kt贸rych wszyscy si臋gaj膮. Mo偶e dzi臋ki temu jestem z pi臋knej zielonej strefie szcz臋艣cia. Model m贸g艂by doda膰 od siebie troch臋 abstrakcji (mo偶e ISP), m贸g艂bym sprawdzi膰 czy wsz臋dzie gdzie jest on wykorzystywany jest to potrzebne, mo偶e rozbi膰 cz臋艣膰 klas na troch臋 mniejsze. Natomiast patrz膮c na Service wida膰 偶e zbli偶a si臋 on do powoli do zbyt wielkiej abstrakcji, lub braku wykorzystania cz臋艣ci jego funkcjonalno艣ci. Warto sprawdzi膰 czy wszystkie jego metody s膮 potrzebne, mo偶e da si臋 cz臋艣膰 z nich tak zmieni膰, aby wykorzystywa艂y jaki艣 wsp贸lny kod.

Z dodatkowych w raporcie ND mo偶na zobaczy膰 ile jest w sumie klas, metod w klasach, w艂a艣ciwo艣ci w klasach, linii kodu w projekcie, klasach, metodach, wszystko to co wymieni艂em mo偶na tak偶e bada膰 pod wzgl臋dem ilo艣ci polece艅 w IL.

Po co utrzymywa膰 kod z kt贸rego nikt nie korzysta? W moim przypadku zosta艂o kilka metod, kt贸re zosta艂y domy艣lnie stworzone przez wizarda podczas tworzenia projektu na Windows Phone, np. ca艂a seria ApplicationLaunching, ApplicationActivated, ApplicationDeactivated czy ApplicationClosing. z kt贸rej nigdzie nie korzystam. Takie proste rzeczy, a czyni膮 kod z kt贸rym si臋 pracuje przyjemniejszym w utrzymaniu.

ND wspiera MSVC 2008, 2010 oraz 2012. Umo偶liwia badanie kodu prosto z menu kontekstowego w edytorze:
Raporty mo偶na zapisywa膰, a nast臋pnie por贸wnywa膰 czy zmiany wprowadzane id膮 ku lepszemu. Dzi臋ki integracji z VS mo偶na tak偶e prosto edytowa膰 i uruchamia膰 zapytania CQL – prosto ze 艣rodowiska pracy.
Na kr贸tkich filmikach widzia艂em tak偶e, 偶e ND potrafi por贸wnywa膰 ze sob膮 poszczeg贸lne wersje aplikacji. Niestety nie wiem jak do tego doj艣膰, podejrzewam, 偶e trzeba pilnowa膰 numer贸w wersji w assembly.
Odpalany z linii polece艅 powinien by膰 prosty do integracji z system CI (w domu takiego czego艣 nie posiadam) i generowa膰 odpowiednio konfigurowalne raporty – menad偶erowie si臋 uciesz膮. Mo偶liwo艣膰 zdefiniowania w艂asnych regu艂 przy pomocy CQL umo偶liwi generowanie ostrze偶e艅 podczas budowania kodu, kt贸ry np. nie posiada test贸w.

Pisa艂em wcze艣niej o tym, 偶e warto rozmawia膰. Zadawa膰 pytania i czyta膰 kod nie tylko sw贸j. Poprosi膰 znajomego o sprawdzenie tego co stworzyli艣my. ND wydaje si臋 by膰 czym艣 co mo偶e ten proces cz臋艣ciowo zast膮pi膰. Nie warto jednak od razu usuwa膰 ludzi z listy kontakt贸w. Jasna sprawa, 偶e dla mnie czy innego Kowalskiego (pozdrawiam Tomka je艣li to czyta) jest on raczej drogim narz臋dziem 299 euro, szczeg贸lnie gdy w domu piszemy kod do szuflady. Ale gdy zarabia si臋 na oprogramowaniu to 艣wietne rozwi膮zanie, senior czy inny architekt mo偶e na pocz膮tku projektu ustali膰 pewne zasady, kt贸ry kod musi spe艂nia膰 i dopiero gdy czekin w repozytorium spe艂ni je wszystkie, zostanie przes艂any do osobistego review. Pozwali to zaoszcz臋dzi膰 wszystkim du偶o czasu (czas to pieni膮dz) oraz pomin膮膰 g艂upie i cz臋sto powtarzaj膮ce si臋 b艂臋dy, np. brak s艂owa sealed przy klasie nie przeznaczonej do dziedziczenia.

TL;DR; (podsumowanie)
NDepend to dobre narz臋dzie do statycznego sprawdzenia kodu. Szczeg贸lnie przydatne w komercyjnych projektach, pozwoli automatycznie pilnowa膰 porz膮dku w kodzie, zapewni przestrzeganie przyj臋tych zasad w projekcie. Zadowoli menad偶er贸w wymagaj膮cych nudnej papierologii. Nawet je艣li piszesz do szuflady, to na koniec lub po zako艅czeniu projektu, wykorzystaj wersj臋 14 dniow膮 i sprawd藕 sw贸j kod. Mo偶e si臋 okaza膰, 偶e da si臋 lepiej.
Je艣li mia艂bym narzeka膰, to mogliby da膰 wersj臋 darmow膮 do domowego u偶ytku.

Jest tak偶e NDepened dla Javy oraz dla C++. Niestety nie wiem jak dobre/z艂e s膮.

Linki:
NDepend strona domowa: http://www.ndepend.com/Default.aspx
Cennik: http://www.ndepend.com/Purchase.aspx
Lista ficzer贸w, cz臋艣膰 z nich posiada filmiki. Zabawne jest to, 偶e korzystaj膮 z syntezatora mowy: http://www.ndepend.com/Features.aspx

Je艣li macie pytania to prosz臋 o kontakt, je艣li chcecie 偶ebym opisa艂 jak膮艣 cz臋艣膰 funkcjonalno艣ci ND to piszcie. Je艣li chcecie abym sprawdzi艂 jaki艣 kod to piszcie.

One thought on “NDepend4 – co potrafi statyczna analiza kodu.

Dodaj komentarz

Tw贸j adres email nie zostanie opublikowany. Pola, kt贸rych wype艂nienie jest wymagane, s膮 oznaczone symbolem *