You are on page 1of 84

���������������������������������

�����������������������������������

�����������������������������������������������������������������������������
�����������������������������������������������������������������������������
�������������������������������������������������������������������������������
����������������������������

���������������������������������������������������������������������������
��������������������������������������������������������������������������������
������������������

�����������������������������������������������������������������������������������
��������������������������������������������������������������������������������
���������������������������������������������������������������������������������
������������������������������������������������������������������������������

���������������������������������������������

�����������������������������������������������������������������������������������������������
03/2010 (183)

SPIS TREŚCI
15 Opis DVD SZTUCZNA INTELIGENCJA
20 Paradygmat programowania CLP
– Metody rozwiązywania trudnych problemów
kombinatorycznych
BIBLIOTEKA MIESIĄCA Łukasz Mazur
Wysoka efektywność metod CLP jest rezultatem wykorzystania
6 Boost String Algorithms – Eleganckie i efektywne procedur propagacji ograniczeń oraz dystrybucji zmiennych,
przetwarzanie napisów w języku C++ w celu poszukiwania rozwiązań spełniających wszystkie przyjęte
Rafał Kocisz ograniczenia. Procesy te realizowane są w sposób klasyczny, jak
Czy próbowałeś kiedyś budować zaawansowane narzędzia do i rozproszony, dając bardzo dobre rezultaty obliczeniowe.
przetwarzania tekstu, bazując na funkcjonalności klasy std::
string? Jeśli tak, to założę się, że nie wspominasz zbyt dobrze tego
doświadczenia. Podstawowe udogodnienia związane z przetwa-
rzaniem napisów w C++ są, delikatnie mówiąc... mało wygodne.
Na szczęście – istnieje alternatywa!
BEZPIECZEŃSTWO
32 Niezawodność systemów informatycznych
Andrzej Olchawa
Nieustanny postęp technologiczny, zwłaszcza ten dotyczący
PROGRAMOWANIE C++ świata IT, sprawia, że mamy do czynienia z globalną komputery-
zacją oraz informatyzacją, która z dnia na dzień zatacza coraz to
12 Tworzenie kopii obiektów – Wzorzec prototypu szersze kręgi. Postęp służyć powinien globalnemu dobru, jednak
Robert Nowak wraz postępem pojawiają się coraz to nowe problemy oraz pułap-
Kopiowanie obiektów, czyli tworzenie duplikatów, przechowu- ki, których nie sposób traktować z przymrużeniem oka.
jących te same informacje bez niszczenia oryginału, jest jedną
z podstawowych operacji, które wykorzystujemy w programowa-
niu. Artykuł opisuje tę czynność, analizując techniki wspierające
proces tworzenia kopii w języku C++.
WARSZTATY
36 Hibernate Search API – Mechanizm
wyszukiwania pełnotekstowego w Hibernate
PROGRAMOWANIE JAVA Łukasz Antoniak
Aplikacje bazodanowe stanowią obecnie znaczący odsetek
16 Przewodnik po SCJP oprogramowania tworzonego na zlecenie prywatnych firm, jak
– czyli certyfikat z Javy - część 3 i ogromnych korporacji. Większość aplikacji realizuje warstwę do-
Krzysztof Rychlicki - Kicior stępu do danych za pomocą relacyjnie zorientowanej implemen-
Proces zdobywania certyfikatów, potwierdzających umiejętno- tacji bazy danych (ang. Relational Database Management Sys-
ści z różnych dziedzin wiedzy, stał się jednym z ważniejszych tem). Wybór ten ogranicza swobodę przeszukiwania zawartych
elementów osobistego rozwoju. Proces ten ma miejsce również informacji do zbioru ściśle sformalizowanych zapytań udostęp-
w branży IT; certyfikaty dla programistów (Java lub .NET), admini- nianych przez aplikację. Artykuł ten wprowadza w zagadnienia
stratorów czy sieciowców (Cisco) można coraz częściej odnaleźć przeszukiwania pełnotekstowego oferowanego przez Hibernate
w CV osób starających się o pracę, zwłaszcza w owianym złą sła- Search oraz Apache Lucene.
wą kryzysie gospodarczym.

44 Spring.NET – uniwersalny spinacz.


Wprowadzenie do konfiguracji fabryki obiektów.
Piotr Wyczółkowski
Spring to bardzo wygodne i szeroko konfigurowalne narzędzie
pozwalające spinać ze sobą poszczególne obiekty, jak i integro-
wać całe warstwy aplikacji.

4 03/2010
APLIKACJE BIZNESOWE
Miesięcznik Software Developer’s Journal (12 numerów w roku)
56 SOA – Tworzenie serwisów wspomagających jest wydawany przez Software Press Sp. z o.o. SK
proces integracji
Paweł Pietrasz
Redaktor naczelny:
Tworzenie rozwiązań integracyjnych to nie trend, ale wymóg sta- Łukasz Łopuszański lukasz.lopuszanski@software.com.pl
wiany przed projektantami systemów informatycznych. Coraz bar-
dziej złożone procesy biznesowe wymagają od nas projektowania Projekt okładki: Agnieszka Marchocka
rozwiązań dotykających coraz to większej ilości systemów, które
w przeszłości często nie były projektowane w sposób zapewniający Skład i łamanie:
Tomasz Kostro www.studiopoligraficzne.com
łatwą możliwość integracji.

Kierownik produkcji:
Andrzej Kuca andrzej.kuca@software.com.pl

Dział produkcji i kolportażu:

PRACA W ZESPOLE Alina Stebakow alina.stebakow@software.com.pl

66 Audyt techniczny – Czyli jak sprawdzić jakość


prac dostawcy IT?
Karolina Zmitrowicz Nakład: 6 000 egz.
Instytucja zlecająca realizację prac IT z definicji pragnie, by jakość
tych prac była jak najlepsza, a wymagania dotyczące produkcji Adres korespondencyjny:
Software Press Sp. z o.o. SK,
systemu oraz samego produktu spełnione na odpowiednim po- ul. Bokserska 1, 02-682 Warszawa, Polska
ziomie. Zapewnienia i deklaracje dostawcy to jedno – a uzyska- tel. +48 22 427 36 91, fax +48 22 224 24 59
www.sdjournal.org cooperation@software.com.pl
nie konkretnych, obiektywnych dowodów spełnienia wymagań
to co innego.

Dział reklamy: adv@software.com.pl

Obsługa prenumeraty: EuroPress Polska

EFEKTYWNOŚĆ PRACY software@europress.pl

Dołączoną do magazynu płytę CD przetestowano programem


74 Klient, który wie czego chce AntiVirenKit firmy G DATA Software Sp. z o.o.
– Czyli sztuka zadawania pytań Redakcja dokłada wszelkich starań, by publikowane w piśmie
Michał Bartyzel, Mariusz Sieraczkiewicz i na towarzyszących mu nośnikach informacje i programy były
Jeśli zdarza Ci się spotykać z osobami nietechnicznymi i musisz poprawne, jednakże nie bierze odpowiedzialności za efekty
wykorzystania ich; nie gwarantuje także poprawnego działania
pozyskiwać od nich konkretne informacje, aby móc sprawnie im- programów shareware, freeware i public domain.
plementować swoje zadania, to ten artykuł jest dla Ciebie. Skupi-
liśmy się w nim na technice zadawania pytań, która ogólne infor- Uszkodzone podczas wysyłki płyty wymienia redakcja.

macje pomaga przekuć na mierzalne konkrety. Wszystkie znaki firmowe zawarte w piśmie są własności
odpowiednich firm.
Zostały użyte wyłącznie w celach informacyjnych.

Redakcja używa systemu automatycznego składu

FELIETON Osoby zainteresowane współpracą prosimy o kontakt:


cooperation@software.com.pl
62 Certyfikacja i co dalej?
Oliwia Łączyńska Druk: Artdruk www.artdruk.com
Obecna sytuacja na rynku pracy oraz otwarcie rynków europej-
skich dla polskich pracowników powoduje, że coraz częściej za-
Wysokość nakładu obejmuje również dodruki. Redakcja nie
stanawiamy się nad sposobem poniesienia własnych kwalifi- udziela pomocy technicznej w instalowaniu i użytkowaniu
kacji. Szukamy metod, które są postrzegane jako wartościowe programów zamieszczonych na płycie CD-ROM dostarczonej
i uznawane nie tylko przez polskich pracodawców i manage- razem z pismem.
rów. Rozwiązaniem coraz częściej wybieranym przez Programi- Sprzedaż aktualnych lub archiwalnych numerów pisma po
stów zajmujących się Java są certyfikacje SUNa ze względu na innej cenie niż wydrukowana na okładce – bez zgody wydawcy
ich uniwersalność. – jest działaniem na jego szkodę i skutkuje odpowiedzialnością
sądową.

www.sdjournal.org 5
Biblioteka miesiąca

Boost String Algorithms


Eleganckie i efektywne przetwarzanie napisów w języku C++

Czy próbowałeś kiedyś budować zaawansowane narzędzia do


przetwarzania tekstu, bazując na funkcjonalności klasy std::string? Jeśli
tak, to założę się, że nie wspominasz zbyt dobrze tego doświadczenia.
Podstawowe udogodnienia związane z przetwarzaniem napisów w C++
są, delikatnie mówiąc... mało wygodne. Na szczęście – istnieje alternatywa!

pem kontenera (np. std::string). W kon-


Dowiesz się: Powinieneś wiedzieć: tekście tej biblioteki pojęcie napis oznacza
• Co oferuje biblioteka Boost String Algori- • Jak programować w języku C++; sekwencję znaków przechowywanych w do-
thms i dlaczego warto jej używać; • Podstawowa znajomość biblioteki STL. wolnym kontenerze. Podobnie, pod pojęciem
• Jak można wykorzystać ją w praktyce. znak niekoniecznie muszą kryć się typy char
i wchar_t.
Prezentowana biblioteka jest częścią pakie-
tu Boost; jako że składa się ona z samych pli-
cych na napisach, których brakuje w biblio- ków nagłówkowych, jej konfiguracja jest bar-
tece standardowej języka C++. Algorytmy te dzo prosta: wystarczy pouczyć kompilator,
Poziom można sklasyfikować w ramach kilku pod- gdzie ma szukać nagłówków.
trudności stawowych grup: operacje przycinania napi- Więcej informacji na temat konfiguracji bi-
sów (ang. trimming), operacje konwersji zna- blioteki znajdziesz w ramce Szybki Start.
ków (ang. case conversion) oraz funkcje służące
do wyszukiwania, zamiany i usuwania ciągów Pierwszy przykład

S
tandardowe udogodnienia biblioteki znaków (ang. search, replace, erase). Zanim rozważymy szczegółowo możliwości
języka C++, dedykowane przetwarza- Boost String Algorithms skonstruowa- biblioteki Boost String Algorithms, spójrzmy
niu napisów, pozostawiają wiele do ży- na jest w sposób, który nie ogranicza jej do na krótki, prosty przykład jej użycia (patrz:
czenia. Wielu programistów uważa, że klasa współpracy z jednym, z góry narzuconym ty- Listing 2).
std::string to jedna z większych wpadek
twórców standardu tego języka. Szablon std:
Listing 1. Implementacja operacji przycięcia zbędnych znaków (np. spacji) z początku i końca
:basic_string jest przykładem klasy o roz- napisu, bazująca na funkcjonalności std::string
dmuchanym, niespójnym interfejsie, mało in-
tuicyjnej w użyciu, udającej kontener STL, ale void trim( string& str )
nie będącej nim do końca i nieelastycznej. Je- {
śli nie wierzysz, to spróbuj przy pomocy std: string::size_type pos = str.find_last_not_of( ' ' );
:basic_string wykonać operację przycię-
cia zbędnych znaków (np. spacji) z początku if (pos != string::npos)
i końca napisu (ang. trimming)... {
Oczywiście, da się to zrobić – po uprzed- str.erase( pos + 1 );
nim zapoznaniu się z takimi metodami klasy pos = str.find_first_not_of( ' ' );
std::string jak find_first_not_of, find_
last_not_of oraz erase (patrz: Listing 1). if ( pos != string::npos )
Ale czy nie można by zrobić tego prościej...? {
A co w sytuacji, kiedy nasz napis reprezento- str.erase( 0, pos );
wany jest jako wektor char'ów? }
Zanim załamiesz ręce, poczekaj! Na szczę- }
ście – jest... else
{
...światełko w tunelu... str.erase( str.begin(), str.end() );
...w postaci biblioteki Boost String Algori- }
thms. Biblioteka ta oferuje uogólnione (ang. }
generic) implementacje algorytmów działają-

6 03/2010
Programowanie w języku C++

Zadanie, które ma zrealizować nasz przy- padku Boost String Algorithms. Patrząc na • Przekazywanie argumentów: w odróżnie-
kład, jest bardzo proste: chcemy usunąć białe przykład z Listingu 2, da się zauważyć kilka niu od STL Boost String Algorithms prefe-
znaki z początku i końca napisu, a następnie podstawowych konwencji: ruje przekazywanie kontenera do funkcji
stworzyć nowy napis będący kopią poprzed-
niego, z tą różnicą, że wszystkie litery z orygi-
nalnego napisu zamienione będą na małe. Bo-
Szybki start
Aby rozpocząć pracę z Boost String Algorithms musimy zainstalować pakiet bibliotek Bo-
ost String Algorithms pozwala zrealizować to ost. Pakiet ten można pobrać pod adresem http://www.boost.org. Przeważająca część biblio-
zadanie za pomocą dwóch prostych, intuicyj- tek wchodzących w skład tego pakietu jest zakodowana w plikach nagłówkowych i z tej racji
nych funkcji. Morał z tego przykładu jest na- można ich używać od ręki. Tak właśnie jest w przypadku biblioteki prezentowanej w niniej-
stępujący: nie mając pod ręką odpowiedniej bi- szym artykule. Jeśli używasz kompilatora z rodziny Microsoft Visual Studio to wystarczy we
właściwościach projektu (ang. Properties), w zakładce Con�guration Properties \ C/C++ \ Ge-
blioteki, musielibyśmy funkcje do przycinania
neral odpowiednio ustawić pole Additional Include Directories (patrz: Rysunek 1). Ja de�niuję
i konwersji zaimplementować sami. Niby pro- sobie zawsze zmienną środowiskową %BOOST_HOME%, która wskazuje na miejsce (katalog),
sta rzecz, aczkolwiek nie do końca. Jeśli two- w którym zainstalowany jest pakiet Boost. Na Rysunku 1 pokazane jest jak odwołuję się do
rzony przez nas kod miałby być kodem pro- tej zmiennej. Oczywiście można tutaj podać również względną (w odniesieniu do katalogu,
dukcyjnym, to należałoby poważnie zastano- w którym znajduje się projekt) bądź bezwzględną ścieżkę wskazującą na to miejsce.
wić się nad takimi aspektami jak: poprawność Trochę więcej zachodu jest ze skon�gurowaniem biblioteki Boost Regex. Nie jest stano-
wi ona co prawda meritum niniejszego artykułu, aczkolwiek – z racji tego, iż korzystam z niej
(szczegółowe rozważenie wszystkich przypad-
w kilku prezentowanych tu przykładach – pozwolę sobie napisać klika słów na temat jej in-
ków użycia), wydajność, rozszerzalność, ob- stalacji. Boost Regex jest jednym z nielicznych komponentów Boost, które wymagają od-
sługa błędów itd. Trzeba by zapewne zapro- dzielnego zbudowania. Na szczęście, pakiet posiada swój własny system budowania źró-
jektować i zaimplementować zestaw testów deł – w dużej mierze niezależny od platformy. Aby skorzystać z tego systemu potrzebny
modułowych. Krótko mówiąc, trywialne zda- jest programu bjam. Link do strony na której można pobrać ten program (oczywiście za dar-
mo) znajduje się pod adresem http://www.boost.org/doc/libs/1_41_0/more/getting_started/
nie, które chcielibyśmy rozwiązać w kilka se-
windows.html. Pod tym samym adresem znajduje się również bardzo szczegółowa instrukcja
kund, urasta nam nagle do rozmiarów tworze- budowania źródeł pakietu Boost. Proces kompilacji całej biblioteki jest czasochłonny i wy-
nia własnej biblioteki – co już trywialnym za- maga sporej ilości wolnego miejsca na dysku. Na szczęście istnieje możliwość zbudowania
daniem nie jest. wybranych komponentów. W celu zbudowania biblioteki Boost Regex w katalogu głównym
Dla odmiany, Boost String Algorithms da- biblioteki (tam gdzie znajduje się plik Jamroot) należy wydać polecenie:
je nam dokładnie to, czego potrzebujemy:
bjam --with-regex
proste, dobrze przetestowane, wydajne im-
plementacje operacji na napisach. Wystar- Zanim to uczynimy, należy upewnić się, czy program bjam.exe znajduje się w ścieżce wykona-
czy dołączyć właściwy nagłówek (#include nia (zmienna środowiskowa PATH) oraz czy z poziomu konsoli dostępne są narzędzia dewelo-
<boost/algorithm/string.hpp>) i po kłopo- perskie Microsoft Visual Studio C++ (aby uzyskać dostęp do tych narzędzi należy uruchomić
cie. Aż chciałoby się zacytować motto użyt- plik vcvars32.bat znajdujący się w podkatalogu bin, w miejscu gdzie zainstalowano wspomnia-
ne środowisko).
kowników języka Perl: niechaj proste rzeczy po- Podana wyżej komenda spowoduje zbudowanie biblioteki Boost Regex i zainstalowa-
zostaną proste. nie jej w katalogu %BOOST_HOME%\bin.v2. Uruchamiając przykłady zamieszczone w niniej-
szym artykule należy pamiętać o tym aby skon�gurować program łączący (ang. Linker) tak
Konwencje aby używał skompilowanej biblioteki Boost Regex. W przypadku korzystania z pakietu Mi-
Każda biblioteka narzuca pewne zasady doty- crosoft Visual Studio wystarczy we właściwościach projektu (ang. Properties) w zakładce Con-
�guration Properties \ Linker \ General ustawić odpowiednio pole Additional Library Directories,
czące korzystania z niej. Podobnie jest i w przy-
tak aby podana tam ścieżka wskazywała na miejsce, w którym znajduje się plik ze skompilo-
waną biblioteką.
Listing 2. Prosty przykład użycia biblioteki
Boost String Algorithms

#include <boost/algorithm/string.hpp>
#include <iostream>

using namespace std;


using namespace boost;

int main()
{
string str1(" Hello WOrLd! ");
cout << '[' << str1 << ']' << endl;

trim( str1 );
cout << '[' << str1 << ']' << endl;

string str2 = to_lower_copy( str1


);
cout << '[' << str2 << ']' << endl;

return 0;
}
Rysunek 1. Kon�guracja narzędzia Microsoft Visual Studio przy pracy z biblioteką Boost String Algorithms

www.sdjournal.org 7
Biblioteka miesiąca

w postaci pojedynczego argumentu. Kon- wych ułatwiających implementację algo- dwie potrzeby i udostępnia swoje algo-
wencja STL (przekazywanie pary iterato- rytmów uogólnionych i w tym przypadku rytmy zarówno w wersjach modyfikują-
rów) daje oczywiście wielką elastyczność, idealnie spełnia swoją rolę. cych argumenty, jak i kopiujących nowy
aczkolwiek wiąże się z pewnymi ograni- • Modyfikowanie argumentów: w przy- wynik (te ostatnie można rozpoznać po
czaniami, między innymi z brakiem moż- kładzie pokazanym na Listingu 2 widzi- końcówce _ copy w nazwie funkcji).
liwości składania wywołań kilku funkcji my, że przy przetwarzaniu napisów cza- • Nazewnictwo: w tym przypadku Boost
czy z mniejszą czytelnością kodu. Złotym sami występuje potrzeba modyfikacji ar- String Algorithms trzyma się konwencji
środkiem stosowanym przez Boost String gumentów przekazywanych do funkcji, narzuconej przez bibliotekę standardową.
Algorithms jest inna biblioteka z pakie- a czasami chcielibyśmy zachować sobie W związku z tym nazwy algorytmów pi-
tu Boost: Range Library. Biblioteka ta jest kopię oryginalnego napisu. Biblioteka sane są małymi literami, zaś słowa w na-
zbiorem konceptów i narzędzi użytko- Boost String Algorithms respektuje oby- zwie rozdzielone są znakiem podkreśle-
nia. Oprócz końcówki _ copy, w przy-
Listing 3. Przykład użycia algorytmów przycinania padku funkcji zwracających wynikowy
napis, pojawia się jeszcze przedrostek i,
#include <boost/algorithm/string.hpp> występujący wtedy, gdy dany algorytm
#include <iostream> działa w sposób niezależny od wielkości
znaków (np.: ifind _ first()). Podobnie
using namespace std; postfiks _ if zarezerwowany jest dla algo-
using namespace boost; rytmów wykorzystujących predykaty de-
finiowane przez użytkownika.
#define DUMP( str ) cout << #str << " == \"" << str << "\"" << endl;
Operacje przycinania
int main() Gratuluję Ci Drogi Czytelniku! Szczęśliwie
{ przebrnąłeś przez wprowadzenie do tematu!
string str1 = " hello world! "; Czas przejść do konkretów. Na początek omó-
wimy operacje przycinania.
string str2 = trim_left_copy( str1 ); Idea tego typu operacji jest prosta: chodzi
DUMP( str2 ); // str2 == "hello world! " o to, aby usunąć z napisu zbędne znaki znaj-
dujące się na jego początku i/lub końcu. Mogą
string str3 = trim_right_copy( str1 ); być to wcięcia w kodzie źródłowym, znaki no-
DUMP( str3 ); // str3 == " hello world!" wego wiersza w kolejnych liniach pliku teksto-
wego czy pomyłkowo wpisane przez użytkow-
trim( str1 ); nika spacje w polu formularza.
DUMP( str1 ); // str1 == "hello world!" Boost String Algorithms oferuje nam trzy al-
} gorytmy odpowiadające za przycinanie:

• trim _ left() – przycina napis z lewej


Listing 4. Przykład użycia algorytmów przycinania z wykorzystaniem predykatów
strony;
#include <boost/algorithm/string.hpp> • trim _ right() – przycina napis z prawej
#include <iostream> strony;
• trim() – przycina napis z obydwu stron.
using namespace std;
using namespace boost; Każdy z tych algorytmów występuje w czte-
rech wariantach: modyfikującym swój argu-
#define DUMP( str ) cout << #str << " == \"" << str << "\"" << endl; ment, kopiującym wynikowy napis, z predy-
katem i bez predykatu. Dla przykładu, z al-
int main() gorytmem trim _ left() skojarzone są nastę-
{ pujące cztery szablony funkcji:
string str1( "3254832746 hello world!" );
string str2( " 54 32 46 hello world! $$$+-+- " ); • trim _ left _ copy _ if(),
string str3( "hello world! +-11$$%76 " ); • trim _ left _ if(),
• trim _ left _ copy(),
trim_left_if( str1, is_digit() || is_space() ); • trim _ left().
DUMP( str1 ); // str1 == "hello world!"
Na Listingu 3 przedstawiony jest przykład
trim_if( str2, is_digit() || is_space() || is_any_of( "+-%$" ) ); wykorzystania operacji przycinania nie ko-
DUMP( str2 ); // str2 == "hello world!" rzystających z predykatów.
W komentarzach obok wywołań makra DUMP
trim_right_if( str3, is_digit() || is_space() || is_any_of( "+-%$" ) ); przedstawione są wartości poszczególnych na-
DUMP( str3 ); // str3 == "hello world!" pisów po wykonywaniu kolejnych operacji.
} Pozostają jeszcze operacje przycinania ko-
rzystające z predykatów. Te omówię w kolej-
nym punkcie.

8 03/2010
Programowanie w języku C++

Predykaty i klasyfikacja
Głównym zadaniem predykatu, w kontekście Listing 5. Przykład użycia algorytmu wyszukiwania
biblioteki Boost String Algorithms, jest spraw- #include <boost/algorithm/string.hpp>
dzenie, czy zadany napis spełnia określony wa- #include <boost/assign.hpp>
runek. Prezentowana biblioteka oferuje szereg #include <boost/foreach.hpp>
podstawowych predykatów (wszystkie one są #include <iostream>
zdefiniowane w nagłówku boost/algorithm/
string/predicate.hpp). Dla przykładu, predykat using namespace std;
istarts_with() weryfikuje, czy napis podany using namespace boost;
jako pierwszy argument rozpoczyna się od cią- int main()
gu znaków przekazanego jako argument drugi. {
Dodatkowo, przedrostek i na początku nazwy vector< char > text = boost::assign::list_of
predykatu sugeruje, iż w tym przypadku roz- ('H')('e')('l')('l')('o')(',')(' ')
miary liter w obydwu napisach nie będą bra- ('w')('o')('r')('l')('d')('!');
ne pod uwagę. iterator_range< vector< char >::iterator > result
Predykaty są bardzo użytecznym narzę- = find_last( text, "world" );
dziem w bibliotece Boost String Algorithms, if ( result )
gdyż można przekazywać je do algorytmów po {
to, aby dostosować ich działanie do indywidu- to_upper( result );
alnych potrzeb użytkownika. Co więcej, moż- }
na je łączyć ze sobą za pomocą operatorów lo- BOOST_FOREACH( char ch, text )
gicznych. Rozważmy przykład przedstawiony {
na Listingu 4. cout << ch;
Widać tutaj, na czym polega siła predyka- }
tów: w elegancki i prosty sposób jesteśmy w sta- cout << endl;
nie dopasować funkcjonalność algorytmów }
z rodziny trim do naszych potrzeb. W roz-
ważanym tu przypadku predykat złożony
Listing 6. Wyszukiwanie frazy na podstawie wyrażenia regularnego
jest z trzech klasyfikatorów. Zadaniem klasy-
fikatora jest sprawdzenie, czy wszystkie znaki #include <boost/algorithm/string.hpp>
w określonym napisie należą do określonej kla-
sy (np. czy są to cyfry bądź znaki alfabetu). Peł- // Dołączamy odpowiedni nagłówek, aby móc skorzystać z find_regex().
na lista klasyfikatorów dostępnych w ramach #include <boost/algorithm/string/regex.hpp>
Boost String Algorithms znajduje się w nagłów- #include <iostream>
ku boost/algorithm/string/classification.hpp.
W kolejnych punktach niniejszego artyku- using namespace std;
łu będę powracał jeszcze do tematu predyka- using namespace boost;
tów, pokazując konkretne przykłady ich zasto-
sowania. int main()
{
Operacje wyszukiwania // Wyrażenie regularne opisujące wzorzec adresu e-mail.
Biblioteka Boost String Algorithms udostęp- const static boost::regex email_regex(
nia cały szereg algorytmów pozwalających "[\\w.%-]+"
znajdować zadane ciągi znaków w napisach: "@"
"[A-Za-z0-9.-]+"
• find _ first() –znajduje pierwsze wystą- "\\.[A-Za-z]{2,4}" );
pienie napisu w wejściowym ciągu;
• find _ last() – znajduje ostatnie wystą- // Tekst zawierający adres e-mail.
pienie napisu w wejściowym ciągu; string text("my email adress is Rafal.Kocisz@gmail.com");
• find _ nth() – znajduje n-te wystąpienie
napisu w wejściowym ciągu (licząc od // Wyszukiwanie adresu e-mail w napisie.
zera); iterator_range< string::iterator > result = find_regex( text, email_regex );
• find _ head() – znajduje początkowy
fragment napisu o zadanej długości; // Jeśli wyszukiwanie się powidło, to zamieniamy wszystkie litery w
• find _ tail() – znajduje końcowy frag- // wyszukanym ciągu na małe.
ment napisu o zadanej długości; if ( result ) to_lower( result );
• find _ token() – znajduje pierwszy pasu-
jący token w napisie; // Wyświetlamy wyszukany ciąg na standardowym wyjściu.
• find _ regex() – znajduje fragment napi- cout << "Found: \"";
su pasujący do zadanego wyrażenia regu- copy( result.begin(), result.end(), ostream_iterator< char >( cout ) );
larnego; cout << "\"" << endl;
• find() – uogólniony algorytm wyszuki- }
wania.

www.sdjournal.org 9
Biblioteka miesiąca

Dodatkowo, pierwsze trzy algorytmy wy-


Listing 7. Wyszukiwanie znaku spełniającego zadany predykat
stępują w wariantach ignorujących wielkość
#include <boost/algorithm/string.hpp> znaków (np. ifind _ first()). Przykład wyko-
rzystania operacji wyszukiwania przedsta-
#include <iostream> wiony jest na Listingu 5.
Na wspomnianym przykładzie daje się za-
using namespace std; obserwować kilka ciekawych szczegółów. Po
using namespace boost; pierwsze, tym razem zdecydowaliśmy się użyć
wektora znaków (std::vector< char >) ja-
int main() ko reprezentacji napisu. Fakt, iż prezentowa-
{ ny przykład kompiluje się i działa bez żadne-
string text("int delta = b*b - 4*a*c"); go problemu, pokazuje dobitnie, jak bardzo
elastyczną biblioteką jest Boost String Algo-
// Szukamy znaku będącego cyfrą. rithms. Po drugie, warto zauważyć, iż funk-
iterator_range< string::iterator > result cja find_last() zwraca jako rezultat zakres
= find_token( text, is_digit() ); iteratorów (iterator_range), który wskazu-
je na znaleziony ciąg znaków. Obiekty typu
cout << "Found: \""; iterator_range posiadają operator konwer-
copy( result.begin(), result.end(), sji do typu bool, dzięki czemu można uży-
ostream_iterator< char >( cout ) ); wać ich w instrukcjach warunkowych. Ponie-
cout << "\"" << endl; waż wszystkie algorytmy z Boost String Algo-
} rithms działają na zakresach, rezultat wyszuki-
wania można przekazywać do innych funkcji
z tej biblioteki. W naszym przykładzie, obiekt
Listing 8. Wyszukiwanie frazy na podstawie wyrażenia regularnego
zwrócony z find_last() przekazujemy do al-
#include <boost/algorithm/string.hpp> gorytmu to_upper(), skutkiem czego będzie
zmodyfikowanie znalezionego ciągu znaków
// Dołączamy odpowiedni nagłówek, aby móc skorzystać z find_regex(). (zamiana na duże litery).
#include <boost/algorithm/string/regex.hpp> W przypadku operacji wyszukiwania warto
zwrócić uwagę na dwa algorytmy udostępniane
#include <iostream> przez Boost String Algorithms: find_regex()
oraz find_token(). Pierwsza z nich pozwala
using namespace std; wyszukiwać określone frazy w napisie na pod-
using namespace boost; stawie wyrażenia regularnego (z wykorzysta-
niem biblioteki Boost Regex), druga zaś – wy-
int main() szukiwać tzw. tokeny, czyli znaki spełniające pe-
{ wien predykat. Proste przykłady wykorzystania
const static boost::regex email_regex( tych funkcji (wraz z komentarzami) znajdują
"[\\w.%-]+" się odpowiednio na Listingu 6 i 7.
"@" Przy wyszukiwaniu fraz w tekście często po-
"[A-Za-z0-9.-]+" jawia się potrzeba znalezienia wszystkich jej wy-
"\\.[A-Za-z]{2,4}" ); stąpień, a nie tylko pierwszego. Boost String Al-
gorithms ułatwia swoim użytkownikom wyko-
string text( "You can reach me at rafal.kocisz@gmail.com or at" nanie tego zadania, oferujące tzw. iterator wy-
"rafal.kocisz@game-lion.com. In case of any technical" szukiwania (ang. find iterator). Rozważmy frag-
"problems contact with admin@game-lion.com." ); ment kodu przedstawiony na Listingu 8.
Prezentowany fragment kodu ma za zada-
vector< string > emails; nie wyszukać we fragmencie tekstu wszyst-
kie adresy e-mail. W tym celu wykorzystamy,
typedef find_iterator< string::iterator > string_find_iterator; tak jak w przykładzie z Listingu 6, wyrażenie
regularne. Tym razem jednak użyjemy iterato-
for ( string_find_iterator it = ra wyszukiwania. Iterator ten jest tworzony za
make_find_iterator( text, regex_finder(email_regex) ); pomocą wywołania specjalnej funkcji:
it != string_find_iterator(); ++it )
{ make_find_iterator( text, regex_finder(
emails.push_back( copy_range< std::string >( *it ) ); email_regex ) );
}
Funkcja ta przyjmuje dwa argumenty: na-
BOOST_FOREACH( const string& email, emails ) cout << email << endl; pis (zakres), który chcemy przeszukiwać,
} oraz obiekt szukacza (ang. finder). W na-
szym przypadku korzystamy z szukacza ty-
pu regex _ finder, ale oczywiście Boost
String Algorithms udostępnia również inne

10 03/2010
Programowanie w języku C++

opcje w tym zakresie. Stworzony w ten spo-


Listing 9. Przykład użycia algorytmów zamiany
sób iterator wyszukiwania w kolejnych kro-
kach wskazywał będzie na zakresy opisujące #include <boost/algorithm/string.hpp>
znalezione frazy. Proponuję w tym momencie
poeksperymentować przez moment z kodem #include <iostream>
przedstawionym na Listingu 8.
W następnym podpunkcie rozważymy: #define DUMP( str ) cout << #str << " == \"" << str << "\"" << endl;

Operacje zamiany i usuwania using namespace std;


Operacja zamiany (ang. replace) wiąże się nie- using namespace boost;
odłącznie z operacją wyszukiwania. Nie ma
chyba ani jednego nowoczesnego edytora tek- int main()
stu, który nie oferowałby opcji wyszukaj i za- {
mień (ang. search and replace). string email( "rafal.kocisz@gmail.com" );
Rodzina algorytmów zamiany dostępnych
w ramach biblioteki Boost String Algorithms replace_first( email, ".", "[dot]" );
jest całkiem obszerna i bardzo podobna do ze- DUMP( email ); // email == "rafal[dot]kocisz@gmail.com"
stawu funkcji wyszukujących. Aby się o tym
przekonać, spójrzmy na Listing 9. replace_last( email, ".", "[dot]" );
Prawda, że wygląda to znajomo? Różnice DUMP( email ); // email == "rafal[dot]kocisz@gmail[dot]com"
w stosunku do algorytmów z rodziny find są
następujące: replace_nth( email, "@", 0, "[at]" );
DUMP( email ); // email == "rafal[dot]kocisz[at]gmail[dot]com"
• w przypadku zamiany możemy określić }
zakres, który pojawi się jako zamiennik
wyszukanego ciągu; replace_all( email, ".", "[dot]"); do Twojej podręcznej skrzynki narzędziowej.
• algorytmy zamiany występują również Główne zalety biblioteki to:
w wersjach niemodyfikujących argument Dociekliwi Czytelnicy zastanawiają się za-
(oznaczone postfiksem _ copy). pewne, w jaki sposób biblioteka obsługuje • prostota i spójność interfejsu;
modyfikacje ciągów, na których wykonywane • lekkość i prostota konfiguracji (cała bi-
Szczególnym przypadkiem zamiany jest usu- są operacje zamiany. Dzieje się to za pośred- blioteka zaimplementowana jest w pli-
wanie. Boost String Algorithms oferuje dla nictwem tzw. cech sekwencji (ang. sequence kach nagłówkowych);
każdej funkcji z rodziny replace jej zamien- traits), na podstawie których Boost String Al- • elastyczność i rozszerzalność;
nik służący do usuwania. Dla przykładu, od- gorithms potrafi wybrać najbardziej efektyw- • zgodność z filozofią STL;
powiednikiem funkcji replace _ first jest ny schemat postępowania dla zadanego ciągu. • ortogonalność (biblioteka oferuje wie-
erase _ first. Więcej na ten temat można znaleźć w doku- le małych, niezależnych narzędzi, które
W przypadku gdy chcemy zamienić wszyst- mentacji biblioteki (patrz: ramka W sieci). można łatwo łączyć w celu realizacji bar-
kie wystąpienia zadanego ciągu za jednym dziej złożonych operacji).
zamachem, możemy skorzystać z funkcji Podsumowanie
replace_all() (nie ma potrzeby używać tu- Biblioteka Boost String Algorithms to niewąt- Reasumując: polecam tę bibliotekę każde-
taj żadnego iteratora, jak w przypadku algo- pliwie ciekawe i użyteczne rozwiązanie. Jeśli mu programiście tworzącemu aplikacje w ję-
rytmu find()). Dla przykładu, kropki wystę- programujesz w C++ i przynajmniej od cza- zyku C++!
pujące w adresie e-mail w przykładzie z Listin- su do czasu zdarza Ci się wykonywać operacje Aha! Jeszcze jedno: żądnych wiedzy Czy-
gu 9 moglibyśmy zamienić jednym wywoła- na napisach, to zapoznaj się z tą biblioteką ko- telników zapraszam do przestudiowania do-
niem funkcji: niecznie! Gwarantuję Ci, że trafi ona na stałe kumentacji biblioteki dostępnej w Internecie
(patrz: ramka W Sieci) – można tam znaleźć
jeszcze sporo dodatkowych ciekawostek, któ-
W Sieci re warto poznać.
• http://www.boost.org/doc/libs/1_41_0/doc/html/string_algo.html – strona domowa biblio-
teki Boost String Algorithms; RAFAŁ KOCISZ
• http://www.boost.org – strona domowa pakietu bibliotek Boost; Pracuje na stanowisku Dyrektora Techniczne-
• http://www.boost.org/doc/libs/1_41_0/doc/html/string_algo/quickref.html – tu znajdziesz go w �rmie Gamelion, wchodzącej w skład Grupy
przegląd wszystkich algorytmów dostępnych w ramach Boost String Algorithms.
BLStream. Rafał specjalizuje się w technologiach
związanych z produkcją oprogramowania na
platformy mobilne, ze szczególnym naciskiem na
tworzenie gier. Grupa BLStream powstała, by efek-
Licencja
Pakiet bibliotek Boost (a co za tymi idzie również i biblioteka Boost String Algorithms) jest udo- tywniej wykorzystywać potencjał dwóch szybko
stępniany na licencji Boost Software License 1.0. Pełny tekst tej licencji (w języku angielskim) rozwijających się producentów oprogramowania
jest dostępny pod adresem http://www.boost.org/LICENSE_1_0.txt. Licencja przewiduje możli- – BLStream i Gamelion. Firmy wchodzące w skład
wość wykorzystywania biblioteki bez uiszczania żadnych opłat, tak w otwartych, jak i w komer- grupy specjalizują się w wytwarzaniu oprogramo-
cyjnych projektach. Używanie Boost nie pociąga również potrzeby publikowania kodów źró-
wania dla klientów korporacyjnych, w rozwiąza-
dłowych docelowego produktu. Jedynym narzuconym wymogiem jest nakaz dołączania tek-
stu licencji biblioteki do wszystkich kopii stworzonego przy jej pomocy oprogramowania. niach mobilnych oraz produkcji i testowaniu gier.
Kontakt z autorem: rafal.kocisz@game-lion.com

www.sdjournal.org 11
Programowanie C++

Tworzenie kopii obiektów


Wzorzec prototypu

Kopiowanie obiektów, czyli tworzenie duplikatów, przechowujących te


same informacje bez niszczenia oryginału, jest jedną z podstawowych
operacji, które wykorzystujemy w programowaniu. Artykuł opisuje
tę czynność, analizując techniki wspierające proces tworzenia kopii
w języku C++.
ne powyżej. Na początku wykonujemy ko-
Dowiesz się: Powinieneś wiedzieć: pię płytką, która jest przeprowadzana szyb-
• Co to jest leniwe kopiowanie; • Jak pisać proste programy w C++; ko i umożliwia poprawne odczytywanie in-
• Co to jest wzorzec prototypu; • Co to jest dziedziczenie i funkcje formacji przechowywanych w zarządzanym
• Jak stworzyć fabrykę prototypów. wirtualne; obiekcie. Przy próbie modyfikacji obiektu
• Co to są szablony. badamy, czy obiekt jest wskazywany przez
jeden, czy przez kilka wskaźników. Jeże-
li istnieje tylko jeden wskaźnik, to mody-
fikacja odbywa się na zarządzanym obiek-
kopiowanie obiektów wskazywanych. Two- cie, natomiast jeżeli wskaźników jest wię-
rzenie takiej kopii zajmuje więcej czasu i zaso- cej, wykonuje się głęboką kopię wskazywa-
Poziom bów, ale obiekt i kopia są od siebie niezależne. nego obiektu i modyfikuje się tę kopię. Leni-
trudności Zmiany obiektu nie mają wpływu na kopię. we kopiowanie umożliwia więc optymalne
Na Rysunku 1 pokazano zawartość wskaźni- połączenie obu strategii, a ceną jest koniecz-
ków po wykonaniu płytkiej i głębokiej kopii, ność przechowywania dodatkowej składo-
przykład kodu zawiera Listing 1. wej, która pozwala rozstrzygnąć, czy nale-

K
opiowanie obiektów jest operacją ży robić głęboką kopię. Składową tą jest licz-
wykonywaną bardzo często: prze- Kopiowanie opóźnione nik odniesień lub flaga. Można pozbyć się
kazując argumenty przez wartość, Kopiowanie opóźnione lub leniwe wyko- tej składowej, tworząc głęboką kopię obiek-
zwracając wyniki obliczeń, przechowując rzystuje obie strategie kopiowania opisa- tu za każdym razem, gdy wołana jest opera-
elementy w kontenerach i w wielu innych
sytuacjach są tworzone kopie. Jeżeli obiekt Listing 1. Tworzenie kopii płytkiej i głębokiej
jest dostępny pośrednio, na przykład przez
wskaźnik, to można wykonać kopię wskaźni- class Foo { //klasa pomocnicza
ka (lub innego uchwytu) albo całego obiek- public:
tu. W związku z tym możemy wyróżnić trzy Foo() : i_(0) {}
rodzaje kopiowania: kopiowanie płytkie, gdy int get() const { return i_; }
kopiujemy uchwyty (wskaźniki), kopiowa- void set(int i) { i_ = i; }
nie głębokie, gdy tworzymy kopię obiektu, };
oraz kopiowanie leniwe, które łączy kopiowa- Foo* shellCopy(Foo* f) { //płytka kopia
nie płytkie i głębokie. Do demonstracji tych return f; //wskaźniki pokazują na ten sam obiekt
technik będziemy używali klasy Foo pokaza- }
nej na Listingu 1. Foo* deepCopy(Foo* f){ //głęboka kopia
Kopią płytką nazywa się kopiowanie jedy- return new Foo(*f); //wskaźniki pokazują na różne obiekty
nie obiektów pośredniczących, wskaźników, }
referencji, uchwytów itp. Kopia taka jest Foo* p1 = new Foo();
tworzona szybko, ponieważ wskaźnik lub in- Foo* p2 = shellCopy(p1); //płytka kopia
ny obiekt pośredniczący jest zazwyczaj ma- Foo* p3 = deepCopy(p1); //głęboka kopia
łym obiektem. Po wykonaniu płytkiej kopii p1->set(2); //zmiana obiektu wskazywanego przez p1
ten sam obiekt jest dostępny z wielu miejsc, assert( p2->get() == 2 ); //obiekt wskazywany przez p2 został zmieniony
obiekt wskazywany nie jest kopiowany, zmia- assert( p3->get() == 1 ); //obiekt wskazywany przez p3 nie został zmieniony
na jego stanu będzie widoczna we wszystkich
kopiach. Głęboka kopia oznacza rzeczywiste

12 3/2010
Wzorzec prototypu

cja modyfikująca, ale wtedy wiele kopii jest cja fastDeepCopy, pokazana na Listingu 3, SDJ 2/2010), a my dysponujemy tylko ty-
zbędnych. wykorzystuje dodatkowy argument, który pem interfejsu. Rzeczywisty typ obiektu
Przykład leniwego kopiowania został jest tworzony w czasie kompilacji na podsta- może być inny.
pokazany na Listingu 2. Przedstawiona wie informacji o typie. Jego wartość nie jest Wzorzec prototypu, nazywany też wir-
tam klasa wykorzystuje sprytne wskaźni- istotna, natomiast typ pozwala wybrać od- tualnym konstruktorem, opisany w książce
ki boost::shared_ptr, które zostały omó- powiednią funkcję kopiującą. Jeżeli obiekty ,,Wzorce projektowe'' przez „bandę czworga''
wione w SDJ 11/2009. Sprytne wskaźniki mogą być kopiowane za pomocą funkcji ko- (Gamma, Helm, Johnson, Vlissides), pozwa-
to szablony, które pozwalają automatycznie piującej fragmenty pamięci, to jest ona wo- la na tworzenie głębokiej kopii w takich przy-
usuwać obiekt utworzony na stercie, prze- łana, w przeciwnym wypadku woła się kon- padkach. Pomysł polega na przeniesieniu od-
chowują one i aktualizują licznik odnie- struktor kopiujący. Technika trejtów została powiedzialności za tworzenie obiektów do
sień do wskazywanego obiektu. Szablony opisana w SDJ 11/2009. klas konkretnych, wykorzystując mechanizm
te wspierają tworzenie leniwej kopii, dostar- funkcji wirtualnych. Klasa bazowa dostarcza
czają metodę unique, która pokazuje, czy Wzorzec prototypu metody czysto wirtualnej, która jest nadpi-
zarządzany obiekt jest wskazywany przez Jeżeli posługujemy się wskaźnikiem lub re- sywana w klasach konkretnych (gdzie znany
jeden, czy więcej wskaźników. Metoda ta ferencją do klasy bazowej, to możemy wy- jest typ), więc można utworzyć głęboką kopię
jest wykorzystana w klasie LazyFoo do roz- konać jedynie płytką kopię. Kopia głęboka obiektu. Przykład pokazano na Listingu 4,
strzygania, czy można modyfikować bieżący jest niedostępna, ponieważ przy tworzeniu klasa bazowa Figure dostarcza metody czy-
obiekt, czy raczej należy zrobić kopię. obiektu należy podać konkretny typ (patrz sto wirtualnej clone. Metoda ta jest nadpisy-
Tworząc kopię głęboką obiektu tymcza-
sowego, który będzie usunięty po zakoń- Listing 2. Leniwa kopia z użyciem boost::shared_ptr
czeniu operacji kopiowania, można wyko-
nać kopię płytką i nie usuwać tego obiek- class LazyFoo { //przechowuje leniwą kopię obiektu typu Foo (Listing 1)
tu, co przypomina przeniesienie właściciela public:
obiektu. Taki mechanizm dla wskaźników LazyFoo(int i) : ptr_(new Foo(i) ) {}
dostarcza std::auto_ptr (SDJ 11/2009), LazyFoo(const LazyFoo& l) : ptr_(l.ptr_) {}
w ogólnym przypadku wymaga on wspar- int get() const { return ptr_->get(); }
cia w języku. Takie wsparcie będzie dostar- void set(int i) { //metoda zmienia stan obiektu
czone w nowym standardzie C++200x po- if(ptr_.unique() ) { ptr_->set(i); } //bada czy istnieje konieczność
przez referencję do r-wartości, co pozwoli tworzenia kopii
na implementację różnych konstruktorów else { ptr_ = PFoo(new Foo(i) ); }
kopiujących. Używając konstruktora ko- }
piującego do r-wartości, będzie można prze- private:
nieść zawartość obiektu, unikniemy wtedy typedef shared_ptr<Foo> PFoo;
zbędnej kopii. PFoo ptr_;
};
Szybkie kopiowanie głębokie
Dla pewnych typów obiektów kopia głęboka
może być wykonana bez użycia konstrukto- Listing 3. Wykorzystanie klasy cech do wyboru algorytmu kopiowania
ra kopiującego za pomocą operacji kopiują-
cych fragmenty pamięci. Obiekty, które bę- template<typename T> //kopiowanie za pomocą memcpy
dą w ten sposób kopiowane, nie mogą mieć T* doFastDeepCopy(const T* element, true_type) {
składowych, które są wskaźnikami, bo wska- char* mem = new char[sizeof(T)]; //przydziela pamięć
zywane przez te składowe obiekty także bę- memcpy(mem, element, sizeof(T));
dą musiały być kopiowane przy tworze- return reinterpret_cast<T*>(mem);//zwraca obiekt odpowiedniego typu
niu kopii głębokiej. Informacji o tym, czy }
obiekt może być kopiowany za pomocą ko- template<typename T> //woła konstruktor kopiujący
piowania bajtów, dostarcza klasa cech (trejt) T* doFastDeepCopy(const T* element, false_type) {
has_trivial_copy , który jest dostarcza- return new T(*element);
ny przez bibliotekę boost::traits. Funk- }
template<class T> //algorytm tworzenia kopii wykorzystuje trejty
T* fastDeepCopy(const T* element) {

Szybki start return doFastDeepCopy(element, has_trivial_copy<T>() ); //tworzy dodatkowy


Aby uruchomić przedstawione przykła- argument
dy, należy mieć dostęp do kompilatora }
C++ oraz edytora tekstu. Niektóre przy-
kłady korzystają z udogodnień dostar-
czanych przez biblioteki boost, warun-
kiem ich uruchomienia jest instalacja bi-
bliotek boost (w wersji 1.36 lub nowszej).
Na wydrukach pominięto dołączanie od-
powiednich nagłówków oraz udostęp-
nianie przestrzeni nazw, pełne źródła do-
łączono jako materiały pomocnicze.
Rysunek 1. Kopia płytka i głęboka dla obiektów dostępnych pośrednio

www.sdjournal.org 13
Programowanie C++

Listing 4. Wzorzec prototypu


wana w klasach konkretnych, jeżeli ją będzie-
my wołali, to będzie tworzona głęboka kopia
class Figure {//klasa bazowa obiektu o odpowiednim typie.
public: Jeżeli jest dostępny wirtualny konstruktor,
virtual Figure* clone() const = 0;//wirtualny konstruktor możemy tworzyć głęboką kopię, wykorzy-
virtual ~Figure(){} stując interfejs klasy bazowej, wołając meto-
}; dę clone(). Listing 4 zawiera przykład, któ-
class Square : public Figure {//klasa konkretna ry tworzy głęboką kopię kolekcji figur i wyko-
public: rzystuje przedstawioną technikę.
Square(int size) : size_(size) {}
Square(const Square& sq) : size_(sq.size_) {} Fabryka prototypów
Figure* clone() const { return new Square(*this); } //tworzy głęboką kopię Wzorzec prototypu możemy wykorzystać
private: w fabryce, która będzie dostarczała obiek-
int size_; tów danego typu, nazywanej fabryką pro-
}; totypów. Fabryki są to klasy pośredniczą-
class Circle : public Figure {//klasa konkretna ce w tworzeniu nowych obiektów, jeden
public: z rodzajów fabryk został omówiony w SDJ
Circle(int r) : r_(r) {} 2/2010. Fabryka prototypów przechowu-
Circle(const Circle& c) : r_(c.r_) {} je obiekty wzorcowe, które będą kopiowa-
Figure* clone() const { return new Circle(*this); }//tworzy głęboką kopię ne, jeżeli użytkownik zleci utworzenie no-
private: wego obiektu. Fabryka taka pozwala two-
int r_; rzyć obiektów różnych typów na podstawie
}; identyfikatora, ponadto możemy nadać róż-
ne identyfikatory obiektom tego samego ty-
//przykład użycia wirtualnego konstruktora do tworzenia głębokiej kopii obiektów pu różniącym się stanem. Fabryki prototy-
typedef vector<Figure*> Figures; pów zazwyczaj zużywają więcej zasobów niż
Figures figures;//kolekcja figur, która będzie kopiowana fabryki obiektów, konieczne jest przechowy-
figures.push_back(new Square(2) ); wanie obiektów wzorcowych, na podstawie
figures.push_back(new Circle(3) ); których będą tworzone kopie. Przykład ta-
figures.push_back(new Circle(1) ); kiej fabryki pokazano na Listingu 5.
Figures copy; //głęboka kopia kolekcji figur Fabryki prototypów pozwalają wygodnie
for(Figures::const_iterator ii = figures.begin(); ii != figures.end(); ++ii) tworzyć obiekty z danej hierarchii klas, wy-
copy.push_back( (*ii)->clone() );//wykorzystuje wzorzec prototypu magają, aby w tej hierarchii był implemento-
wany wzorzec prototypu. Dodatkowym kosz-
tem tego rodzaju fabryki jest używanie me-
Listing 5. Fabryka prototypów chanizmu późnego wiązania (funkcje wirtu-
alne), więc obiekty muszą zawierać wskaźnik
class FigCloneFactory { //fabryka prototypów dla hierarchii figur na tablicę funkcji wirtualnych, wołanie meto-
public: dy clone() odbywa się pośrednio.
int registerFig(Figure* prototype, int id) { //rejestruje nowy obiekt oraz jego
identyfikator Podsumowanie
prototypes_.insert( make_pair(id, prototype) ); Przedstawione techniki związane z tworze-
} niem kopii są powszechnie stosowane w róż-
Figure* create(int id) {//tworzy obiekt danego typu i w danym stanie nych językach programowania. Ich znajo-
map<int, Figure*>::const_iterator i = prototypes_.find(id); mość pozwala na tworzenie płytkiej lub głę-
if(i ! = prototypes_.end() ) //jeżeli znalazł odpowiedni wpis bokiej kopii w zależności od potrzeb.
return prototypes_.find(id)->second->clone(); //wzorzec prototypu
return 0L; //zwraca nullptr jeżeli nie znalazł prototypu
}
private:
W Sieci
• http://www.boost.org – dokumentacja
map<int, Figure*> prototypes_;//przechowuje obiekty wzorcowe bibliotek boost;
}; • http://www.open-std.org – dokumenty
opisujące nowy standard C++.

ROBERT NOWAK
Więcej w książce Adiunkt w Zakładzie Sztucznej Inteligencji Insty-
Zagadnienia dotyczące współcześnie stosowanych technik w języku C++, wzorce projekto-
we, programowanie generyczne, prawidłowe zarządzanie zasobami przy stosowaniu wy- tutu Systemów Elektronicznych Politechniki War-
jątków, programowanie wielowątkowe, ilustrowane przykładami stosowanymi w bibliotece szawskiej, zainteresowany tworzeniem aplikacji
standardowej i bibliotekach boost, zostały opisane w książce ,,Średnio zaawansowane pro- bioinformatycznych oraz zarządzania ryzykiem.
gramowanie w C++'', która ukaże się niebawem. Programuje w C++ od ponad 10 lat.
Kontakt z autorem:rno@o2.pl

14 3/2010
Opis DVD

Programowanie w języku Java wania klasy ServletContext i interfejsu ServletContextListener.


Ponadto zostanie przedstawiony sposób organizacji logiki inter-
Od Witaj świecie do aplikacji korporacyjnych. Aplikacje fejsu użytkownika oraz logiki biznesowej na przykładzie klasy
internetowe – Aplikacja zarządzania konferencjami służącej do trwałego zapisywania danych.
W efekcie powstanie działający fragment systemu z zastosowa-
Szósty odcinek serii to przykład zastosowania dotychczas zdo- niem mechanizmów serwletów i JSP.
bytych umiejętności do stworzenia aplikacji internetowej. Ce-
lem działań będzie zrealizowanie fragmentu funkcjonalności
aplikacji do zarządzania konferencjami – tworzenia, przeglą-
dania i aktualizacji konferencji.
Pierwszym krokiem będzie stworzenie stron nawigacyjnych
z odpowiednimi pozycjami menu, używając do tego podstawo-
wych konstrukcji HTML i JSP. Archiwum Linux+ 2009
Następnie zostanie stworzony serwlet zajmujący się dyna-
miczną częścią aplikacji, której zadaniem będzie interpreta-
cja danych otrzymanych w żądaniu od użytkownika oraz wy-
korzystaniu ich do zmian systemu. Przedstawione zostaną ele-
menty komunikacji między sewletami a stronami JSP, zastoso-

Jeśli nie możesz


odczytać zawartości
płyty DVD, a nie jest ona Redakcja
uszkodzona mechanicznie, nie udziela pomocy
sprawdź ją na co najmniej dwóch technicznej w instalowaniu
napędach DVD. i użytkowaniuprogramów
W razie problemów z płytą, prosimy pisać zamieszczonych na płytach DVD-ROM
pod adres: cd@software.com.pl dostarczonych razem z pismem.

15
Programowanie Java

Przewodnik po SCJP
Czyli certyfikat z Javy – część 3
Proces zdobywania certyfikatów, potwierdzających umiejętności
z różnych dziedzin wiedzy, stał się jednym z ważniejszych elementów
osobistego rozwoju. Proces ten ma miejsce również w branży IT;
certyfikaty dla programistów (Java lub .NET), administratorów czy
sieciowców (Cisco) można coraz częściej odnaleźć w CV osób starających
się o pracę, zwłaszcza w owianym złą sławą kryzysie gospodarczym.
List lista = new List();
Dowiesz się: Powinieneś wiedzieć: lista.add(new Integer(3));
• Jakie klasy uczestniczą w procesie i18n; • Jak skompilować i uruchomić programy
• Jakie klasy wejścia/wyjścia musisz znać do w Javie; Ten krótki fragment kodu prezentuje działa-
egzaminu; • Jakie są podstawy składni języka; nie klasy opakowującej (z ang. wrapper) dla ty-
• Na czym polega mechanizm autoopakowy- • Jakie są ogólne zasady korzystania z API pu int. Wartość typu prymitywnego (3) zo-
wania. w Javie. stała przekazana do konstruktora tej klasy. No-
wo utworzony obiekt możemy bez przeszkód
dodać do listy.
niach (podstawy omówimy jedynie w przy- Na podobnej zasadzie funkcjonują pozo-
padku asercji); kluczowe są przeróżne sztuczki stałe klasy opakowujące. Tabela 1 zawiera spis
Poziom i ruczki, za pomocą których twórcy egzaminu wszystkich typów prymitywnych i odpowiada-
trudności chcą utrudnić programistom zdanie go. jących im klas.
Wiemy już, jak zamienić wartość typu pry-
Typy prymitywne a sprawa klas mitywnego na obiekt, a co z operacją odwrotną?
Programowanie w Javie wiąże się nieodłącznie Wystarczy skorzystać z metody intValue(),

W
trzeciej części cyklu artykułów, z wykorzystywaniem obiektów. Trudno zna- aby uzyskać wartość prymitywną:
poświęconego przygotowaniom leźć program, który ich nie używa. Jak już zosta-
do egzaminu Sun Certified Java ło wcześniej napisane, w Javie posługujemy się Integer obiekt = (Integer)lista.get(0);
Programmer for Java SE 6, zajmiemy się kolej- referencjami do obiektów, a nie obiektami sa- int liczba = obiekt.intValue();
nym zagadnieniem – API Contents, czyli głów- mymi w sobie. Oznacza to, że dowolna zmien-
nie (acz nie tylko) funkcjonalnością J2SE. na nie przechowuje obiektu, a jedynie odniesie- Przedstawione powyżej rozwiązania są jak
W trakcie omawiania niniejszego zagadnie- nie (wskaźnik) do niego. Gwoli ścisłości trzeba najbardziej poprawne. Już w tym momen-
nia zwrócimy uwagę na kilka zasadniczych po- jednak zaznaczyć, że nie wszystkie zmienne są cie wiem, że niejeden Czytelnik zdążył zapro-
dzagadnień: powiązane z obiektami! W przypadku typów testować – „Przecież wywołanie rodzaju li-
prymitywnych (int, char, byte, boolean, float, sta.add(3); działa! O co tutaj chodzi?”.
• Klasy opakowujące typy prymityw- double, short, long) zmienne przechowują war- Problem wynika, jak to zwykle w takich sy-
ne (m.in. Integer, Character, Byte) tości tych typów, a nie referencje do nich. Teoria tuacjach, z powodów historycznych. Powyższe
i związane z nimi operacje automatyczne- teorią, ale jak to stwierdzenie ma się do codzien- rozwiązanie jest jedynym poprawnym rozwią-
go pakowania/rozpakowania; nej pracy programisty? zaniem w Javie do wersji 1.4 włącznie. Od Javy
• Operacje na łańcuchach znaków i podobne; Zasada jest prosta. Z formalnego punktu wi- 5 wprowadzono mechanizm autoopakowania
• Operacje na plikach z wykorzystaniem dzenia we wszystkich metodach, które przyj- (ang. autoboxing), który odpowiada za automa-
klas czytających/zapisujących (Reader / mują jako parametr(y) obiekt(y), przekaza- tyczne opakowywanie wartości prymitywnych,
Writer i pochodne); nie zmiennej typu prymitywnego to błąd. Ko- jak i ich powrotną konwersję:
• Dostosowywanie informacji (teksto- nieczne jest zastosowanie obiektu specjalnej kla-
wych, liczbowych, dat) do ustawień sy (innej dla każdego typu prymitywnego), któ- lista.add(5);
regionalnych – klasy DateFormat, ry „opakuje” zmienną prymitywną. Jako pełno- int liczba = (int)lista.get(0);
NumberFormat, Locale ; prawny obiekt będzie można go przekazać do
• Wykorzystywanie wyrażeń regularnych żądanych metod. Rzutowanie jest niezbędne do wykonania kon-
w praktyce. O jakich metodach mowa? Chociażby o naj- wersji z typu Object (nasza przykładowa lista
prostszych operacjach związanych z kolekcja- nie jest generyczna), jednak pośrednia kon-
Podobnie jak w poprzednich artykułach, nie mi (więcej na ich temat w jednym z kolejnych wersja do typu Integer dokonuje się automa-
będziemy skupiać się na całych zagadnie- artykułów): tycznie.

16 03/2010
Certyfikat SCJP

Na szczęście zadania związane z klasami opa- go fragmentu brzmi: 3 (dwa z nich zostały wyja- StringBuilder i StringBuffer
kowującymi nie są trudne; część z nich (związa- śnione, a trzeci musisz znaleźć samodzielnie). – tacy sami, ale nie ci sami...
na z przeciążaniem metod) została omówiona Na zakończenie tego podzagadnienia nie Przy przetwarzaniu względnie dużej ilości in-
w pierwszej części kursu (SDJ 11/09). Przede mógłbym pominąć kwestii puli łańcuchów formacji z użyciem klasy String mogą wystąpić
wszystkim, musisz pamiętać dokładnie nazwy (ang. string pool). Dzięki niezmienności łańcu- problemy związane z wydajnością. Załóżmy, że
klas. Trzeba uważać, aby nazwy klas opakowują- chów możemy osiągnąć pewne korzyści. Załóż- w jakimś programie podczas wczytywania da-
cych nie pomyliły Ci się z nazwami typów. my, że tworzysz łańcuch za pomocą bezpośred- nych cyklicznie dołączamy znaki do łańcucha.
niego przypisania: Oznacza to, że każde dołączenie tworzy nowy
Łańcuchowe szaleństwo łańcuch, a jednocześnie przeznacza do usunię-
Krótki opis klas opakowujących z poprzednie- String s = "tekst"; cia stary. Co za tym idzie – jeśli w swoim pro-
go ustępu ułatwia zrozumienie działania typów gramie chcesz intensywnie modyfikować i two-
prymitywnych w obiektowym świecie. Nie Java w tym momencie dodaje do owej puli wy- rzyć nowe łańcuchy, absolutnie nie powinieneś
wspomniałem w nim jednak o jednej z klas, któ- żej wymieniony literał tekstowy. Jeśli w dal- używać do tego celu klasy String.
ra chyba najczęściej jest zaliczana do typów pry- szym fragmencie kodu ten sam literał pojawi Z powyższego kłopotu wybawią Cię kla-
mitywnych w Javie. Mowa o klasie String. się ponownie: sy StringBuilder i StringBuffer. Obie kla-
Klasa String odpowiada za przechowywanie sy mają identyczną funkcjonalność, która spro-
tekstów – zbiorów znaków. Klasa ta otrzymała String s2 = "tekst"; wadza się do możliwości dynamicznego dołą-
(jako jedyna) od twórców Javy specjalne przywi- czania, usuwania i modyfikacji znaków w ob-
leje – możemy w jej przypadku korzystać z ope- to zamiast tworzyć nowy obiekt, JVM skorzy- rębie wewnętrznego bufora. Różnią je dwie
ratorów + i = (co nie jest możliwe w przypadku sta z obiektu istniejącego już w puli! Nie daj się cechy – klasa StringBuffer jest synchronizo-
innych klas, bo przeciążanie operatorów jako ta- zatem zwieść – wywołanie dwóch instruk- wana (dzięki czemu dostęp do obiektu tej kla-
kie w Javie nie występuje). Początkujący progra- cji w obrębie jednego bloku kodu spowoduje sy przez różne wątki nie spowoduje powstania
mista, widząc taki zapis: utworzenie tylko jednego obiektu! Jednak już bezsensownych danych), a StringBuilder nie
utworzenie łańcucha znaków za pomocą kon- (dzięki czemu działa ona nieznacznie szybciej);
String s = "tekst"; struktora: ponadto klasa StringBuilder została wprowa-
s = s + "inny"; dzona dopiero w Javie 5.
String s3 = new String("tekst"); Funkcjonalność obu klas stanowi połączenie
może istotnie pomylić klasę String i uznać ją niektórych możliwości klasy String (np. meto-
za typ prymitywny. To jednak nie koniec pro- spowoduje utworzenie nowego obiektu. dy substring(), length(), indexOf()) z ope-
blemów – z klasą String wiąże się wiele cie- racjami dołączania (append()), wstawiania (in-
kawych zagadnień, które mogą znaleźć się na Metody klasy String sert()) i usuwania (delete()) znaków. Zwróć
Twoim egzaminie. Nie będziemy w tym miejscu dogłębnie oma- uwagę, że te trzy metody, wraz z kilkoma po-
Zaczniemy z wysokiego c – zajmiemy się wiać metod klasy String. Opis działania moż- dobnymi metodami tej klasy, zwracają zmody-
kwestią modyfikowalności, inaczej zwaną na zobaczyć w dokumentacji. Warto jednak fikowany obiekt. Dzięki temu możesz tworzyć
zmiennością (z ang. mutability). Cechą charak- zwrócić uwagę na kilka szczegółów, dotyczą- (nomen omen) łańcuchy wywołań:
terystyczną łańcuchów jest ich niezmienność. cych wszystkich metod:
Oznacza to, że w raz utworzonym łańcuchu nie StringBuffer sb = new StringBuffer();
możesz zmienić np. drugiego znaku. Co więcej, • Opanuj arytmetykę łańcuchową, czyli wy- sb.append("tekst").append("
nie możesz także dołączać innych łańcuchów liczanie znaku na danej pozycji, a także inny").delete(1, 2);
na początku, ani na końcu już istniejącego łań- uwzględnianie w obliczeniach długości łań-
cucha. To zdanie jest sprzeczne z powyższym cuchów. Nie jest to skomplikowane, jednak Konwersję do zwykłego łańcucha znaków uzy-
przykładem, więc spieszę z wyjaśnieniem – w bardziej złożonych przykładach określa- skuje się za pomocą metody toString(). Na
drugi wiersz (z operacją konkatenacji – złącza- nie podłańcuchów może zająć trochę czasu. egzaminie podchwytliwymi mogą okazać się
nia łańcuchów) nie zmienia obiektu tekst, tylko • Zapoznaj się z metodą intern(). W prak- pytania związane z arytmetyką łańcuchów –
tworzy zupełnie nowy obiekt, zawierający tekst tyce jest ona wykorzystywana niezwykle zwróć uwagę, że w metodzie delete() (i kilku
tekstinny. Nie zapominaj, że zmienna s jest jedy- rzadko, jednak na egzaminie może poja- podobnych) indeks początkowy jest wliczany
nie referencją! Po wykonaniu pierwszej instruk- wić się w kontekście zagadnienia opisane- do wykonywanej operacji (inclusive), a indeks
cji wskazuje ona na jeden obiekt, a po wykona- go w poprzednim akapicie. końcowy – nie (exclusive)!
niu drugiej – już na zupełnie inny! • Zwróć uwagę, że drugim parametrem me-
W tym momencie dochodzimy do często tody substring() jest indeks ostatniego Tabela 1. Typy prymitywne i odpowiadające im
spotykanego na egzaminach pytania – na pod- znaku, a nie liczba znaków do pobrania! klasy opakowujące
stawie fragmentu kodu musisz określić, ile • W ramach ćwiczeń dotyczących arytme- Nazwa typu Klasa opakowująca
obiektów typu String zostało w nim utworzo- tyki łańcuchowej uwzględnij intensywne prymitywnego
nych. Odpowiedź na to pytanie dla poprzednie- użycie metod substring() i replace(). int Integer
boolean Boolean
Listing 1. Schemat wyświetlania sformatowanej daty byte Byte
// Wyświetla aktualną datę w najbardziej rozbudowanym formacie obowiązującym w USA char Character
Locale l = new Locale("en","US"); short Short
Calendar c = Calendar.getInstance(l);
long Long
DateFormat df = DateFormat.getDateInstance(DateFormat.FULL, l);
�oat Float
System.out.println(df.format(c.getTime()));
double Double

www.sdjournal.org 17
Programowanie Java

Operacje wejścia/wyjścia – zdanie egzaminu. Przede wszystkim, mu- • dwuparametrowy konstruktor


Ten niezwykle rozległy temat na egzaminie jest sisz znać ogólne działanie poszczególnych klas. Locale(String język, String kraj)
(na szczęście) poruszany w dość ograniczony Warto znać także skrót i18n, z angielskiego in- – język to dwuliterowy kod języka (ISO-
sposób. Musisz znać klasy File, FileWriter, ternationalization (pomiędzy i a n znajduje się 639, pisany małymi literami, np. en), a kraj
FileReader, BufferedReader, BufferedWriter 18 liter) – tym mianem określa się wszystkie – dwuliterowy kod języka (ISO-3166 pisa-
i PrintWriter. Krótki opis klas znajdziesz w Ta- czynności w trakcie tworzenia oprogramowa- ny wielkimi literami, np. US).
beli 2., jednak to nie on w rozwiązywaniu zadań nia, związane z przystosowywaniem progra- • metoda statyczna getDefault() pobierają-
jest najważniejszy. W przypadku tych klas nale- mów do różnych języków/ustawień regional- ca domyślne ustawienia na danym kompu-
ży wiedzieć, w jaki sposób można wiązać ze so- nych. To oczywiście dopiero początek – naj- terze.
bą obiekty tych klas, aby uzyskać obiekt o żąda- istotniejszy typ zadań polega na analizie ko- • szereg statycznych pól, określających usta-
nej funkcjonalności. Jednym słowem – wzorzec du wykonującego operacje i18n (wskazaniu wienia dla niektórych krajów (np. FRENCH,
projektowy dekorator w pełnej krasie. błędów, określeniu wyświetlanych komuni- GERMAN)
Zarówno strumienie, jak i pozostałe klasy katów etc.). Z tego względu ważna jest znajo-
wejścia/wyjścia były tworzone zgodnie z zasad- mość kluczowych metod wyżej opisanych klas Po utworzeniu ustawień lokalnych musisz po-
mi działania dekoratora. W dużym skrócie, de- – ich połączenie w logicznie działający kod sta- brać odpowiedni obiekt do formatowania. Za-
korator opakowuje oryginalny obiekt, zachowu- je się wtedy banalne. czniemy od liczb (walut), dlatego będzie to
jąc jego funkcjonalność, a dodatkowo wzbogaca- Na początku zazwyczaj jest tworzony obiekt obiekt klasy NumberFormat. W tym przypad-
jąc ją o nowe możliwości. Na przykład, zwykły klasy java.util.Locale. To właśnie ten obiekt ku najpierw musisz utworzyć obiekt, korzysta-
obiekt typu FileReader umożliwia odczyt da- przechowuje informację na temat kraju i/lub jąc z jednej ze statycznych metod:
nych w postaci bajtów, ale udekorowany za po- konkretnych ustawień regionalnych. Jest on
mocą obiektu klasy BufferedReader pozwala niezależny od klas formatujących (choć klasy • getInstance() – działa jak getNumberIn-
na odczyt całych wierszy tekstu: te wykorzystują go dość intensywnie), dlatego stance();
warto stworzyć go na początku. Do najważniej- • getNumberInstance() – zwraca obiekt
BufferedReader br = new BufferedReader szych składników klasy należą: formatujący zwykłe liczby;
(new FileReader("plik.txt"));

Pytania
Oczywiście każda z klas dokładnie określa, ja- 1. Wybierz instrukcje, które nie spowodują błędu kompilacji przy następującej deklaracji:
kie obiekty można przekazać w konstruktorze. List<Integer> lista = new List<Integer>();
Jednym z najczęściej spotykanych typów zadań a) lista.add(new Integer(3));
egzaminacyjnych jest wybór poprawnych kon- b) lista.add(3);
c) lista.add(new Integer(3).intValue());
struktorów dla danej klasy. W przypadku klasy
d) lista.add(new Integer(3).valueOf(3));
BufferedReader możemy skorzystać jedynie
z klas pochodzących od klasy Reader. 2. Które z poniższych wyrażeń zwróci tekst 1232345?
Same operacje zapisu i odczytu nie są trak- a) String s = "12345";
towane w specjalny sposób. Inaczej ma się sytu- s.substring(1, 4).substring(2,3) + "2345");
b) new StringBuffer("12345").append("45").replace(3, 5, "23");
acja z operacjami na samych plikach, a nie we-
c) new StringBuffer("54321").insert(2,new StringBuffer("2323").reverse().subs
wnątrz nich. Musisz więc wiedzieć, jakie możli- tring(2)).reverse().append("23").delete(4, 6)
wości oferuje klasa File. Standardowo zalecam
więc zwracanie uwagi na nazwy metod, przyj- 3. Wybierz wywołania, które skompilują się poprawnie:
mowane przez nie parametry i typy zwraca- a) BufferedReader br = new BufferedReader(new File("plik.txt"));
b) FileReader file = new FileReader(new InputStreamReader("plik.txt"));
nych obiektów.
c) PrintStream ps = new PrintStream("plik.txt");
d) PrintWriter pw = new PrintWriter(new File("plik.txt"));
Wyświetlanie danych
Gdy dysponujesz już danymi pobranymi z pli- 4. Wybierz poprawny(-e) schemat(y) prowadzący do wyświetlenia sformatowanej daty:
ku, musisz je w jakiś sposób wyświetlić. Twór- a) utworzenie obiektu klasy Locale -> utworzenie obiektu typu Date -> utworzenie obiektu
cy pytań egzaminacyjnych o tym nie zapo- formatującego NumberFormat -> pobranie daty z kalendarza -> wyświetlenie daty
b) utworzenie obiektu typu Date -> utworzenie obiektu formatującego DateFormat -> wy-
mnieli, dzięki czemu ten dość specyficzny te- świetlenie daty
mat jest traktowany na egzaminie stosunkowo c) pobranie obiektu typu Calendar -> utworzenie obiektu formatującego DateFormat ->
poważnie. pobranie daty -> wyświetlenie daty
Aby proces formatowania tekstu nie wydał
się zbyt prosty, musisz w nim uwzględnić usta- 5. Wybierz prawidłowe odpowiedzi:
a) Poniższy kod wyświetli tekst 0 abaabc:
wienia regionalne, specyficzne dla danego kra- Pattern p = Pattern.compile("[abc]+");
ju (a nawet regionu) – za co odpowiada osobna Matcher m = p.matcher("abaabc");
klasa o nazwie Locale. To właśnie ona, w połą- while (m.find())
System.out.println(m.start()+" "+m.group());
czeniu z klasą DateFormat (w przypadku dat)
b) Poniższy kod wyświetli tekst 0 abaabc:
i NumberFormat (w przypadku liczb i walut), Pattern p = Pattern.compile("[abc]+");
pozwala na pełną kontrolę sposobu wyświetla- Matcher m = new Matcher(p).matcher("abaabc");
while (m.find())
nia danych. Do kompletu przyda się odrobina System.out.println(m.start()+" "+m.group());
wiedzy na temat klas Calendar i Date; czasa- c) Poniższy kod wyświetli tekst 0 0 1 1 2 2 3 3
mi trzeba przecież wykonywać operacje zwią- Pattern p = Pattern.compile("\d+\s");
zane z datami. Matcher m = p.matcher("0 1 2 3 ");
while (m.find())
Zagadnienie samo w sobie jest dość cie- System.out.println(m.start()+" "+m.group());
kawe, jednak nam przyświeca konkretny cel

18 03/2010
Certyfikat SCJP

• getCurrencyInstance() – zwraca obiekt ustawień regionalnych z określonym sty- Klasa Pattern reprezentuje pojedyncze wyra-
formatujący z uwzględnieniem konwencji lem daty. żenie regularne. Aby uzyskać obiekt tej klasy, mu-
zapisu walut. • getDateInstance() i getInstance() sisz skorzystać ze statycznej metody compile():
– pobierają formater dostosowany do do-
Powyższe wersje metod zwracają obiekty do- myślnych ustawień regionalnych ze sty- Pattern p = Pattern.compile("\s[a-z]+\s");
stosowane do domyślnych ustawień regional- lem DEFAULT – w przypadku metody
nych – istnieją też warianty tych metod, przyj- getDateInstance() i ze stylem SHORT – Powyższe wyrażenie regularne dopasowuje
mujące obiekt klasy Locale. Po utworzeniu w przypadku metody getInstance(). ciąg słów (pisanych małych literami), bez pol-
obiektu nie pozostaje Ci nic innego, jak wy- skich znaków, przedzielonych białymi znaka-
wołać metodę format(), aby wyświetlić liczbę Styl daty określa sposób wyświetlania daty i cza- mi. Po utworzeniu obiektu musisz skorzystać
w żądany sposób: su – do dyspozycji masz zbiór kilku stałych, za- z metody matcher(), aby dopasować podane
deklarowanych w klasie DateFormat: (DEFAULT, wyrażenie regularne do danych wejściowych:
System.out.println(numberFormatter.format(3 SHORT, FULL, MEDIUM , LONG). Ich dokładne warto-
000000)); ści zależą od ustawień regionalnych. Warto za- Matcher m = p.matcher("test");
uważyć, że obecnie domyślny styl daty przecho-
Nieco bardziej skomplikowany schemat obo- wuje tę samą wartość, co styl MEDIUM . Jeśli chcesz Teraz możesz zacząć przeszukiwać dane wej-
wiązuje w przypadku formatowania daty. Po sformatować także czas, skorzystaj z metod za- ściowe, pobierając informacje na temat kolej-
pierwsze, musisz najpierw pobrać datę, a po wierających dodatkowo słowo Time w nazwie. nych pasujących do wyrażenia regularne pod-
drugie – utworzenie obiektu formatujące- Po uzyskaniu obiektu musisz wywołać meto- ciągów:
go dla dat jest bardziej złożone. Zacznijmy od dę parse(), podając jako argument obiekt daty.
pierwszego etapu. Cały kod (dla wariantu z datą) jest przedstawio- while (m.find()) {
Uzyskanie obiektu klasy Date, który można ny na Listingu 1. System.out.println(m.start() + " " +
sformatować za pomocą klasy DateFormat, jest Cały schemat wyświetlania danych przedsta- m.group());
możliwe na dwa sposoby. Po pierwsze, możesz wiłem dość drobiazgowo, ponieważ równie dro- }
po prostu utworzyć obiekt: biazgowe pytania mogą pojawić się na egzami-
nie. Jeśli jakiś element pojawił się w moim omó- Metoda start() zwraca indeks początkowy
Date d = new Date(); wieniu, oznacza to, że ma on znaczenie. podciągu, który pasuje do wyrażenia, a meto-
da group() – cały podciąg. Metoda find() wy-
Obiekt d zawiera datę i czas jego utworzenia. Wyrażenia regularne (nie)?fajne szukuje kolejne podciągi pasujące do wyraże-
Możesz skorzystać z metod klasy Date; jest jed- są\? nia. Dopóki wyszukiwanie będzie przynosiło
nak jedno małe „ale”. Metody te zostały uzna- Obsługa wyrażeń regularnych stanowi istotne wyniki – będzie zwracana wartość true.
ne za przestarzałe już w JDK 1.1. Znamieni- zagadnienie w chyba każdym szanującym się ję- Powyższy schemat jest jednym z najczęściej
ta funkcjonalność tej klasy została zastąpiona zyku programowania, dlatego nie mogło jej za- sprawdzanych mechanizmów na egzaminie.
przez klasę Calendar. Uzyskanie obiektu kla- braknąć w Javie, jak również na egzaminie. Wie- Warto wiedzieć, że do sprawdzenia pojedyn-
sy Date w przypadku tej klasy wymaga wyko- dza niezbędna na egzaminie składa się z dwóch czego dopasowania możesz skorzystać z meto-
nania dwóch kroków: podzagadnień: znajomości wybranych wyrażeń dy matches() obiektu klasy Matcher (utwo-
regularnych, jak również sprawnego poruszania rzonego w taki sam sposób, jak w poprzednim
• pobrania obiektu klasy Calendar – za po- się wśród klas je obsługujących. Samo omówie- przykładzie):
mocą metody getInstance() dla domyśl- nie wyrażeń regularnych (z uwagi na ograniczo-
nych ustawień regionalnych lub z parame- ny rozmiar artykułu) sprowadzę jedynie do ich boolean pasuje = m.matches();
trem klasy Locale; wypisania (za java.sun.com):
• wywołania metody getTime(). Zagadnienie serializacji i obsługa metody
. (kropka), * (gwiazdka), +, ?, \d, \s, \w, [], (). printf(), które w pewnych zestawach ćwi-
Gdy dysponujesz obiektem do sformatowania, czeniowych pojawia się w ramach tego dzia-
musisz jeszcze utworzyć obiekt formatujący Nawiasy są wykorzystywane jedynie do grupo- łu, zostanie omówione w jednym z kolejnych
klasy DateFormat. W tym przypadku również wania (bez obsługi przechwytywania). Kwan- artykułów.
możesz skorzystać z metod statycznych: tyfikatory *, + i ? występują jedynie w wersji za- W tym momencie nie pozostało Ci nic inne-
chłannej. Informacje na temat powyższych in- go, jak rozwiązać zadania załączone do tego ar-
• getDateInstance(int styl, Locale lokale) formacji w Internecie znajdziesz bez liku. Gdy tykułu. Powodzenia!
– pobiera formater dostosowany do ustawień wyrażenia regularne staną się dla Ciebie banal-
regionalnych z określonym stylem daty. ne, możesz zacząć z nich korzystać z Javie, ko-
• getDateInstance(int styl) – pobie- rzystając z wielu klas. Zaczniemy od najbar-
Bibliogra�a:
ra formater dostosowany do domyślnych dziej standardowych – Pattern i Matcher. • Sierra K., Bates B. – Sun Certi�ed Pro-
grammer for Java 5 Study Guide
otrzymasz tekst 0 0 2 1 4 2 6 3.
że metoda start() będzie zwracać kolejne indeksy zliczane wraz ze spacjami, więc na standardowym wyjściu
5. a – b nie, ponieważ klasa Matcher nie zawiera konstruktora. Przykład c jest prawie dobry – problem w tym,
jest też dwukrotne pobieranie daty, chociaż nie jest to formalnie rzecz biorąc błąd.
4. b, c – a nie, ponieważ do formatowania daty nie korzystamy z obiektu typu NumberFormat. Niepotrzebne
KRZYSZTOF RYCHLICKI  KICIOR
3. a, c, d – b nie, ponieważ konstruktor klasy FileReader nie przyjmuje jako argumentu obiektu klasy Reader. Autor programuje w Javie i .NET. Pisze książki i ar-
potwierdzić wyniki). tykuły na różne tematy związane z programowa-
niem. Jest posiadaczem certy�katu SCJP i SCWCD;
2. b – pozostałe warianty generują inne wartości (sprawdź jakie, a następnie skompiluj podane wyrażenia, aby
metr przyjmuje łańcuch znaków.
1. a, b, c. Odpowiedź d jest nieprawidłowa, ponieważ metoda valueOf() jest statyczna, a dodatkowo jako para- od kwietnia 2007 do kwietnia 2008 legitymował
się tytułem Microsoft MVP w kategorii Visual C#.
Odpowiedzi
Kontakt z autorem: kitikatpl@gmail.com

www.sdjournal.org 19
Sztuczna inteligencja

Paradygmat
programowania CLP
Metody rozwiązywania trudnych problemów
kombinatorycznych.
Wysoka efektywność metod CLP jest rezultatem wykorzystania procedur
propagacji ograniczeń oraz dystrybucji zmiennych, w celu poszukiwania
rozwiązań spełniających wszystkie przyjęte ograniczenia. Procesy te
realizowane są w sposób klasyczny, jak i rozproszony, dając bardzo dobre
rezultaty obliczeniowe.
blem) oraz wersję dynamiczną DynCSP
Dowiesz się: Powinieneś wiedzieć: (Dynamic CSP - składa się ona ze skończo-
• O deklaratywnym podejściu do zapisu/ • O zagadnieniach optymalizacji oraz wybranych nej sekwencji klasycznych problemów CSP
rozwiązywania trudnych problemów decy- aspektach z obszaru badań operacyjnych; (np.: csp(0), csp(1),…, csp(n)), w której każdy
zyjnych; • Podstawowe informacje na temat paradyg- podproblem jest inny – np. poprzez zmia-
• Informacji o różnych wariantach reprezentacji matów programowania oraz algorytmiki; nę ograniczeń w kolejnych krokach). Sku-
wiedzy dla problemu spełnienia ograniczeń; • Obszary sztucznej inteligencji z zakresu sys- piają się one na odpowiednim zapisie pro-
• Jakie rodzaje narzędzi oraz mechanizmów temów wieloagentowych (MAS). blemu w celu jego rozwiązania przez sys-
są nieodłączną częścią paradygmatu CLP. tem. System taki musi być odpowiednio
wyposażony w mechanizmy oraz algoryt-
my heurystyczne, służące do poszukiwa-
wionych metod programowania zaowoco- nia rozwiązania.
wało stworzeniem narzędzia (podejścia), Kolejnym obszarem silnie badanym są
które w większości zastosowań jest bardziej też poszczególne warianty optymalizacji
Poziom wydajne od zwykłego programowania lo- problemu spełnienia ograniczeń. Warianty
trudności gicznego. Stale przybywa sporo nowej wie- takie dla konkretnej odmiany czy podejścia
dzy na temat rozwiązywania problemów przedstawiają się następująco: CSOP (Con-
z ograniczeniami oraz rozwijane są meto- straint Satisfaction Optymization Problem)

S
ystemy klasy CLP (Constraint Logic dy optymalizacji trudnych do rozwiązania – dla klasycznego problemu oraz DCOP
Programming) są szczególną odmia- problemów. Sama technika nie jest do koń- (Distributed Constraint Optymization Pro-
ną mechanizmów opartą o paradyg- ca zrozumiała przez wielu ludzi i jest przez blem) – dla problemu rozproszonego. Dla-
mat programowania z ograniczeniami. Me- to mało popularna. Zupełnie odwrotnie ma tego celem artykułu jest przegląd obejmu-
toda CLP łączy w sobie dwa paradygma- się to do jej efektywności, która jest wyso- jący przedstawienie reprezentacji wiedzy
ty programowania: programowanie logicz- ka. Jak można zauważyć, systemy takie ma- w wybranych obszarach zapisu problemu
ne (Logic Programming) oraz programowa- ją wiele możliwych oraz naturalnych do im- oraz przedstawienie narzędzi. Aby opisy-
nie z ograniczeniami (Constraint Program- plementacji zastosowań. Z powodzeniem wane zagadnienia były lepiej zrozumiałe,
ming). W przeciwieństwie do imperatyw- można je stosować w rzeczywistych środo- dołączono także przykłady, odnoszące się
nych języków programowania, w których wiskach produkcyjnych, w których są odpo- do wybranego zapisu problemu.
podaje się sekwencje poleceń do wykona- wiednim rozwiązaniem systemowym.
nia, w językach programowania logicznego Rzeczywiste problemy
specyfikuje się zestaw zależności, na pod- Różne warianty modelu CLP Główne obszary zastosowań opisywanych
stawie których system dedukcyjny próbu- W wypracowanych dotychczas wariantach technik obejmują zadania klasy kombina-
je udowodnić zadane twierdzenie. Z ko- istnieje wiele stosowanych odmian tego pa- torycznej oraz optymalizacji dyskretnej.
lei programowanie z ograniczeniami pole- radygmatu. Możemy wyróżnić podejście W szczególności technika ta znajduje zasto-
ga na podaniu pewnych ograniczeń, które klasyczne do rozwiązania problemu: czyli sowanie do sterowania dyskretnymi procesa-
określają właściwości poszukiwanego roz- problem CSP (Constraint Satisfaction Pro- mi produkcyjnymi. W tych obszarach opi-
wiązania. Wyrażają one relacje pomiędzy blem), jego wersję rozproszoną - DisCSP sywane narzędzie obliczeniowe jest bardzo
zmiennymi. Połączenie dwóch przedsta- (Distributed Constraint Satisfaction Pro- przydatne między innymi dla:

20 03/2010
Paradygmat programowania CLP

• wspomagania harmonogramowania; poszukiwania rozwiązań, czynią środowi- ne przy budowie dedykowanych systemów
• szeregowania zadań, a w szczególności ska CLP bardzo atrakcyjnym do szybkiego wspomagania decyzji, które charakteryzują
przydziału zadań i zasobów dla poszcze- modelowania i rozwiązywania problemów się specyficznymi właściwościami, struktu-
gólnych maszyn; decyzyjnych. Jest to szczególnie przydat- rą czy ograniczeniami.
• optymalizacji planu dla projektu.

Rzeczywiste problemy, z jakimi mamy


styczność podczas tworzenia dedykowa-
nych narzędzi do ich rozwiązywania, są
głównie problemami decyzyjnymi. Wy-
�� � � �� ��������������
mienione wyżej zagadnienia należą do pro-
blemów optymalizacji dyskretnej z ograni-
� �
czeniami. �

Tradycyjne podejścia matematyczne do
rozwiązania tego typu problemów, czyli znaj-
dowania rozwiązań optymalnych, a nawet � � � ����������������
w niektórych przypadkach tylko dopuszczal-
nych, są mało efektywne. Spowodowane jest
to tym, iż w takiego rodzaju zadaniach istnie-
je tzw. zjawisko eksplozji kombinatorycznej,
wynikające z dużej złożoności obliczeniowej ���� ���� ����
���������������
zadania. Zadania takie zaliczane są do klasy
zadań NP-trudnych.
W proponowanych przez większość ist-
niejących na rynku rozwiązań, dla takiego
Rysunek 1. Przykład interpretacji gra�cznej problemu/zadania
typu zadań, odchodzi się powoli od metod
poszukiwania rozwiązania problemu za po-
mocą języków imperatywnych na rzecz now-
szego narzędzia (podejścia), którym jest de-
klaratywny język programowania z ograni-
czeniami. Wraz ze swoistymi mechanizma-
mi, bazującymi na programowaniu w logice, � � �

posiada ono duży potencjał obliczeniowy do ���


wykorzystania.

Klasyczny problem
spełnienia ograniczeń ���
� � �
Programowanie w logice z ograniczeniami
CLP(Constraint Logic Programming) to dzie-
dzina nauki, którą można ulokować pomię- ���
� �
dzy sztuczną inteligencją, badaniami ope-
racyjnymi oraz językami programowania.
Jest paradygmatem (koncepcją czy też tech-
niką) programowania tak jak np. programo- �
wanie zorientowane obiektowo czy progra-
mowanie funkcyjne (które to jest filozofią
programowania będącą odmianą progra-
Rysunek 2. Graf wartości zmiennych oraz relacje ograniczeń pomiędzy nimi
mowania deklaratywnego, w której funkcje
należą do wartości podstawowych, a nacisk
kładzie się na wartościowanie funkcji, a nie
na wykonywanie poleceń). Koncepcja ta
stosowana jest do modelowania, rozwiązy-
wania oraz zapisu problemów, które mogą
być dane za pomocą zbioru zmiennych i ich
dziedzin, oraz relacji pomiędzy nimi wyra-
żonych w postaci ograniczeń. Ograniczenia
takie odzwierciedlają zależności pomiędzy
zmiennymi problemu. Łatwość modelo-
wania problemów decyzyjnych, a w szcze-
gólności tych, które posiadają w swojej na-
turze ograniczenia, brak przepaści seman-
tycznej pomiędzy modelem a metodyką je-
go rozwiązywania oraz efektywne metody Rysunek 3. Przeszukiwanie przestrzeni rozwiązań: a) algorytmy standardowe; b) zawężanie dziedziny

www.sdjournal.org 21
Sztuczna inteligencja

De�nicja CSP
����������������� Podstawowym zagadnieniem reprezentacji wie-
������������������� dzy w programowaniu w logice z ograniczenia-
��� ����������
mi jest tzw. problem spełnienia ograniczeń CSP
(Constraint Satisfaction Problem). Klasyczny pro-
blem spełnienia ograniczeń zapisujemy w po-
� staci trójki zdefiniowanej następująco:

( V, D, C )

gdzie:

� • V – skończony zbiór zmiennych;


• – związane ze zmiennymi skończone
D
� � � � � � � � � � dziedziny;
• (są one odpowiednio dziedzinami dla
poszczególnych zmiennych).
• C – skończony zbiór ograniczeń (wię-
Rysunek 4. Przykład redukcji dziedzin, podczas procesu propagacji w trakcie rozwiązywania zadania
zów) spełnianych przez zmienne ze zbio-
ru V.

��� ��� Przykład 1:


Przykładowy zapis zadania reprezentujący
wiedzę o postawionym problemie może mieć
� następującą postać:

• V = {x, y, z} – zbiór zmiennych;


• D = {x::{0..9}, y::{0..9}, z::{0..9}}
– są to poszczególne dziedziny dla
zmiennych;
• C = {x < y, z = x + y, x>=3, z =
8} – jest to zapis zbioru ograniczeń, jakie
występują w problemie.

������ Rozwiązaniem tak zapisanego problemu jest


takie przyporządkowanie każdej zmiennej
pewnej wartości z jej dziedziny, aby wszyst-
��� kie ograniczenia były spełnione (jednocze-
śnie). Inaczej mówiąc, jest to dowolne war-
tościowanie zmiennych spełniające wszyst-
Rysunek 6. Przykład zbioru agentów (wymieniających się komunikatami) oraz intra-agenta
kie ograniczenia.
Problem CSP jest głównie rozwiązywany
przez standardowe w tej dziedzinie algorytmy
�������������������
takie jak: backtracking (nawracanie), dynamicz-
ny backtracking, back jumping (odskakiwanie
do tyłu) oraz foward checking (sprawdzanie do
przodu). Problem ten może być również roz-
wiązywany w oparciu o reprezentację grafową
�� metodą sprawdzania spójności łukowej. Spój-
�� �� ność łukowa sprawdza spełnialność więzów lo-
kalnie pomiędzy nieprzypisanymi zmiennymi
������������������
(czyli zmiennymi, które nie mają jeszcze okre-
�������������������� ślonej wartości). Łuki są spójne, gdy dla warto-
ści każdej zmiennej danego węzła istnieje przy
zadanym ograniczeniu odpowiednia wartość
zmiennej z węzła, do którego została ona przy-
��
�� �������������������������� pisana. Poniżej podano zapis przykładowego
zadania oraz jego interpretacje za pomocą gra-
fu (Rysunek 2) :
������������������������������������������������������������������������������������
V = { x, y, z };
D = {{1, 2}, {1, 2}, {1, 2}};
Rysunek 5. Przykład problemu, w którym operujemy na zmiennych typu znakowego C = { x = y, x<>z, y > z }.

22 03/2010
Paradygmat programowania CLP

Na Rysunku 2 przedstawiającym reprezen- • D = {x::{0..9}, y::{0..9}, z::{0..9}} • C = {x < y, z = x + y, x > 3, z =


tację graficzną zadania graf jest spójny wte- – (dziedziny dla zmiennych); 8} – (ograniczenia).
dy, gdy zmienne przyjmują następujące war-
tości: x =2, y=2, z=1 (rozwiązanie zadania).
Metoda rozwiązywania bazująca na spraw-
dzeniu spójności łuków w grafowej reprezen- ���
tacji problemu nazywana jest AC (Arc Consy-
stency).
W metodzie tej istnieje szereg algorytmów
��������������������������������
wyznaczających rozwiązanie. Podstawowy- ��������������������������������
mi algorytmami w tej grupie są : AC-1, AC-3, ��������������������������������
���
AC-4 oraz jeszcze wiele innych (szeroko opi-
sywane w literaturze fachowej), lecz nieuży-
wanych tak często jak te wymienione w ar-
tykule.

Propagacja i dystrybucja
– jako główne mechanizmy CLP

Większość metod rozwiązywania zadania w
środowiskach opisywanych w artykule bazu-
je na naprzemiennym stosowaniu procedur �
propagacji (ograniczania dziedzin zmiennych
decyzyjnych) nazywanych w skrócie propaga- � � � � � � � � � �
torami i dystrybucji (ukonkretniania warto-
ści zmiennych decyzyjnych w celu wyszuka-
�������������������������
nia rozwiązania). ���������������������
Propagacja to operacja, która polega na ��������������
sukcesywnym zawężaniu dziedzin zmien- ��������������������
nych zgodnie z semantyką więzów, w celu
usunięcia elementów, z których nie można
zbudować żadnego rozwiązania. Porządek
kroków propagacji nie ma wpływu na wy-
nik końcowy. Rysunek 7. Przykładowy początek problemu (dziedziny zmiennych są kompletne)
Propagacja nie jest operacją wystarczają-
cą do rozwiązania problemu CSP, zwiększa
ona jednak efektywność procesu (znacząco
przyśpiesza) poszukiwania rozwiązania do- �����������������������
puszczalnego.
Propagatory są implementowane w śro-
dowiskach jako współbieżnie pracujące ������������������
����������������
agenty (w formie osobnych procesów) obli- ������������������
�����������
czeniowe, które starają się zawęzić domeny �����
zmiennych występujących w danym ogra- ������������������
���������������
niczeniu.
Przeważnie implementacja ich wykony-
wana jest za pomocą wątków. Jeśli wszyst- �
kie wartości wszystkich zmiennych speł-
niają dane ograniczenie, propagator prze-
staje istnieć: �

przykłady: x < y oraz x = {3..5} i y ={6..9}



Propagatory wymuszają dodatkowe ograni-
czenia (nieproste), czyli powiązania pomię- � � � � � � � � � �
dzy dwoma lub więcej zmiennymi:

przykłady: a) x < y lub b) x + y = z ������������������ �����


����������� ��������
����� ����������
Aby przybliżyć efekt działania propagato-
rów, przeanalizujmy wcześniej zdefiniowa-
ne w przykładzie 1 zadanie:

• V = {x, y, z} – (zbiór zmiennych); Rysunek 8. Redukcja dziedzin po wymianie komunikatów i uzgodnieniu wartości zmiennych

www.sdjournal.org 23
Sztuczna inteligencja

Na Rysunku 4 został przedstawiony przy-


Listing 1a. Dane w osobnym pliku kład: efektem działania propagacji dla
Produkty = { "gas" "chloride" }; pierwszego ograniczenia x < y jest wyłą-
Skladniki = { "nitrogen" "hydrogen" "chlorine" }; czenie dwóch wartości z dziedzin zmien-
Zapotrzebowanie = [ [1 3 0] [1 4 1] ]; nych: dla x jest to 9, a dla y jest to 0. W na-
Zysk = [30 40]; stępnym etapie są sprawdzane pozostałe
Sklad = [50 180 40]; ograniczenia.
W większości przypadków propagacja
Listing 1b. Kod programu w OPL Studio ograniczeń nie prowadzi do rozwiązania.
{string} Produkty = ...; Dlatego programowanie z ograniczeniami
{string} Skladniki = ...; jest ściśle związane z dystrybucją połączo-
ną z poszukiwaniem. Dystrybucja polega
// deklaracja zmiennych przechowujących dane na wprowadzeniu dodatkowego ogranicze-
float Zapotrzebowanie[Produkty][Skladniki] = ...; nia (często jest to przyporządkowanie jed-
float Zysk[Produkty] = ...; nej wartości do zmiennej, a zadaniem dys-
float Sklad[Skladniki] = ...; trybucji jest odpowiednie wybranie zmien-
nej i wartości).
// zmienna decyzyjna (decision variable) Kiedy to nastąpi, sprawdzana jest spój-
dvar float+ Produkcja[Produkty]; ność poprzez propagację ograniczeń na po-
zostałe zmienne. Istnieją wtedy trzy moż-
// deklaracja ograniczenia liwości:
constraint ograniczenie;
• znalezione zostanie rozwiązanie (wszyst-
// zdefiniowanie funkcji celu kie zmienne mają po jednej wartości
maximize w swojej dziedzinie);
sum( p in Produkty ) • dziedziny niektórych zmiennych zostaną
Zysk[p] * Produkcja[p]; zawężone, ale jednoznaczne rozwiązanie
nie jest wciąż wyznaczone, więc dystrybu-
// zadanie ograniczeń cja jest dokonywana na kolejnej zmiennej;
subject to { • dodatkowe ograniczenie jest niespójne
forall( s in Skladniki ) z pozostałymi ograniczeniami, więc pro-
ograniczenie = ces nawrotu jest dokonywany, a wybra-
sum( p in Produkty ) na wartość z dziedziny wybranej zmien-
Zapotrzebowanie[p][s] * Produkcja[p] <= Sklad[s]; nej jest usuwana.
}
Ten proces jest dokonywany iteracyjnie i jest
Listing 1c. Wynik programu w OPL Studio nazywany poszukiwaniem. Poszukiwanie
//======================================== jest odpowiedzialne za zatrzymanie po zna-
/*Final solution with objective = 1800: lezieniu pierwszego rozwiązania lub pew-
Produkcja = [6.6667 40]; */ nej liczby rozwiązań lub wszystkich roz-
//======================================== wiązań. Poszukiwanie tworzy tzw. drzewo
poszukiwań, gdzie każdy węzeł jest stanem
zmiennej.
Podsumowując więc, proces dystrybu-
cji prowadzi do utworzenia dwóch lub wię-
����������������������� cej rozłącznych przestrzeni rozwiązań (np.
przestrzenie liczb całkowitych dodatnich),
wywodzących się z przestrzeni głównej, po-
przez wprowadzenie sprzecznych ograni-
��������������������������
czeń:

• przykład: podział na dwie rozłączne


� przestrzenie: x = 1, x <>1
• przykład: podział na trzy rozłączne prze-
strzenie: y = 1, y = 2, y > 2

Strategia dystrybucji jest zbiorem reguł
określających:

• którą ze zmiennych niezdeterminowa-


� � � � � � � � � �
nych wybrać do dystrybucji;
• w jaki sposób podzielić dziedzinę tej
Rysunek 9. Rozwiązanie problemu, czyli przyporządkowanie do zmiennych konkretnych wartości zmiennej na rozłączne podzbiory.

24 03/2010
Paradygmat programowania CLP

Jest to działanie wystarczające do rozwią- mi wieloagentowymi MAS (Multi Agents runkuje realizację wspólnych celów agentów,
zania problemu CSP, gdyż dziedzinę każdej Systems), w których zachodzi zjawisko ko- która wymaga współpracy pomiędzy agenta-
zmiennej można stopniowo dzielić na coraz operacji niezależnych jednostek programo- mi i koordynowania ich działań. Zatem ko-
mniejsze podzbiory, aż wszystkie zmienne wych, oddalonych od siebie (również fizycz- operacja w tego typu systemach może być po-
zostaną zdeterminowane do pewnej war- nie), działających we wspólnym środowisku. strzegana jako problem rozproszonego speł-
tości. Podział taki jest niekoniecznie jed- Interakcja pomiędzy poszczególnymi repre- nienia ograniczeń (Distributed CSP). Problem
nakowo efektywny czasowo. Efektywność zentantami takiego systemu zachodzi przy taki przyjmuje więc następującą postać:
może być podnoszona poprzez sterowanie pomocy wymiany komunikatów.
procesem obliczeń, który obejmuje wybór Znalezienie rozwiązania może być zatem • istnieje zbiór agentów: {1, 2, ... , n};
kolejności podstawiania zmiennych decy- postrzegane jako osiągnięcie wewnętrznej • każdy agent posiada jedną albo wie-
zyjnych, wybór kolejnych wartości zmien- spójności w zbiorze agentów. To z kolei wa- le zmiennych (ma przyporządkowaną
nych decyzyjnych czy też liczbę podsta-
wień poszczególnych zmiennych. Sterowa-
nie zatem sprowadza się do określenia efek-
tywnej strategii podstawiania w kontek-
��
ście rozwiązywanego problemu. Jest to bar-
dzo istotny aspekt całego procesu, mający
wpływ na szybkość uzyskania rozwiązania. ��
��������������������������
�� �����������������������������
Dziedziny zmiennych �� ���������
Do modelowania problemów decyzyjnych
istnieje potrzeba określenia rodzaju zmien-
nych, które najlepiej odzwierciedlą zapisywa-
ny problem. Jeżeli problem wymaga do mo-
��
delowania zbyt skomplikowanych struktur, �����������������������
������������������������
należy go sprowadzić do problemu CSP, któ- ��

���������
������� �������������
ry można później zapisać w wybranym środo- ����
wisku w celu rozwiązania go.
W zbiorze ograniczeń wyróżnia się pod-
zbiór ograniczeń podstawowych (basic con-
�������������������������
straints),
które explicite określają dziedziny zmien-
nych, np. ograniczenie x::{2..8} mówi, że
wartości, jakie może przyjmować zmienna x,
są liczbami całkowitymi ze zbioru [2..8]. Rysunek 10a. Przykładowa reprezentacja algorytmu działającego w środowisku agentów (iteracyjne
Zmienna o dziedzinie jednoelemento- ulepszanie)
wej nosi nazwę zmiennej zdeterminowanej.
W systemach programowania klasy CLP sto-
suje się (są możliwe do wykorzystania) stan-
dardowe typy dziedzin dla poszczególnych
zmiennych, takie jak: �������������������������������
���������������������
������������
������������
���������������������������������� �������������������� �������������
��������
���������
• FD (finite domain) – skończone zbiory ���������������������� ����������������������

nieujemnych liczb całkowitych; ������������������������


�����������������������������
• FS (finite sets) – skończone zbiory, któ- ��������������������������������
rych elementami są dziedziny FD; �����������������������
• B (binary set) – zbiór binarny {0, 1};
�������
• R (real sets) – skończone zbiory liczb rze- ����������
�������������������������� ������������ �����������
czywistych wymiernych. �������������
����������������������������������
• Dodatkowo środowiska CLP umożliwią �������������������������������
����

także implementacje ograniczeń logicz- ������������������������������


nych, symbolicznych, które są niedo-
stępne w klasycznych środowiskach pro- �������������������
��������������
������������������������������� ����������������������� �����
gramowania matematycznego. Zmien- �������������������������������
������������������� ����������
������������ ����������������������
ne definiowane są poprzez literały, np.: ���������������� �
����������
{czerwony, zielony, niebieski}

(przykład zobrazowany na Rysunku 5). ��������������������������������

Problem rozproszonego
spełnienia ograniczeń
Reprezentacja wiedzy dla środowisk roz- Rysunek 10b. Przykładowa reprezentacja algorytmu działającego w środowisku agentów (iteracyjne
proszonych jest ściśle związana z systema- ulepszanie)

www.sdjournal.org 25
Sztuczna inteligencja

część zmiennych poszukiwanego roz- • wysyłanie komunikatu możliwe jest dy, gdy istnieje przyporządkowanie przez
wiązania); wtedy, gdy agent zna adres odbiorcy; agenta takiej wartości do swojej zmiennej,
• istnieje inter-agent reprezentujący ogra- • komunikat dociera do odbiorcy po skoń- która będzie spełniać zadane ograniczenia.
niczenia. czonym losowym czasie; Formalna definicja rozproszonego problemu
• dla dowolnej pary agentów porządek od- spełnienia ograniczeń przyjmuje postać po-
De�nicja Distributed CSP bioru jest zgodny z porządkiem wysła- niżej prezentowanej szóstki:
W definicji problemu zakłada się, iż w zbio- nia;
rze agentów możliwa jest komunikacja i speł- • każdy agent ma tylko częściową wiedzę ( A, V, D, C, b, k )
nione są następujące warunki: o problemie.
gdzie:
• agenty komunikują się poprzez wysyła- Zadanie rozproszonego spełnienia ograni-
nie komunikatów; czeń jest rozwiązane w zbiorze agentów wte- • A – zbiór agentów;
• V – skończony zbiór zmiennych, dla któ-

Listing 2a. Przykład problemu kolorowania mapy Australii 3-ma kolorami rych szukamy wartości;
• – związane ze zmiennymi skończone
D
public class LMMapColoring extends Example { dziedziny (gdzie: );
• C – skończony zbiór ograniczeń;
public void modelAustralia() { • b – relacja przynależności zmiennej do
System.out.println("\n \n Program to solve coloring problem: agenta;
modelAustralia() \n \n"); • k – relacja posiadania wiedzy o ograni-
// deklaracja listy zmiennych oraz magazynu czeniu dla zmiennej (agent posiada in-
// przechowującego strukturę całego problemu formację o ograniczeniu nałożonym na
store = new Store(); konkretną zmienną).
vars = new ArrayList<Variable>();
Każdy z agentów próbuje przypisać wartość
//(red, green, blue) swoim zmiennym, przy czym pomiędzy
//( 0, 1, 2 ) agentami występują zależności, które muszą
// przypisanie dziedzin do zmiennych być uwzględnione w proponowanych pod-
FDV WA = new FDV(store, "WA", 0, 2); stawieniach. Zakłada się ponadto, iż każda
FDV NT = new FDV(store, "NT", 0, 2); zmienna jest związana z jednym agentem,
FDV SA = new FDV(store, "SA", 0, 2); gdyż przypadek współdzielenia zmiennych
FDV Q = new FDV(store, "Q", 0, 2); przez wielu agentów może być zastąpiony
FDV NSW = new FDV(store, "NSW", 0, 2); przez wprowadzenie dodatkowych zmien-
FDV V = new FDV(store, "V", 0, 2); nych (lokalnie dla agenta) i ograniczeń na
FDV T = new FDV(store, "T", 0, 2); równość ich wartości.
Przykładowe zadanie reprezentowane
// dodanie zmiennych do listy w omawiany sposób możemy zapisać w na-
// zmienne reprezentują obszary na mapie Australii stępującej formie:
vars.add(WA); vars.add(NT); vars.add(SA);
vars.add(Q); vars.add(NSW); vars.add(V); A = {a1, a2, a3};
vars.add(T); V = {x, y, z};
D = {x::{0..9}, y::{0..9}, z::{0..9}};
// zadanie ograniczeń C = { c1: x < y, c2: z = x + y, c3: x>=3
store.impose(new XneqY(WA,NT)); } ( inter-agent );
store.impose(new XneqY(WA,SA)); b = { belongs(x, a1), belongs(y, a2), .
store.impose(new XneqY(NT,SA)); . . };
store.impose(new XneqY(NT,Q)); k = { known(c1, a1)}, known(c1, a2)},
store.impose(new XneqY(SA,Q)); known(c2, a1)},
store.impose(new XneqY(SA,NSW)); known(c1, a2), .
store.impose(new XneqY(SA,V)); . . }.
store.impose(new XneqY(Q,NSW));
store.impose(new XneqY(NSW,V)); gdzie:
store.impose(new XneqY(V,T)); // Tasmania

// kolorowanie startuje dla czerwonego jako pierwszego koloru


store.impose(new XeqC(WA,0));

// pomocniczy zapis problemu do pliku XML


LMUtil.toXML(store, -1, ".", "LMMapColoringModelAustralia.xml");
}//!modelAustralia()
...

Rysunek 11. Przykład wizualizacji przez system GPS

26 03/2010
Paradygmat programowania CLP

• b:relacja belongs(xj, i) oznacza, że Łatwość modelowania problemów decy- nią tę koncepcję jako bardzo atrakcyjny spo-
agent i ma określić wartość zmiennej xj, zyjnych, a w szczególności tych, które po- sób szybkiego modelowania i rozwiązywa-
każda zmienna xj należy więc do jedne- siadają w swojej naturze ograniczenia, brak nia problemów decyzyjnych. Jest to szcze-
go i - tego agenta (ta relacja jest reprezen- przepaści semantycznej pomiędzy modelem gólnie ważny aspekt podczas budowy dedy-
towana jako belongs( xj, i)); a metodyką jego rozwiązywania oraz efek- kowanych systemów wspomagania decyzji,
• k: relacja known(pk, j) oznacza, iż agent tywne metody poszukiwania rozwiązań czy- które to charakteryzują się specyficznymi
j zna ograniczenie, czyli predykat pk,
(ograniczenia są więc rozproszone mię- Listing 2b. Przykład budowy struktury searcha dla rozważanego problemu
dzy agentów).
. . .
Przyjmuje się, że zadanie DisCSP jest roz- public boolean searchAllAtOnce() {
wiązane w zbiorze agentów, wtedy i tyl- // zmienne potrzebne do obliczenia czasu przeszukiwania
ko wtedy, gdy: w odniesieniu do każdej long T1, T2;
pary: (agent, zmienna), spełniającej rela- T1 = System.currentTimeMillis();
cję belongs(), dokonano podstawienia za // wskazanie heurystyki wyboru zmiennej i wartości
zmienną takiej wartości, że w dowolnej pa- SelectChoicePoint select = new SimpleSelect(vars.toArray(new Variable[1]),
rze: (predykat, agent) spełniającej relację new MostConstrainedStatic(), new IndomainMin());
known(), predykat przy tym podstawieniu // wywołanie procedury przeszukiwania w głąb
jest prawdziwy, czyli wartość zmiennej speł- search = new DepthFirstSearch();
nia ograniczenia. search.getSolutionListener().searchAll(true);
Na Rysunku 8 (graficzna reprezentacja za- search.getSolutionListener().recordSolutions(true);
dania wcześniej zdefiniowanego) została za- search.setAssignSolution(true);
prezentowana propagacja ograniczeń, wy- boolean result = search.labeling(store, select);
stępująca po rozesłaniu komunikatów po- T2 = System.currentTimeMillis();
między agentami, która zawężała dziedziny if (result) {
zmiennych: System.out.println("Number of solutions " + search.getSolutionListener().
Możliwość rozwiązywania w taki spo- solutionsNo());
sób problemu ma duże znaczenie prak- search.printAllSolutions();
tyczne ze względu na powszechne wystę- }
powanie rozproszonych systemów pro- else
dukcyjnych w gospodarce. Istotne jest System.out.println("Failed to find any solution");
zatem prawidłowe i formalne wyspecyfi- System.out.println("\n\t*** Execution time = " + (T2 - T1) + " ms");
kowanie systemu – jego opis matematycz- return result;
ny, uwzględnienie warunków kolejnościo- }
wych, właściwe odzwierciedlenie ograni- ...
czeń zmiennych.
W wyniku opisu zazwyczaj zostaje zde- Listing 2c. Funkcja main() wykonująca program
finiowane trudne zadanie programowa-
nia matematycznego, o dużym rozmia- ...
rze, wymagające zastosowania specyficz- //--------------------------------------
nych technik programowania, z koniecz- public static void main(String args[]) {
ności pozostawiających duży margines dla
heurystyk. LMMapColoring problem = new LMMapColoring();
problem.modelAustralia();
Model dynamicznego
spełnienia ograniczeń DynCSP // uruchomienie przeszukiwania (wszystkie rozwiązania)
Przedstawiony w dalszej części artykułu mo- if ( problem.searchAllAtOnce() )
del zapisu wiedzy jest składnikiem (jednym System.out.println("Solution(s) found");
z wielu konwencji) paradygmatu CLP. Pro- }//!main()
gramowanie w logice z ograniczeniami jest }
dziedziną nauki, która zawiera się pomię-
dzy sztuczną inteligencją, badaniami opera-
cyjnymi oraz językami programowania. Jest
paradygmatem programowania tak jak pro-
gramowanie obiektowe czy też programo-
wanie funkcyjne. Podejście takiej reprezen-
tacji wiedzy stosowane jest do modelowania
oraz zapisu problemów, jakie mogą być da-
ne za pomocą zbioru zmiennych: V, ich dzie-
dzin: D, oraz relacji pomiędzy nimi, wyra- ����� ����������������������������������� �����������������������������������
żonych w postaci ograniczeń: C. Ogranicze-
nia te odzwierciedlają zależności pomiędzy
zmiennymi. Rysunek 12. Gra�czna reprezentacja dynamicznego CSP

www.sdjournal.org 27
Sztuczna inteligencja

właściwościami, swoistą strukturą czy rów- miczne. Wedle tego podziału w proble- ściowania zmiennych, aby spełniło zadane
nież charakterystycznymi dla siebie ograni- mach dynamicznych poszukiwana jest ograniczenia.
czeniami. funkcja rzeczywista, a w statycznych wek- Jako dynamiczną odmianę problemu
tor będący rozwiązaniem. Można by się od- można przyjąć DynCSP (co dalej zosta-
De�nicja Dynamic CSP nieść w tym stwierdzeniu, iż problemem ło szerzej opisane), który to jest sekwencją
W teorii optymalizacji przyjmuje się po- statycznym jest jedna instancja problemu statycznych problemów występujących ko-
dział problemów na statyczne oraz dyna- CSP, w której poszukujemy takiego warto- lejno po sobie. W modelu takim kolejne in-
stancje różnią się od siebie zestawem ograni-
czeń lub rozmiarem dziedzin dla konkret-
nych zmiennych.
Problemy numeryczne, występujące w za-
daniach koordynacji, badaniach operacyj-
nych, sterowaniu produkcją czy też innych
pokrewnych gałęziach przemysłu, mogą
być transformowane do problemów (mo-
delu) CSP oraz do problemów optymaliza-
cji COP (Constraint Optimization Problem).
W wielu praktycznych aplikacjach softwa-
rowych nie istnieje jeden statyczny problem
CSP. W rzeczywistości problemy, które ma-
my do rozwiązania, często zmieniają się
w czasie. Zmiany mogą wydarzyć się w dwo-
jaki sposób:

• poprzez dołączenie do modelu dodatko-


wej informacji;
• lub poprzez zmianę charakteru proble-
mu, którego próbujemy rozwiązać.

Jako przykład zmiany warunków dane-


go problemu podać można działanie sys-
temu nawigacji GPS, który musi przeli-
czyć (rekalkulować) trasę podczas wystą-
pienia sytuacji, gdy samochód nie podą-
żył proponowaną wstępnie przez ten sys-
tem drogą.
Gdy rozwiązywana jest zmodyfikowa-
na wersja problemu CSP , nowy zmienio-
Rysunek 13. Prosty przykład zadania (przed rozwiązaniem)
ny problem jest często (w większości przy-
padków) podobny do problemu poprzed-
niego (starego): różni się on tylko kilko-
ma ograniczeniami lub zmiennymi. Istnie-
je możliwość, iż mała zmiana modelu pro-
blemu tworzy większe zmiany w rozwią-
zaniu optymalnym, jednak w większości
praktycznych przypadków optymalne roz-
wiązania podobnych do siebie problemów
nie różnią się zbyt wiele od siebie. Przykła-
dem może być wspominany system GPS,
w sytuacji gdy samochód jedzie prosto za-
miast skręcić w lewo, pozycja inicjalizacyj-
na jest taka sama w obydwu przypadkach,
więc dalej (w następnym kroku) zachodzi
konieczność jedynie skręcić w lewo (co wią-
że się ze zmianą niewielkiej ilości danych
w problemie).
Postać problemów, która często ulega
zmianie (zmiana warunków zadania) pod-
czas działania systemu – w konwencji pa-
radygmatu CLP, nazywa się problemem dy-
namicznego spełnienia ograniczeń i oznacza
skrótem DynCSP (Dynamic Constraint Satis-
Rysunek 14. Przykład wizualizacji zadania szeregowania (po znalezieniu rozwiązania) faction Problem) dla sekwencji klasycznego

28 03/2010
Paradygmat programowania CLP

problemu oraz DynCOP dla sekwencji pro- na część tego rozwiązania (lokalnie) zostaje zaletą jest także jago równoległość, co czy-
blemu optymalizacji (Dyynamic Constraint modyfikowana, zachowując aktualne przy- ni bardzo atrakcyjną ofertę do możliwości
Optimization Problem). pisanie wartości tej zmiennej, aż do uzyska- implementacji systemu jako wariantu roz-
Przypominając wcześniej opisywane aspek- nia spójności (czyli do przywrócenia stanu, proszonego.
ty paradygmatu, podstawowym zagadnie- w którym ograniczenia są spełnione). Jeśli Poniżej został przedstawiony podział waż-
niem reprezentacji wiedzy w programowa- jest to niemożliwe, podstawiane są inne war- niejszych środowisk wspierających omawia-
niu w logice z ograniczeniami jest tzw. pro- tości dla rozpatrywanej zmiennej w danej in- ną metodykę:
blem spełnienia ograniczeń CSP. Dynamicz- stancji problemu.
ne środowisko jest przedstawiane (widziane) Generalną zasadą tego podejścia jest cią- • Środowiska oparte na językach PRO-
jako sekwencja statycznych problemów klasy głe rozwiązywanie zadania (klasycznego LOG – CLP:
CSP (Rysunek 12): CSP) na podstawie zmian założeń, które • Constraint Handling in Prolog —
Model matematyczny dla dynamicznego pojawiają się w trakcie życia systemu. Isto- CHIP.
CSP jest więc skończoną sekwencją takich tą pamiętania poprzedniego rozwiązania • Język OZ ze środowiskiem MO-
(klasycznych) problemów CSP, przedstawia- (czyli wszystkich przypisań wartości do ZART rozwijane m.in. przez na-
jących się w sposób: zmiennych) jest fakt mniejszego nakładu ukowców z DFKI (Niemieckiego
obliczeń na poprawę niespójnego zadania Centrum Badań nad Sztuczną Inte-
<csp(0), csp(1),…, csp(n)> w kroku następnym. ligencją) oraz SICS (Szwedzki Insty-
tut Informatyki).
Każdy z podproblemów csp(i) jest instan- Przegląd narzędzi • Środowiska oparte na językach niższego
cją problemu DynCSP, gdzie różni się od – środowisk CP/CLP rzędu jak np. C++:
poprzedniej (lub następnej) poprzez do- Efektywność metod CP/CLP jest rezulta- • ILOG Solver – firmy Ilog Inc., to śro-
danie lub usunięcie niektórych ograni- tem wykorzystania procedur propagacji, dowisko, w którym problemy zapisy-
czeń. Wszystkie możliwe zmiany w danej które pozwalają na wzajemne ograniczanie wane są w zbliżonym do języka C++
instancji problemu DynCSP mogą być wy- dziedzin zmiennych decyzyjnych, oraz dys- języku OPL (Optimization Program-
rażone tylko jako usunięcie lub dodanie trybucji zmiennych do zawężonych prze- ming Language). Wspiera ono roz-
ograniczenia w kolejnym punkcie czaso- strzeni dziedzin w celu wyselekcjonowania wiązywanie klasycznych problemów
wym. Rozwiązanie całego dynamicznego rozwiązań spełniających wszystkie przyjęte oraz ich optymalizację.(przykład za-
CSP implikuje rozwiązanie każdej jego in- ograniczenia. Zawężanie dziedzin zmien- pisu prostego problemu produkcyj-
stancji (z osobna), występującej w sekwen- nych decyzyjnych prowadzi do ogranicze- nego w ILOG OPL, przedstawiony
cji całego problemu. nia potencjalnej przestrzeni rozwiązań, co został na Listingach: 1a, 1b, 1c).
Pierwsza składowa problemu csp(0) w efekcie pozwala znacząco skrócić czas • Gecode – biblioteka/środowisko do
jest rozwiązana od początku (na podsta- potrzebny na obliczenia. Efektem naprze- rozwoju systemów opartych o tech-
wie zadanych warunków początkowych). miennego stosowania tych dwóch proce- nologię ograniczeń.
Dopuszczalnym jest rozwiązywanie każ- dur jest szybki sposób wyszukiwania roz- • Minion – Solver C++ do rozwiązy-
dego elementarnego problemu od warun- wiązań dopuszczalnych bądź wykazanie je- wania problemu CSP.
ków początkowych i zastosowanie się tak go braku. • Platformy programistyczne dostępne ja-
do wszystkich późniejszych instancji całe- W podejściach programowania mate- ko narzędzia komercyjne:
go problemu. Jednak takie podejście jest matycznego ograniczenia np. wynikają- • SICStus Prolog: (Szwedzki Instytut
nieefektywne i może być przyczyną niesta- ce z problemu przydziału modelowane są Informatyki);
bilności pomiędzy kolejno po sobie nastę- sztucznie, przy użyciu binarnych zmien- • ECLiPSe: początkowo ECRC, IC-
pującymi rozwiązaniami. Z tego powodu nych decyzyjnych o wartościach zerojedyn- Parc, obecnie rozwijany przez CI-
podczas rozwiązywania dynamicznego pro- kowych. Dlatego ważne jest zastosowanie SCO;
blemu CSP istnieje potrzeba wykorzystania środowisk, w których modelowanie ograni- • CHIP: ECRC, obecnie rozwijany
w możliwie największym stopniu rozwią- czeń jest naturalne. Środowiskami takimi przez COSYTEC;
zań z poprzednich instancji. są niewątpliwie środowiska umożliwiające • również ILOG Solver (darmowa
Istnieje kilka podejść (metod) do rozwią- formułowanie programu w sposób dekla- wersja odnosi się do zastosowań wy-
zywania dynamicznego problemu CSP. Naj- ratywny. Programowanie w logice z ogra- łącznie naukowo/badawczych).
efektywniejsze z nich skupiają się na algo- niczeniami (Constraint Logic Programming) • Platformy służące do symulacji proble-
rytmie lokalnych zmian LC (local changes), jest paradygmatem programowania, który mu jako podejścia rozproszonego:
który próbuje naprawić poprzednie rozwią- niewątpliwie wspiera to podejście, oferu- • DisChoco – platforma rozproszone-
zanie. Kiedy przypisana wartość do zmien- jąc szereg strategii poszukiwania rozwią- go programowania, oparta na języku
nej staje się niezgodna (niespójna) z roz- zania oraz metod optymalizacji. Naturalną Java;
wiązaniem poprzedzającym, wtedy niespój-

Literatura
W Sieci
• Eisenberg C.: Distributed Constraint Satisfaction For Coordinating and Integrating a large-
• http://www.ilog.com/; scale, Heterogeneous Enterprise.
• http://www.gecode.org/; • Meseguer P., Gonzalez S.: Open, Interactive and Dynamic CSP.
• http://jacop.osolpro.com; • Rossi F., Van Beek P., Walsh T.: Handbook of Constraint Programming.
• http://minion.sourceforge.net/; • Russell N.: Constraint Satisfaction Problems.
• http://www.emn.fr/x-info/choco-solver; • Yokoo M., Durfee E. H., Ishida T., Kuwabara K.: The distributed constraint satisfaction pro-
• http://www.sics.se/isl/sicstuswww/site/. blem: formalization and algorithms.

www.sdjournal.org 29
Sztuczna inteligencja

• Frodo – framework do symulacji al- Przedstawiany proces jest prezentowany ce w przepustowości procesów (np. na po-
gorytmów rozproszonego rozwiązy- w formie wizualnej za pomocą grafów dla ko- szczególnych maszynach na wydziale), to
wania. lejnych kroków propagacji ograniczeń, w któ- część z nich jest w pewnym stopniu niewy-
• Platformy typu OpenSource: rych następuje redukcja dziedzin zmiennych korzystana. Pociąga to za sobą dodatkowe
• Choco – solver w postaci bibliote- (czyli wstępne poszukiwanie właściwej war- koszty. Posługiwanie się techniką opartą
ki Java, który może być używany tości). (lub wspieraną) o mechanizmy CLP (np.:
do nauki, badań, jak również za- W przykładowych appletach Javy moż- zastosowaną do planowania potrzeb mate-
stosowany w aplikacjach komercyj- na uzyskać wizualizację sprawdzania spój- riałowych MRP) może w znacznym stop-
nych; ności łuków (AC) (wcześniej opisywanej) niu ograniczyć koszty przedsiębiorstwa
• JaCoP – efektywna obliczeniowo bi- dla testowo zdefiniowanych problemów oraz pozwolić uniknąć kłopotów spowodo-
blioteka programistyczna Javy, im- (dostarczonych wraz z programem, np.: wanych brakiem jakichś zasobów na okre-
plementująca paradygmat progra- Rysunek 14) lub dla problemów utwo- ślony czas.
mowania z ograniczeniami. rzonych od początku przez siebie (Rysu- Rozwinięciem rozważań poruszanych
nek 13). w artykule jest przedstawienie rozproszo-
(przykład zapisu problemu kolorowania Należy mieć na uwadze także to, iż formu- nej wersji problemu spełnienia ograniczeń
w JaCoP: przedstawiono na Listingu 2a, 2b, łując własny problem, wynik wygenerowany (DisCSP), która jest implementacją podej-
2c). przez mechanizm (w trakcie rozwiązywania ścia działającego w środowisku (systemie)
Wiele opracowanych systemów na tych problemu) musi spełniać wszystkie zadane kooperujących ze sobą agentów, wymienia-
platformach wykorzystuje heurystyczne ograniczenia, o ile jest to możliwe, może wy- jących informacje za pomocą komunikatów
algorytmy programowania całkowitolicz- stąpić jednak sytuacja nadmiernego związa- (wiadomości).
bowego z ograniczeniami. Rozwiązywane nia problemu, co implikuje brak jakiegokol- Metoda ta ma proste i naturalne zastoso-
przez nie problemy są zazwyczaj wysoce wiek rozwiązania. wanie w rzeczywistości, w której wiele pro-
złożone już w przypadku niewielkiej licz- cesów posiada rozproszone zasoby. Wystę-
by argumentów problemu (liczba zadań, Podsumowanie puje wtedy potrzeba komunikacji ze sobą
maszyn, pełnionych funkcji itp.). Dzieje W artykule autor przedstawił przegląd oraz oddalonych jednostek wykonawczych w ce-
się to głównie ze względu na konieczność możliwości reprezentacji wiedzy dla wybra- lu wymiany wiedzy o wspólnie rozwiązy-
uwzględnienia licznych ograniczeń zmien- nych metodyk klasy CP/CLP. Przedstawio- wanym problemie.
nych stanu, licznych zmiennych decyzyj- no zapis definiowania problemu wraz z kon- Zawarto także zarys przykładowych moż-
nych oraz warunków odnoszących się do kretnym celem jego zastosowania. Wyszcze- liwości wykorzystania omawianych technik
porządku i czasu wystąpienia zdarzeń dys- gólniono reprezentację wiedzy dla klasycz- w środowiskach produkcyjnych, gdzie bar-
kretnych (czyli w odpowiednich chwilach nego problemu spełnienia ograniczeń, jak dzo dobrze radzi sobie podejście dynamicz-
czasowych), zachodzących w sformułowa- też jego wariantu rozproszonego oraz dy- ne (DynCSP) (czyli sekwencja kolejno wy-
nym zadaniu. namicznego. Realizacja przedstawionych stępujących po sobie klasycznych proble-
W istniejących środowiskach CLP sam etapów dotyczących mechanizmów wyko- mów CSP).
model jest już programem. Dostępne są do rzystywanych w metodykach CP/CLP pro- Myślę, iż taka forma przedstawiania wie-
użycia (zaproponowania przez użytkowni- wadzi do budowy narzędzi w postaci syste- dzy na temat paradygmatu CLP, który sku-
ka środowiska) również odpowiednie wa- mów do wspomagania decyzji, które pozwa- pia się na rozwiązaniu problemu CSP, mo-
rianty metod poszukiwania rozwiązania, lają poszukiwać rozwiązań dla zadań proble- że w znaczny sposób przybliżyć czytelnikowi
będące integralną częścią środowiska CLP, mów decyzyjnych o charakterze kombinato- korzyści płynące z odpowiedniej formy zapi-
do których należą między innymi: propa- rycznym. su zadania podczas podjęcia się próby imple-
gacja ograniczeń, dystrybucja zmiennych W praktyce programowanie z ogranicze- mentacji w systemie.
oraz kombinacje szereg algorytmów poszu- niami jest wysoce deklaratywne, co pozwa- Przedstawiane techniki reprezentowa-
kiwania rozwiązania jak backtracking (na- la wiele rzeczywistych problemów opisy- nia wiedzy można wykorzystać na etapie
wracanie) czy foward checking (sprawdza- wać, używając ograniczeń, które odzwiercie- formułowania (zapisu) problemu w spo-
nie do przodu) z możliwością wyboru heu- dlają zależności pomiędzy zmiennymi pro- sób najlepiej oddający rzeczywistość (na-
rystyki kolejności przeszukiwania zmien- blemu. Taki sposób specyfikacji problemu turę zadania). Korzystając z systemów kla-
nych oraz ich wartości. może być wprowadzony w wielu tradycyj- sy: CP/CLP (umożliwiających rozwiązywa-
nych środowiskach programowania, ale naj- nie tej klasy zadań), jesteśmy w stanie tak
Przydatne oprogramowanie lepszy rezultat jest osiągany, kiedy wykorzy- sformułowane zadanie rozwiązywać bar-
Proces rozwiązania problemu przy użyciu stujemy paradygmat programowania w logi- dzo efektywnie czasowo.
metody CLP składa się z określenia ograni- ce, który również opiera się na deklaratyw-
czeń, a następnie poszukiwania rozwiąza- ności i relacjach.
nia za pomocą szeregu heurystycznych al- Opisywany paradygmat może być wy-
gorytmów poszukiwania, propagacji ogra- korzystany w teorii ograniczeń, która jest
niczeń oraz dystrybucji zmiennych. Jest to metodyką usprawniania systemów. Zakła-
często słabo dostrzegalne przez użytkow- da się, iż w każdym systemie zbudowa- ŁUKASZ MAZUR
nika tej technologii (można powiedzieć, nym z wielu powiązanych ze sobą dzia- Doktorant AGH Kraków, obecnie zajmuje się
iż cała mechanika ukryta jest pod ma- łań znajduje się jedno działanie ograni- analizą danych oraz rozwojem hurtowni da-
ską), dlatego aby ułatwić naukę o technolo- czające skuteczność całego systemu. Ce- nych, prowadzi także prace badawcze nad al-
gii CLP, można wstępnie posłużyć się pro- lem systemu może być maksymalizacja zy- gorytmami optymalizacji w konwencji para-
gramami, które w sposób wizualny przed- sku. W przedsiębiorstwie może funkcjono- dygmatu programowania w logice z ograni-
stawią krokowo przebieg rozwiązywanego wać wiele procesów, z których jeden limi- czeniami.
problemu. tuje jego zysk. Jeżeli występują duże różni- Kontakt z autorem: lukash.mazur@gmail.com

30 03/2010
Bezpieczeństwo

Niezawodność systemów
informatycznych
Nieustanny postęp technologiczny, zwłaszcza ten dotyczący świata
IT, sprawia, że mamy do czynienia z globalną komputeryzacją oraz
informatyzacją, która z dnia na dzień zatacza coraz to szersze kręgi. Postęp
służyć powinien globalnemu dobru, jednak wraz postępem pojawiają
się coraz to nowe problemy oraz pułapki, których nie sposób traktować
z przymrużeniem oka.
systemu monitorowania komponentów siecio-
Dowiesz się: Powinieneś wiedzieć: wych celem agentów będzie dostarczanie in-
• Jak może wyglądać podstawowa struktura • Co to jest usługa sieciowa; formacji na temat poszczególnych komponen-
wieloagentowego systemu monitoringu sieci; • Podstawowe informacje na temat systemów tów, potrzebnych do określenia aktualnego sta-
• Podstawowe zagadnienia związane z bez- informatycznych świadczących usługi; nu, w jakim się one znajdują.
pieczeństwem oraz niezawodnością usług. • Podstawowe informacje na temat popular- Zacząć należy jednak od zdefiniowania
sieciowych nych narzędzi monitorujących sieć. struktury sieci, w której działać będą oba syste-
my: monitorowany system informatyczny oraz
system monitorujący. Do naszego celu doskona-
funkcjonalności - które dostarczane są czę- le pasuje struktura trójwarstwowa, w której wy-
sto przez zewnętrzne oprogramowanie (np. różniamy poszczególne warstwy (Rysunek 1):
Poziom typowe usługi sieciowe: HTTP, FTP, SMTP,
trudności ostatnio popularny VoD i wiele, wiele in- • najniższa – warstwa odpowiedzialna za
nych) – musimy zadbać o jak największą dostarczanie potrzebnych informacji;
ich niezawodność (tudzież dostępność) • środkowa – warstwa odpowiedzialna za

Z
jawisko to dotyczy niemalże wszyst- oraz bezpieczeństwo. Pod uwagę bierzemy analizę danych oraz podejmowanie de-
kich płaszczyzn funkcjonowania spo- aspekty związane z serwerami back-up, re- cyzji – np. adaptacyjnych, zmiany kon-
łeczeństwa (począwszy od instytucji plikacjami baz danych, jak również samych figuracji etc;
naukowych, poprzez przemysł, biznes, komu- aplikacji odpowiedzialnych za dostarczanie • najwyższa – odpowiedzialna za zobrazo-
nikacje, urzędy) dzięki czemu spotykane jest konkretnych już funkcjonalności. wanie aktualnego stanu całej struktury
podczas wykonywania nawet najprostszych Budując „niezawodny system informatycz- systemu monitorowanego – np. konsola
czynności w naszym codziennym życiu. ny” z uwzględnieniem wszystkich założonych administratora.
Powszechnie znanym oraz na co dzień sto- w projekcie aspektów bezpieczeństwa i nieza-
sowanym słowem jest: usługa (ang. service), wodności, nie sposób pominąć kwestię mo- Taka struktura sieci nie jest oczywiście wy-
dziś również w świecie IT – np. usługa siecio- nitorowania jego poszczególnych komponen- mogiem. System wieloagentowy jest na tyle
wa. Ostatnio popularny model dostarczania tów w celu zobrazowania aktualnego stanu elastycznym tworem, że daje zastosować się
usług – Cloud Computing, obejmujący modele systemu oraz podejmowania właściwych de- do wielu rodzajów struktur sieci.
usług takich jak SaaS, PaaS czy IaaS, oferuje po- cyzji. Niniejszy artykuł pokrótce opisuje ar- W naszym przypadku (staramy się stworzyć
nadto całkowicie przezroczystą warstwę dostę- chitekturę wieloagentowego systemu moni- system monitorujący komponenty dostarczają-
pu do usługi z punktu widzenia usługobiorcy. torowania komponentów sieciowych, wcho- ce usługi sieciowe), projektując strukturę sieci,
Użytkownik (usługobiorca) nie musi wiedzieć, dzących w skład systemu informatycznego należy zadbać o to, aby znalazło się w niej miej-
gdzie fizycznie znajduje się dana usługa ani znać zorientowanego na usługi. sce przynajmniej dla dwóch najniższych warstw
szczegółów jej implementacji. W jego zaintere- – warstwa monitorująca oraz warstwa analizu-
sowaniu leży przede wszystkim funkcjonalność Architektura wieloagentowego jąca i podejmująca decyzje.
oraz rezultat dostarczany przez wybraną usłu- systemu monitorowania sieci W artykule tym skupimy się na najniższej
gę. Oczywistym jest fakt, że bez względu na Pojęcie systemu wieloagentowego jest obec- warstwie struktury, tj. warstwie odpowiedzial-
typ usługi powinna być w pełni świadczona jej nie dobrze znane przez ludzi ze środowiska nej za dostarczanie informacji dotyczących kom-
funkcjonalność i jednocześnie w sposób jak naj- IT. Jak wskazuje typ takiego systemu, składa ponentów świadczących dane usługi sieciowe.
bardziej niezawodny oraz bezpieczny. się on z komunikujących się ze sobą niezależ- Ponadto opisana zostanie warstwa środkowa,
Projektując system informatyczny, udo- nych bytów – Agentów (ang. Agents), reali- analizująca zebrane dane oraz podejmująca pew-
stępniający wiele różnorakich usług, oprócz zujących jednak ten sam cel. W przypadku ne decyzje oparte o rezultaty analizy. Warstwa ta

32 03/2010
Niezawodność systemów informatycznych

zostanie potraktowana bardzo ogólnie i jedynie informatycznego oraz jaką rolę odgrywa środ- sieciowe takie jak router czy zarządzalne switch-
w kontekście warstwy najniższej (analiza oraz kowa warstwa systemu monitorującego. Jest e mają wbudowane oprogramowanie umoż-
podejmowanie decyzji warstwy środkowej są to oczywiście bardzo ogólny zarys, bez żadnych liwiające przesyłanie logów w formacje np. sy-
zagadnieniami, które mogłyby stanowić temat konkretnych informacji na temat samej techni- slog-a w miejsce ich przeznaczenia. Agent, mają-
na co najmniej jeszcze jeden artykuł), gdyż obie ki kolekcjonowania i analizowania danych oraz cy możliwość „nasłuchiwania” na plikach logów
warstwy stanowią nieodzowną całość w opisy- podejmowania decyzji na podstawie rezultatów lub portach TCP, do których wysyłane są logi
wanym modelu systemu monitoringu. dostarczonych przez algorytmy analizy danych. z poszczególnych serwisów, przechwytuje oraz
Jak widać na Rysunku 1, cała sieć (system in- Opis ten pozwala nam jednak na sporządzenie przekazuje je poprzez sieć (np. przy pomocy pro-
formatyczny dostarczający usługi sieciowe) zo- oraz zaprojektowanie ogólnych założeń syste- tokołu UDP lub innego, w zależności od polityki
stała podzielona na swego rodzaju komórki. mu monitoringu. Na Rysunku 2 przedstawio- bezpieczeństwa) do agenta decyzyjnego.
Każda z nich zawiera kolekcję agentów dostar- ny został ogólny zarys systemu monitorowa- Jednak logi dostarczane przez serwisy świad-
czających informacje na temat monitorowanych nia wraz z przepływem danych między jego po- czące usługi na danym hoście są tylko jednym ro-
komponentów sieciowych oraz jednego Agenta szczególnymi komponentami. Wyraźnie widać dzajem (z wielu) informacji, jakie będą nam po-
Decyzyjnego (ang. DecisionAgent), kolekcjonu- trójwarstwową strukturę (podobnie jak struk- trzebne do uzyskania rzeczywistego obrazu sta-
jącego (zapisującego, np. do bazy danych) oraz turę sieci, którą chcemy monitorować), w skład nu maszyny (hosta). Innym rodzajem informa-
analizującego informacje, a następnie podejmu- której wchodzą (kolejno od warstwy najniższej): cji, które są niemniej istotne, to dane dotyczące
jącego odpowiednie decyzje w oparciu o rezul- monitorowane hosty (lub urządzenia sieciowe), aktualnego zużycia procesora, pamięci czy nawet
taty wykonanej analizy. Agent Decyzyjny jest agent decyzyjny wraz z bazą danych (najczęściej obciążenia na karcie sieciowej. Dzięki tym infor-
szczególnym przypadkiem zwykłego agenta, w postaci osobnego hosta lub wielu hostów, na macjom możemy monitorować aktualną dostęp-
którego funkcjonalność rozszerzona jest o me- których zainstalowany jest cały system bazoda- ność poszczególnych usług oraz czas odpowiedzi
tody analizy i podejmowania decyzji. Innymi nowy) oraz konsola, mająca na celu zobrazowa- na żądanie od klienta. Aktualnie jest wiele narzę-
słowy, jest to centralny komponent każdej z po- nie aktualnego stanu monitorowanego systemu dzi potrafiących dostarczyć tego typu informacje,
szczególnych komórek. Zbiór omawianych ko- wraz z jego poszczególnymi podzespołami. np.: SNORT, Statgrab, SNTP czy WMI, jednak są
mórek, wraz z agentami decyzyjnymi, w cało- Zajmijmy się teraz najniższą warstwą, czy- to tylko przykłady. Tak więc nie zależy nam na
ści składają się na środkową warstwę systemu li monitorowanym hostem. Jak wspomniane wymyślaniu koła raz jeszcze, a jedynie wykorzy-
monitoringu. W fizycznym projekcie sieci każ- było na początku niniejszego artykułu, usługi staniu dostępnych dla ogółu narzędzi. Agent re-
da komórka mogłaby stanowić osobną podsieć, dostarczane są zazwyczaj poprzez zewnętrzne zydujący na hoście powinien być zaprojektowany
a agenci znajdować się w różnych przestrzeniach aplikacje/systemy instalowane na hostach we- w taki sposób, aby dać możliwość pozyskiwania
adresowych. Oczywiście jest to tylko propozycja, wnątrz naszej sieci. Przykładem takich usług danych z dowolnych systemów zewnętrznych.
podział na komórki może być czysto abst rakcyj- mogą być: WebServer, DNS, FTP i wiele innych. Cel ten można osiągnąć poprzez założoną z góry
ny, a o podziale stanowić będzie jedynie infor- Każda z tych usług posiada możliwość logowa- modularyzację Agenta, co zresztą przedstawione
macja o tym, z którymi agentami decyzyjnymi nia zdarzeń. Logi zapisywane są w różnych for- jest na Rysunku 2 (dodatkowe wtyczki w posta-
komunikują się agenci dostarczający informa- matach oraz w różnych postaciach (np. do pli- ci bibliotek – tzw. „sensory” dostarczające lub po-
cje o monitorowanych podzespołach. Po opisie ków na dysku lub w formacie Syslog-a), które zyskujące informacje o hoście).
tym można wywnioskować, że nie jest to stan- w prosty sposób możemy pozyskać oraz przeka- Drugą – przedstawioną na Rysunku 2, ro-
dardowy model systemu wieloagentowego. Po- zać do dalszej analizy. To właśnie jest główną ro- lą agenta, jest umożliwienie zmiany konfigu-
szczególni agenci pozyskujący i dostarczający in- lą agenta monitorującego dany host. Czym więc racji hosta. Przykładowo, otrzymując infor-
formacje o monitorowanych komponentach nie jest Agent? W najczęstszej postaci będzie to apli- macje o niepoprawnym działaniu danej usłu-
muszą mieć możliwości komunikowania się ze kacja rezydująca na monitorowanej maszynie gi, możemy nakazać agentowi na reakcję, np.
sobą nawzajem. W zasadzie nie muszą nawet lub urządzeniu. Najczęściej, gdyż urządzenia zrestartowanie wadliwie działającej usługi.
wiedzieć o swoim istnieniu. Ich zadaniem jest
przede wszystkim zdobycie potrzebnych infor-
������������
macji oraz przesłanie ich do agenta centralnego
����������������
– agenta decyzyjnego, który musi już znać loka- �������
lizację poszczególnych agentów oraz mieć moż-
liwość komunikacji z każdym z nich w ramach
komórki, do której należy. Ponadto agent decy-
������������
zyjny powinien komunikować się ze wszystkimi
������� �������
innymi agentami decyzyjnymi stanowiącymi
agentów centralnych pozostałych komórek.
���������������� ����������������
Z tego miejsca wiem już, jak zorganizowana
może być struktura monitorowanego systemu

���������
Projekt Armazd
Armazd, jest to projekt oparty na licencji
opensource (GNU GPL v2). Podstawowym
założeniem, jest stworzenie systemu moni-
torującego oraz podejmującego decyzje re- ������� ����� ������� ������� ����� �������
kon�guracyjne, w oparciu o analizę zebra-
nych danych, na temat monitorowanej sie-
ci komputerowej. Jeśli jesteś zainteresowany
tą tematyką, polecam stronę projektu: http:/
/hardtechnology.org/armazd.
Rysunek 1. Przykładowa struktura sieci – systemu informatycznego świadczącego usługi sieciowe

www.sdjournal.org 33
Bezpieczeństwo

Moduł ten jest oczywiście mocno ograniczo- Już na tym etapie widać, jak złożona może być zawodność systemu informatycznego, którego
ny restrykcjami narzuconymi z góry poprzez jednostka agenta centralnego oraz jak szeroki podstawowymi cechami są:
przyjętą politykę bezpieczeństwa, gdyż wy- wachlarz możliwości daje się zastosować, aby
magałoby to nadania odpowiednich upraw- zadbać o jak największą dostępność oraz bez- • monitorowanie komponentów siecio-
nień agentowi w systemie (wielu administra- pieczeństwo usług systemu informatycznego. wych;
torów nie zgadza się na tego typu czynności • gromadzenie oraz analiza zebranych da-
w sieciach zostawionych pod ich opiekę). Co Przykład nych;
do samej implementacji agenta powinna być implementacji oraz zastosowanie • podejmowanie decyzji rekonfiguracyj-
ona przeprowadzona w taki sposób, aby sam Opisywane powyżej zagadnienia, nie są tyl- nych poszczególnych jak również całych
agent miał jak najmniejszy wpływ na obcią- ko kawałkiem – oderwanej od rzeczywisto- grup komponentów sieciowych;
żenie hosta, na którym rezyduje. Oznacza to ści – teorii. Problem niezawodności usług sie-
implementację na relatywnie niskim pozio- ciowych jest również jak najbardziej realny. Po- Jest to jednak tylko przykład implementa-
me (np. C/C++) oraz ewentualne uwzględ- woduje to pojawianie się różnorodnych narzę- cji rozwiązań problemów z rodziny bezpie-
nienie obciążenia powodowanego przez dzi mających na celu zmaksymalizowanie bez- czeństwa oraz niezawodności.
agenta w algorytmach analizy danych. pieczeństwa i niezawodności systemów infor- Nietrudno natomiast wyobrazić sobie przy-
W ogólności, przepływ danych w systemie matycznych. Mogą być to na przykład rozpro- kład zastosowania tego typu systemu monito-
monitorującym może wyglądać w następują- szone systemy backup-owe, tworzące oraz za- ringu. Przykładem może być firma świadczą-
cy sposób: rządzające kopiami zapasowych, jak również ca popularne ostatnio usługi VoD. Stale mo-
narzędzia monitorujące oraz diagnozujące ca- nitorując np. zużycie procesora, pamięci czy
• wysyłanie logów przez serwisy do agentów łą strukturę sieci komputerowej. Przykładem obciążenie na łączu, jesteśmy w stanie szybko
lub pozyskiwanie danych przez agentów; takiego narzędzia, może być ogólnie dostępny i niemalże automatycznie reagować na sytu-
• wysyłanie danych przez agentów do agen- system Armazd (ramka: Projekt Armazd). Sys- acje, gdy którykolwiek z wymienionych współ-
ta decyzyjnego; tem ten, został zaprojektowany oraz zaimple- czynników jest zbyt wysoki. Jeśli jest duże ob-
• odbieranie danych przez agenta decyzyj- mentowany zgodnie z zagadnieniami opisany- ciążenie na łączu, automatycznie spada dostęp-
nego oraz ich analiza i ewentualne zapisa- mi w poprzednim rozdziale. Dzięki temu, po- ność świadczonych usług, łatwo możemy to wy-
nie w bazie danych; zwala gromadzić dane z wszystkich komponen- kryć i zmienić konfigurację routera. W sytuacji,
• podejmowanie odpowiednich decyzji tów sieciowych (takich jak router, switch, hosty gdy zużycie procesora znacznie podnosi się po-
w reakcji na dane zdarzenie (jeśli taka jest świadczące usługi sieciowe czy nawet stacje ro- nad normę, również najczęściej mamy do czy-
wymagana); bocze). Implementacja przeprowadzona została nienia z drastycznym spadkiem świadczonych
• wysyłanie informacji o reakcji przez agen- na względnie niskim poziome (języki C/C++). usług. W przypadku braku wystarczającej ilo-
ta decyzyjnego do jednego (bądź wielu) Funkcjonalność systemu, w obecnej fazie roz- ści pamięci, narażeni jesteśmy przykładowo na
agentów rezydujących na monitoro- woju, sprowadza się do monitorowania kom- błędne działanie aplikacji odgrywających klu-
wanych maszynach; ponentów sieciowych, pozyskiwanie interesują- czową rolę w procesie świadczenia usługi. Tego
• wykonanie polecenia (np. zmieniającego cych nas danych oraz przekazywanie ich w zde- typu parametrów może jest wiele. Natomiast,
konfigurację usługi) przez agenta rezydu- finiowane miejsce przeznaczenia. Projekt doty- wszystkie wymienione sytuacje powodują spad-
jącego. czy jednak całego procesu podnoszącego nie- kiem bezpieczeństwa oraz niezawodności syste-
mów informatycznych.

���������������� Podsumowanie
������� ������������������� Bezpieczeństwo, niezawodność czy dostęp-
���������������� ność usług sieciowych to bez wątpienia niezwy-
kle ważne zagadnienia dzisiejszego świata IT.
Ilość i rodzaj usług oraz liczba usługodawców
����������������������
�������� IT różnego typu wzrasta z dnia na dzień. Wraz
�����������������
������ z tym postępem technologicznym obserwuje-
my wzrost odpowiedzialności, jakie biorą na sie-
��
������������� bie jednostki świadczące dane usługi (od banko-
���������������
wości po instytucje publiczne takie jak np. urzę-
dy czy organy prawa). Dlatego wdrażając syste-
my informatyczne zorientowane na usługi, nie
�������������� sposób pominąć wyżej wymienione zagadnie-
nia bezpieczeństwa, na które kładziony jest na-
����� cisk, nieraz równoważny z zapewnieniem funk-
cjonalności świadczonych usług.

��������������
������
��������������
������������
ANDRZEJ OLCHAWA
Autor niniejszego artykułu pracownikiem �rmy Po-
wer Media S.A., na stanowisku Software Developer.
���������������������
Interesuje się bezpieczeństwem oraz niezawodno-
����������
ścią w kontekście systemów informatycznych. Wię-
cej informacji na temat autora czytelnik może zna-
leźć, odwiedzając stronę: http://hardtechnology.org.
Rysunek 2. Architektura wieloagentowego systemu monitoringu z podziałem na warstwy Kontakt z autorem: andrzejolchawa@gmail.com

34 03/2010
Warsztaty

Hibernate Search API


Mechanizm wyszukiwania pełnotekstowego w Hibernate
Aplikacje bazodanowe stanowią obecnie znaczący odsetek
oprogramowania tworzonego na zlecenie prywatnych firm, jak i ogromnych
korporacji. Większość aplikacji realizuje warstwę dostępu do danych
za pomocą relacyjnie zorientowanej implementacji bazy danych (ang.
Relational Database Management System). Wybór ten ogranicza swobodę
przeszukiwania zawartych informacji do zbioru ściśle sformalizowanych
zapytań udostępnianych przez aplikację. Artykuł ten wprowadza
w zagadnienia przeszukiwania pełnotekstowego oferowanego przez
Hibernate Search oraz Apache Lucene.
terystycznych dla danego dokumentu in-
Dowiesz się: Powinieneś wiedzieć: formacji (wyrazów). W przypadku Apache
• Co to jest i jak działa wyszukiwanie pełno- • Podstawy programowania w języku Java; Lucene zadania te realizują tzw. Analyze-
tekstowe; • Podstawy zagadnień baz danych; r’y (np. StandardAnalyzer). Każdy Analy-
• Jak wzbogacić aplikację wykorzystującą Hi- • Podstawy Hibernate. zer składa się z Tokenizer'a i łańcucha fil-
bernate o nowy mechanizm; trów kolejno przetwarzających wprowadzo-
• Czy Apache Lucene jest rzeczywiście wydajny ny tekst. Tokenizer analizuje wejściowy ciąg
i nadaje się do komercyjnych zastosowań. symboli, a następnie zwraca strumień toke-
n’ów – poszczególnych wyrazów – bez bia-
łych znaków oraz symboli interpunkcyj-
którego powszechnie znanym przykładem nych. Wynikowy strumień token’ów pod-
jest internetowa wyszukiwarka Google. Po- lega filtracji. W najbardziej powszechnym
Poziom siada ona jedno przyjazne użytkownikowi przypadku operacja ta sprowadza się do za-
trudności pole tekstowe stanowiące alternatywę dla miany wszystkich liter na małe oraz wyklu-
skomplikowanych formularzy zawierają- czenia tzw. stop-słów, czyli wyrazów nie-
cych logikę biznesową. Ściślej mówiąc, me- wnoszących żadnej konkretnej informa-
chanizm wyszukiwania pełnotekstowego cji, np. on, który, dlaczego (patrz Listing 2).

M
echanizm wyszukiwania stanowi opiera się na wyborze zestawu słów charak- Etap ten pozornie wydawać się może rzeczą
podstawową funkcjonalność nie- terystycznych dla danego dokumentu, ich banalną, lecz stanowi serce całego mechani-
mal wszystkich aplikacji bazoda- optymalnym przechowaniu (np. w posta- zmu. To właśnie Analyzer zapewnia wyszu-
nowych. Zwyczajowo, jego realizacja opiera ci odwróconego indeksu) oraz efektywnym kiwanie po synonimach czy też akceptację
się na udostępnieniu prostego formularza przeszukiwaniu uwzględniającym na przy- błędów związanych z zamianą kolejności li-
reprezentującego dopuszczalne kryteria za- kład synonimy, aproksymację oraz oceniają- ter. Diagram 1 przedstawia przykładowe
pytania. Na podstawie wypełnionych przez cym trafność poszczególnych rekordów wy- działanie prostego Analyzer’a.
użytkownika pól generowane jest zapytanie nikowych. Z pewnością, Czytelnicy posia- Drugą fazą operacji indeksowania do-
SQL, którego wyniki zostają przedstawione dający umysł ścisły lepiej zrozumieją dzia- kumentu jest jego zapisanie w strukturze
w formie tabelki. Wyszukiwanie danych tek- łanie wyszukiwarek pełnotekstowych po umożliwiającej późniejsze, łatwe przeszuki-
stowych bywa udoskonalone o ignorowanie lekturze kolejnych części artykułu przed- wanie. Apache Lucene wykorzystuje algo-
wielkości znaków (funkcja UPPER) i przeszu- stawiających techniczne aspekty realizacji rytm invert indexing. Algorytm ten porów-
kiwanie fragmentów tekstu (klauzula LIKE owego mechanizmu na przykładzie Hiber- nać można do tradycyjnego spisu treści. To-
oraz słowo kluczowe %). Wciąż jednak użyt- nate Search i Apache Lucene. ken’y zwrócone przez Analyzer gromadzo-
kownik nie posiada możliwości wyszukiwa- ne są w swego rodzaju tablicy. Każda komór-
nia po synonimach, aproksymacji ewentu- Architektura Hibernate ka przechowuje pojedynczy wyraz oraz wska-
alnych błędów literowych czy też porządko- Search oraz Apache Lucene zuje na dokumenty go zawierające. Wspo-
wania otrzymanych wyników innego niż al- Idea wyszukiwania pełnotekstowego skła- mniana struktura danych przetrzymywa-
fabetyczne sortowanie. Z pomocą w mini- da się z trzech, ściśle zależnych od siebie na być może w pamięci operacyjnej, jak i fi-
malizacji owych ograniczeń przychodzi me- operacji. Pierwsza z nich zajmuje się eks- zycznie na dysku twardym w postaci zbio-
chanizm przeszukiwania pełnotekstowego, trakcją tekstu oraz wydobyciem charak- ru plików. Za przechowywanie indeksu od-

36 03/2010
Hibernate Search API

powiedzialne są klasy DirectoryProvider. dy opracowany zostanie mechanizm inter- obiektowe Hibernate Core z wyszukiwar-
Hibernate Search oferuje dwie wbudowa- pretujący w pełni nieustrukturalizowane, ką pełnotekstową Apache Lucene. Narzę-
ne implementacje: FSDirectoryProvider potoczne zapytania. dzie to zapewnia przezroczysty dla pro-
oraz RAMDirectoryProvider. Istnieje po- Uważni Czytelnicy zastanawiają się pew- gramisty system indeksowania wyspecyfi-
nadto możliwość wskazania własnej imple- nie, jaką rolę odgrywa Hibernate w całym kowanych (przy pomocy adnotacji) atry-
mentacji zapisującej indeks np. bezpośred- opisanym wyżej mechaniźmie. Hiberna- butów danej encji. Programista, chcąc za-
nio w bazie danych. Celowo wskazałem tutaj te Search integruje mapowanie relacyjno- pisać nowy rekord lub zmodyfikować ist-
przykład bazy danych, gdyż z pewnością wie-
lu z Was uważać go będzie za bardzo atrakcyj-
ny. Emmanuel Bernard (deweloper Hiberna-
te Search oraz autor książki Hibernate Search
In Action) wskazuje następujące wady owego
rozwiązania:

• Indeks przechowywany jest w obiektach


typu BLOB, które w zależności od imple-
mentacji konkretnego RDBMS nie są
najszybszą strukturą bazodanową;
• Współbieżna edycja indeksu jest nie-
możliwa, ze względu na wymóg peł-
nej blokady (czytania i pisania) całego
indeksu przez każdy proces modyfiku-
jący dane.

Z punktu widzenia dużych systemów pro-


dukcyjnych najwłaściwszą implemen-
tacją DirectoryProvider okazuje się
FSDirectoryProvider. W odróżnieniu od
RAMDirectoryProvider, jego pojemność jest
niemal nieograniczona oraz nieulotna, lokal-
ne systemy plików są wystarczająco szyb-
kie, aby sprawnie odczytywać dane indeksu; Rysunek 1. Luke – narzędzie do przeglądania i mody�kacji indeksu Apache Lucene
rozwiązanie to jest najlepiej przetestowane;
Apache Lucene posiada własny cache (prze-
chowywany w pamięci RAM) w celu mini- Listing 1. Przykładowa kon�guracja fabryki sesji Hibernate
malizacji liczby odczytów z dysku twarde- hibernate.dialect = org.hibernate.dialect.DataDirectOracle9Dialect
go; łatwość wykonywania kopii zapasowych. hbm2ddl.auto = create
RAMDirectoryProvider powszechnie wyko- hibernate.show_sql = true
rzystywany jest w implementacji testów jed- hibernate.format_sql = false
nostkowych. hibernate.search.default.directory_provider = org.hibernate.search.store.FSDirecto
Ostatnią fazą, wchodzącą w skład prze- ryProvider
szukiwania pełnotekstowego, jest udostęp- hibernate.search.default.indexBase = C:\index\
nienie prostego języka zapytań. Apache Lu-
cene oferuje bogaty zestaw meta znaków
przedstawionych w Tabeli 1. Przeanalizuj-
Tabela 1. Składnia języka zapytań Apache Lucene (http://lucene.apache.org/java/2_0_0/index.html)
my przykładową kwerendę: title:(+Star
-”Star Wars”)^2 AND content:”Capta?n Meta znak Opis działania
Enter*”~10 AND publicationDate: [nazwa _ pola]: De�niuje nazwę pola oraz zapytanie
[zapytanie]
[19730101 TO 20090801]. Zwrócone rekor-
dy powinny zawierać w tytule wyraz Star, AND, + Wynik powinien zawierać wszystkie wyspecy�kowane frazy
lecz nie frazę Star Wars (warunek dwukrot- OR Wynik powinien zawierać dowolną z wyspecy�kowanych fraz
nie ważniejszy niż kolejne). Ponadto wyrazy, NOT, - Wynik nie powinien zawierać danej frazy
jakie można dopasować do formuły Capta?n
[min TO max] Wartość liczbowa lub data powinna mieścić się w zadanym prze-
oraz Enter*, muszą znajdować się w odstę-
dziale
pie maksymalnie 10 innych wyrazów znaj-
? Zastępuje dowolny pojedynczy znak
dujących się w atrybucie content. Data pu-
blikacji powinna również mieścić się w prze- * Zastępuje dowolną ilość dowolnych znaków
dziale między pierwszym stycznia 1973 ro- () Grupowanie wyrażeń
ku a pierwszym sierpnia 2009. Za proces ^[liczba] Zwiększa wagę dopasowania danej frazy (liczba całkowita)
parsowania zapytań wprowadzanych bezpo-
"[wyrazy]" De�niuje frazę składającą się z wielu wyrazów
średnio przez użytkownika odpowiedzialny
~[liczba] FuzzyQuery (liczba ułamkowa) lub PhraseQuery (liczba całkowita)
jest QueryParser, który przesłonić można
własną implementacją. Ciekawi mnie, kie- (opisane w dalszej części artykułu)

www.sdjournal.org 37
Warsztaty

niejący, wykonuje standardowe operacje


Listing 2. Przykład mapowania encji z wykorzystaniem adnotacji Hibernate Search save() i update() na obiekcie Session.
@Entity Hibernate Search zapewnia automatyczną
@javax.persistence.SequenceGenerator(name="BOOKS_SEQ_GEN", sequenceName="BOOKS_SEQ") synchronizację indeksu z bazą danych oraz
@Table(name="BOOKS") bardzo szybkie pobieranie samego obiek-
@Indexed tu z bazy przez odwołanie po kluczu głów-
@ClassBridge(name="secret", impl=SecretBridge.class, index=Index.UN_TOKENIZED) nym. Model danych Apache Lucene posia-
@FullTextFilterDef(name="public", impl=PublicFilterFactory.class) da strukturę płaską, przez co indeksowa-
@AnalyzerDef(name="standardBookAnalyzer", ne relacje muszą zostać zdenormalizowa-
tokenizer=@TokenizerDef(factory=StandardTokenizerFactory.class), ne, co skutkuje zwiększeniem rozmiaru in-
filters={@TokenFilterDef(factory=StandardFilterFactory.class), deksu. Konfiguracja Hibernate Search, je-
@TokenFilterDef(factory=LowerCaseFilterFactory.class), go API, testy wydajnościowe oraz zagadnie-
@TokenFilterDef(factory=StopFilterFactory.class) nia optymalizacyjne opisane są w kolejnych
}) częściach artykułu.
@Analyzer(definition="standardBookAnalyzer")
public class BookEntity { Przykładowa aplikacja
... Część praktyczna artykułu zrealizowa-
na została na przykładzie prostej aplikacji
@Id przechowującej dane o autorach i wyda-
@GeneratedValue(strategy=GenerationType.SEQUENCE, generator="BOOKS_SEQ_GEN") nych przez nich książkach. Celem aplika-
@DocumentId cji jest prezentacja możliwie wielu funkcji
public Long getId() { Hibernate Search oraz testy wydajnościowe
return id; owego narzędzia. W dalszej części owej sek-
} cji nie zamierzam skupiać się na logice biz-
nesowej aplikacji, sensowności i przydatno-
@Column(name="TITLE", nullable=false, length=100) ści niektórych rozwiązań, lecz na prezenta-
@Fields({ cji technologii i maksymalnym jej obciąże-
@Field(index=Index.TOKENIZED), niu podczas testów.
@Field(name="title_sort", index=Index.UN_TOKENIZED)
}) Kon�guracja fabryki
@Boost(2.0f) sesji oraz mapowań encji
public String getTitle() { Pracę z Hibernate Search należy rozpocząć
return title; od konfiguracji obiektu SessionFactory
} oraz opatrzenia indeksowanych encji odpo-
wiednimi adnotacjami. Bardzo podstawo-
@Column(name="PUBLICATION_DATE", nullable=false) wą konfigurację SessionFactory przedsta-
@Field(index=Index.UN_TOKENIZED) wia Listing 1.
@DateBridge(resolution=Resolution.DAY) Parametr hibernate.search.default.di
public Date getPublicationDate() { rectory_provider określa domyślną używa-
return publicationDate; ną implementację DirectoryProvider’a (sło-
} wo kluczowe default). Istnieje możliwość
wskazania różnych DirectoryProvider’ów
@Column(name="CONTENT", nullable=false) dla poszczególnych indeksowanych klas.
@Lob W tym przypadku słowo kluczowe default
@Field(index=Index.TOKENIZED) zastąpić należy nazwą indeksu (np. edu.la
@FieldBridge(impl=PDFStringBridge.class) ntoniak.hibernate.search.model.BookEn
public byte[] getContent() { tity). Drugi parametr hibernate.search.
return content; default.indexBase określa miejsce składo-
} wania indeksu. Ukończywszy konfigurację
SessionFactory,programista powinien za-
@ManyToMany(targetEntity=AuthorEntity.class, cascade=CascadeType.ALL) jąć się opatrzeniem indeksowanych encji ad-
@JoinTable(name="AUTHORS_BOOKS", joinColumns=@JoinColumn(name="BOOKS_ID"), notacjami Hibernate Search. Kilka przykła-
inverseJoinColumns=@JoinColumn(name="AUTHORS_ID")) dowych atrybutów z odmienną filozofią in-
@IndexedEmbedded(depth=1) deksowania przedstawia Listing 2.
public Set<AuthorEntity> getAuthors() { Aby klasa brała udział w procesie indek-
return authors; sowania, powinna zostać opatrzona adnota-
} cją @Indexed.
Pierwszy atrybut id stanowi klucz głów-
... ny encji BookEntity. Adnotacją @DocumentId
} powoduje zapisanie wartości owego pola w in-
deksie jako identyfikator rekordu, co umożli-
wia Hibernate Core szybkie pobranie odpo-
wiedniego obiektu z bazy danych.

38 03/2010
Hibernate Search API

Drugi atrybut title przechowuje ty-


tuł książki. Wartość zmiennej tej indekso- Listing 3. Przykład zapytania opartego o wyrażenia regularne
wana jest dwukrotnie (adnotacje @Fields public List<BookEntity> getBooksByTitleRegExp(String regExpTitle) {
i @Field) – raz pod kluczem title, drugi Session session = getSession();
raz jako title_sort. W przypadku klucza FullTextSession fullTextSession = Search.getFullTextSession(session);
title, wartość zmiennej rozbita zostanie RegexQuery regexQuery = new RegexQuery(new Term("title", regExpTitle));
na poszczególne token’y (index=Index.TO- FullTextQuery fullTextQuery = null;
KENIZED). Dla przykładu, tekst Hiberna- List<BookEntity> list = null;
te Search API zostałby podzielony na trzy try {
wyrazy – Hibernate, Search oraz API. Każ- fullTextQuery = fullTextSession.createFullTextQuery(regexQuery,
dy z owych token’ów wskazywałby na jedną BookEntity.class);
i tę samą książkę (patrz algorytm invert in- list = fullTextQuery.list();
dexing) – przechowywałby jako odwołanie } finally {
tę samą wartość zmiennej id. Jeśli pragnie- releaseSession(session);
my zaoferować możliwość sortowania wy- }
ników, potrzebujemy oryginalnej wartości return list;
zmiennej title, przetrzymywanej w polu }
title_sort (index=Index.UN_TOKENIZED).
Domyślnie Hibernate Search zwraca listę Listing 4. Przykład de�nicji �ltra oraz skorzystanie z niego podczas wykonywania zapytania
obiektów posortowanych malejąco po traf- public class PublicFilterFactory {
ności dopasowania dokumentu. Atrybut @Factory
title prezentuje jeszcze jedną przydatną public Filter getPublicFilter() {
własność określoną przez @Boost. Adno- Term term = new Term("secret", "false");
tacja ta definiuje mnożnik stosowany przy Query query = new TermQuery(term);
wyliczaniu trafności dopasowania danego return new QueryWrapperFilter(query);
dokumentu. Potocznie mówiąc, dopasowa- }
nie wartości zmiennej title do oczekiwa- }
nej jest w tym przypadku dwa razy ważniej- public List<BookEntity> getPublicBooksByTitle(String title) {
sze niż innych atrybutów. Session session = getSession();
W modelu danych Apache Lucene, war- FullTextSession fullTextSession = Search.getFullTextSession(session);
tości wszystkich zmiennych zapisywane są FullTextQuery fullTextQuery = null;
w formie tekstowej. Nie istnieją typy licz- List<BookEntity> list = null;
bowe, boolowskie, daty czy też referencje. try {
Aby zamienić dowolny typ na postać tek- Analyzer analyzer = fullTextSession.getSearchFactory().
stową, stosowane są tzw. Bridge. Adnotacja getAnalyzer(BookEntity.class);
@DateBridge transformuje format daty na Query query = MultiFieldQueryParser.parse(new String[] {title},
reprezentację tekstową z określoną dokład- new String[] {"title"}, analyzer);
nością. Bridge posiadają także wiele innych fullTextQuery = fullTextSession.createFullTextQuery(query,
zastosowań. Jednym z nich może być roz- BookEntity.class);
różnienie wartości składowanej w indek- fullTextQuery.enableFullTextFilter("public");
sie od tej przetrzymywanej w bazie danych. Criteria fetchingStrategy =
W przykładowej aplikacji atrybut content fullTextSession.createCriteria(BookEntity.class).
klasy BookEntity przechowuje ścieżkę do setFetchMode("authors", FetchMode.JOIN);
pliku PDF z daną książką (wartość składo- fullTextQuery.setCriteriaQuery(fetchingStrategy);
wana w bazie danych). Aby móc wyszuki- list = fullTextQuery.list();
wać książkę po fragmencie jej treści, pole } catch (ParseException e) {
content przechowywane w indeksie zawie- log.error("Parse exception: " + e);
ra zindeksowaną całą treść danej pozycji. } finally {
Implementacja własnego Bridge przedsta- releaseSession(session);
wia się bardzo prosto. Wystarczy przecią- }
żyć metodą objectToString() przyjmują- return list;
cą dany obiekt, a zwracającą jego tekstową }
reprezentację. @ClassBridge to szczegól-
ny przypadek Bridge umożliwiający gene-
rację dodatkowych pól na podstawie atry- Luke
butów danej klasy. W zamieszczonym na Luke to bardzo pomocna aplikacja umożliwiająca przeglądanie oraz mody�kację indeksu Apache
płycie CD przykładzie każdy dokument Lucene zapisanego na dysku twardym. Narzędzie składa się z pięciu zakładek, z których pierwsze
BookEntity zawierać będzie pole secret trzy są szczególnie interesujące dla osoby rozpoczynającej pracę z Hibernate Search. Pierwsza
z nich, Overview, pokazuje ogólne dane na temat indeksu, takie jak nazwy pól, liczba przecho-
o wartości wygenerowanej przez metodę
wywanych dokumentów oraz terminów. Zakładka Documents pozwala na proste przeszukiwanie
objectToString() klasy SecretBridge.
oraz mody�kację poszczególnych wpisów. Najczęściej używaną funkcjonalność Luke zawiera pa-
@ClassBridge są bardzo przydatne w połą- nel Search. Oferuje on możliwość wykonywania zapytań, wybór Analyzer’a, przeglądanie otrzy-
czeniu z filtrami opisanymi w dalszej czę- manych wyników oraz wyjaśnienie, jak obliczona została trafność danego dokumentu.
ści artykułu.

www.sdjournal.org 39
Warsztaty

Fakt, iż Apache Lucene przechowuje da- authors.firstName). Aby indeksowanie 91 do 94). Należy ponadto zwrócić uwagę,
ne wyłącznie w formie tekstowej, impli- relacji działało poprawnie, relacja powin- iż indeksowanie relacji znacznie zwiększa
kuje konieczność denormalizacji wszel- na być dwukierunkowa, a druga jej strona rozmiar indeksu.
kich indeksowanych relacji. W przypad- opatrzona adnotacją @ContainedIn. Dzię- Ostatnim elementem konfiguracyjnym
ku konieczności udostępnienia zapytań ki temu Hibernate powtórnie indeksu- wykorzystywanym w fazie zapisywania in-
o własności enkapsulowane w innej encji, je dokument encji nadrzędnej po modyfi- deksu jest wybór domyślnego Analyzer’a
atrybut relacji należy opatrzyć adnotacją kacji (operacji UPDATE, INSERT lub DELETE) dla danej klasy, lub w szczególności dla
@IndexedEmbedded. Pozwala ona określić powiązanego obiektu podrzędnego. Uwa- konkretnego atrybutu. Listing 2 przedsta-
stopień zagłębienia dalszego rekursywnego ga implementacyjna: mechanizm powtór- wia definicję standardowego Analyzer’a,
indeksowania podrzędnych relacji. Jako wy- nego indeksowania działa poprawnie tyl- którego działanie zostało opisane na po-
nik owego działania dokument BookEntity ko w przypadku modyfikacji obiektu posia- czątku poprzedniej sekcji artykułu. Hiber-
zawierać będzie wszystkie informacje na te- dającego aktualną referencję do encji nad- nate Search udostępnia jednak bardziej zło-
mat każdego z powiązanych autorów (np. rzędnej (patrz plik TestRunnable.java, linie żone filtry (wykorzystywane przy defini-
cji analizatora) obsługujące wyszukiwanie
Listing 5. Stronicowanie zwracanych wyników po synonimach (SynonymFilterFactory),
podobieństwie fonetycznym (Phonetic-
public Object[] getAuthorsByNamePaginating(String name, int pageNumber, int window) { FilterFactory), rodzinie danego wyrazu
Session session = getSession(); (SnowballPorterFilterFactory) czy też
FullTextSession fullTextSession = Search.getFullTextSession(session); akceptujące błędy literowe (NGramFilter-
FullTextQuery fullTextQuery = null; Factory). Konfiguracja Analyzer’a wpły-
List<AuthorEntity> list = null; wa na wielkość indeksu, szybkość jego za-
int resultSize = -1; pisu oraz Analyzer konieczny do genera-
try { cji poprawnego zapytania. Dla przykładu,
Analyzer analyzer = SynonymFilterFactory, na podstawie pła-
fullTextSession.getSearchFactory().getAnalyzer(AuthorEntity.class); skiego pliku definiującego synonimy, ge-
Query query = MultiFieldQueryParser.parse(new String[] {name, name}, neruje wszystkie możliwe wyrazy blisko-
new String[] { "firstName", "lastName" }, analyzer); znaczne danego słowa, a następnie zapisu-
fullTextQuery = je je do pliku indeksu, znacznie zwiększa-
fullTextSession.createFullTextQuery(query, AuthorEntity.class); jąc jego objętość. Filtr ten stanowi ponadto
list = fullTextQuery.setFirstResult((pageNumber - 1) * window). wyjątek reguły nakazującej stosowanie tego
setMaxResults(window).list(); samego Analyzer’a podczas zapisywania in-
resultSize = fullTextQuery.getResultSize(); deksu oraz generacji zapytania. Ze względu
} catch (ParseException e) { na złożoność działania niektórych filtrów,
log.error("Parse exception: " + e); odsyłam zainteresowanych Czytelników
} finally { do lektury ich dokumentacji oraz książki
releaseSession(session); Hibernate Search In Action. W żadnym wy-
} padku nie powinno się stosować wszyst-
return new Object[] {resultSize, list}; kich wymienionych wcześniej filtrów jed-
} nocześnie ze względu na czas indeksowania
oraz potencjalnie niewielką trafność zwra-
canych później wyników. Testowa aplika-
Tabela 2. Pomiar czasów procesu indeksowania dla FSDirectoryProvider cja zawiera przykładowe definicje każdego
Liczba słów do Liczba zindek- Czas indekso- Czas indeksowa- Zajętość miej- z wyżej omówionych filtrów. Do dyspozy-
zindeksowania sowanych termi- wania BookEnti- nia AuthorEnti- sca [KB] cji Czytelnika pozostawiam zamianę uży-
nów ty [ms] ty [ms] wanego Analyzer’a przez klasę BookEntity,
1453788 10700 48071 835 320 uruchomienie aplikacji oraz obserwację
3261806 15012 100878 1616 588 różnic w plikach indeksu przeglądanych
dzięki Luke.
4585970 18435 142773 2415 820
6916213 21539 179535 3236 980 Implementacja
9301547 26067 226505 4672 1380 metod pełnotekstowego
przeszukiwania danych
Posiadając skonfigurowaną fabrykę sesji
Tabela 3. Pomiar czasów procesu indeksowania dla RAMDirectoryProvider
oraz poszczególne encje, możemy przystą-
Liczba słów do Liczba zindek- Czas indekso- Czas indeksowa- Zajętość miej- pić do implementacji mechanizmu wyszu-
zindeksowania sowanych termi- wania BookEnti- nia AuthorEnti- sca [KB]
nów ty [ms] ty [ms]
kiwania. Hibernate Search oferuje kilka ro-
dzajów zapytań oraz samego sposobu zwra-
1453788 10700 47341 122 320
cania wyników. Do najczęściej stosowanych
3261806 15012 98727 167 588 zapytań należą TermQuery (wyszukiwanie
4585970 18435 140013 220 820 po pojedynczym atrybucie, umożliwia sto-
6916213 21539 178325 253 980 sowanie meta znaków takich jak ? czy *)
oraz MutiFieldQueryParser (analogiczne do
9301547 26067 218019 365 1380
TermQuery, lecz pozwalające wyszukiwać po

40 03/2010
Hibernate Search API

zbiorze atrybutów). Jedno z ciekawszych ro- kordów (tzw. okna). Stronicowanie minima- 2 Duo T9300 2,5 GHz, 3 GB RAM, HDD
dzajów zapytań to FuzzyQuery. Mechanizm lizuje nakład pracy bazy danych oraz redu- 7200 RPM, Windows XP Professional), na
ten wymaga określenia oczekiwanego podo- kuje wykorzystanie procesora i liczbę odczy- zbiorze pięćdziesięciu książek elektronicz-
bieństwa między dwoma wyrazami. W przy- tów z dysku przeprowadzanych przez Apa- nych zapisanych w formacie PDF. W sumie
padku różnej skali podobieństwa między ter- che Lucene. Ponadto zmniejszona zostaje zindeksowano 26 tysięcy terminów spośród
mami, lista zwracanych wyników może oka- liczba danych przesyłanych przez sieć, zuży- niespełna 10 milionów wyrazów, co zaję-
zać się zupełnie inna. Dla podobieństwa rów- cie procesora oraz pamięci aplikacji po stro- ło niecałe cztery minuty oraz 1,4 MB prze-
nego 0,1, po wpisaniu wymaganego zwrotu nie klienta, a w rezultacie czas odpowiedzi strzeni dyskowej. Do ekstrakcji tekstu z ksią-
eihrbnate, otrzymamy wyniki zawierające wy- programu. Użytkownicy przeglądają zazwy- żek PDF użyłem biblioteki PDFBox. Pomiar
raz Hibernate. Zwiększając wymagane podo- czaj jedynie pierwsze sto wyników spośród czasu wykonania poszczególnych metod war-
bieństwo do domyślnego 0,5, nie otrzymamy np. 100000 zwracanych, a dzięki dynamicz- stwy dostępu do danych zrealizowałem za po-
tak rozbieżnych rezultatów, lecz pojedyncza nej wielkości okna liczba ta może zostać mocą framework’u Java Execution Time Me-
przypadkowa zamiana kolejności liter zwró- dopasowana do indywidualnych potrzeb. asurement prezentującego zmierzone wyniki
ci oczekiwane pozycje. W wykonywaniu za- Przykładową implementację stronicowania w formie przejrzystej tabeli dostępnej pod ad-
pytań złożonych z całej frazy bardzo dobrze przedstawia Listing 5. resem http://localhost:40000. JETM wymaga
sprawdza się PhraseQuery. Implementacja ta Podsumowując, każdy programista powi- konfiguracji jedynie w pliku spring-config.xml,
potrafi dopasowywać wyniki ze zmienioną nien dopasować stosowany model zapytań dzięki czemu nie pogarsza przejrzystości ko-
kolejnością wyrazów. Parametr slop definiu- oraz zwracania ich wyników do wymogów du źródłowego. Obciążenie procesora oraz
je odległość między wyrazami (domyślnie 0 biznesowych oraz wydajnościowych konkret- pamięci śledzić można, uruchamiając na-
– wyrazy występujące w pierwotnie wprowa- nego projektu. rzędzie JConsole dostarczone wraz z maszy-
dzonej kolejności). Zaawansowani użytkow- ną wirtualną firmy Sun Microsystems. Uzy-
nicy wymagać mogą udostępnienia mecha- Testy wydajnościowe skane wykresy obciążenia sprzętu oraz czasy
nizmu wyszukiwania wykorzystującego wy- oraz optymalizacja wstawiania danych do indeksu dla różnych
rażenia regularne. Funkcjonalność tą oferuje Testy wydajnościowe przeprowadzone zo- implementacji DirectoryProvider’a przed-
biblioteka Apache Lucene Regex, której pro- stały na domowym komputerze (Intel Core stawiają Tabele 2, 3 oraz Wykresy 2 i 3.
ste użycie przedstawia Listing 3.
Przykłady stosowania omówionych rodza-
jów zapytań znajdują się w kodzie źródło-
wym testowej aplikacji dołączonej do czaso-
pisma na płycie CD.
Zwracane wyniki zapytań można ponad-
to zawężać, stosując bardzo wydajne filtry.
Filtry zawierają dodatkowe, predefiniowa-
ne dla danej klasy lub atrybutu kryteria wy-
szukiwania. Mechanizm ten działa analogicz-
nie do znanego tag’u filter-def oraz meto-
dy enableFilter ,wchodzących w skład Hi-
bernate Core (patrz Listing 4). Testy wydaj-
nościowe poszczególnych rodzajów zapytań
zaprezentowane zostaną w kolejnej sekcji ar-
tykułu.
Istotnym aspektem ze względów wydaj-
nościowych staje się sposób zwracania wy-
ników danego zapytania. Hibernate Se- Rysunek 2. Wykres obciążenia procesora podczas indeksowania 10 milionów wyrazów
arch dostarcza (standardowych dla narzę-
dzi rodziny Hibernate) metod list(), Listing 6. Kon�guracja asynchronicznego wątku Worker'a Hibernate Search
uniqueResult(), iterate() oraz scroll().
Funkcja list() to najprostszy i jednocze- hibernate.search.worker.execution = async
śnie najmniej wydajny sposób zwracania du- hibernate.search.worker.thread_pool.size = 2
żej liczby wyników, gdyż wszystkie obiek- hibernate.search.worker.buffer_queue.max = 50
ty zaciągane są od razu przy wykonywaniu
kwerendy. Problem ten częściowo rozwiązu- Listing 7. Kon�guracja automatycznej optymalizacji indeksu
je metoda scrollable(). Oferuje ona łatwe hibernate.search.default.optimizer.transaction_limit.max=50
w nawigowaniu API oraz ładowanie kon- hibernate.search.default.optimizer.operation_limit.max=100
kretnych pełnych obiektów wraz z doku-
mentami Apache Lucene dopiero w przy- Listing 8. Ręczna optymalizacja indeksu encji BookEntity
padku chęci z nich skorzystania, zmniejsza- public void optimize() {
jąc przy tym zużycie pamięci i czas ocze- Session session = getSession();
kiwania. Najbardziej wydajnym mechani- FullTextSession fullTextSession = Search.getFullTextSession(session);
zmem zwracania rezultatów okazuje się jed- fullTextSession.getSearchFactory().optimize(BookEntity.class);
nak stronicowanie. Algorytm ten polega na releaseSession(session);
wyspecyfikowaniu pozycji pierwszego ele- }
mentu oraz liczby kolejnych pożądanych re-

www.sdjournal.org 41
Warsztaty

Wyniki przeprowadzonych testów Większość programistów, skończywszy ne wąskim gardłem staje się czas wsta-
świadczą o niewielkiej różnicy w cza- implementacje określonej funkcjonalno- wiania danych do pliku indeksu. Przypo-
sie indeksowania dużych encji między ści systemu, zadaje sobie pytanie, czy nie minam, iż Apache Lucene wymaga cał-
dwoma popularnymi implementacjami istnieje możliwość przyspieszenia stworzo- kowitej blokady modyfikowanego indek-
DictionaryProvider'ów (kolumna doty- nego oprogramowania. W przypadku me- su oraz nie posiada metody modyfikacji
cząca BookEntity). Ponadto, czasy indekso- chanizmów wyszukiwania pełnoteksto- wcześniej wprowadzonych danych. Każ-
wania tak dużego zbioru danych wydają się wego optymalizacji podlegać może proces da zmiana (nawet pojedynczego atrybu-
w pełni akceptowalne. W przypadku testów wstawiania oraz wyszukiwania informa- tu) danego rekordu powoduje więc usu-
wydajnościowych poszczególnych rodzajów cji. Pierwsze pytanie, jakie powinien po- nięcie starego, powiązanego z nim doku-
zapytań bardzo duże znaczenie odgrywa sa- stawić przed sobą architekt aplikacji, doty- mentu, a następnie wstawienie nowego.
ma ich konfiguracja. Dla przykładu, im więk- czy konieczności indeksowania wszystkich Domyślnie, indeksowanie danych odbywa
sza wartość parametru similarity zapytań wskazanych pierwotnie danych. W apre- się synchronicznie podczas wykonywania
FuzzyQuery, tym szybciej wykonuje się dana zentowanym przykładzie należałoby in- metody commit(), co wymaga oczekiwania
kwerenda. Czasy mogą wahać się nawet od deksować jedynie krótkie streszczenie na uzyskanie pełnego dostępu do indek-
30 do 140 ms. Analogicznemu zachowaniu danej książki, a nie całą jej treść. Wymaga- su w przypadku uruchomienia wielu pro-
podlega PhraseQuery i parametr slop. Pod- nie to zależy jednak wyłącznie od warun- cesów współbieżnie modyfikujących da-
czas testów najszybciej wypadły zapytania ków logiki biznesowej i nie będę poświęcał ne. Istnieje jednak możliwość wykonywa-
TermQuery, dla których nie udało mi się prze- mu więcej czasu. nia operacji indeksowania asynchronicz-
kroczyć 0 ms. Czasy wykonania kwerend nie. Dodatkowo programista okręcić mo-
RegexQuery zależał silnie od samego wyraże- Optymalizacja indeksowania danych że maksymalną liczbę wątków współbież-
nia regularnego, lecz nawet przy użyciu tzw. Dla aplikacji wykonujących wiele współ- nie modyfikujących indeks oraz maksy-
wildcard'ów oscylował w granicach 70 ms. bieżnych operacji modyfikujących da- malną wielkość kolejki. Przykładową kon-
figurację obiektu SessionFactory przed-
stawia Listing 6.
Podczas wielokrotnego wstawiania i usu-
wania danych plik indeksu podlega frag-
mentacji. Pozostają w nim nieaktualne do-
kumenty, niepotrzebnie zajmujące prze-
strzeń dyskową oraz spowalniające wsta-
wianie oraz wyszukiwanie danych. De-
fragmentacją plików indeksu zajmuje się
proces optymalizacji. Proces ten urucho-
mić można automatycznie po wykonaniu
określonej liczby transakcji, pojedynczych
operacji lub też ręcznie dzięki metodzie
optimize() (Listing 7 i 8).
Większość tworzonych współcześnie
aplikacji posiada trójwarstwową architek-
turę klient-serwer. Warstwy dostępu do
danych, logiki biznesowej oraz prezenta-
cji uruchamiane są na osobnych maszy-
nach – komputerze klienckim, serwerze
Rysunek 3. Wykres zużycia pamięci podczas indeksowania 10 milionów wyrazów aplikacyjnym oraz serwerze bazy danych.

Listing 9. Zwracanie wyników zapytania specy�kując pożądane atrybuty dokumentu

public List<Object[]> getAuthorsIdAndFirstName(String lastName) {


Session session = getSession();
FullTextSession fullTextSession = Search.getFullTextSession(session);
FullTextQuery fullTextQuery = null;
List<Object[]> list = null;
try {
fullTextQuery = fullTextSession.createFullTextQuery(MultiFieldQueryParser.parse(new String[] {lastName}, new String[] {
"lastName" }, fullTextSession.getSearchFactory().getAnalyzer(AuthorEntity.class)), AuthorEntity.class);
list = fullTextQuery.setProjection(FullTextQuery.ID, "firstName").list();
} catch (ParseException e) {
log.error("Parse exception: " + e);
} finally {
releaseSession(session);
}
return list;
}

42 03/2010
Hibernate Search API

Hibernate Search umożliwia oddelegowa- wym. Komputery klienckie pobierają regu- nych atrybutów wchodzących w skład skom-
nie procesu indeksowania do dedykowa- larnie zmodyfikowane pliki indeksu (np. co plikowanych encji. Hibernate Search udo-
nego serwera. Diagram 5 przedstawia mo- godzinę). Jedyną wadą owego rozwiązania stępnia metodę setProjection() pozwa-
del owej architektury. Komputery klienc- wydaje się opóźnienie w propagacji zmo- lającą na wyspecyfikowanie pól zwracanych
kie posiadają lokalne kopie plików indek- dyfikowanych danych. W przypadku chęci przez zapytanie (Listing 9). Wartości atry-
su, na których wykonują operacje wyszuki- zapoznania się ze szczegółami konfiguracji butów tych muszą być jednak przechowy-
wania. Chęć modyfikacji danych zgłaszana master’a oraz slave’ów odsyłam zaintereso- wane zarówno w bazie danych, jak i w pli-
jest przez umieszczenie odpowiedniej wia- wanego Czytelnika do książki Hibernate Se- kach indeksu (opcja store=Store.YES ad-
domości w kolejce JMS serwera. Proces ten arch in Action. notacji @Field). Dzięki projekcjom progra-
odbywa się asynchronicznie, co nie wstrzy- mista unika przesyłania przez sieć nadmia-
muje pracy komputerów klienckich. Ser- Optymalizacja wyszukiwani danych rowych danych, przechowywania ich w pa-
wer odpowiedzialny za indeksowanie da- Optymalizacja procesu wyszukiwania da- mięci oraz ewentualną niepotrzebną ob-
nych (master) przetwarza żądania klien- nych w dużym stopniu przypomina opty- róbkę na terminalu klienckim. Znaczący
tów (slave) oraz umieszcza wynikowe pliki malizację zapytań SQL. Należy zwrócić wzrost wydajności systemu obserwuje się
indeksu w udostępnionym folderze siecio- uwagę na pobieranie wyłącznie wymaga- podczas stosowania algorytmu stronicowa-
nia w celu zwracania wyników zapytań. Hi-
bernate nie pobiera wówczas ogromnej ilo-
ści danych, większości których użytkownik
i tak nie przejrzy.

Podsumowanie
Artykuł ten zaprezentował podstawy me-
chanizmu wyszukiwania pełnotekstowe-
go opartego na Hibernate Search. Dzięki
�������� bardzo przystępnemu oraz w dużej mie-
����
��������
rze przezroczystemu dla programisty API,
���� system ten wprowadzić można do działają-
cych już aplikacji bez konieczności grun-
townej zmiany implementacji warstwy
dostępu do danych. Hibernate Search
������ ������ ������ ������ ������
������ ������
udostępnia ponadto szeroką gamę para-
������ ������ ������
������� ������� ������� ������� �������� metrów, umożliwiając dopasowanie dzia-
łania owego narzędzia do własnych po-
trzeb. Podstawową sprawą wydaje się jed-
nak dobór indeksowanych danych, Analy-
zer’a oraz rodzaju wykonywanego zapyta-
nia, gdyż właśnie te czynniki wpływają na
jakość zwracanych rekordów, które powin-
ny zadowalać użytkownika końcowego. Hi-
�����
�����
����� ����� ����� bernate Search to ciekawa alternatywa dla
����� ����� �����
���� ���� ���� ������������ usługi Full-Text Search dostępnej w Mi-
����
crosoft SQL Server 2005/2008 (opisanej
����������� w Software Developer’s Journal 7/2009).
���������
Przewagę omawianego narzędzia stanowi
niezależność od implementacji konkret-
nego RDBMS, bezpłatny, powszechny do-
stęp oraz możliwość większego rozprosze-
nia aplikacji – rozłożenia mocy oblicze-
niowej. W celu dalszego zgłębiania swo-
���������������������������������
������������������
jej wiedzy na temat Hibernate Search po-
������������ lecam Czytelnikom książkę Hibernate Se-
arch in Action.

ŁUKASZ ANTONIAK
Rysunek 5. Architektura z wykorzystaniem asynchronicznego klastra (źródło: Emmanuel Bernard – Łukasz Antoniak pracuje w �rmie Oracle Polska
„Hibernate Search in Action”)
na stanowisku programisty Java EE/SE. Na co
dzień zajmuje się tworzeniem aplikacji bazoda-
nowych z wykorzystaniem produktów rodziny
W Sieci Oracle Fusion Middleware. Od niedawna stosu-
• Strona domowa projektu Hibernate Search: https://www.hibernate.org/410.html; je także popularne rozwiązania open-source: Hi-
• Dzone Refcardz: http://refcardz.dzone.com/refcardz/getting-started-with-hibernate. bernate oraz Spring Framework.
Kontakt z autorem: lukasz.antoniak@oracle.com

www.sdjournal.org 43
Warsztaty

Spring.NET
– uniwersalny spinacz
Wprowadzenie do konfiguracji fabryki obiektów

Spring to bardzo wygodne i szeroko konfigurowalne narzędzie


pozwalające spinać ze sobą poszczególne obiekty, jak i integrować całe
warstwy aplikacji.
tów. Lekki oznacza, że nie integruje się z apli-
Dowiesz się: Powinieneś wiedzieć: kacją, a zależności w kodzie są minimalne lub
• Podstaw kon�gurowania fabryki Springa. • Czytelnik powinien znać podstawy języka żadne. Ponadto nie potrzebuje do swojego
• W jaki sposób działa odwrócenie kontroli C# oraz składnię XML. działania specjalnego środowiska uruchomie-
oraz wstrzykiwanie zależności. niowego, można go zatem wykorzystywać za-
równo w aplikacji sieciowej, jak i okienkowej
czy konsolowej. Konfiguruje się go za pomo-
cą metadanych definiowanych w pliku XML.
Za pomocą pliku konfiguracyjnego można
z niezwykle przydatnego narzędzia, jakim w Springu deklaratywnie zdefiniować zależ-
jest Spring.NET. W poniższym artykule po- ności w całej aplikacji. Od połączenia do ba-
Poziom staram się przybliżyć zasadę działania oraz zy danych, poprzez konfigurację usług sie-
trudności możliwości podstawowego modułu szkie- ciowych (ang. web service), na kontrolerach
letu, jakim jest wspomniany już wcześniej i walidatorach warstwy prezentacji kończąc,
kontener Odwróconej kontroli. Artykuł ten a to i tak nie wszystko. Spring ponadto zarzą-
jest kierowany do początkujących progra- dza cyklem życiowym poszczególnych obiek-

S
pring Framework powstał domyślnie na mistów .NET lub tych, którzy jeszcze nie tów, co można również definiować za pomo-
platformę Java ponad 5 lat temu. Szybko mieli okazji zetknąć się ze Springiem. Za- cą pliku XML. Domyślnie wszystkie obiek-
zdobył dużą popularność ze względu na pewniam, że naprawdę warto się tym na- ty pobierane z fabryki są singletonami, czyli
bardzo interesujący model działania. Osiowym rzędziem zainteresować, ponieważ znacz- możemy mieć pewność, że raz zdefiniowany
elementem szkieletu był tak zwany kontener nie ułatwia ono tworzenie, testowanie oraz i skonfigurowany obiekt jest dostępny przez
IoC, czyli Inversion of Control (szczegóły w ram- późniejszy rozwój i utrzymanie aplikacji. cały czas działania aplikacji w postaci jednej
ce Inversion of Control – odwrócenie kontro- A więc zacznijmy. instancji. W zależności jednak od potrzeb
li) oraz Dependency Injection (szczegóły w ram- można obiekt tworzyć na nowo za każdym
ce Dependency Injection – wstrzykiwanie zależ- Jak działa Spring razem, kiedy zaistnieje potrzeba jego użycia
ności). Wspomniany kontener w łatwy sposób Spring, jak już zostało to wspomniane lub, w przypadku aplikacji sieciowej, ograni-
umożliwiał konfigurowanie aplikacji. W toku w Ramkach, jest lekkim kontenerem obiek- czać czas życia obiektów do charakterystycz-
swojego rozwoju Spring otrzymywał kolejne
możliwości integracji kontenera z innymi popu- Inversion of Control – odwrócenie kontroli
larnymi platformami wspomagającymi tworze- Termin ten opisuje ogólną zasadę działania wzorca projektowego fabryki, lokalizatora usług
nie aplikacji we wszystkich jej warstwach. Licz- lub innych wymienionych w ramce Dependency Injection – wstrzykiwanie zależności. Zwy-
ne zalety platformy sprawiły, że Spring szybko czajowo obiekty aplikacji są tworzone w kodzie poprzez użycie operatora new. Odwróce-
zyskał ogromną popularność i w równie krót- nie kontroli polega zatem na pobieraniu obiektów poprzez wywołanie odpowiedniej me-
tody z obiektu fabrykującego. Wzorzec ten wielokrotnie udowodnił swoją przydatność i jest
kim czasie stał się podstawowym narzędziem
jednym z najpowszechniej wykorzystywanych szablonów projektowych. Niewątpliwą zale-
tworzenia średnich i dużych aplikacji. Począt- tą jest brak zależności w kodzie aplikacji od faktycznej implementacji wykorzystywanej usłu-
kowo rozwijany tylko na platformie Java, znalazł gi. Kod aplikacji jest skupiony na wykonywaniu swojego zadania, czyli delegowaniu wyko-
również zainteresowanie w środowisku .NET. nania pewnych działań do obiektów usług, nie dbając o to, jak te działania są wykonywa-
I tak narodził się osobno rozwijany projekt w ra- ne. Efektem tego jest większa swoboda mody�kacji aplikacji, jako że kod nie jest uzależnio-
mach Spring Framework – Spring.NET. ny od konkretnych , a zatem nie ma potrzeby kontrolowania kodu w wielu miejscach w razie
zmiany wykorzystywanej implementacji. Kontener IoC Springa to scentralizowane miejsce,
Jako że platforma .NET nie jest tak popu- skąd są pobierane wszystkie de�nicje obiektów, dodatkowo jest on kon�gurowany za pomo-
larna w naszym kraju jak Java, to mam na- cą plików XML, co w konsekwencji prowadzi do całkowitego braku potrzeby mody�kowania
dzieję, że ten artykuł znajdzie zaintereso- kodu w razie zmiany implementacji usług.
wanie i zachęci czytelników do korzystania

44 03/2010
Wprowadzenie do Spring.NET

nych dla protokołu HTTP zasięgów request, ciu operatora new w kodzie aplikacji. Poda- cją). Nazwy te będą uważane za aliasy te-
session czy application. ne id musi być unikatowe i przestrzegać ob- go obiektu.
Spring, jakkolwiek, nie jest typem rozwią- ostrzeń nałożonych na element id w for- Specyfikując typ inicjowanego obiektu, nale-
zania, które wymusza użycia całego zestawu macie XML. Można jednak podać dowol- ży pamiętać o podaniu pełnej ścieżki przestrze-
swoich funkcji, można bowiem wykorzystać ną ilość nazw w elemencie name (rozdzie- ni nazw, jak i nazwy assembly, w którym skom-
tylko niewielki zakres jego możliwości dopa- lonych przecinkiem, średnikiem lub spa- pilowany jest dany typ. Spring zawsze użyje naj-
sowany do aktualnych potrzeb. Spring Frame-
work jest podzielony na szereg modułów, każ- Listing 1. Przykład kon�guracji aplikacji za pomocą pliku App.con�g
dy z nich to osobna biblioteka, nie ma zatem
również potrzeby importowania niepotrzeb- <configuration>
nych przestrzeni nazw, z których w ogóle by <configSections>
się nie korzystało. Dodatkowo Spring umoż- <sectionGroup name="spring">
liwia rozbudowę każdego swojego elemen- <section name="context" type="Spring.Context.Support.ContextHandler,
tu. Wszystkie oferowane możliwości są opar- Spring.Core"/>
te na interfejsach, które w zależności od po- </sectionGroup>
trzeb można zaimplementować, dostarczając <sectionGroup name="common">
własnych rozwiązań. <section name="logging" type="Common.Logging.ConfigurationSectionHandler,
Common.Logging" />
Kontener IoC </sectionGroup>
– podstawy konfiguracji </configSections>
Teraz, mając już stworzony nowy projekt i za-
importowane biblioteki oraz skonfigurowa- <common>
ny kontekst Springa (patrz ramka Konfigura- <logging>
cja), możemy napisać pierwszy przykład. Plik <factoryAdapter type="Common.Logging.Simple.TraceLoggerFactoryAdapter,
konfiguracyjny app-config.xml powinien wy- Common.Logging">
glądać ępująco – Listing 2. <arg key="level" value="OFF" />
Głównym elementem pliku konfiguracyj- </factoryAdapter>
nego jest element objects, który będzie za- </logging>
wierał w sobie kolejne elementy definiujące </common>
poszczególne obiekty. Aby nasz plik XML
mógł być walidowany przez środowisko pro- <spring>
gramistyczne, zostały do elementu objects <context>
dodane dodatkowe atrybuty definiujące loka- <resource uri="assembly://SpringExample1/SpringExample1.config/app-config.xml"
lizację pliku typu XML Schema, który odpo- />
wiada za poprawność struktury dokumentu. </context>
Warto już w tej chwili wspomnieć, że </spring>
Spring umożliwia logiczne rozbicie konfigu- </configuration>
racji XML na kilka plików. Aby definicje z in-
nych plików były widoczne przez kontener, Listing 2. Przykład podstawowej de�nicji pliku kon�guracyjnego app-con�g.xml
należy zaimportować je za pomocą elemen- <objects xmlns="http://www.springframework.net"
tu import. Na przykład: xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.net
<import resource="services.xml"/> http://www.springframework.net/xsd/spring-objects.xsd">

Można też to uczynić, podając więcej niż je- </objects>


den element resource do definicji konstruk-
tora kontenera (patrz ramka Konfiguracja).
Pierwszą i najważniejszą możliwością kon-
tenera jest definiowanie obiektów. Możliwe
Dependency Injection – wstrzykiwanie zależności
Wyobraźmy sobie sytuację, w której otrzymujemy obiekt z fabryki. Nie jest on jeszcze, z re-
jest tworzenie obiektu za pomocą jego kon- guły, gotowy do użycia, wymaga bowiem skon�gurowania zależności, czyli przypisania re-
struktora lub za pomocą metody fabrykują- ferencji do innych obiektów, z których korzysta. Należałoby zatem pobrać z fabryki instancje
cej, zarówno statycznej, jak i należącej do in- wszystkich obiektów zależnych i przypisać referencje ręcznie. W przypadku złożonych zależ-
stancji y. ności kod byłby bardzo długi i nieczytelny, a w szczególności niepotrzebnie skupiałby się na
działaniach, z jego punktu widzenia, nieistotnych. Wstrzykiwanie zależności robi to dokład-
nie za nas, dając nam w pełni skon�gurowany i gotowy do użycia obiekt w chwili pobrania go
Inicjowanie obiektu z fabryki. Nie ma zatem potrzeby wielokrotnego odwoływania się do niej i ręcznego przypi-
za pomocą domyślnego sywania wartości lub referencji. W ten sposób kod staje się bardziej czytelnym i prostszym w
konstruktora bezargumentowego utrzymaniu. Dodatkowym atutem wynikającym z faktu, że a nie wie, skąd pobierać swoje za-
Zdefiniujmy przykładową klasę Object- leżności, jest łatwość testowania kodu. Wynika to z faktu, że interfejsy, na których, z reguły,
Factory – Listing 3. operuje a, mogą być na potrzeby testów zastąpione obiektami naśladującymi. Obiekty te po-
zbawione są faktycznej logiki biznesowej, a jedynie zwracają oczekiwane wartości za każdym
Przykład na Listingu 4. pokazuje, jak zde-
razem, gdy wywołuje się ich metody.
finiować obiekt o nazwie ObjectFactory, Odwrócenie kontroli w Springu jest realizowane poprzez wstrzykiwanie do właściwości typu
który jest typu ObjectFactory. Jest to pro- set oraz wstrzykiwanie do konstruktorów. Obie techniki zostały szerzej opisane w artykule.
sta definicja obiektu odpowiadająca uży-

www.sdjournal.org 45
Warsztaty

nowszej wersji assembly dostępnego w kontek-


Listing 3. De�nicja klasy ObjectFactory ście aplikacji. Jeśli jednak zajdzie potrzeba uży-
public class ObjectFactory cia konkretnej wersji, należy ją również wów-
{ czas wyspecyfikować. Nazwę assembly, moż-
public static string GetObjectStatically() na pominąć, wówczas Spring domyślnie będzie
{ szukał skompilowanych w assembly, w kontek-
return "New string obtained from static factory method"; ście którego uruchamiana jest aplikacja.
} Jeśli typ posiada typ wewnętrzny, wówczas
public string GetObject() inicjujemy go za pomocą operatora +
{
return "New string obtained from instance factory method"; <object id="ObjectFactory"
} type="SpringExample1.ObjectFactor
public class NestedClass y+NestedClass,
{ SpringExample1"/>
public string Name { get; set; }
} Inicjowanie obiektu za pomocą
} statycznej metody fabrykującej
Możliwe jest również zainicjowanie nowego
Listing 4. Przykład stworzenia pojedynczego obiektu obiektu za pomocą statycznej metody fabry-
kującej. Wówczas jako typ podajemy ę zawie-
<object id="ObjectFactory" rającą statyczną metodę oraz dodajemy ele-
type="SpringExample1.ObjectFactory, SpringExample1"/> ment factory-method, którego wartość za-
wiera nazwę metody zwracającej obiekt.
Listing 5. Przykład stworzenia pojedynczego obiektu, wykorzystując konkretną wersję assembly
<object id="ObjectFromStaticFactoryMethod"
<object id="ObjectFactory" type="SpringExample1.ObjectFactory"
type="SpringExample1.ObjectFactory, SpringExample1, Version=1.0.0.0"/> factory-method="GetObjectStatically"/>

Listing 6. De�nicja klasy Container<T> Inicjowanie obiektu


public class Container<T> za pomocą niestatycznej metody
{ fabrykującej należącej do instancji klasy
public T Content { get; set; } Tworzenie obiektu za pomocą metody fabry-
public NameValueCollection NameValue { get; set; } kującej należącej do instancji klasy wygląda
} identycznie, z tą różnicą, że należy dodatko-
wo wyspecyfikować wcześniej zdefiniowany
obiekt fabryki.
Kon�guracja <object id="ObjectFromInstanceFactoryMethod"
Aby korzystać z możliwości oferowanych przez Springa, należy oczywiście pobrać odpowiednie
biblioteki. Można to zrobić, korzystając z poniższego linka http://www.springframework.net/. Na factory-method="GetObject"
tej stronie również można znaleźć szczegółową dokumentację w języku angielskim. Po pobraniu factory-object="ObjectFactory"/>
i rozpakowaniu archiwum od razu rzucą się w oczy pliki *.sln, będące gotowymi projektami Visu-
al Studio. Uruchamiając je ,możliwe będzie łatwe przeglądanie kodów źródłowych, co jest zawsze Powyższy przykład pokazuje kolejną istotną,
bardzo pomocne, oraz ręczna kompilacja bibliotek. Skompilowane biblioteki będą się znajdowały
omawianą wcześniej, funkcjonalność Springa
w katalogu build. Są to pliki *.dll, które należy przekopiować do własnego projektu. Do podstawo-
wej pracy ze Springiem potrzeba zaimportować bibliotekę Spring.Core oraz używaną przez Spring – wstrzykiwanie zależności. O tym jednak na-
bibliotekę Common.Logging. Do projektu należy dodać plik App.con�g oraz, najlepiej w podkatalo- piszę później w sekcji Wstrzykiwanie zależności.
gu con�g, umieścić, na razie pusty, plik app-con�g.xml. W pliku App.con�g wpisujemy ępujący kod,
deklaratywnie de�niując tym samym kontener – Listing 1. Inicjowanie typów generycznych
Powyższa kon�guracja formułuje kontekst Springa, czyli skąd mają być pobierane metadane W przeciwieństwie do języka Java, typy gene-
de�niujące kontener IoC oraz logowanie, z którego Spring korzysta. Logowanie w naszych
ryczne na platformie .NET nie są tylko informa-
przykładach nie będzie wykorzystywane, zatem możemy je wyłączyć (stąd poziom logowa-
nia ustawiony jest na OFF). Plik metadanych najwygodniej jest załączyć jako zasób wbudo- cją dla kompilatora, ale częścią deklaracji typu.
wany, tak jak widać w przykładzie, jest jednak możliwość wczytywania pliku znajdującego Dlatego Spring.NET umożliwia deklarowanie
się na dysku, jak również znajdującego się w sieci Internet pod dowolnym adresem URL. obiektów generycznych w pliku konfiguracyj-
W naszym przykładzie należy pamiętać o oznaczeniu pliku app-con�g.xml jako Embedded Re- nym. Najpierw zdefiniujemy przykładową kla-
source, co jest bardzo istotne, ponieważ w przeciwnym razie aplikacja nie będzie mogła zna-
sę generyczną Container<T> (patrz Listing 6.)
leźć pliku, a co za tym idzie w ogóle się nie uruchomi.
Można oczywiście zainicjować kontener Springa również bezpośrednio w kodzie aplikacji, Następnie pokażemy, jak zadeklarować ją
ale chcemy mieć jak najmniej zależności w kodzie oraz nie chcemy kompilować programu w pliku konfiguracyjnym Springa.
ponownie za każdym razem, zmieni się ścieżka lub nazwa pliku kon�guracyjnego.
Aby móc odwołać się do powyżej zde�niowanego kontenera, wystarczy wywołać poniższy kod: <object id="Container"
type="SpringExample1.Container&lt;string>"/>
IApplicationContext springContainer = ContextRegistry.GetContext();

W ten sposób mamy skon�gurowany projekt i możemy przystąpić do napisania pierwszego Z powodu ograniczeń nałożonych na składnię
przykładu. XML, znak mniejszości musi być zapisany za
pomocą tak zwanego bytu HTML – &lt;

46 03/2010
Wprowadzenie do Spring.NET

W tej sekcji poznaliśmy podstawowy mecha-


nizm kontenera Springa, jakim jest deklarowa- Listing 7. De�nicja klasy MyClass
nie definicji obiektów. Na podstawie tych de- public class MyClass
finicji Spring inicjalizuje obiekty w momen- {
cie powołania do życia kontenera obiektów, a public MyClass() { }
następnie przekazuje do dyspozycji aplikacji,
gdy instancja danego obiektu będzie wymaga- public MyClass(string description, int value)
na. Aby wydobyć instancję obiektu z kontenera {
Springa , wystarczy wywołać poniższy kod: this.Value = value;
this.Description = description;
string text1 = springContainer.GetObject(" }
Text1") as string;
public string Description { get; set; }
Rzutowanie na typ string jest w tym wy- public int Value { get; set; }
padku niezbędne, jako że wszystkie obiekty }
zwracane przez fabrykę są typu object.
Istnieje również alternatywna metoda uzy- Listing 8. Wstrzykiwanie zależności do obiektów referencyjnych za pomocą elementu ref.
skania obiektu, bardziej preferowana przez <object id="Container2" type="SpringExample1.Container<SpringExample1.MyClass>">
programistów C#: <property name="content">
<ref object="MyClass2"/>
string text2 = springContainer["Text2"] </property>
as string; </object>

W powyższym przykładzie zastosowane zo- Listing 9. Zagnieżdżone obiekty anonimowe


stało przeciążenie operatora indeksującego. <object id="Container3" type="SpringExample1.Container<SpringExample1.MyClass>">
Inicjalizowanie samych obiektów na nie- <property name="content">
wiele się zda, jeśli nie będą one miały w peł- <object type="SpringExample1.MyClass">
ni skonfigurowanych zależności. Następny <property name="description" value="..."/>
rozdział skupi się na kolejnej fundamental- </object>
nej funkcjonalności Springa – wstrzykiwa- </property>
niu zależności. </object>

Wstrzykiwanie zależności Listing 10. Klasa będąca kontenerem kolekcji


Czym jest wstrzykiwanie zależności, zostało public class CollectionsDependantClass
objaśnione w ramce. Skupmy się zatem od ra- {
zu, na czym to polega z punktu widzenia kon- public IList List { get; set; }
figuracji Springa. public ISet Set { get; set; }
public NameValueCollection NameValueCollection { get; set; }
Wstrzykiwanie zależności public IDictionary Dictionary { get; set; }
za pomocą właściwości typu set }
Jeśli klasa definiuje bezargumentowy kon-
struktor domyślny, wówczas zostanie zaini- Listing 11. Deklarowanie elementów listy
cjowany pusty obiekt. Aby zdefiniować za- <object id="Collections1" type="SpringExample1.CollectionsDependantClass">
leżności, używamy do tego właściwości ty- <property name="list">
pu set, które również muszą być zdefiniowa- <list>
ne w klasie dla każdego pola konfigurowane- <value>List text</value>
go za pomocą Springa. Pola klasy są ustawia- <ref local="MyClass2"/>
ne już po pełnym zainicjowaniu obiektu, czy- </list>
li po wywołaniu jego konstruktora. </property>
Jako przykład weźmy klasę MyClass (Li- </object>
sting 7). Klasa MyClass posiada dwa rodzaje
zależności. Poniżej przedstawiony jest sposób Listing 12. Deklarowanie elementów zbioru
zdefiniowania zależności w pliku XML. <object id="Collections2" type="SpringExample1.CollectionsDependantClass">
<property name="set">
<object id="MyClass" <set>
type="SpringExample1.MyClass"> <value>Set text</value>
<property name="description" <value>Set text</value>
value="Opis"/> </set>
<property name="value" value="25"/> </property>
</object> </object>

Powyżej zdefiniowany został obiekt ty-


pu MyClass, który definiuje właściwości

www.sdjournal.org 47
Warsztaty

Description oraz Value i ustawia je na war- wej konwersji typu z postaci tekstowej. Potrafi Wstrzykiwanie
tość „Opis” oraz wartość 25. on przekonwertować każdy typ wbudowany. zależności za pomocą konstruktora
Zależność deklaruje się, wskazując najpierw Jeśli obiekt nie definiuje żadnej właściwości lub Wstrzykiwanie zależności za pomocą kon-
nazwę właściwości, która jest definiowana, a na- po prostu żadnej ze zdefiniowanych nie chcemy struktora odbywa się poprzez wywołanie
stępnie podaje się jej wartość. Spring potrafi na ustawić, wówczas element object pozostaje pu- konstruktora, którego parametry stano-
podstawie typu właściwości dokonać prawidło- sty, jak we wcześniejszych przykładach. wią zależności. Definiowanie konstruktora
oraz metody fabrykującej wygląda w zasa-
Listing 13. Deklarowanie elementów kolekcji typu nazwa-wartość dzie identycznie, jako że stosuje się w obu
przypadkach te same elementy definiujące
<object id="Collections3" type="SpringExample1.CollectionsDependantClass"> argumenty.
<property name="nameValueCollection"> Argumenty konstruktora definiuje się
<name-values> podobnie jak właściwości typu set, jed-
<add key="text" value="NVC text"/> nak zamiast elementu property używamy
<add key="object" value="It can only be string"/> constructor-arg. Należy pamiętać, że cza-
</name-values> sem typ parametru może być niejednoznacz-
</property> ny i Spring nie poradzi sobie z jego rozwikła-
</object> niem. Możemy wówczas użyć trzech metod
dopasowywania typu.
Listing 14. Deklarowanie elementów słownika
Dopasowywanie
<object id="Collections4" type="SpringExample1.CollectionsDependantClass"> po indeksie argumentu
<property name="dictionary"> Jest to domyślne zachowanie. Spring postara
<dictionary> się dokonać konwersji typu według typów za-
<entry> deklarowanych w konstruktorze w takiej ko-
<key> lejności, w jakiej zdefiniowane zostały w pli-
<value>key</value> ku XML, czyli:
</key>
<ref local="MyClass2"/> <object id="MyClass1"
</entry> type="SpringExample1.MyClass">
<entry key="textKey" value="textValue"/> <constructor-arg value="Opis1"/>
<entry key-ref="MyClass2" value-ref="MyClass3"/> <constructor-arg value="1"/>
</dictionary> </object>
</property>
</object> Jeśli kolejność argumentów zostałaby za-
mieniona, wówczas Spring zgłosiłby wyją-
Listing 15. a będąca kontenerem kolekcji generycznych tek w momencie inicjalizowania obiektu,
twierdząc, że wartość „Opis” nie ma wła-
public class GenericCollectionsDependantClass ściwego formatu, by przekonwertować ją
{ na ę Int32. Można jednak jawnie zadeklaro-
public IList<Container<MyClass>> List { get; set; } wać kolejność użycia argumentów. Służy do
public IDictionary<string, int> Dictionary { get; set; } tego atrybut index, który powie Springowi,
} do którego argumentu dopasować deklaro-
waną wartość.
Listing 16. Deklarowanie kolekcji generycznych
<object id="MyClass2"
<object id="GenericCollections" type="SpringExample1.GenericCollectionsDependantC type="SpringExample1.MyClass">
lass"> <constructor-arg index="1" value="2"/>
<property name="list"> <constructor-arg index="0"
<list element-type="int"> value="Opis2"/>
<value>1</value> </object>
<value>2</value>
<value>3</value> Należy pamiętać, że indeksowanie zaczyna
</list> się od zera.
</property>
<property name="dictionary"> Dopasowywanie według
<dictionary key-type="string" value-type="int"> jawnie zadeklarowanego typu
<entry key="value1" value="5"/> Jak zostało wspomniane w poprzedniej sek-
<entry key="value2" value="10"/> cji, zamiana kolejności spowoduje błąd, moż-
<entry key="value3" value="15"/> na jednak podpowiedzieć Springowi, jakie-
</dictionary> go typu jest dany argument tak, by był w sta-
</property> nie dokonać prawidłowej konwersji niezależ-
</object> nie od kolejności argumentów. Służy do tego
atrybut type.

48 03/2010
Wprowadzenie do Spring.NET

<object id="MyClass3" • <ref parent="MyClass2"/> – dzia- W ten sposób nie wstrzykujemy referencji
type="SpringExample1.MyClass"> ła podobnie jak atrybut object, z tą do obiektu, a jedynie wartość id zdefiniowa-
<constructor-arg type="int" value="3"/> różnicą, iż wskazuje na poszukiwa- ną w pliku konfiguracyjnym. Użyteczne, je-
<constructor-arg type="string" nie obiektu w kontenerze fabryki nad- śli kiedyś któryś ze zdefiniowanych obiektów
value="Opis3"/> rzędnej. Bardzo rzadko stosowany potrzebowałby bezpośrednio odwołać się do
</object> w praktyce. fabryki, by wydobyć konkretny obiekt.
Element ten również jest rzadko stosowa-
Dopasowywanie po nazwie argumentu Możliwe jest również stworzenie dowiąza- ny w praktyce.
To dopasowanie odbywa się na podstawie za- nia do wartości id innego obiektu za pomocą Istnieje również skrócona notacja wstrzyki-
deklarowanej w klasie nazwy argumentu, którą elementu idref. Na przykład: wania referencji do właściwości:
wskazuje się w pliku XML za pomocą atrybutu
name. Działa to podobnie jak indeksowanie argu- <idref local="MyClass2"/> <property name="content" ref="MyClass2"/>
mentów, z tą różnicą, że jest bardziej czytelne.
Listing 17. Scalanie kolekcji
<object id="MyClass4"
type="SpringExample1.MyClass"> <object id="Parent" type="SpringExample1.CollectionsDependantClass"
<constructor-arg name="value" abstract="true">
value="4"/> <property name="nameValueCollection">
<constructor-arg name="description" <name-values>
value="Opis4"/> <add key="key1" value="value1"/>
</object> <add key="key2" value="value2"/>
</name-values>
Wstrzykiwanie zależności za pomocą właści- </property>
wości, jak i konstruktora można ze sobą łą- </object>
czyć. Nic nie stoi na przeszkodzie, by pew-
ne zależności zdefiniować w konstruktorze, <object id="Child" parent="Parent">
a inne za pomocą właściwości. Kiedy uży- <property name="nameValueCollection">
wać którego podejścia? Ogólnie, za pomocą <name-values merge="true">
konstruktora powinno się ustawiać zależno- <add key="key3" value="value3"/> <!-- Dodana zostanie nowa wartość pod
ści wymagane oraz tylko do odczytu, zaś za kluczem 'key3' -->
pomocą właściwości te opcjonalne oraz te, <add key="key2" value="new value"/> <!-- Stara wartość pod kluczem 'key2'
które mogą być swobodnie modyfikowane. zostanie zastąpiona nową -->
</name-values>
Szczegółowe omówienie </property>
konfiguracji zależności </object>
Do tej pory we wszystkich przykładach ope-
rowaliśmy na typach prostych, takich jak Listing 18. Przykład klasy deklarującej zależność od zagnieżdżonej listy list, tablicy asocjacyjnej
oraz tablicy wielowymiarowej.
string czy int. Możliwe jest jednak również
deklarowanie typów referencyjnych czy ko-
lekcji, i na tym skupią się kolejne sekcje. public class IndexedClass
{
Wstrzykiwanie zależności od obiektów public IList List { get; set; }
referencyjnych za pomocą elementu ref. public IDictionary Dictionary { get; set; }
Element ref służy do definiowania zależ- public int[,] Table { get; set; }
ności od innych zdefiniowanych wcześniej
obiektów referencyjnych. Używa się go w na- public IList this[int index]
stępujący sposób – Listing 8. {
Może on przyjmować ępujące postaci: get { return this.List[index] as IList; }
set { this.List[index] = value as IList; }
• <ref object="MyClass2"/> – odwołuje }
się do innego zdefiniowanego wcześniej public object this[string key]
obiektu w fabryce. Wartość atrybutu ob- {
ject może wskazywać zarówno na id in- get { return this.Dictionary[key]; }
nego obiektu, jak i na dowolną wartość set { this.Dictionary[key] = value; }
atrybutu name. }
• <ref local="MyClass2"/> – odwołuje się public int this[int dim1Index, int dim2Index]
do innego zdefiniowanego obiektu w obrę- {
bie tego samego dokumentu XML. War- get { return this.Table[dim1Index, dim2Index]; }
tość atrybutu local musi wskazywać na set { this.Table[dim1Index, dim2Index] = value; }
id obiektu zdefiniowanego w edytowa- }
nym pliku. Umożliwia to sprawdzenie po- }
prawności użytej nazwy już na etapie wali-
dacji dokumentu XML.

www.sdjournal.org 49
Warsztaty

W ten jednak sposób domyślnie używamy by jednego obiektu. Nie ma zatem potrzeby ne. Obiekt zagnieżdżony definiujemy zatem
zakresu object. definiować go jako niezależnego bytu z wła- ępująco – Listing 9.
snym id. Wystarczy zadeklarować go jako
Zagnieżdżone obiekty anonimowe obiekt zagnieżdżony. Nie będzie go jednak Deklarowanie wartości kolekcji
Nieraz zdarza się, że definicja danego obiek- można już wówczas bezpośrednio pobrać Częstym przypadkiem jest zależność obiek-
tu jest używana tylko jednokrotnie na potrze- z fabryki, ale przecież nie będzie to potrzeb- tów od kolekcji. Spring udostępnia cztery ty-
py elementów: list, set, name-values i dic-
Listing 19. De�niowanie niegenerycznych kolekcji klasy za pomocą indekserów tionary, które służą do deklarowania zależ-
ności w kolekcjach typów (odpowiednio):
<object id="IndexedClass" type="SpringExample1.IndexedClass"> IList, ISet, NameValueCollection i IDic-
<property name="list"><!-- Inicjujemy listę do której elementów będziemy się tionary. Przykłady użycia znajdują się poni-
odwoływać za pomocą indeksu --> żej, zdefiniujmy jednak najpierw ę, której bę-
<list> dziemy używać jako kontenera naszych ko-
<list> lekcji (Listing 10).
<value>0</value>
</list> Lista
</list> Listę deklarujemy za pomocą elementu list.
</property> Następnie znajdują się elementy listy. Ponie-
<property name="dictionary"><!-- Inicjujemy instancję słowika --> waż lista nie jest generyczna, można jej przy-
<dictionary/> pisać dowolny typ wartości, co też widać w
</property> przykładzie. Możliwe jest dalsze zagnież-
<property name="table" expression="new int[1,1]"/> <!-- Inicjumemy instancję dżanie kolekcji lub utworzenie obiektu we-
tablicy --> wnętrznego – wszystkie elementy definiują-
ce zależności są dozwolone.
<property name="[0][0]"><!-- Ustawiamy pierwszy element listy będący pierwszym
elementem listy 'list' za pomocą indeksu --> Zbiór
<value>-5</value> Deklaracja zbioru wygląda prawie identycz-
</property> nie. Jedyna różnica wynika z definicji zbioru,
który uniemożliwia przechowywanie iden-
<property name="['keyOne']" value="10"/><!-- Ustawiamy element słownika pod tycznych elementów. Proszę się zatem nie
kluczem 'keyOne' w tym wypadku dodajemy nową wartość do zdziwić, jeśli po zadeklarowaniu zbioru we-
pustej tablicy asocjacyjnej --> dług powyższego przykładu, zawierającego
z pozoru dwa elementy, po wyświetleniu za-
<property name="[0,0]"><!-- Ustawiamy pierwszy i jedyny element tablicy wartości okaże się, że zdefiniowany zbiór za-
dwuwymiarowej za pomocą indeksu --> wiera tylko jeden wpis.
<value type="int">-24</value>
</property> Kolekcja nazwa-wartość
</object> Jest to specyficzny typ kolekcji, który zawie-
ra elementy składające się z dwóch wartości
Listing 20. Generyczna klasa z indekserami tekstowych, z których pierwsza jest kluczem,
public class GenericIndexedClass<T> a druga wartością.
{ Kolekcję nazwa-wartość deklaruje się za po-
public IList<IList<T>> List { get; set; } mocą elementu name-values, zaś poszczegól-
public IDictionary<string, T> Dictionary { get; set; } ne wpisy za pomocą elementu add, wewnątrz
public T[,] Table { get; set; } którego za pomocą atrybutów key oraz value
definiujemy faktyczną zawartość danego wpi-
public IList<T> this[int index] su kolekcji.
{
get { return this.List[index]; } Słownik
set { this.List[index] = value; } Słownik jest tablicą asocjacyjną, podobnie jak
} kolekcja nazwa-wartość, z tą różnicą, że klucz
public T this[string key] oraz wartość mogą być dowolnymi obiekta-
{ mi. Słownik definiuje się za pomocą elemen-
get { return this.Dictionary[key]; } tu dictionary. Poszczególne wpisy w słow-
set { this.Dictionary[key] = value; } niku dodaje się za pomocą elementu entry.
} Wewnątrz niego umieszcza się element key,
public T this[int dim1Index, int dim2Index] w którym zawierać się mogą dowolne ele-
{ menty, takie jak value, ref, idref i inne, po-
get { return this.Table[dim1Index, dim2Index]; } dobnie jak w przypadku listy czy zbioru. ęp-
set { this.Table[dim1Index, dim2Index] = value; } ny element wewnątrz entry definiuje war-
} tość i może znowu być dowolnym dozwolo-
} nym elementem definiującym. Istnieje rów-
nież notacja skrócona, jak w przykładzie,

50 03/2010
Wprowadzenie do Spring.NET

umożliwiająca w jednaj linijce zdefiniować w fabryce obiektu, który posiada zależność od oraz nadpisanie już istniejących. Funkcjonal-
wpis za pomocą atrybutów elementu entry. kolekcji, może zdefiniować tę kolekcję na nowo. ność ta szczególnie się przydaje w sytuacji, gdy
Atrybutami tymi są: Efektem będzie dodanie elementów nowych mamy jeden wspólny obiekt rodzicielski z li-

• key – klucz będący tekstem; Listing 21. De�niowanie generycznych kolekcji klasy za pomocą indekserów
• – klucz będący referencją do
key-ref
wcześniej zdefiniowanego obiektu; <object id="GenericIndexedClass" type="SpringExample1.GenericIndexedClass<double>
• value – wartość będąca tekstem; ">
• value-ref – wartość będąca referencją. <property name="list">
<list element-type="System.Collections.Generic.IList<double>">
Oczywiście wszystkie cztery kombinacje <list element-type="double">
użycia są dozwolone. <value>0</value>
</list>
Deklarowanie </list>
wartości kolekcji generycznych </property>
Deklarowanie kolekcji generycznych wyglą-
da podobnie, z tą różnicą, że nie można mie- <property name="dictionary">
szać typów elementów w kolekcji, jak miało <dictionary key-type="string" value-type="double"/>
to miejsce w przykładach z poprzedniej sek- </property>
cji. W tym wypadku odpadają nam również
kolekcje typu nazwa-wartość oraz zbiór, po- <property name="table" expression="new double[1,1]"/>
nieważ nie są generyczne.
Zdefiniujmy najpierw ę zawierającą kolek- <property name="[0][0]">
cje generyczne (Listing 15). <value type="double">-18.6</value>
Deklarowanie kolekcji generycznych wy- </property>
gląda ępująco – Listing 16.
Jak widać w przykładzie, elementy list <property name="['keyTwo']">
oraz dictionary mają specjalne atrybuty, za <value type="double">30.4</value>
pomocą których deklarujemy typ elementów </property>
kolekcji. Należy jednak pamiętać o zgodności
typów. Jeśli spróbujemy utworzyć niegene- <property name="[0,0]">
ryczną deklarację kolekcji generycznej (i vi- <value type="double">6.23e+2</value>
ce versa), wówczas podczas tworzenia fabry- </property>
ki Spring zgłosi wyjątek, mówiąc, że nie mo- </object>
że utworzyć kolekcji, ponieważ zaistniała nie-
zgodność typów. Wyjątek ten może wyglądać Listing 22. Przykład klasy de�niującej zdarzenia
ępująco:
public class Processor<T>
Core.TypeMismatchException: Cannot convert {
property value of public event ProcessorEventHandler<T> ProcessingComplete;
type [System.Collec public event ProcessorEventHandler<T> ProcessingStarted;
tions.ArrayList] to
required type [Sys public void ProcessData(T data, Func<T, T> action)
tem.Collections.Ge {
neric.IList`1] for processingStarted(data);
property 'list'. new Thread(() => { processingComplete(action(data)); }).Start();
}
Taka postać zgłoszonego wyjątku wynika private void processingComplete(T processedData)
z faktu, że z powodu braku generycznego ty- {
pu w deklaracji listy Spring próbuje do gene- if (ProcessingComplete != null)
rycznego interfejsu przypisać niegeneryczną {
implementację, co jest błędem. ProcessingComplete(this, new ProcessorEventArgs<T>(processedData));
}
Scalanie kolekcji }
Spring umożliwia (od wersji 1.3) scalanie private void processingStarted(T dataToBeProcessed)
kolekcji zdefiniowanej w obiekcie rodziciel- {
skim z kolekcją w obiekcie dziedziczącym. if(ProcessingStarted != null)
Na temat dziedziczenia obiektów w fabry- {
ce Springa użytkownik będzie mógł prze- ProcessingStarted(this, new ProcessorEventArgs<T>(dataToBeProcessed));
czytać później w sekcji Dziedziczenie defini- }
cji obiektów. }
Zasada scalania kolekcji polega na tym, że }
obiekt dziedziczący z innego zdefiniowanego

www.sdjournal.org 51
Warsztaty

stą, która powinna być zdefiniowana podobnie Ustawianie stać specjalny moduł Springa, jakim jest ję-
dla każdego dziecka. Użytkownik, chcąc dodać wartości list za pomocą indekserów zyk wyrażeń. Atrybut expression występu-
nowe lub zmienić niektóre z elementów w jed- Bardzo ciekawą własnością języka C# jest prze- je w każdym elemencie definiującym wartość
nym z dziedziczonych obiektów bez potrzeby ciążanie operatora indeksującego. Można za jego i jest alternatywą dla atrybutu value, w prze-
definiowania kolekcji od nowa, może skorzystać pomocą odwoływać się do elementów klasy, jak ciwieństwie do którego umożliwia obliczenie
z mechanizmu scalania kolekcji, który właśnie do kolekcji (najczęściej do wewnętrznej kolekcji wartości na podstawie podanego wyrażenia.
to umożliwia. Proszę prześledzić poniższy przy- klasy). Spring umożliwia zatem konfigurowanie W tym wypadku zainicjowania nowej jedno-
kład – Listing 17. wartości pól klasy za pomocą indeksów. elementowej tablicy dwuwymiarowej.
W powyższym przykładzie zadeklarowany zo- Zdefiniujmy przykładową klasę IndexedClass Język wyrażeń (SpEL) dostarczany przez
stał obiekt rodzicielski parent, stanowiący sza- zawierającą trzy najczęściej używane typy kolek- Springa jest potężnym i wygodnym narzę-
blon dla obiektu potomnego child. Dokładny cji: zagnieżdżoną listę list, tablicę asocjacyjną oraz dziem, którego dokładny opis wykracza poza
mechanizm dziedziczenia zostanie wyjaśniony tablicę wielowymiarową. Banalny przypadek ta- ramy tego artykułu. Zainteresowanych odsy-
później, w tej chwili istotne jest, że obiekt dzie- blicy jednowymiarowej został pominięty. łam do dokumentacji Springa.
dziczący definiuje atrybut merge="true" dla ko- Teraz zdefiniujemy zawartość kolekcji tej Dodatkową rzeczą, na którą chciałbym zwró-
lekcji, którą scala. W przypadku braku tego atry- klasy za pomocą jej indekserów – Listing 19. cić uwagę czytelnika, jest deklaracja typu ele-
butu kolekcja zostałaby nadpisana całkowicie. Proszę zwrócić uwagę na nowy atrybut, ja- mentu w przypadku dostępu za pomocą in-
Dzięki niemu zaś kolekcja wynikowa ma trzy ele- ki pojawił się w elemencie property inicjują- deksera wielowymiarowego. Z niewiadomych
menty (nie dwa) jako efekt scalenia. Dodatkowo cym tablicę dwuwymiarową – expression. przyczyn brak tej deklaracji powoduje zgłosze-
wartość elementu key2 została nadpisana nową. Za pomocą tego atrybutu możemy wykorzy- nie wyjątku o nieprawidłowym typie indeksu.
Jest to o tyle dziwne, że występuje tylko w przy-
Listing 23. Typ delegujący de�niujący rodzaj funkcji obsługujących zdarzenia padku indeksera wielowymiarowego.
To jednak nie wszystko – skoro możliwe jest
public delegate void ProcessorEventHandler<T>(object source, ProcessorEventArgs<T> definiowanie typów generycznych oraz kolekcji
args); generycznych, dlaczego nie pokusić się o defini-
cję łączącą oba elementy w jedną całość.
Listing 24. Klasa będąca kontenerem argumentów zdarzeń Rozważmy następującą klasę (Listing 20).
public class ProcessorEventArgs<T> A następnie zdefiniujmy jej zawartość (Li-
{ sting 21).
public T ProcessedData { get; private set; } Tym razem deklaracja typu jest obecna na
każdym elemencie definiującym i nie powin-
public ProcessorEventArgs() { } na już dziwić.
W kilku powyższych sekcjach omówione
public ProcessorEventArgs(T processedData) zostały szczegółowe sposoby definiowania
{ specyficznych typów zależności, takich jak na
this.ProcessedData = processedData; przykład listy. W ępnej sekcji pokażemy, jak
} można deklaratywnie skonfigurować metody
} obsługi zdarzeń.

Listing 25. Klasa będąca kontenerem funkcji obsługi zdarzeń Deklaratywne rejestrowanie
public class ProcessorListener<T> metod obsługi zdarzeń
{ Zdarzenia w języku C# są częścią jego specyfi-
public void ProcessingStartedHandleEvent(object source, ProcessorEventArgs<T> args) kacji. Za pomocą słowa kluczowego event de-
{ finiuje się zdarzenie, do którego podpina się
//operacje wykonywane przed rozpoczęciem przetwarzania jedną lub więcej funkcji, które zostaną wyko-
} nane w momencie aktywowania zdarzenia.
public void ProcessingCompleteHandleEvent(object source, ProcessorEventArgs<T> args) Spring umożliwia deklaratywne podpięcie
{ funkcji obsługujących zdarzenia do obiektów
//operacje wykonywane po zakończeniu przetwarzania je zgłaszających w reakcji na ich aktywację.
} Rozważmy klasę definiującą dwa zdarzenia
} (Listing 22).
Klasa ta jest prostym odpowiednikiem klasy
Listing 26. De�niowanie obsługi zdarzeń za pomocą Springa BackgroundWorker z pakietu .NET. Jedynym jej
<object id="Processor" type="SpringExample1.Processor<string>"/> zadaniem jest uruchomienie funkcji przekaza-
nej jako parametr w osobnym wątku, informu-
<object id="ProcessorListener" type="SpringExample1.ProcessorListener<string>"> jąc poprzez zdarzenia o rozpoczęciu oraz zakoń-
<listener event="ProcessingStarted" method="ProcessingStartedHandleEvent"> czeniu przetwarzania danych.
<ref local="Processor"/> Na potrzeby naszego przykładu potrzeb-
</listener> ny będzie również typ delegacyjny, definiu-
<listener event="ProcessingComplete" method="ProcessingFinishedHandleEvent"> jący rodzaj funkcji obsługujących zdarzenia
<ref local="Processor"/> (Listing 23).
</listener> Klasa ProcessorEventArgs jest kontene-
</object> rem argumentów przekazywanych do funk-
cji obsługi zdarzenia (Listing 24).

52 03/2010
Wprowadzenie do Spring.NET

Ostatnim niezbędnym elementem jest często w sytuacji, w której czas potrzebny na gdy po raz pierwszy fabryka otrzyma żądanie
a będąca kontenerem funkcji obsługi zdarzeń inicjalizację obiektu jest długi lub gdy chce- zwrócenia danego obiektu.
(Listing 25). my już na etapie uruchamiania aplikacji być
Mając zdefiniowane wszystkie niezbędne ele- poinformowani o błędach w procesie two- Autowiązanie zależności
menty, możemy przystąpić do spięcia wszystkie- rzenia obiektów. Czasem jednak obiekty są W tej sekcji zajmiemy się bardzo interesującą
go w całość za pomocą Springa – Listing 26. wykorzystywane bardzo rzadko i nie ma po- funkcjonalnością dostarczaną przez Springa,
W powyższym listingu zdefiniowaliśmy trzeby tworzenia ich podczas startu aplikacji. jaką jest możliwość automatycznego wstrzyk-
obiekt klasy Processor, który następnie zo- Można zatem nakazać fabryce ich inicjaliza- nięcia zależności do obiektów poprzez anali-
staje przekazany jako źródło zdarzeń do me- cję dopiero w momencie ich pierwszego uży- zę struktury zdefiniowanego kontenera. Au-
tod obsługujących zdarzenia. Jak widać w przy- cia. Służy do tego atrybut lazy-init umiesz- towiązanie jest definiowane na poziomie de-
kładzie, zadeklarowany został obiekt klasy czany w elemencie object. Jeśli zostanie on finicji obiektu za pomocą atrybutu autowire.
ProcessorListener, którego dwie metody zo- ustawiony na true, instancja obiektu nie zo- Jest zatem możliwe, aby dla pewnych obiek-
stały podpięte do zdarzeń zgłaszanych przez nasz stanie utworzona w momencie inicjalizacji tów tę funkcjonalność włączyć, podczas gdy
procesor. Teraz wystarczy już jedynie pobrać tak kontenera Springa, ale dopiero w momencie, dla innych dowiązywać zależności ręcznie.
skonfigurowany obiekt procesora z fabryki i wy-
wołać jego metodę ProcessData, by zobaczyć, Listing 27. Przykład klasy implementującej interfejs IObjectFactoryAware
jak nasza konfiguracja sprawuje się w praktyce.
Deklaratywne podpinanie funkcji obsługi public class FactoryAwareContainer<T> : IObjectFactoryAware where T : class
zdarzeń dostarczane przez Springa umożliwia {
także wykorzystywanie wyrażeń regularnych private IObjectFactory factory;
do automatycznego podłączenia większej ilości
funkcji do danego zdarzenia lub kilku naraz. public T Content
Dość częstą praktyką jest nazywanie funk- {
cji obsługi zdarzeń w taki sposób, aby się get
z nim kojarzyła. Można zatem wykorzystać {
wyrażenia regularne, aby łatwo podpiąć funk- return this.factory["Content"] as T;//zależność od API Springa
cje za pomocą jednej deklaracji. Dla naszego }
przykładu będzie to: }

<object id="ProcessorListener" public IObjectFactory ObjectFactory


type="SpringExample1. {
ProcessorListener&lt;string>"> set { this.factory = value; }
<listener method="${event}HandleEvent"> }
<ref local="Processor"/> }
</listener>
</object> Listing 28. Przykład klasy de�niującej sygnaturę metody, która zostanie przez Springa
zamieniona metodą wyszukującą

W powyższym przykładzie widzimy, że nie


zdefiniowaliśmy konkretnej metody dla kon- public abstract class MethodInjectedContainer<T>
kretnego zdarzenia, ale raczej podpięliśmy {
funkcje do wszystkich zgłaszanych zdarzeń. public T Content
To, jaka funkcja zostanie użyta dla danego zda- {
rzenia, zależeć będzie od jego nazwy. get
Możliwe jest również podpięcie większej {
ilości funkcji do zdarzenia za pomocą jedne- return GetContent();
go wyrażenia regularnego. }
}
<object id="ProcessorListener"
type="SpringExample1. protected abstract T GetContent();
ProcessorListener&lt;string>"> }
<listener method=".+HandleEvent">
<ref local="Processor"/> Listing 29. Wstrzykiwanie metody wyszukującej
</listener>
</object> <object id="MyClass" type="SpringExample1.MyClass" singleton="false">
<constructor-arg index="1" value="42"/>
W ten sposób dla każdego zdarzenia zosta- <constructor-arg index="0" value="Opis"/>
ną wykonane funkcje, których nazwa koń- </object>
czy się na HandleEvent.
<object id="MethodInjectedContainer"
Opóźniona type="SpringExample1.MethodInjectedContainer <SpringExample1.MyClass>">
inicjalizacja obiektów <lookup-method name="GetContent" object="MyClass"/>
Domyślnie wszystkie obiekty w fabryce Sprin- </object>
ga są preinicjalizowane. Przydaje się to bardzo

www.sdjournal.org 53
Warsztaty

Autowiązanie umożliwia zredukowanie lub • Autowiązanie wybierane automatycznie W związku z tym, klasa może w swoim ko-
zupełne wyeliminowanie potrzeby definio- (autodetect) – Spring samodzielnie wy- dzie zażądać określonego obiektu bezpośred-
wania argumentów konstruktora lub właści- biera autowiązanie po typie lub do kon- nio z fabryki za każdym razem, gdy będzie te-
wości, prowadząc w konsekwencji do zmniej- struktora w zależności od definicji klasy. go potrzebowała. Implementowanie interfejsu
szenia ilości pisanego kodu. Jeśli klasa posiada konstruktor domyśl- IObjectFactoryAware ma jednak jedną bardzo
Autowiązanie ma pięć trybów, które cha- ny, wówczas zostanie wykorzystane wią- niepożądaną konsekwencję. Uzależnia się nasz
rakteryzują się różnymi sposobami dopaso- zanie po typie. kod aplikacji od API Springa oraz wymusza się
wywania wstrzykiwanych zależności. Są to: konkretną nazwę dla definiowanego w fabryce
Warto podkreślić, że jakiekolwiek ręczne obiektu (w tym wypadku „Content”).
• Autowiązanie wyłączone (no lub default) zdefiniowanie właściwości lub argumentów Drugie rozwiązanie jest zdecydowanie bar-
– jest to tryb domyślny. Konfiguracja za- konstruktora nadpisuje działanie autowią- dziej eleganckie i polega na tytułowym dla tej
leżności musi być wykonywana ręcznie, zania, czyli innymi słowy ustawienia auto- sekcji wstrzykiwaniu metod wyszukujących.
co ma tę zaletę, że wszystkie zależności są wiązania zostają wówczas przez Springa zi- Nasza klasa zależna od kłopotliwej właści-
dobrze udokumentowane. Ten tryb jest gnorowane. wości musi zadeklarować metodę mającą na-
zalecany przy dużych projektach, ponie- stępującą sygnaturę:
waż zbyt duże skomplikowanie zależno- Wstrzykiwanie
ści w przypadku wiązania automatyczne- metod wyszukujących <public|protected> <abstract|virtual>
go może doprowadzić do bardzo nieczy- Jeśli obiekt korzysta z innych obiektów i ich cy- <return-type>
telnej, trudnej w analizie i utrzymaniu kle życiowe są zgodne (na przykład obiekt typu MethodName(no-
konfiguracji. singleton korzysta również z obiektów single- arguments);
• Autowiązanie po nazwie (byName) – tonowych), wówczas wszystkie zależności mo-
Spring analizuje strukturę kontenera ,wy- gą być wstrzyknięte w chwili tworzenia obiek- Na przykład tak jak w przykładziew listin-
szukując obiekty nazwane dokładnie tak, tu nadrzędnego. Problem zaczyna się w mo- gu 28.
jak właściwość obiektu (za pomocą atry- mencie, gdy potrzebujemy wymieszać cykle ży- Naturalnie klasa sama w sobie musi być za-
butu id lub name), który ma włączony ten ciowe obiektów. Jeśli obiekt typu singleton ko- deklarowana jako abstrakcyjna w momencie,
tryb automatycznego wiązania. Jeśli ta- rzysta z obiektu prototypowego, wówczas za- gdy chcemy zadeklarować metodę jako abs-
ki znajdzie, wówczas zostanie on wstrzyk- leżność zostanie wstrzyknięta tylko raz pod- trakcyjną. Natomiast jeśli nie chcemy, aby na-
nięty jako zależność. Ten tryb jest rzadko czas inicjowania kontenera. Może to prowadzić sza klasa była abstrakcyjna, musimy zadekla-
wykorzystywany, ponieważ wymusza do- do nieprzewidzianych konsekwencji (o cyklach rować metodę jako wirtualną.
pasowywanie nazw deklarowanych obiek- życiowych obiektów będziemy jeszcze pisać). Teraz wystarczy powiedzieć Springowi, co
tów do nazw właściwości, co może powo- Bez specjalnej konfiguracji nie ma możliwości, ma robić – Listing 29.
dować niejasności i konflikty, ponieważ aby obiekt singletonowy uzyskał nową instancję W powyższej konfiguracji powiedzieliśmy
różne klasy mogą mieć właściwości o tych obiektu za każdym razem, gdy chce go użyć. Springowi, aby zastąpił zdefiniowaną przez
samych nazwach. Dość częstą sytuacją jest również potrze- nas metodę GetContent swoją implementa-
• Autowiązanie po typie (byType) – Spring ba zdefiniowania w singletonowym obiekcie cją, która jako rezultat zwracać będzie kon-
analizuje strukturę kontenera i wyszuku- serializowanym zależności od obiektu niese- kretny obiekt (tutaj „MyClass”) za każdym
je obiekty o takim samym typie co dowią- rializowanego. W takiej sytuacji niezbędne razem, gdy zostanie wywołana. Nasz będący
zywana właściwość. Jeśli znajdzie zero lub jest ustawienie pola nieserializowanego jako singletonem kontener będzie zatem otrzymy-
więcej niż jeden obiekt danego typu, wów- [NonSerialized], ale wówczas po deserializa- wał nową instancję niesingletonowego obiek-
czas zostanie zgłoszony wyjątek. cji obiektu referencja ta będzie pusta. Pisanie tu „MyClass” za każdym razem, gdy zostanie
• Autowiązanie do konstruktora (construc- zaś własnego mechanizmu serializacji wydaje odczytana jego właściwość Content.
tor) – podobne w działaniu do wiązania się być zadaniem karkołomnym. Spring umożliwia jeszcze zastępowanie
po typie, z tą różnicą, że wstrzyknięcie za- Spring umożliwia zatem rozwiązanie takie- konkretnych istniejących implementacji me-
leżności nie ępuje poprzez właściwość, ale go problemu na przynajmniej dwa sposoby. tod innymi implementacjami napisanymi
poprzez konstruktor. Podobnie jak w przy- Jeden z nich polega na tym, że obiekt imple- przez użytkownika. Jest to jednak funkcjo-
padku wiązania po typie, jeśli w kontene- mentuje interfejs IObjectFactoryAware. Im- nalność rzadko wykorzystywana i nie będę jej
rze nie jest zadeklarowany dokładnie jeden plementacja tego interfejsu wymusza doda- tutaj opisywał. Zainteresowanych odsyłam do
obiekt pasujący do typu argumentu defi- nie do klasy właściwości ObjectFactory, która dokumentacji Springa.
niowanego przez konstruktor, wówczas zo- jest wykorzystywana przez Springa do wstrzyk-
stanie zgłoszony wyjątek. nięcia zależności, jaką jest fabryka obiektów. Zasięg widoczności obiektów
Każda definicja obiektu pojawiająca się w pli-
Listing 30. Dziedziczenie de�nicji obiektów ku konfiguracyjnym Springa jest wzorcem
dla konkretnych obiektów, które zostaną
<object id="parent" type="SpringExample1.MyClass" abstract="true"> utworzone przez fabrykę. Instancji danego
<property name="value" value="5"/> wzorca może być wiele lub może być tylko
<property name="description" value="Opis"/> jedna. Spring umożliwia definiowanie zasię-
</object> gu widoczności obiektów spośród pięciu do-
starczanych przez sam kontener.
<object id="child" type="SpringExample1.YourClass" parent="parent">
<property name="value" value="10"/><!-- Nadpisanie wartości z definicji • Singleton – tylko jedna instancja da-
rodzicielskiej --> nej definicji obiektu będzie istniała w in-
</object> stancji fabryki. Każde odwołanie się do
id takiej definicji zwróci zawsze dokład-

54 03/2010
Wprowadzenie do Spring.NET

nie tę samą instancję obiektu. Typ single- chanizmy, dzięki którym obiekty mogą zostać lass musi deklarować właściwości Value oraz
ton jest domyślnym zakresem widocz- poinformowane przez kontener o zaistnieniu Description, podobnie jak klasa MyClass.
ności obiektów, można go jednak jaw- wspomnianych sytuacji. Mechanizmy te wystę- Dziecko dziedziczy wszystkie elementy od ro-
nie zadeklarować, używając atrybutu pują również w dwóch formach – implementa- dzica, takie jak argumenty konstruktora, wła-
singleton="true" na elemencie object. cji odpowiednich interfejsów lub deklaratywne ściwości, metody inicjujące i inne, oraz mo-
• Prototyp – dokładne przeciwieństwo zdefiniowanie, która metoda powinna zostać że definiować swoje własne. Każda ponowna
singletonu. Każde odwołanie się do id wywołana w momencie zaistnienia opisanych deklaracja tego samego elementu definiujące-
definicji obiektu spowoduje utworzenie wcześniej zdarzeń. go nadpisuje ustawienia rodzicielskie, tak jak
nowej instancji obiektu. Deklaruje się go Wspomniane interfejsy to: w przykładzie. Atrybut abstract znajdują-
za pomocą atrybutu singleton="false" cy się na definicji obiektu parent jest wskaza-
na elemencie object. • IInitializingObject – dostarcza on niem dla fabryki obiektów, że definicja ta jest
• Request – dana instancja obiektu jest wi- metodę AfterPropertiesSet, która zo- jedynie szablonem dla innych i nie powinna
doczna w zakresie HTTP Request. Każdy staje wywołana zaraz po zainicjowaniu zostać zainicjalizowana instancja obiektu na jej
request ma swoją własną instancję obiektu, instancji obiektu. podstawie. Każda próba użycia definicji rodzi-
która jest singletonem podczas jego trwa- • IDisposable – dostarcza on metodę cielskiej jako wartości elementu ref lub próba
nia. Zakończenie danego żądania HTTP Dispose, która zostaje wywołana w momen- wyłuskania definicji z fabryki spowoduje zgło-
kończy również cykl życiowy obiektu cie, gdy cykl życiowy obiektu się skończy. szenie wyjątku. Ma to dość duże znaczenia,
o zasięgu widoczności typu request. Mo- ponieważ szablon rodzicielski nie musi dekla-
że być używany tylko w kontenerze webo- Nie zaleca się jednak stosowania powyższego rować wszystkich elementów, które mogą być
wym. Deklaruje się go za pomocą atrybutu podejścia ze względu na to, że niepotrzebnie niezbędne do prawidłowego funkcjonowania
scope="request" na elemencie object. wiąże to kod klasy z API Springa (w przypad- obiektu, na przykład typu (wówczas atrybut
• Session – działa identycznie jak zakres ku użycia interfejsu IInitializingObject). abstract jest wymagany). Możliwa jest rów-
request, z tą różnicą, że obiekty są wi- Dlatego też istnieje drugie podejście – dekla- nież sytuacja odwrotna, czyli brak deklaracji
doczne w zakresie danej sesji HTTP. ratywne. Można na elemencie definiującym typu obiektu dziedziczącego, w takiej sytuacji
Podobnie jak request może być uży- obiekt umieścić atrybut wskazujący, któ- będzie on tego samego typu, co rodzic, o ile typ
wany tylko w kontenerze webowym. ra metoda z danej klasy zostanie wywołana. został zdefiniowany dla rodzica.
Deklaruje się go za pomocą atrybutu Atrybuty owe to:
scope="session" na elemencie object. Zakończenie
• Application – analogiczny jak dwa po- • init-method="<method-name>" – wska- W ten sposób dotarliśmy do końca tego artyku-
wyższe, z tą różnicą, że widoczność obej- zuje, która metoda zostanie wywołana łu. Zawarte w nim zostały wszystkie najważniej-
muje cykl życiowy aplikacji webowej. zaraz po zainicjowaniu obiektu. Meto- sze i najczęściej używane funkcjonalności defi-
Jest to zatem w zasadzie singleton, jeśli da ta nie może przyjmować żadnego ar- niowania obiektów i zależności oferowanych
nasza konfiguracja nie jest współdzielo- gumentu ani zwracać żadnej wartości. przez Springowy kontener IoC. Nie są to jednak
na przez kilka instancji aplikacji webo- • destroy-method="<method-name>" – wszystkie możliwości przez kontener udostęp-
wej. Deklaruje się go za pomocą atrybu- wskazuje, która metoda zostanie wywo- niane, te jednak, które zostały pominięte, są rza-
tu scope="application" na elemencie łana w momencie niszczenia obiektu. dziej używane lub są zbyt zaawansowane dla po-
object. Podobnie jak w przypadku metody post- czątkującego użytkownika. Informacje zawarte
inicjalizacyjnej także i ta nie może przyj- w niniejszym artykule są niemniej wystarcza-
Wymienione powyżej zakresy widoczności ty- mować żadnego argumentu ani zwracać jące, by stworzyć w pełni funkcjonalną aplika-
pu request, session oraz application mogą żadnych wartości. cję, jakkolwiek jedynie okienkową lub konso-
być używane jedynie w odpowiedniej imple- lową. W kolejnych artykułach przybliżę czy-
mentacji interfejsu IapplicationContext, ja- Dziedziczenie definicji obiektów telnikowi wsparcie Springa dla poszczególnych
ką jest WebApplicationContext, która jest spe- Już wcześniej w tym artykule zostało wspo- warstw aplikacji webowej, a wspiera on każdą
cyficzna dla kontenera webowego. Jeśli któ- mniane, przy okazji omawiania kwestii scala- z nich, od umożliwienia deklaratywnego defi-
ryś z tych zasięgów zostałby użyty w stoso- nia kolekcji, że definicje obiektów mogą być niowania połączenia do bazy danych i obsługi
wanej w naszych przykładach implementacji dziedziczone. Teraz bliżej przyjrzymy się te- transakcji oraz warstwy DAO, poprzez warstwę
XmlApplicationContext, wówczas podczas mu zagadnieniu. logiki biznesowej, której funkcjonalności są wy-
inicjalizacji kontekstu zgłoszony zostałby wy- Definicja obiektu, jak to zostało przedsta- stawiane poprzez usługi sieciowe, a na wsparciu
jątek mówiący, że został użyty nieznany zakres wione wcześniej, może obejmować wiele ele- warstwy prezentacji kończąc. Mam nadzieję, że
widoczności. mentów deklaratywnie formułujących postać ten artykuł zainteresował czytelnika możliwo-
obiektu, który później zostanie zainicjalizo- ściami udostępnianymi przez Springa oraz dał
Informowanie obiektu wany. Definicje dziedziczące, podobnie jak choć lekki wgląd w to, jak potężnym i niezwy-
o jego cyklu życiowym w każdym języku obiektowym, mogą przej- kle pomocnym jest narzędziem. Zapraszam do
W poprzednich sekcjach opisane zostały dość mować deklaracje rodzicielskie, jak również przeczytania kolejnych artykułów, bo prawdzi-
szczegółowo metody konfiguracji obiektów nadpisywać je swoimi (Listing 30). wa zabawa dopiero się zacznie.
oraz ich zależności. Czasem zachodzi dodat- W powyższym przykładzie widzimy defi-
kowo potrzeba przeprowadzenia dodatkowych nicję obiektu rodzicielskiego typu MyClass
operacji po zainicjowaniu obiektu (na przykład oraz dziedziczącego po nim obiektu typu PIOTR WYCZÓŁKOWSKI
sprawdzenia, czy wszystkie zależności zosta- YourClass. Klasy obiektów mogą być iden- Programista zajmujący się na co dzień systemami
ły poprawnie ustawione) lub na chwilę przed tyczne lub zupełnie różne, niezwiązane ze so- typu enterprise opartymi na szkielecie Springa.
zniszczeniem kontenera (na przykład zamknię- bą nawet dziedziczeniem . Jedyne, co musi je Zawodowo związany z Javą, zafascynowany jed-
cie uchwytów do zasobów plikowych lub połą- łączyć, to kompatybilność definicji właściwo- nak możliwościami języka C# 3.0 i technologii LI-
czenia do bazy danych). Spring udostępnia me- ści lub konstruktorów. Dlatego też a YourC- NQ, zajmuje się hobbystycznie platformą .NET.

www.sdjournal.org 55
Aplikacje biznesowe

SOA
Tworzenie serwisów wspomagających proces integracji

Tworzenie rozwiązań integracyjnych to nie trend, ale wymóg stawiany przed


projektantami systemów informatycznych. Coraz bardziej złożone procesy
biznesowe wymagają od nas projektowania rozwiązań dotykających coraz
to większej ilości systemów, które w przeszłości często nie były projektowane
w sposób zapewniający łatwą możliwość inetgracji.
część procesu obejmować będzie przygoto-
Dowiesz się: Powinieneś wiedzieć: wanie wyzwalacza (ang. Trigger) po stronie
• Jak integrować aplikacje stworzone w JEE z • Podstawowa znajomość standardu JEE; MQ odpowiedzialnego za wywołanie apli-
instniejącymi aplikacjami; • Znajomość podstawowych pojęć związa- kacji odpowiedzialnej za przetworzenie ko-
• Jak skon�gurować Websphere AS do pracy nych z Websphere MQ (SDJ 10/2008); munikatu umieszczonego w kolejce (Rysu-
z Websphere MQ; • Znajomość zagadnień kon�guracji We- nek 2).
• Czym jest tzw. triggering w MQ i jak go wy- bsphere AS do pracy z Websphere MQ (SDJ Mając zarys procesu, przejdźmy do anali-
korzystać w procesie integracji. 9/2009). zy technologicznej. Do przygotowania ser-
wisu wykorzystamy JAX-WS, JMS oraz ser-
wer Websphe AS 7. Mechanizm kolejek zo-
mat tego, w oparciu o jakie technologie, na stanie zrealizowany przez Websphere MQ
jaką platformę itp zostało przygotowane na- 7, który wykorzysta mechanizm wyzwala-
Poziom sze rozwiązanie. czy w celu wywołania aplikacji Java odpo-
trudności Od strony biznesowej chcemy przygotowac wiedzialnej za przetworzenie komunikatów
rozwiązanie przyjmujące pewne dane, które (Rysunek 3).
zostaną przekazane w miejsce, gdzie w spo- W naszej analizie przyjęliśmy dwa istot-

S
OA (ang. Service Oriented Architectu- sób właściwy zostaną przetworzone, dając ne kryteria. Pierwsze to fakt, iż część zwią-
re) to pewna koncepcja, rodzaj podej- oczekiwany rezultat (Rysunek 1). zana z przetwarzaniem komunikatów po
ścia w tworzeniu oprogramowania, Nasz proces będzie podzielony na dwie stronie MQ powinna być odseparowana
w której staramy się tworzyć niezależne usłu- części (komponenty), które mogą być do- i niedostępna na zewnątrz , czego konse-
gi, które następnie są udostępniane w celu starczone przez niezależnych dostawców. kwencją było drugie kryterium związane
wykonania określonego zadania lub łączone Pierwsza część procesu związana jest z na- ze stworzeniem niezależnej warstwy po-
w łańcuchy kolejnych wywołań, tworząc tzw. pisaniem aplikacji JEE, a dokładnie serwi- średniej, dostępnej dla zewnętrznych apli-
łańcuchy procesów biznesowych. su odpowiedzialnego za przekazanie odpo- kacji klienckich. Warstwa pośrednia po-
Tak naprawdę trudno w kilku zdaniach wiednio sparsowanej wiadomości do kolej- winna być uniwersalnym pośrednikiem od-
powiedzieć, czym jest SOA. W tym artykule ki MQ (ang. Message Queue) ,wykorzystu- powiadającym za wywołanie pewnego zde-
skupimy się na tworzeniu usług sieciowych, jąc JMS (ang. Java Message Service). Druga finiowanego procesu biznesowego. Opiera-
wykorzystując JAX-WS, które wykorzystamy
jako wygodne narzędzie wspomagające pro-
ces integracji wielu systemów.

Definicja procesu,
analiza problemu
Pracę zaczniemy od zdefiniowania procesu,
na podstawie którego przeprowadzimy ana-
lizę architektoniczną. Naszym celem jest
przygotowanie pewnego procesu bizneso-
wego który udostępnimy zewnętrznym od-
biorcom. Zgodnie z modelem SOA chce-
my oprogramować pewien proces, dla które-
go udostępnimy interfejs dla zewnętrznych
odbiorców. Proces ma być hermetyczny, na-
si klienci nie potrzebują mieć wiedzy na te- Rysunek 1. Schemat procesu biznesowego

56 03/2010
SOA

jąc się o model SOA, wykorzystamy do te-


go celu Webservice, który będzie interfej-
sem dostępowym dla niezależnych klien-
tów. Z punktu widzenia klienta, dostaje-
my interfejs do usługi, która odpowiada za
odebranie danych i odpowiednie ich prze-
procesowanie. Cała usługa jest hermetycz-
na, mamy interfejs odpowiedzialny za do-
stęp do procesu, który odbiera dane, parsu-
je, a następnie przesyła do kolejki, gdzie na-
stępuje przetworzenie tych danych i wyge-
nerowanie odpowiedniego rezultatu. Rysunek 2. Schemat procesu biznesowego z podziałem na komponenty

Tworzenie usługi sieciowej


z wykorzystaniem JAX-WS
W pierwszej fazie implementacji naszego
procesu biznesowego zajmiemy się utwo-
rzeniem Webservice’u odpowiedzialne-
go za odebranie komunikatu i przekaza-
niu go do asynchronicznego przetwarzania.
Jak już wcześniej wspomniałem, wykorzy-
stamy standard JEE do utworzenia serwisu
oraz uzyskania dostępu do obiektów zwią-
zanych z JMS. Pierwszym krokiem będzie
utworzenie naszego serwisu, który poprzez Rysunek 3. Schemat procesu biznesowego z uwzględnieniem technologii
JMS prześle komunikat do kolejki. Dzię-
ki wsparciu dla Websphere MQ od strony Listing 1. Webservice w JAX-WS
Websphere AS zostaną utworzone obiekty
QueueConnectionFactory oraz Queue , któ- @WebService
re dzięki odpowiedniej konfiguracji będą public class MyService {
naszym interfejsem dostępowym do We- private static final Logger LOGGER = Logger.getLogger(MyService.class);
bsphere MQ. W pierwszym kroku utwo-
rzymy instancje obiektu QueueConnection- @Resource(mappedName="MQFactoryJNDI")
Factory, wykorzystując Websphere MQ ja- private QueueConnectionFactory queueConnectionFactory;
ko dostawcę usługi zarządzania komunika-
tami (Rysunek 4). @Resource(mappedName="SDJQueue")
Po utworzeniu QueueConnectionFactory, private Queue queue;
ustawienia naszej fabryki powinny nawiązy-
wać do tego, co zostało zdefiniowane po stro- public Boolean sendData(InputData input){
nie MQ. W naszym przypadku dla fabryki LOGGER.debug("Invoking MyService.sendData");
połączeń konfiguracja została przedstawiona LOGGER.debug(input);
na Rysunku 5.
W sposób analogiczny tworzymy obiekt try{
Queue, który musi zostać powiązany z odpo- QueueConnection conn = queueConnectionFactory.createQueueConnection();
wiadającą mu kolejką po stronie MQ (dokład- Session session = conn.createSession(false, Session.AUTO_ACKNOWLEDGE);
ny opis konfiguracji Websphere AS do pracy MessageProducer producer = session.createProducer(queue);
z Websphere MQ za pomocą JMS został omó- TextMessage msg = session.createTextMessage();
wiony w SDJ 9/2009).
Mając zdefiniowane obiekty JMS, może- msg.setText(input.mqMessage());
my stworzyć nasz serwis do przekazywania
komunikatów do kolejki MQ. W tym celu LOGGER.debug("Sending message to mq");
wykorzystamy standard JEE, a dokładnie LOGGER.debug(input.mqMessage());
adnotację @Webservice, która pozwala nam producer.send(msg);
w bardzo prosty sposób stworzyć kod nasze-
go Webservice’u (Listing 1) oraz obiektu conn.close();
wejściowego (Listing 2). return new Boolean(true);
Po prawidłowej instalacji aplikacji na ser- }catch(JMSException ex) {
werze powinniśmy mieć możliwość wy- LOGGER.error(ex);
generowania WSDL-a (Listing 3). W tym return new Boolean(false);
celu należy wpisać w przeglądarce http: }
//localhost:9080/sdjservice/MyServiceService- }
?wsdl. Oczywiście url może wyglądać nieco }
inaczej, w moim przypadku serwis został za-

www.sdjournal.org 57
Aplikacje biznesowe

instalowany na lokalnej maszynie z ustawio- go za odebranie danych od klienta i prze- części procesu biznesowego pozwala dość
nym kontekstem sdjservice. kazanie ich do kolejki. Dzięki podzieleniu łatwo zdywersyfikować dostawców kom-
Na tym etapie dysponujemy poprawnie za- naszego procesu biznesowego na dwa nie- ponentów do naszego systemu, a co za tym
instalowanym serwisem, który wykorzystu- zależne komponenty możemy przeprowa- idzie zmniejszyć ryzyko związane z uzależ-
jąc odpowiednio zdefiniowane obiekty JMS dzić test i ostatecznie dostarczyć w peł- nieniem projektu od jednego konkretnego
prześle komunikat do kolejki zdefiniowanej ni funkcjonalny komponent niezależnie dostawcy.
po stronie MQ. od tego, czy dostawca odpowiedzialny za W celu przeprowadzenia testu nasze-
utworzenie części związanej z przetwa- go komponentu wykorzystamy komunikat
Test usługi sieciowej rzaniem komunikatu po stronie MQ do- SOAP, którym wywołamy nasz serwis (Li-
W tej chwili możemy przeprowadzić pełny starczył już swój komponent, czy nie. Ta- sting 4).
test naszego komponentu odpowiedzialne- kie podejście wyodrębniania niezależnych Po wywołaniu naszego serwisu do MQ zo-
stał przekazany komunikat, który możemy
podejrzeć za pomocą narzędzia MQ Explo-
ler (Rysunek 6) oraz zwrócony komunikat
SOAP (Listing 5).

Tworzenie
i konfiguracja aplikacji
– konsumenta komunikatów MQ
Druga faza naszego procesu jest związana
z przetwarzaniem komunikatu umieszczo-
nego w MQ. Nasz proces biznesowy z zało-
Rysunek 4. Kon�guracja dostawcy zarządzania komunikatami żenia ma być częścią większego systemu,
który w oparciu o pewne kryteria wywoła
nasz proces lub nie. Załóżmy więc, że mo-
że istnieć sytuacja, w której nie będzie co
przetwarzać przez kilka lub kilkanaście go-
dzin. Jak w takiej sytuacji zapewnić wydaj-
ne oraz optymalne przetwarzanie komuni-
katów? Zastosowanie klasycznej aplikacji
wielowątkowej na pewno spełni nasze ocze-

Listing 2. De�nicja klasy InputData

@XmlAccessorType(XmlAccessType.FIELD)
@XmlRootElement(namespace=
"http://model.sdj",name="InputData")

public class InputData {


private String code;
private Integer num;

@Override
public String toString() {
StringBuilder sb =
new StringBuilder();
sb.append("InputData \n");
sb.append("code="+code + ";");
sb.append("num="+num + ";");

return sb.toString();
}

public String mqMessage(){


StringBuilder sb =
new StringBuilder();
sb.append("code="+code + ";");
sb.append("num="+num + ";");
return sb.toString();
}
}
Rysunek 5. Kon�guracja QueueConnectionFactory

58 03/2010
SOA

kiwania w zekresie funkcjonalnym, ale czy


będzie rozwiązaniem optymalnym i wydaj- Listing 3. WSDL serwisu MyService
nym na płaszczyźnie naszego problemu?
Czy stworzenie wątku głównego, który sta- <?xml version="1.0" encoding="UTF-8"?>
le będzie musiał w krótkich odstępach cza- <definitions name="MyServiceService" targetNamespace="http://service.sdj/"
su odpytywać MQ o to, czy istnieją jakieś xmlns="http://schemas.xmlsoap.org/wsdl/" xmlns:xsd="http://www.w3.org/2001/
komunikaty, jest rozwiązaniem oczekiwa- XMLSchema"
nym ? Bardzo możliwe, że w pewnych wa- xmlns:tns="http://service.sdj/" xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/">
runkach tak, natomiast w naszych na pew- <types>
no nie. Zakładamy, że nasz proces jest czę- <xsd:schema>
ścią większego systemu, który może w pew- <xsd:import namespace="http://service.sdj/" schemaLocation="MyServiceService
nych warunkach poprosić nas o asynchro- _schema1.xsd"/>
niczne przetworzenie pewnych informa- </xsd:schema>
cji we względnie krótkim czasie, ale zara- <xsd:schema>
zem może nas o to nie prosić przez dłuż- <xsd:import namespace="http://model.sdj" schemaLocation="MyServiceService_
szy okres. W takiej sytuacji oczekiwanym schema2.xsd"/>
rozwiązaniem byłby mechanizm, który po- </xsd:schema>
zwalałby konsumować komunikaty tylko </types>
wtedy, kiedy będą w kolejce, unikając sytu- <message name="sendDataResponse">
acji, w której komunikat czeka w kolejce na <part name="parameters" element="tns:sendDataResponse">
przetworzenie. </part>
MQ dostarcza nam taki mechanizm, tzw. </message>
triggering, który pozwala zdefiniować po stro- <message name="sendData">
nie MQ proces odpowiedzialny za wywołanie <part name="parameters" element="tns:sendData">
aplikacji – konsumenta w chwili nadejścia </part>
nowego komunikatu do kolejki. </message>
Od strony programisty naszego kompo- <portType name="MyService">
nentu kod nie ulega dużym modyfikacjom. <operation name="sendData">
Tworzymy aplikację odpowiedzialną za na- <input message="tns:sendData">
wiązanie połączenia z managerem kolej- </input>
ki, pobraniem komunikatu i wykonaniem <output message="tns:sendDataResponse">
dedykowanej logiki biznesowej w oparciu </output>
o informacje zawarte w komunikacie (Li- </operation>
sting 6). </portType>
Tak przygotowany kod wraz z odpowied- <binding name="MyServicePortBinding" type="tns:MyService">
nim plikiem MANIFEST.MF (Listing 7) na- <soap:binding style="document" transport="http://schemas.xmlsoap.org/soap/
leży zapakować w plik jar i wraz z zależnymi http"/>
bibliotekami umiejscowić gdzieś na dysku. <operation name="sendData">
Jest to o tyle istotne, ponieważ MQ pozwa- <soap:operation soapAction=""/>
la wywoływać za pomocą triggera pliki wy- <input>
konywalne, zatem chcąc wywołać naszą apli- <soap:body use="literal"/>
kację JAVA, będziemy wykonywać polecenie </input>
„java -jar D:\lib\mqclient.jar”. <output>
W ostatnim etapie dokonamy niezbęd- <soap:body use="literal"/>
nej konfiguracji po stronie MQ. W pierw- </output>
szym kroku należy stworzyć kolejkę (INI- </operation>
TQ) wykorzystywaną przez monitor wyzwa- </binding>
lacza (ang. Trigger Monitor). Od strony czy- <service name="MyServiceService">
sto technicznej proces wyzwalania aplikacji <port name="MyServicePort" binding="tns:MyServicePortBinding">
przez MQ przebiega w czterech podstawo- <soap:address location="http://ewadl00gb1c74j.ams.com:9080/sdjservice/
wych krokach: MyServiceService"/>
</port>
• wstawienie wiadomości do kolejki </service>
QUEUE _ SDJ ; </definitions>
• wygenerowanie wiadomości – wyzwa-
lacza (ang. Trigger control message) i wsta-
wienie jej do kolejki INITQ (proces ten
przebiega automatycznie); W Sieci
• odebranie zgłoszenia przez monitor z ko-
lejki INITQ; • http://publib.boulder.ibm.com/infocenter/wmqv7/v7r0/index.jsp?topic=/com.ibm.mq.amqtac.doc/
wq11350_.htm;
• wyzwolenie (uruchomienie) naszej apli- • http://publib.boulder.ibm.com/infocenter/wasinfo/v7r0/index.jsp;
kacji JAVA poprzez wykonanie polece- • http://java.sun.com/javaee/5/docs/tutorial/doc/.
nia „java -jar D:\lib\mqclient.jar”.

www.sdjournal.org 59
Aplikacje biznesowe

Drugim krokiem będzie odpowiednia kon-


figuracja kolejki głównej (QUEUE_SDJ) do
wykorzystywania mechanizmu wyzwala-
nia (Rysunek 7). Do najważniejszych usta-
wień można zaliczyć:

• kontrola wyzwalacza – ustawia możli-


wość wykorzystywania mechanizmu
wyzwalaczy dla kolejki, musi być włą-
czona;
• wyzwalacz uruchamiany zapełnieniem
– ilość komunikatów, która spowoduje
uruchomienie naszej aplikacji;
• kolejka inicjująca – kolejka skojarzona
z monitorem, ustawiamy na INITQ;
• nazwa procesu – nazwa procesu, z któ-
rym zostanie skojarzona nasza aplikacja
Rysunek 6. Przeglądarka komunikatów – konsument.

Trzecim i zarazem ostatnim krokiem będzie


zdefiniowanie procesu powiązanego z na-
szą kolejką QUEUE _ SDJ. W tym celu należy
rozwinąć QM_SDJ->Zaawansowane i utwo-
rzyć nowy proces o nazwie SDJ _ PROCESS
i wybrać Dalej. W kolejnym oknie w polu ID
aplikacji należy wpisać java -jar D:\lib\
mqclient.jar (Rysunek 8).

Listing 4. Komunikat SOAP do wywołania


serwisu MyService

<soapenv:Envelope xmlns:soapenv=
"http://schemas.xmlsoap.org/soap/
envelope/" xmlns:ser="http:/
/service.sdj/">
<soapenv:Header/>
<soapenv:Body>
<ser:sendData>
<arg0>
<code>A1B2C3</code>
Rysunek 7. Kon�guracja QUEUE_SDJ <num>875</num>
</arg0>
</ser:sendData>
</soapenv:Body>
</soapenv:Envelope>

Listing 5. Komunikat SOAP z odpowiedzią


z MyService
<soapenv:Envelope xmlns:soapenv=
"http://schemas.xmlsoap.org/soap/
envelope/">
<soapenv:Body>
<dlwmin:sendDataResponse xmlns:
dlwmin="http://service.sdj/">
<return xmlns:ns2=
"http://model.sdj">
true</return>
</dlwmin:sendDataResponse>
</soapenv:Body>
</soapenv:Envelope>

Rysunek 8. Kon�guracja procesu

60 03/2010
SOA

Po przeprowadzeniu konfiguracji może-


Listing 6. Klient do przetwarzania komunikatów
my przejść do etapu testowania naszego kom-
public class MQClient { ponentu.

private static String qMgrName = "QM_SDJ"; Test konsumenta


private static String qName = "QUEUE_SDJ"; W celu przetestowania części związa-
nej z przetwarzaniem komunikatów na-
private static MQQueueManager qMgr; leży uruchomić monitor na kolejce QU-
private static MQQueue queue; EUE_SDJ, który będzie oczekiwał zgłosze-
nia nadejścia komunikatu do kolejki i osta-
public static void main(String[] args) throws EOFException, IOException { tecznie uruchamiał aplikacje konsumenta.
System.out.println("Rozpoczecie przetwarzania"); W tym celu należy z katalogu bin wykonać
try { polecenie:
qMgr = new MQQueueManager(qMgrName);
System.out.println("Polaczenie z Queue Managerem : " + qMgrName); runmqtrm –m QM_SDJ –q INITQ

int openOptions = MQC.MQOO_INPUT_SHARED | W momencie nadejścia komunikatu do ko-


MQC.MQOO_FAIL_IF_QUIESCING | MQC.MQOO_SET; lejki, nasz monitor wywoła aplikację klienc-
ką, która przetworzy nasz komunikat (Ry-
queue = qMgr.accessQueue(qName, openOptions); sunek 9).

MQMessage msg = new MQMessage(); Podsumowanie


W przedstawionym artukule omówiłem
MQGetMessageOptions gmo = new MQGetMessageOptions(); pewien scenariusz integracyjny dla zdefi-
gmo.options = MQC.MQGMO_WAIT; niowanego procesu biznesowego. Oczywi-
gmo.waitInterval = MQC.MQWI_UNLIMITED; ście to pewna koncepcja, ponieważ w za-
leżności od potrzeb i możliwości techno-
queue.get(msg, gmo); logicznych nasz scenariusz integracyjny
System.out.println("Komunikat odebrany"); może wyglądać zupełnie inaczej. W przy-
padku intagracji większych systemów,
String msgString1 = msg.readStringOfByteLength(msg.getMessageLength()); w których nasza aplikacja kliencka miałaby
System.out.println("Tresc: " + msgString1); pełnić rolę pośrednika pomiędzy kolejnymi
kolejkami, zamiast tworzyć aplikacje prze-
queue.setTriggerControl(MQC.MQTC_ON); twarzające komunikaty, możemy wykorzy-
queue.close(); stać technologię IBM Message Broker. Wy-
System.out.println("Kolejka " + qName + " zamknieta"); korzystanie Message Broker-a pozwala wy-
godnie definiować przepływy MQ, zwal-
qMgr.disconnect(); niając nas z konieczności implementacji
aplikacji odpowiedzialnej za przetworzenie
}catch (MQException ex) { i przesłanie komunikatu.
System.out.println("Completion code " +
ex.completionCode + " Reason code " + ex.reasonCode);
}
}
} PAWEŁ PIETRASZ
Consultant, CGI Information Systems and Mana-
gement Consultants (Polska) Sp. z o. o.,
Warszawa, ul. Sienna 39, tel. 022 526 57 00
Kontakt: pawel.pietrasz@gmail.com

Listing 7. Plik MANIFEST.MF

Manifest-Version: 1.0
Package: sdj.client
Main-Class: sdj.client.MQClient
Class-Path: com.ibm.mq.jar
com.ibm.mq.headers.jar
com.ibm.mq.pcf.jar
com.ibm.mq.jmqi.jar jta.jar
connector.jar
com.ibm.mq.com
monservices.jar
Rysunek 9. Monitor wyzwalacza

www.sdjournal.org 61
Felieton

Certyfikacja i co dalej?
Obecna sytuacja na rynku pracy oraz otwarcie rynków europejskich
dla polskich pracowników powoduje, że coraz częściej zastanawiamy
się nad sposobem poniesienia własnych kwalifikacji. Szukamy metod,
które są postrzegane jako wartościowe i uznawane nie tylko przez
polskich pracodawców i managerów. Rozwiązaniem coraz częściej
wybieranym przez Programistów zajmujących się Java są certyfikacje
SUNa ze względu na ich uniwersalność.
(SCEA), do której podchodzi każdego roku je-
Dowiesz się: Powinieneś wiedzieć: dynie kilkanaście osób w Polsce i pokrywa on ca-
• Jakie znaczenie na rynku pracy maja certy�katy • Znajomość podstawowych pojęć związa- łe spektrum Java Enterprise Edition.
SUNa nych z programowaniem w Java’ie Faktem jest, że zainteresowanie ścieżkami cer-
• Czy warto inwestować w egzaminy certy�kacyjne • Czym są egzaminy certy�kacyjne SUNa tyfikacyjnymi rośnie z roku na rok w bardzo zna-
• Jak certy�kacja SUNa postrzegana jest przez ludzi, czącym tempie. Polska jest jednym z tych kra-
którzy już certy�katy posiadają jów europejskich, w których certyfikacja sta-
ła się podstawowym elementem oferty Działu
Szkoleń, a tym samym jednym z ważniejszych.
nadzieję, że poniższy artykuł i przedstawione Na tym etapie byłoby ciężko odpowiedzieć na
w nim wyniki badań przeprowadzone w jed- pytanie dlaczego tak się dzieje, co spowodowało
Poziom nym z europejskich krajów pomogą odpowie- w ostatnich latach takie zainteresowanie egzami-
trudności dzieć na zadane pytania. nami. To, co bez wątpienia narzuca się, to fakt, że
Program certyfikacyjny Suna składa się profesjonaliści są bardziej świadomi swoich moż-
z ośmiu egzaminów dotyczących trzech plat- liwości i wartości na dzisiejszym rynku IT nie tyl-
form Javy. Ich tematyka ściśle wiąże się z wyko- ko w obrębie Polski, ale i na rynku europejskim.

O
d samego początku pojawienia się nywanymi przez działy IT zadaniami, ich rolami Aktualnie certyfikacja stała się twardym dowo-
technologii Java zyskuje ona co- i koncentruje się na trzech grupach: Programi- dem kompetencji, ambicji pracownika oraz mo-
raz więcej zwolenników, głównie ze stach, Deweloperach i Architektach. tywacją do dalszego rozwoju. Jest niewątpliwie
względu na możliwości, jakie daje użytkowni- wartością dodaną profesjonalisty dla jego obec-
kom. Certyfikacje Sun Microsystems z zakre- Ścieżka certyfikacyjna Java nego lub przyszłego pracodawcy. Dla kadry za-
su Javy stały się jednymi z najpopularniejszych Najczęściej podejmowanym certyfikatem jest rządzającej certyfikacje Sun są postrzegane jako
na rynku programistów. Statystyki pokazują, że Sun Certified Java Programmer (SCJP) jako zbiór kompetencji, zdobytych umiejętnościach
certyfikację Suna zrealizowało ponad 600 tyś. podstawa do dalszego rozwoju. Zdecydowanie i rozwijania wiedzy technicznej. W swojej wie-
osób na całym świecie. Niewątpliwa większość mniej osób decyduje się na ścieżkę Dewelopera loletniej pracy nie raz spotkałam się z opinią, że
to oczywiście egzaminy z zakresu technologii Ja- wymagającą większego doświadczenia. Obser- każdy zdobyty przez pracowników certyfikat
va, a Europa jest liderem w tej tematyce. wując rynek IT, stosunek procentowy jest w cią- jest poświadczeniem jego wiedzy i praktycznych
Dlaczego tak się dzieje? Co jest powodem za- gu ostatnich trzech lat bardzo elastyczny i zmie- umiejętności. Wzrost zainteresowania egzami-
interesowania programami certyfikacyjnymi nia się na korzyść zaawansowanych certyfikacji. nami jest na tę opinię jedynie żywym dowodem.
w tak dużym stopniu? W jaki sposób certyfika- Najbardziej jednak „ekskluzywną” ścieżką wy- Świadomość tego, że członkowie zespołu mogą
cja może wpłynąć na karierę zawodową? Mam daje się być Sun Certified Enterprise Architect wykazać się wiedzą praktyczną potwierdzoną
dodatkowo certyfikatem, jest zdecy-
dowanie atutem w środowisku infor-
����������������������������������������� matycznym.
�������������� �������������� ��������������� ��������������
Jednocześnie z rozwojem popu-
��������������
������ ��������������� �������������� ������������������� ������������������� ������������������� larności Javy coraz więcej firm za-
������ ��������� ���������� ������������ ��������� częło się na niej koncentrować, co
������� ������� �������� �������
spowodowało duże zapotrzebowa-
nie na specjalistów w tej dziedzinie.
������������ ������������������������������������
Ten moment rozwoju samej techno-
��������� ����������������������������������� logii stał się kluczem do sukcesu cer-
tyfikacji, a jednocześnie zmotywował
��������� ��������� ���������
pracodawców do inwestycji w swo-
Rysunek 1. Ścieżka certy�kacyjna Java ich pracowników. Taka tendencja by-

62 03/2010
63
Felieton

ła widoczna przez kilka lat, jednak ostatnie czte- od lat wspomaga ścieżki certyfikacyjne pakietami dym rokiem popularność bardziej zaawansowa-
ry lata pokazują, że pracownicy coraz częściej sa- ePractice, które są zbiorem próbnych pytań egza- nych certyfikacji wzrasta, jednak wciąż najbar-
mi inwestują w swój rozwój i podejmują się cer- minacyjnych i elementem wspomagającym zdo- dziej wymagającym jest Sun Certified Java Ar-
tyfikacji na własny rachunek. Spowodowane jest bytą wiedzę. Pozwalają na zapoznanie się z samą chitect i to potwierdzają również badania prze-
to niewątpliwie ciągłą fluktuacją pracowników formą egzaminu czy stopniem trudności pytań. prowadzone na rynku belgijskim.
na rynku informatycznym i chęcią podnoszenia Dodatkowo od kilku lat na terenie Euro- W większości ankietowani przyznają, że war-
własnych kwalifikacji. py, w tym również w Polsce, prowadzimy Bo- to było podejść do egzaminu nie tylko dla same-
otcampy z technologii Java. Mają one na celu go „papierka”. Z drugiej jednak strony jednym
Faktyczna wartość przygotować uczestników do zaawansowanych z wniosków narzucających się po analizie an-
Obecnie certyfikacja z technologii Java jest wy- certyfikacji, tj. Sun Certified Java Architect. Se- kiety jest fakt, że w opinii uczestników Java Pro-
soko ceniona nie tylko przez programistów, de- sja taka trwa sześć dni i prowadzona jest przez grammer to zupełna podstawa Javy - sama Javy
weloperów czy architektów, ale również przez najlepszych w tej dziedzinie, sprawdzonych in- Standard Edition i nie wymaga specjalistycznej
pracodawców oraz samego Suna – twórcy tech- struktorów Suna. Uczestnicy takich warszta- wiedzy podpartej praktyką. Czy tak faktycznie
nologii. Dla Suna ważne jest, żeby technologia tów upewniają nas tylko, że zajęcia są potrzebne jest? SCJP to w ścieżce certyfikacyjnej pierwszy
rozwijała się, ważne jest promowanie jakości ko- i przede wszystkim wychodzą z nich z faktycz- krok do kolejnych zaawansowanych egzaminów
dowania w Javie. Z drugiej strony pracodawcom ną wiedzą, a nie tylko książkowym zarysem. wymagających dużo doświadczenia i znajomo-
zależy na zatrudnianiu certyfikowanych specja- Studenci dzielą się posiadaną wiedzą, dyskutu- ści tematu ponad samą Javę SE, w tym Mobile
listów choćby z czysto ekonomicznego punktu jąc o różnych przypadkach zaczerpniętych z ich oraz Enterprise Edition. Podejście do tego egza-
widzenia, co jednocześnie wpływa na wzrost praktyki zawodowej. minu nie wymaga wieloletniej praktyki w tema-
wartości profesjonalistów na rynku IT. W roku 2009 przeprowadziliśmy sesję certy- cie technologii Java, ale niewątpliwie posiadanie
Programowanie w języku Java jest bardzo fikacyjną z zakresu SCJP, która cieszyła się spo- tej certyfikacji jest atutem na rynku pracy.
powszechne na uczelniach wyższych, co czy- rym zainteresowaniem, a jej założeniem było Certyfikat często przybliża tematy, które są
ni technologię bardziej pożądaną i rozwojową. przybliżyć uczestników do samego egzaminu. nam znane, a jednak w codziennej pracy o nich
Nie zawsze jednak wiedza akademicka jest wy- Zajęcia prowadzone w formie dyskusji i oma- zapominamy czy zwyczajnie je pomijamy.
starczająca do podjęcia się certyfikacji szczegól- wiania problematycznych kwestii, jednocze-
nie tych bardziej zaawansowanych, chociażby śnie kontakt z wieloletnim instruktorem Sun Wartość certyfikacji na rynku pracy
tych wymagających znajomości architektury Ja- – a efekt – kilku kolejnych certyfikowanych Tak naprawdę odpowiedzią na powyższe stwier-
vy EE. Zdawanie egzaminów z Javy z zadowala- programistów! Pomysł na warsztat wypłynął dzenie jest przedstawiony wykres – a wyniki
jącym wynikiem wymaga wiedzy praktyczniej, z inicjatyw naszych klientów, ich potrzeb i zain- są bardzo zbliżone do tego, co obserwujemy na
a taką mogą się pochwalić osoby pracujące na ży- teresowania technologią. Okazuje się, że coraz rynku polskim. Około 87% ankietowanych po-
wym organizmie, jakim jest Java. Szkolenia, któ- chętniej specjaliści sięgają po takie formy nauki i twierdza wartość certyfikatów na rynku pracy.
re Sun przygotował również pod kątem ścieżek nie chodzi tu wyłącznie o szkolenia, ale bardziej Tylko 10% nie zgadza się z tym stwierdzeniem.
certyfikacyjnych, są często dla uczestników uzu- o krótkie, jednodniowe sesje. Na tym etapie pojawia się pytanie, na ile certy-
pełnieniem wiedzy nabytej na studiach czy rów- fikaty odzwierciedlają rzeczywistą wiedzę, a na
nież w pracy zawodowej. Jak postrzegają certyfikację sami ile są jedynie zbiorem teoretycznych zagadnień.
W ciągu ostatnich kilku lat cyklicznie wpro- użytkownicy? Okazuje się jednak, że takie wątpliwości doty-
wadzamy program darmowych powtórek egza- W roku 2009 Java Magazine i Sun Microsys- czą jedynie nielicznych uczestników, a znaczą-
minów (tzw. Second Shot) i bez wahania mogę tems w Belgii opublikowały wyniki ankiety ca większość mówi, że certyfikaty są potwier-
potwierdzić, że cieszy się on ogromnym zainte- przeprowadzonej wśród specjalistów z zakresu dzeniem wiedzy i umiejętności. Faktem jest, że
resowaniem na całym świecie. Po pierwszej edy- Javy. Grupą docelową byli deweloperzy z prak- posiadanie certyfikatu z Javy nie czyni dobrym
cji byliśmy zaskoczeni, jak marginalny procent tyką zawodową oraz zdaną certyfikacją. Ce- programistą, jednak jest wartością dodaną dla
uczestników musiał skorzystać z egzaminu po- lem przeprowadzonego badania było uzyska- każdego, kto podejdzie do egzaminu przygoto-
prawkowego w stosunku do liczby uczestni- nie informacji ,jak programy certyfikacyjne Su- wany i zda go z dobrym wynikiem.
ków, i narzuca się jeden wniosek, że osoby pod- na wpływają na rozwój osób podejmujących się Z szeregu ankiet przeprowadzonych na po-
chodzące do certyfikacji są świetnie przygotowa- tego wyzwania i czy faktycznie mają one wpływ trzeby Suna oraz z bezpośrednich opinii spe-
ne. Dzieje się tak dlatego, że w dzisiejszych cza- na karierę zawodową. W ankiecie wzięło udział cjalistów i ich managerów wynika jednoznacz-
sach nie mamy czasu na poprawki i dodatkowe około 300 osób, a najciekawsze fragmenty zosta- nie, że certyfikacje są na rynku bardzo warto-
przygotowywanie się do egzaminów. Ten przy- ły przedstawione poniżej. ściowym elementem. Są uzupełnieniem wiedzy
kład w dużej mierze świadczy również o warto- i umiejętności oraz wartością dodaną dla każde-
ści certyfikacji – są cenione i traktowane profe- Każdy może zdać egzamin go, kto ma choćby jeden z certyfikatów.
sjonalnie na ryku użytkowników Javy. Z opinii ankietowanych wynika, że około 240 Aktualnie certyfikacja postrzegana jest jako
osób potwierdziło duże znaczenie certyfikacji duża szansa na rozwój i wyzwanie nie tylko dla
Jak się przygotować? w ich karierze zawodowej. Zdecydowanie więk- programistów, deweloperów czy architektów,
Sposobów na dobre przygotowanie się do certy- sza część uczestników (80%) przyznała, że ma ale również pracodawców, którzy na rynku po-
fikacji jest wiele i każdy bazuje w tej dziedzinie certyfikację lub planuje podejście do egzaminu szukują specjalistów najwyższej klasy. Ma to zna-
na własnym doświadczeniu, może nawet z cza- w najbliższej przyszłości. W tym przypadku zna- czenia dla firm, ponieważ świadczy o pewnym
sów szkoły? Najczęściej wybieranym sposobem czącą popularnością cieszy się Sun Certified Java usystematyzowaniu i ugruntowaniu wiedzy
nauki jest douczanie się we własnym zakresie na Programmer jako podstawowy egzamin w ścież- przez członków zespołów Javowych.
podstawie sieci czy książek dostępnych na rynku. ce Javy. Kolejnym krokiem podejmowanym Niezbędne informacje o certyfikacjach znaj-
Ale czy to wystarczy? W niektórych przypadkach przez specjalistów jest Web Component Develo- dują się na stronie www.sun.com.pl/training
pewnie tak, zwłaszcza jeżeli wiedza teoretycz- per – w przypadku rynku polskiego zdecydowa-
na podparta jest praktyką zawodową, ale dlacze- nie częściej podejmowanym jest Java Developer OLIWIA ŁĄCZYŃSKA
go nie spróbować sprawdzonych rozwiązań? Sun i to ten egzamin zajmuje drugie miejsce. Z każ- Business Development Manager Sun Learning Services

64 03/2010
65
Praca w zespole

Audyt techniczny
Czyli jak sprawdzić jakość prac dostawcy IT?

Instytucja zlecająca realizację prac IT z definicji pragnie, by jakość tych


prac była jak najlepsza, a wymagania dotyczące produkcji systemu oraz
samego produktu spełnione na odpowiednim poziomie. Zapewnienia i
deklaracje dostawcy to jedno – a uzyskanie konkretnych, obiektywnych
dowodów spełnienia wymagań to co innego.
Audyt nie jest oceną ogólną – wykonywany
Dowiesz się: Powinieneś wiedzieć: jest na podstawie określonych danych wejścio-
• Na czym polega audyt techniczny; • Podstawowa wiedza z zakresu zarządzania wych, wymagań, standardów etc. Przygotowa-
• Jakich informacji dostarcza klientowi. projektem. nie audytu polega na opracowaniu testów, list
• Podstawowa wiedza z zakresu zarządzania kontrolnych czy metod obserwacji, które obej-
jakością i realizacji audytów. mują wszystkie wymagane aspekty kontroli –
np. jeśli audyt dotyczy dokumentacji, audytor
musi sprawdzić:
• stosowanie ustalonych procedur zarząd-
czych (np. procedur zarządzania zmia- • czy dokumentacja utrzymywana przez do-
Poziom nami); stawcę odpowiada zapisom umowy;
trudności • stosowanie wytycznych określonych • czy dokumentacja przechowywana jest
standardów IT (np. standardów dotyczą- w sposób odpowiedni do udokumentowa-
cych dokumentacji, testowania); nych wymagań;
• wykorzystywanie odpowiednich narzę- • czy narzędzia wykorzystywane do two-

J
ak jednak klient może sprawdzić, czy pra- dzi w pracach projektowych; rzenia i zarządzania dokumentacją to
ce projektowe i ich poszczególne produkty • kod źródłowy zgodny ze standardami (np. te, które były deklarowane w umowie/
odpowiadają jego oczekiwaniom i wyma- zgodny z wytycznymi kodowania w Java). uzgodnieniach;
ganiom? Nierzadko instytucja zlecająca realiza- • czy format dokumentów jest zgodny z za-
cję usług IT nie posiada odpowiednich zasobów, W jakim celu wykonuje się audyt? Powody łożeniami;
by móc zweryfikować jakość np. procesu wy- mogą być następujące: • czy jakość rozumiana jako kompletność,
twórczego czy zgodności architektury z ustale- jednoznaczność, spójność, przejrzystość
niami kontraktowymi. Może nie mieć persone- • by upewnić się, że rzeczywiste prace re- jest zachowana;
lu o odpowiednich kompetencjach lub możli- alizowane w ramach projektu odpo- • czy obieg dokumentacji jest spójny z wy-
wości technicznych sprawdzenia pewnych kwe- wiadają zadeklarowanym w kontrakcie, maganiami etc.
stii – może też pragnąć (z różnych względów, a ich jakość spełnia wymagania klienta;
w tym tzw. politycznych), by kontrola taka wy- • by sprawdzić, czy jakość poszczególnych Pytania te muszą zostać zadane – niekoniecz-
konywana była przez zespół całkowicie nieza- produktów odpowiada zapewnieniom nie dosłownie: większość tzw. dowodów zbie-
leżny i obiektywny. Rozwiązaniem tego proble- dostawcy i oczekiwaniom klienta; ra się podczas wywiadów i obserwacji – a od-
mu jest audyt techniczny. Umożliwi on nieza- • by ujawnić problemy występujące w róż- powiedzi zanotowane celem dalszej analizy.
leżną ocenę procesów, produktów i innych ob- nych obszarach projektu i móc je wyeli- Nieraz obserwacja dostarcza więcej informa-
szarów projektu realizowanego przez dostaw- minować. cji, niż słowa – ponieważ umożliwia obserwa-
cę IT – weryfikację zgodności z wymagania-
mi, identyfikację błędów i usterek oraz dostar- Audyt
czy rekomendacji czy zaleceń, które – wdrożo- Audyt – ocena danej osoby, organizacji, systemu, procesu, projektu lub produktu. Audyt jest
ne przez dostawcę – ulepszą jakość prac. przeprowadzany w celu upewnienia się co do prawdziwości i rzetelności informacji, a także
oceny systemu kontroli wewnętrznej. Celem audytu jest wyrażenie opinii na temat osoby/
organizacji/systemu itd. w ramach oceny w oparciu o przeprowadzone testy.
Audyt – ale co to jest? Audyt polega na ocenie przez kompetentny i niezależny zespół audytujący, czy dany przedmiot
Zgodnie z definicją audyt jest oceną i weryfika- audytu spełnia wymagania. Zespół audytujący składa się z jednego lub więcej audytorów.
cją pewnych hipotez. W kontekście projektu IT Celem audytu może być wery�kacja, czy cel wyznaczony przez organizację audytowaną został
hipotezą taką może być: osiągnięty lub czy jej działania są zgodne z zaakceptowanymi standardami, statusem czy prak-
tykami. Audyt ocenia także procedury kontrolne celem stwierdzenia, czy przedmiot audytu tak-
• zarządzanie projektem zgodnie z określo- że w przyszłości będzie odpowiadał uzgodnionym do stosowania wymaganiom. Oprócz oceny
wskazuje także zalecenia zmian w procedurach, w tym sprawdzających oraz w politykach.
nym standardem;

66 03/2010
Audyt techniczny

cję rzeczywistych zachowań, wyników i prak- • Określenie celu i zakresu audytu. Zlecający audyt dokonuje wyboru jednostki au-
tyk, a nie teorii czy pobożnych życzeń. dytującej. Audytorzy powinni pochodzić z fir-
Postawione powyżej przykładowe pytania Czynność ta należy do organizacji zlecającej my specjalizującej się w danym typie audytu –
kontrolne nie wydają się szczególnie skompli- audyt i polega na określeniu, co ma być przed- lub posiadający odpowiednie kompetencje, by
kowane. Czy zatem rzeczywiście konieczne jest miotem oceny oraz na podstawie jakich kryte- taką ocenę wykonać. Zdarza się, że audyt nie jest
zlecanie audytu instytucji zewnętrznej? Czy or- riów będzie ona wykonywana. Wskazane jest realizowany przez firmę konsultingową, zajmu-
ganizacja klienta nie jest w stanie samodzielnie też sprecyzowanie produktów prac (np. ra- jącą się tylko i wyłącznie wykonywaniem audy-
wykonać oceny prac dostawcy? portów). tów. W przypadku np. opisywanego tu audytu
Odpowiedź brzmi – może i nie może. De- technicznego projektu IT, klient może zlecić au-
cyzja zależy w dużym stopniu od celu posta- • Wybór jednostki audytującej. dyt innemu dostawcy IT – przy założeniu, że:
wionego przed audytem, zależności pomię-
dzy klientem a dostawcą, zasad obowiązują-
cych w instytucji klienta. W przypadku gdy Audytów jest wiele...
klient ma uzasadnione wątpliwości co do ja- Oto wybrane rodzaje audytów związane z branżą IT.
kości prac dostawcy i przestrzegania przez
• Audyt bezpieczeństwa danych (Technicznej infrastruktury) – ma za zadanie zde�niowanie
niego ustaleń umowy, wskazane jest zlece- istniejących zagrożeń i słabych punktów systemu zarządzania bezpieczeństwem infor-
nie audytu zewnętrznego. Dlaczego? Ponie- macji �rmy oraz oszacowanie ryzyka operacyjnego, na jakie narażona jest organizacja
waż wyniki takiego audytu będą obiektyw- klienta. W wyniku audytu powinny zostać też przedstawione rekomendacje w zakresie
ne i klient uniknie posądzeń o próbę mani- bezpieczeństwa informacji oraz propozycje możliwych rozwiązań, które mogą się przy-
pulacji. czynić do podniesienia bezpieczeństwa informacji �rmy oraz do zagwarantowania płyn-
ności procesów biznesowych. Podstawą audytu jest zwykle norma PN-I-07799-2:2004.
Wspomnieliśmy o audycie zewnętrznym • Audyt informatyczny – proces zbierania i oceniania dowodów w celu określenia, czy sys-
– jest i wewnętrzny, czyli audyt przeprowa- tem informatyczny i związane z nim zasoby właściwie chronią majątek, utrzymują integral-
dzany przez ludzi z organizacji klienta. Au- ność danych i dostarczają odpowiednich i rzetelnych informacji, osiągają efektywnie cele or-
dyt taki ma sens, jeżeli zespół audytujący po- ganizacji, oszczędnie wykorzystują zasoby i stosują mechanizmy kontroli wewnętrznej, tak
siada kwalifikacje odpowiednie do postawio- aby dostarczyć rozsądnego zapewnienia, że osiągane są cele operacyjne i kontrolne, oraz że
chroni się przed niepożądanymi zdarzeniami lub są one na czas wykrywane, a ich skutki na
nego celu i jest w stanie rzetelnie ocenić dany
czas korygowane. Normami często stosowanymi w audytach informatycznych są:
przedmiot. Często audyt wewnętrzny jest je- • ISO 9001;
dynie pierwszą fazą całościowej procedury au- • ITIL;
dytu, mającą na celu zidentyfikowanie podsta- • COBIT.
wowych zagrożeń, braków i usterek występu- Normą wyspecjalizowaną w zakresie bezpieczeństwa informatycznego, według której czę-
jących w określonych procesach, infrastruk- sto prowadzi się audyty, jest ISO/IEC 27001. Towarzyszącą normą służącą do budowania sys-
temów zarządzania bezpieczeństwem informacji jest ISO/IEC 27002.
turze, produktach etc. Zazwyczaj zakończe-
nie procedury audytu wewnętrznego wiąże się • Audyt techniczny – wery�kacja realizacji projektu zgodnie z umową (warunkami wskaza-
z podjęciem decyzji o zamówieniu całościowe- nymi przez zlecających projekt lub innych udziałowców); może być wykonywany w każ-
go audytu informatycznego u zewnętrznej wy- dym czasie podczas trwania projektu.
specjalizowanej firmy. • Audyt technologiczny – ocena rzeczywistych możliwości wykorzystania technologii w �r-
mie. Audyt technologiczny to rodzaj kontroli planów wdrożeniowych, kontroli niezależ-
Audyt zewnętrzny przeprowadzany jest nej, udokumentowanej, opartej o określone kryteria. Audyt ten wiąże się z pytaniami:
znacznie sprawniej niż wewnętrzny, jako że or- • jakie są inne technologie w danej dziedzinie?;
ganizacje zajmujące się tym zawodowo mają • jaki jest poziom rozwoju ocenianych technologii?;
doświadczenie i metodologię pozwalającą na • jaki stopień innowacyjności posiada technologia?.
znaczne skrócenie procedury audytu. Bardzo Audyt technologiczny może być: opiniujący, oceniający lub kontrolny.
istotną cechą audytu zewnętrznego jest brak
• Audyt oprogramowania – polega na analizie stanu oprogramowania zainstalowanego
ryzyka stronniczości – gdyż dokonywany jest w �rmie, uporządkowaniu i uzupełnieniu brakujących licencji oraz wdrożeniu procedur
przez niezależną instytucję – dzięki czemu wy- usprawniających zarządzanie oprogramowaniem.
niki oceny lepiej i pełniej oddają stan rzeczywi-
sty. Rekomendacje audytorów zewnętrznych są
też z reguły trafniejsze (co wynika głównie z do-
świadczenia) i umożliwiają realne usprawnie- Na czym się opierać...
nie wadliwych obszarów. • COBIT (Control Objectives for Information and related Technology) – standard opracowa-
Rodzaje audytów to nie tylko wewnętrzny ny przez ISACA oraz IT Governance Institute, zbiór dobrych praktyk z zakresu IT Governan-
i zewnętrzny – audytów w IT jest wiele (ram- ce, które mogą być wykorzystywane w szczególności przez audytorów systemów infor-
ka), w zależności od postawionego celu i tego, matycznych. COBIT 4.1 opisuje 34 wysokopoziomowe procesy, które obejmują 210 celów
co zlecający ocenę chce osiągnąć. kontrolnych pogrupowanych w czterech domenach:
• planowanie i organizacja (Planning and Organization);
Wiemy już, czym jest audyt, przejdźmy teraz • nabywanie i wdrażanie (Acquisition and Implementation);
do tego, jak go przygotować i wykonać. • dostarczanie i wsparcie (Delivery and Support);
• monitorowanie i ocena (Monitoring and Evaluation).
Procedura audytu • ITIL (Information Technology Infrastructure Library) –- kodeks postępowania dla działów infor-
matyki. Zbiór zaleceń, jak efektywnie i skutecznie oferować usługi informatyczne. Podstawą
koncepcji ITIL jest zde�niowanie procesów, które powinny funkcjonować w ramach organi-
Przygotowanie i zakres audytu zacji świadczącej usługi IT. ITIL pozwala na modelowanie procesów zarówno w organizacjach
Audyt, podobnie jak każde przedsięwzięcie, komercyjnych (np. �rmy komputerowe, programistyczne), jak i niekomercyjnych (agencje rzą-
musi zostać odpowiednio zaplanowany i przy- dowe itp.), niezależnie od wielkości �rmy, typu organizacji czy też posiadanych narzędzi. Każ-
gotowany. Etapy realizacji audytu można okre- dy proces powinien posiadać zde�niowane role i odpowiedzialności.
ślić poprzez następujące punkty:

www.sdjournal.org 67
Praca w zespole

• dostawca ów nie jest powiązany z do- nie ma przymusu angażowania wy- cele audytu. Zespół audytujący musi skła-
stawcą poddawanym audytowi; specjalizowanej firmy audytującej. dać się z ludzi będących w stanie ocenić da-
• pracownicy firmy, która będzie reali- • Dobór zespołu audytującego ny przedmiot – dlatego też zwykle audyt re-
zować audyt, posiadają kwalifikacje i alizowany jest przez kilku audytorów, przy
niezbędne umiejętności w zakresie Na audytorach spoczywa odpowiedzialność czym każdy zajmuje się inną specjalnością.
prowadzenia audytu; za proces obiektywny, niezależny i wiary-
• sam dostawca dysponuje zasobami godny. Zgromadzenie dowodów obiektyw- • Analiza informacji wejściowych
i mechanizmami umożliwiającymi nych, pomoc w wykryciu przyczyn źródło-
poprawne wykonanie oceny; wych, informacja zwrotna, sugestie doty- Polega na zebraniu przez zespół audytujący
• klientowi nie zależy na uzyskaniu czące doskonalenia procesów, zasugerowa- danych stanowiących podstawę do wykony-
certyfikatu z wykonanego audytu i nie działań korygujących to podstawowe wania oceny (kryteriów audytu) i opracowa-
niu ich w takiej postaci, by mogły służyć ja-
Standardy audytu systemów informatycznych (IS Auditing Standards) ko mechanizmy przeprowadzania audytu.
Czyli – jeżeli audyt dotyczy oceny procesu
• 010 Prawa i powinności audytu testowania wewnętrznego (funkcjonalnego)
Obowiązki, uprawnienia i odpowiedzialność obszaru działania realizującego funkcję audytu dostawcy, danymi wejściowymi będą np.:
systemów informatycznych mają być odpowiednio udokumentowane w dokumencie regu-
• plan projektu – z uwzględnieniem
lującym prawa i powinności audytu lub w umowie na jego przeprowadzenie.
czasu przeznaczonego na testy, by
• 020 Niezależność skonfrontować go następnie z rze-
We wszystkich sprawach związanych z audytowaniem audytor systemów informatycznych musi czywistym czasem trwania testów
być niezależny od poddawanych audytowi, zarówno co do stanowiska, jak i postępowania. oraz zapisami planu testów;
• 020.020 Powiązania organizacyjne
• plan testów (wraz z wybranym po-
Funkcja audytu systemów informatycznych musi być wystarczająco niezależna od audyto- dejściem do testów np. black box,
wanego obszaru, aby umożliwić obiektywne prowadzenie audytu. podejście oparte na wymaganiach;
harmonogramem testów, składem
• 030 Standardy i etyka zawodowa zespołu testującego, kryteriami
Audytor systemów informatycznych jest zobowiązany do stosowania się do Kodeksu Etyki
wejścia/wyjścia testów);
Zawodowej Stowarzyszenia do spraw audytu i kontroli systemów informatycznych (ISACA –
Information Systems Audit and Control Association). • projekt testów (czyli zbiór przypad-
ków i scenariuszy testowych – ana-
• 030.020 Należyta staranność zawodowa lizowany celem identyfikacji pokry-
Wobec wszelkich aspektów pracy Audytora Systemów Informatycznych obowiązuje należy- cia funkcjonalności testami);
ta zawodowa staranność i przestrzeganie odpowiednich standardów audytu.
• wykaz narzędzi stosowanych do za-
• 040 Kompetencje rządzania testami i wspierania rapor-
Audytor systemów informatycznych ma być kompetentny w zagadnieniach technicznych, towania (by określić, czy narzędzia
posiadając umiejętności i wiedzę niezbędną do wykonywania pracy audytorskiej. owe są rzeczywiście wykorzystywane
w procesie testowym i w jakim stop-
• 040.020 Ustawiczne szkolenie zawodowe
niu);
Audytor systemów informatycznych ma utrzymywać kompetencje dotyczące zagadnień
technicznych poprzez właściwe i ustawiczne szkolenie zawodowe. • dokumentacja procedur – np. obsłu-
gi zgłoszeń błędów, żądań zmian etc.
• 050 Planowanie
Audytor Systemów Informatycznych powinien planować prace związane z audytem sys- Informacje zawarte w danych wejściowych
temów informatycznych pod kątem realizacji celów audytu oraz zgodnie z odpowiednimi
należy przetworzyć celem ustalenia punk-
standardami przeprowadzania audytów.
tów kontroli (tzn. istotnych elementów pro-
• 060 Wykonywanie prac audytowych cesu, które będą poddawane audytowi), któ-
re w następnej kolejności umożliwią opraco-
Personel zajmujący się audytem systemów informatycznych ma być odpowiednio nadzorowany, aby wanie formularzy, list kontrolnych przezna-
zapewnić, że cele audytu są spełnione oraz że są spełnione stosowne, zawodowe standardy audytu.
czonych do dalszego wykorzystania już pod-
• 060.020 Dowody czas przeprowadzania audytu.
Zadaniem Audytora Systemów Informatycznych podczas przeprowadzania audytu jest zgro-
madzenie wystarczających, wiarygodnych, odpowiednich (relewantnych) i użytecznych do- • Opracowanie harmonogramu audytu
wodów, tak by efektywnie zrealizować zadania audytu. Wyniki audytu oraz wnioski powinny
być poparte odpowiednią analizą i interpretacją tychże dowodów.
Audyt nie może odbywać się ad hoc, bez ła-
• 070 Raportowanie du i składu, audytorzy nie mogą biegać bez-
Zadaniem Audytora Systemów Informatycznych jest dostarczenie określonym odbiorcom ładnie po całej placówce, odpytując raz jedną
odpowiednio sformowanego raportu dotyczącego wykonanych prac audytowych. Raport z osobę, raz drugą. Plan przeprowadzania po-
audytu ma przedstawiać obszar, cele, okres oraz rodzaj i zakres wykonanych prac audyto- szczególnych działań audytowych powinien
wych. Raport ma wskazywać organizację, planowanych odbiorców raportu oraz wszelkie za-
być jasno określony i zakomunikowany au-
strzeżenia co do jego obiegu. Raport ma przedstawiać wyniki, wnioski i rekomendacje oraz
wszelkie zastrzeżenia lub uwarunkowania audytora wobec audytu. dytowanym przed rozpoczęciem oceny.
Harmonogram uwzględnia wykonanie
• 080 Dalszy tok działań wszystkich zaplanowanych działań audytowych,
Audytor systemów informatycznych ma domagać się i oceniać stosowne informacje o wcześniej- przez wszystkie osoby wykonujące ocenę i dla
szych wynikach, wnioskach i rekomendacjach, aby określić, czy zostały podjęte na czas właściwe
wszystkich obszarów/przedmiotów oceny. Każ-
działania.
dy dzień audytu powinien rozpoczynać się spo-

68 03/2010
Audyt techniczny

tkaniem otwierającym, które angażuje uczestni-


ków audytu (zarówno ze strony audytującego, Przykład – określenie celu i zakresu audytu dotyczącego procesu
audytowanego, jak i klienta) i polega głównie na wytwórczego dostawcy
przedstawieniu planu działań na dany dzień.
Podobnie – każdy dzień audytu kończy się Cel:
spotkaniem zamykającym, na którym przed- Ocena zgodności procesu wytwórczego z ustaleniami umowy i deklarowanym w DIP podej-
ściem do zarządzania projektem.
stawiane są wyniki dotychczasowej oceny,
wynikłe problemy, uwagi, spostrzeżenia. Zakres prac:

• Przygotowanie list kontrolnych • identy�kacja etapów procesu wytwórczego;


• identy�kacja mechanizmów kontroli jakości w poszczególnych etapach procesu wy-
twórczego;
Na podstawie danych wejściowych – do-
• wery�kacja kompetencji osób realizujących prace rozwojowe;
kumentacji, informacji ustnych – audytor • wery�kacja podejścia do planowania prac przez dostawcę;
opracowuje listy kontrolne i formularze. Po- • analiza procesu dokumentacji realizacji prac przez dostawcę. Sposób dokumentowania
winny one zawierać co najmniej: prac i zarządzanie dokumentacją;
• pytanie kontrolne; • określenie wymagań jakościowych i sposoby wery�kowania ich realizacji;
• referencję do dokumentu związanego/ • analiza zagrożeń i potencjalnych ataków oraz uwzględnienie funkcjonalności zapewnia-
jących ochronę przed zidenty�kowanymi zagrożeniami. Zapewnienie bezpieczeństwa
punktu normy, który jest weryfikowa- w ramach implementacji funkcjonalności;
ny za pomocą danego pytania; • analiza procesu testowania aplikacji;
• pole do odnotowania uwag i spo- • identy�kacja zabezpieczenia kodu przed utratą jego poufności;
strzeżeń. • identy�kacja wymagań związanych z dostarczeniem produktu odbiorcy i utrzymaniem
produktu;
• wery�kacja planu reagowania na zgłoszone problemy z funkcjonowaniem oprogramo-
Przykładowe pytania kontrolne (dotyczy au-
wania.
dytu procesu testowania):
• jakie etapy testowania wykonuje się Oczekiwane wyniki prac:
w ramach projektu;
• na czym oparte są scenariusze i przy- • stwierdzone nieprawidłowości wraz ze wskazaniem ich potencjalnego wpływu na jakość
i bezpieczeństwo oprogramowania;
padki testowe;
• rekomendowane działania korekcyjne wraz z uzasadnieniem i wskazaniem priorytetu.
• w jaki sposób zapewnione jest wymaga-
ne pokrycie funkcjonalności testami;
• w jaki sposób wykonywane są testy
i raportowane ich wyniki. Rola audytora wiodącego
Zadaniem audytora wiodącego jest opracowanie planu audytu. Plan ten powinien
Jak widać, pytania kontrolne są otwarte – uwzględniać informacje dotyczące celu audytu, dokumentów odniesienia, zakresu au-
czyli umożliwiają audytowanemu udziele- dytu, ram czasowych (przy czym audyt nie powinien wybiegać poza godziny pracy au-
dytowanych).
nie swobodnej odpowiedzi, bez ograniczania
Audytor wiodący dokonuje podziału pracy pomiędzy członków zespołu. Wszyscy au-
możliwości wypowiedzi i narzucania czy su- dytorzy przed przystąpieniem do audytu są zobowiązani zapoznać się z dokumentacją
gerowania odpowiedzi właściwej. Pytanie ty- dotyczącą obszarów poddawanych ocenie oraz opracować niezbędne formularze i listy
pu: czy wykonujecie testy zgodnie z planem te- kontrolne.
stów nie jest pytaniem właściwym, jako że

Rysunek 1. Plan audytu

www.sdjournal.org 69
Praca w zespole

Tabela 1. Harmonogram audytu – dzień 1


Temat/ Zakres audytu Kryterium Przed- Audytorzy Godzina
obszar odniesienia stawiciel od
ze strony do
klienta
Spotkanie Przedstawienie planu audytu, opis wykonywanych działań audy- Plan audytu Odpowie- Zespół audy- 09:00 – 09:30
otwiera- towych. dzialny za towy
jące realizację
audytu
Analiza ar- Analiza adekwatności zastosowanej architektury do celu stawiane- Dokumentacja Audytor ds. 09:45 – 10:15
chitektu- go systemowi. architektury architektury
ry rozwią-
Analiza podziału przetwarzania informacji pomiędzy poszczególnymi Dokumentacja Audytor ds. 10:15 – 11:00
zania
aplikacjami. Wery�kacja mechanizmów wymiany informacji pomię- architektury architektury
dzy poszczególnymi aplikacjami i zabezpieczenia danych w trakcie Specy�kacja in-
transferu Wery�kacja mechanizmów wymiany informacji pomiędzy tegracji
danym systemem a innymi systemami informatycznymi.
Wery�kacja optymalności zapisu danych w systemie. Audytor ds. 11:00 – 12:00
architektury

Wery�kacja efektywności zarządzania systemem w kontekście je- Audytor ds. 12:15 – 13:00
go architektury. architektury
Przerwa 13:00 – 14:00
Wery�kacja zapewnienia spójności przetwarzania danych w ra- Audytor ds. 14:00 – 14:30
mach zastosowanej architektury. architektury
Identy�kacja zagrożeń związanych z poszczególnymi komponen- Audytor ds. 14:30 – 15:00
tami rozwiązania i z powiązaniami pomiędzy tymi komponentami. architektury
Wery�kacja mechanizmów logowania zdarzeń. Audytor ds. 15:00 – 15:25
architektury
Zarządzanie zabezpieczeniami (w tym zarządzanie mechanizmami Audytor ds. 15:25 – 16:00
kryptogra�cznymi). architektury
Wery�kacja komponentów sprzętowych wchodzących w skład sys- Audytor ds. 16:00 – 16:30
temu i ich kon�guracja. architektury
Proces wy- Identy�kacja etapów procesu wytwórczego Plan projektu Audytor ds. 09:45 – 10:15
twórczy DIP zarządzania
dostawcy procesem
Identy�kacja mechanizmów kontroli jakości w poszczególnych Plan projektu Audytor ds. 10:15 – 11:00
etapach procesu wytwórczego Plan zarządza- zarządzania
nia jakością procesem
Wery�kacja podejścia do planowania prac przez dostawcę Plan projektu Audytor ds. 11:00 – 11:45
DIP zarządzania
procesem
Analiza procesu dokumentacji realizacji prac przez dostawcę Plan projektu Audytor ds. 11:45– 12:30
DIP zarządzania
procesem
Wery�kacja kompetencji osób realizujących prace rozwojowe Plan projektu Audytor ds. 12:30 – 13:00
Plan zarządza- zarządzania
nia zasobami procesem
Przerwa 13:00 – 14:00 Project Manager
Test Manager
Analityk ze stro-
ny dostawcy
Określenie wymagań jakościowych i sposoby wery�kowania ich re- Plan zarządza- Audytor ds. 14:00 – 15:00
alizacji nia jakością zarządzania
procesem
Analiza procesu testowania aplikacji Plan projektu Audytor ds. 15:00 -
Plan testów zarządzania 16:00
procesem
Wery�kacja planu reagowania na zgłoszone problemy z funkcjo- Plan zarządza- Audytor ds. 16:00 – 16:30
nowaniem oprogramowania nia jakością zarządzania
procesem
Spotka- Potwierdzenie wykonanego planu audytu, opis wykonywanych Audytor ds. 16:30 – 17:00
nie zamy- działań audytowych. architektury
kające ko- Ustalenie spostrzeżeń z przeprowadzonego audytu. Opracowanie Audytor ds.
niec audy- rekomendacji. zarządzania
tu dnia 1 procesem

70 03/2010
Audyt techniczny

sugeruje odpowiedź. Audytor powinien sa- przyjętym dla oceny. Przykładowo, jeśli kry- nie. Usunięcie niezgodności jest komuniko-
modzielnie ocenić zgodność stanu rzeczy na terium oceny dla testów funkcjonalnych jest wane klientowi i może być potwierdzone ko-
podstawie udzielonych, pośrednich odpowie- używanie narzędzia JIRA do zarządzania błę- lejnym audytem (np. jeżeli wykryto znaczną
dzi i własnych obserwacji. Nie wystarcza więc dami, a w wyniku wywiadu okazało się, iż sto- liczbę niezgodności krytycznych).
tylko pytać – ustne deklaracje należy zwery- sowane jest inne narzędzie, należy wykazać to Analiza wyników audytu to nie tylko wy-
fikować np. w przypadku pytania: jakie na- jako niezgodność i umieścić w raporcie koń- kazanie zgodności i niezgodności – to rów-
rzędzia służą do zarządzania testami, należy cowym z audytu. Zalecenia dotyczące usta- nież określenie zaleceń i rekomendacji służą-
sprawdzić, czy rzeczywiście takie narzędzie leń z audytu opisane są szczegółowo w punk- cych udoskonaleniu wadliwych procesów czy
jest wykorzystywane. Jak? Po prostu prosząc cie 6.5.5 normy ISO/DIS 19011 Opracowanie produktów. Rekomendacje nie są przymu-
audytowanego o pokazanie owego narzędzia ustaleń z audytu. Ustalenia z audytu dotyczą- sem, a ich wdrożenie obligatoryjne dla orga-
na stacji roboczej i wglądzie w jego zawartość cego zgodności i niezgodności oraz wspierają- nizacji zlecającej audyt – mogą jednak w zna-
(repozytorium testów). ce je dowody powinny być zapisywane; każde czącym stopniu usprawnić działanie instytu-
spostrzeżenie, informacje zdobyte w oparciu cji czy wybranego obszaru.
• Przeprowadzenie audytu i zbieranie danych o obserwację czy uzyskane w rozmowie z au-
dytowanym powinny być zanotowane. Powód • Spotkanie zamykające i raport dla klienta
Przeprowadzenie audytu musi opierać się na jest prosty – pamięć ludzka jest zawodna, i na-
konkretnych podstawach, by uzyskane od- wet jeżeli audytor doskonale pamięta przebieg Spotkanie zamykające to ostatni punkt au-
powiedzi pozwalały jednoznacznie i rzetel- wywiadu dziś, może nie być w stanie przypo- dytu. Może odbyć się dopiero po wykonaniu
nie ocenić dany problem. Audytor przepro- mnieć go sobie jutro. A informacje z wywia- wszystkich zaplanowanych działań audyto-
wadza wywiady i dokonuje obserwacji, po- dów czy obserwacji są podstawą do opracowa- wych, przeanalizowaniu wyników i opraco-
sługując się opracowanymi przez siebie for- nia raportu końcowego z wyników. waniu raportu końcowego.
mularzami i listami kontrolnymi. Doku- W przypadku wykrytych niezgodności au- Niezgodności wykryte podczas audytu są
menty te zawierają pytania kontrolne doty- dytor powinien określić ich priorytet, czy- komunikowane osobom odpowiedzialnym
czące każdego elementu istotnego dla doko- li stopień, w jakim wpływają na jakość da- za audytowany obszar oraz zapisywane przez
nania oceny – audytor przeprowadza wy- nych prac. Priorytety mogą być określane na- audytora wiodącego (na podstawie informacji
wiad, opierając się na owych pytaniach, w ra- stępująco: uzyskanych od pozostałych audytorów) w od-
zie konieczności już w trakcie dyskusji z au- powiednim dokumencie np. Protokole nie-
dytowanym, dodając nowe pytania i uwa- • niski – niezgodność mająca znikomy zgodności.
gi oraz odnotowując uzyskane odpowiedzi. wpływ na jakość procesu/produktu; Spotkanie zamykające prowadzone jest przez
Wypełnione listy kontrolne służą następnie • normalny – niezgodność wpływająca ne- audytora wiodącego. Podczas tego spotkania
do opracowania wyników – czyli stwierdze- gatywnie na jakość procesu/produktu, omawiane są ustalenia, wnioski z audytu oraz
nia, które z elementów przedmiotu audytu lecz nie krytyczna; mocne i słabe strony przedmiotu oceny.
są zgodne z założeniami, a gdzie wystąpiły • krytyczny – krytyczne uchybienie w zało- Problemem, który może wystąpić w trakcie
niezgodności. żeniach polityki jakości, rażący błąd etc. spotkania zamykającego, jest tzw. czynnik ludz-
ki i reakcje na krytykę. Podczas wywiadów i ob-
• Analiza i opracowanie wyników Niezgodności o priorytecie niskim nieko- serwacji audytorzy są neutralni, skupiają się na
niecznie muszą być usuwane, lub przynajm- zadawaniu pytań i wysłuchiwaniu odpowie-
Zebrane w trakcie audytu informacje nale- niej nie w pierwszej kolejności. Niezgodno- dzi bez oceniania czy wyrażania własnej opinii
ży poddać analizie celem określenia, czy stan ści krytyczne powinny być wyeliminowane bądź krytycznych uwag – spotkanie zamykają-
rzeczy odpowiada wymaganiom i założeniom jak najszybciej – w ściśle określonym termi- ce zmienia ten stan rzeczy: polega na jasnym,

Tabela 2. Lista kontrolna dla procesu testowania


L.p. Pytanie Referencja Komentarz
1 Kto zarządza procesem testowania? Plan testów 4. Odpowiedzialności i Odp. Test manager - Uwaga – zgodne
uprawnienia
2 Kto jest odpowiedzialny za przygotowa- Plan testów 4. Odpowiedzialności i Odp. Odpowiedzialność - Test manager
nie projektu testów? uprawnienia Wykonanie – zespół QA
Uwaga – zgodne
3 Na jakiej podstawie opracowuje się sce- Plan testów 6. Podstawy testów Odp. Specy�kacja projektowa.
nariusze i przypadki testowe? Uwaga – zgodne lecz brak odniesienia do danych testowych
(rekomendacja)
4 Gdzie ewidencjonowane są scenariusze Plan testów 8. Narzędzia Odp. TestLink
i przypadki testowe? Uwaga – zgodne
5 Kto odpowiada za aktualizację i utrzy- Plan testów 4. Odpowiedzialności i Odp. Tester odpowiedzialny za utworzenie
mywanie projektu testów? uprawnienia Uwaga – zgodne
6 Jak wykonywane są testy? Plan testów 5. Podejście do testów Odp. Technika black box, na postawie scenariuszy
DIP Uwaga – zgodne
7 W jaki sposób raportowane są błędy w Plan testów 9. Raportowanie Odp. Po zakończeniu cyklu testów
aplikacji? Uwaga – niezgodne z Plan testów 9. Raportowanie. W planie
jest: „niezwłocznie po znalezieniu błędu”
8 Gdzie raportowane są błędy? Plan testów 8. Narzędzia Odp. JIRA
Plan testów 9. Raportowanie Uwaga – zgodne.
Brak integracji z TestLink (rekomendacja).

www.sdjournal.org 71
Praca w zespole

dosłownym i popartym dowodami wykazaniu nie kontrola, a proces z założenia mający na • Weryfikacja skuteczności działań kory-
braków, niezgodności i usterek. Nie wszyscy po- celu doskonalenie organizacji. Tu nie szu- gujących
trafią przyjąć krytykę bez emocji i prób udo- ka się odpowiedzialnych, winnych i nie oce-
wadniania swoich racji. Zdarza się, iż audytowa- nia – celem jest wskazanie miejsc, które wy- Spotkanie zamykające audyt skutkowało usta-
ny reaguje na wytknięte błędy agresją – dlatego magają ulepszenia i dostarczenie obiektyw- leniem pewnych dalszych działań, które pole-
szczególnie ważne jest zebranie i przedstawie- nej informacji zwrotnej o skali i rodzaju nie- gają na usunięciu zaistniałych niezgodności.
nie niepodważalnych dowodów, faktów wystą- zgodności. Za wykonanie tych działań w ściśle określo-
pienia niezgodności. Audytor nie stawia wnio- Spotkanie zamykające to również ustalenie nym terminie odpowiedzialni są wyznacze-
sków na podstawie swoich przeczuć czy insynu- koniecznych działań korygujących i określe- ni pracownicy (w tym przypadku dostawcy
acji – lecz na postawie faktów, których audyto- nie terminów ich wykonania. Niezgodności IT). Wyniki prac korygujących powinny być
wany nie podważy. zidentyfikowane jako krytyczne lub ważne dla zakomunikowane zespołowi audytującemu
Audytor nie może obawiać się przekaza- jakości procesu powinny zostać usunięte i pod- i klientowi – a ich poprawność i kompletność
nia swojej informacji zwrotnej – audyt to dane kontroli zespołu audytowego. zweryfikowana.
Audyt może być uważany za zakończony
po usunięciu i potwierdzeniu poprawności
Trochę psychologii... wszystkich niezgodności, które zostały prze-
Perspektywa audytu może budzić w pracownikach dostawcy obawy i poczucie zagrożenia.
Audyt nie jest kontrolą, nie polega na doszukiwaniu się błędów i niedociągnięć ze strony au- kazane do korekty.
dytowanego – jednak uczestnicy audytu mogą odczuwać presję i stres, wynikające z poczu-
cia, iż są oceniani. Często audyt odbierany jest jako próba podważenia kompetencji osób au- Podsumowanie
dytowanych lub brak zaufania do rzetelności audytowanego. Audyt to nie kontrola, a audytorzy nie stawia-
To, czy ten problem zostanie rozwiązany, a audytowany nabierze zaufania do oceniających ją sobie za cel numer jeden pognębienie od-
i poczuje się w miarę komfortowo, w dużej mierze zależy od samego zespołu audytorów. Od
ich umiejętności i doświadczenia będzie zależało, czy uda im się nawiązać odpowiednie rela-
pytywanego i udowodnienie mu, że źle wy-
cje i zbudować dobry model współpracy z audytowanymi. Profesjonalny audytor nie stosu- konuje swoją pracę. Dobrze rozumiany au-
je technik, które polegają na przysłowiowym zapędzaniu przesłuchiwanego w kozi róg i łapaniu dyt, z wyraźnie postawionym celem i profe-
za słówka. Zadaniem audytora jest ocena stanu rzeczywistego, nie udowadnianie audytowa- sjonalnym przygotowaniem, pomoże udosko-
nemu, że się myli. Wytyczne odnoszące się do kompetencji personelu przeprowadzającego nalić organizację i wyeliminować błędy, któ-
audyt są przedmiotem punktu 7 normy ISO/DIS 19011 – Kompeten cje audytorów.
rych być może ktoś z wewnątrz danej orga-
Punkt ów mówi, że do prowadzenia audytów jakości należy zatrudniać personel umiejący
je realizować nie tylko z merytorycznego punktu widzenia – tzn. posiadający odpowiednie nizacji nigdy by nie odkrył. Zaangażowanie
kompetencje, znajomość branży, technik oceny dotyczących badania, sporządzania rapor- zewnętrznej firmy audytowej daje pewność,
tów, kierowania, planowania i organizowania. Równie istotne są cechy osobiste charaktery- że uzyskamy obiektywne i pozbawione pew-
zujące audytora – umiejętność skutecznej komunikacji interpersonalnej, dyplomacji, pracy nych uprzedzeń spojrzenie na funkcjonowa-
w zespole, asertywność i przede wszystkim etyczne postępowanie. Od predyspozycji i umie- nie naszej organizacji. Wyniki, które da au-
jętności interpersonalnych audytorów w znaczącym stopniu zależy, czy proces audytu bę-
dyt, będą pozbawione przekłamań i rzetelnie
dzie procesem interaktywnym i umożliwi osiągnięcie postawionych przed nim celów. Dla-
czego? Ponieważ wystraszony i zestresowany audytowany nie jest skory do współpracy. Aby oddadzą rzeczywisty stan rzeczy oraz praw-
porozumiewać się skutecznie, należy używać jasnych sformułowań, aktywnie i uważnie słu- dziwe problemy i zagrożenia – a znając je, ła-
chać, przejąć odpowiedzialność za prowadzenie rozmowy, jeśli jest taka potrzeba, porządko- twiej nam będzie je usunąć.
wać wypowiedzi chaotyczne, podtrzymywać sprzyjający klimat komunikacji. Audyt zewnętrzny może być też począt-
Bardzo ważną kwestią jest komunikacja – jasne poinformowanie audytowanych o celach i za-
kiem wdrażania własnych mechanizmów
kresie audytu może skutecznie wyeliminować negatywne reakcje – opór, kwestionowanie
audytu, złośliwość i agresja. doskonalenia w organizacji, która ów audyt
zleciła – bazując na już zdobytych doświad-
czeniach i obserwacji działań zawodowych
audytorów, firma może opracować i stoso-
Pojęcia wać podobne, w mniejszym zakresie lub
mniej sformalizowane, działania celem oce-
• Audyt – usystematyzowany, niezależny i udokumentowany proces uzyskania dowodu ny innych niż poddane audytowi procesy czy
z audytu i obiektywnej oceny w celu określenia, w jakim stopniu spełniono uzgodnione produkty. I stopniowo udoskonalać całość or-
kryteria audytu;
ganizacji.
• Audytor – osoba posiadająca kompetencje do przeprowadzenia audytu;
• Audytor wyznaczony do kierowania audytem określany jest audytorem wiodącym;
• Audytowany – organizacja, komórka, która jest audytowana;
• Kryteria audytu – zestaw polityk, procedur lub wymagań określonych jako odniesienie; KAROLINA ZMITROWICZ
• Niezgodność – niespełnienie ustalonych wymagań; Pracuje na stanowisku Analityka biznesowe-
• Wnioski z audytu – wynik audytu, przedstawiony przez zespół audytujący w Raporcie z audytu. go w �rmie Pro�-Data. Karolina specjalizuje się
obecnie w modelowaniu wymagań biznesowych
dla ubezpieczeń. Wcześniej pracowała jako Ma-
nager Quality Assurance w projektach informa-
W Sieci
tycznych w sektorze �nansowo – bankowym.
• www.audyty.pl – strona na temat audytów. Opisuje m.in. audyty informatyczne; Pro�-Data to producent oprogramowania spe-
• www.audyt.net – strona zawiera praktyczne informacje dla audytorów wewnętrznych, cjalizujący się w budowie dedykowanych rozwią-
a także narzędzia i wzorce dokumentów audytowych; zań informatycznych dla ubezpieczeń, bankowo-
• www.isaca.org/cobit – o�cjalna strona ISACA, informacje na temat COBIT;
ści i administracji publicznej. Firma posiada cer-
• ww.itil-officialsite.com – o�cjalna strona ITIL;
• http://www.ffiec.gov/ffiecinfobase/booklets/audit/audit_00a_roles_rRespons.html – role ty�kat jakości ISO 9001:2000 w zakresie produk-
i odpowiedzialności w audycie IT. cji oprogramowania.
Kontakt z autorem: karolina_zmitrowicz@wp.pl

72 03/2010
Efektywność pracy

Klient,
który wie czego chce
Czyli sztuka zadawania pytań
Jeśli zdarza Ci się spotykać z osobami nietechnicznymi i musisz
pozyskiwać od nich konkretne informacje, aby móc sprawnie
implementować swoje zadania, to ten artykuł jest dla Ciebie. Skupiliśmy
się w nim na technice zadawania pytań, która ogólne informacje
pomaga przekuć na mierzalne konkrety.
nia dotyczące tej aplikacji. Czy to łatwe za-
Dowiesz się: Powinieneś wiedzieć: danie, czy trudne? O jakich rzeczach bę-
• Jak uzyskiwać potrzebne Ci konkrety z ogól- • Tylko to, co już wiesz. dziesz mówił z tego IT-agnostycznego punk-
nych informacji; tu widzenia?
• Jak omijać impas w rozmowie. Prawdopodobnie opowiesz o:

• swoich wyobrażeniach;
• o tym, co widziałeś w aplikacjach po-
cie czytania tego artykułu przyjął następują- dobnego typu;
ce założenia: • o tym, co ktoś Ci powiedział na temat
Poziom aplikacji tego typu;
trudności • Klient zawsze wie, czego chce – wie, że • o swoich problemach z papierowymi
chce rozwiązać jakiś problem, osiągnąć organizerami;
jakiś cel, coś usprawnić; • o swoich obawach związanych z przej-
• Klient nie zawsze wie, czego potrze- ściem z organizera papierowego na

C
zy nie nurtuje Cię, dlaczego czę- buje – ponieważ jest skupiony przede elektroniczny.
sto uważa się, że klient nie wie, wszystkim na swoich procesach bizne-
czego chce od {programistów | sowych; Chociaż większość klientów jest pewnie
analityków | liderów projektów | teste- • Klient często nie zdaje sobie sprawy o wiele bardziej wyedukowana w kontak-
rów}? Z drugiej strony, dlaczego jest oczy- z konsekwencji swoich oczekiwań – cie z komputerem, to jednak to krótkie do-
wiste, że programiści zawsze wiedzą, cze- gdyż jest ekspertem w obrębie swojej świadczenie pozwoliło Ci spojrzeć na świat
go chcą od klienta? Z pewnością jesteśmy działalności biznesowej, a nie w obsza- oczami stereotypowego klienta. Jakbyś się
bardzo przywiązani do takich przekonań, rze technologii informatycznych. poczuł, gdybyśmy powiedzieli Ci, że nie
zwłaszcza gdy wyrobiliśmy je sobie pod- wiesz, czego chcesz? Pewnie uważałbyś,
czas szeregu spotkań z osobami nietech- Jeśli zgodzisz się na chwilę myśleć w ten że nie mamy racji, przecież Ty wiesz, cze-
nicznymi (oni naprawdę nie wiedzą, cze- sposób, wspólnie poszukamy narzędzi, go chcesz: chcesz mieć elektroniczny orga-
go chcą!). Chyba jednak zgodzisz się z na- które ułatwią pracę z klientem. nizer i starasz się to wytłumaczyć najlepiej
mi, że to jednostronne spojrzenie nie jest jak potrafisz.
do końca sprawiedliwe. Przypatrzenie obu Po drugiej stronie lustra
stronom komunikacji poszerzy naszą per- Czy zastanawiałeś się kiedyś, jakby to było, Po pierwszej stronie lustra
spektywę. gdybyś budząc się pewnego dnia, ze zdzi- Wróćmy teraz do znajomej perspektywy
wieniem zauważył, że przepadła gdzieś ta- programisty. Gdybyś otrzymał zadanie do
Potrzebuję... jemniczo cała twoja, z trudem zbierana, zaimplementowania: Stworzyć elektroniczny
Gdy siedzisz naprzeciw klienta i nie wiesz, wiedza informatyczna, wiedza o programo- organizer, to chciałbyś dowiedzieć się czegoś
co próbuje Ci przekazać, to powinieneś so- waniu, o systemach, że cała Twoja umiejęt- więcej: jak ma wyglądać? Jakie funkcjonal-
bie uświadomić, że ma on jakąś potrze- ność pracy z komputerem sprowadza się do ności ma udostępniać? Jak konkretnie ma
bę (w zależności od człowieka może być wciskania przycisku Power i czasem Reset? działać? To jest sedno sprawy. Aby stwo-
to problem lub cel do osiągnięcia) i uwa- Jakby to było, gdybyś przeżył coś takiego? rzyć oprogramowanie, potrzebujesz bar-
ża, że technologie informatyczne na pew- Trwając w tej perspektywie, wytłumacz dzo konkretnych i szczegółowych informa-
no mu w tym pomogą. Gdyby klient czegoś nam, że chciałbyś, abyśmy stworzyli opro- cji, których klient Ci nie dostarcza. Dlacze-
nie potrzebował, to nie spotykałby się z To- gramowanie, które będzie Twoim osobi- go? Bo nie wie, że powinien. Opisuje swo-
bą. Z tego względu prosimy Cię, abyś w trak- stym organizerem. Opisz swoje oczekiwa- je oczekiwania tak dobrze jak tylko potrafi.

74 03/2010
Klient, który wie czego chce

Dziwi go, że chciałbyś wiedzieć, czy zapiski • usunięć, np.: Po wciśnięciu przycisku ne zachowanie sprawiło, że wyciągnąłeś
w organizerze powinny być trwale przecho- Generuj system od razu generuje ra- wnioski na temat działania systemu?
wywane i jak długo, ile osób ma mieć dostęp port – co to znaczy „od razu”? Jak dłu-
do organizera, czy organizer ma być używa- go ma trwać generowanie raportu? Po- Zadając odpowiednie pytania, możemy
ny na komputerze PC, notebooku, netbo- między jakimi zdarzeniami mierzony jest stopniowo wydobywać cenne informa-
oku, czy telefonie itd. Odpowiedzi na nie- ten czas? Jak konkretnie ma wyglądać ra- cje z tego, co mówi klient lub użytkow-
które pytania są dla klienta oczywiste. Czy port? Jakie informacje ma zawierać? Kto nik. Skąd zatem wiadomo, kiedy przestać
zapiski mają być przechowywane? Jasne, że może wcisnąć przycisk Generuj? W jaki pytać? Wtedy, gdy informacje są komplet-
tak! Jak długo? Na zawsze! Inne pytania bu- sposób system dostarcza raport? ne i jednoznaczne. Gdy na ich podstawie
dzą u klienta zdziwienie, gdyż nie wiedział, • uogólnień, np.: Trzeba odbyć dziesięć można przystąpić do implementacji. Oczy-
że są istotne podczas tworzenia oprogramo- spotkań – kto tak powiedział? Z czego wy- wiście podczas programowania mogą po-
wania. Do momentu, gdy nie wyewoluuje nika ta konieczność? Co by się stało, gdy- jawić się dodatkowe pytania. Może oka-
w ludziach umiejętność telepatii, zadawa- byśmy odbyli osiem lub dziewięć spotkań? zać się, że wymagania nie zostały zebrane
nie pytań jest najlepszym sposobem na po- • zniekształceń, np.: Myślałem, że tak to w wystarczająco konkretnej formie. W ta-
znanie myśli innych osób. ma działać – co sprawiło, że tak pomyśla- kich przypadkach znów sięgamy po narzę-
łeś? Czy jakieś moje zachowanie? Co kon- dzie, jakim jest Sztuka Zadawania Pytań.
Potęga pytań kretnie w moim zachowaniu sprawiło, że Warto wspomnieć również o jednej waż-
Częstym zarzutem powtarzanym przez tak pomyślałeś? W jaki sposób to konkret- nej rzeczy: zanim zaczniesz zadawać pyta-
użytkowników w kierunku programistów
jest to, że programiści na wszystkie prośby
o dodanie lub zmianę funkcjonalności ma-
Usunięcia
Powstają, gdy rozmówca pomija część informacji niezbędnych do prawidłowego zrozumie-
ją tę samą odpowiedź: Nie da się! Użytkow- nia przekazu.
nicy skarżą się, że o cokolwiek by nie prosili,
pierwsze, co słyszą, to odmowa. Łatwo mo- • Interfejs ma być intuicyjny – po czym poznasz, że interfejs jest intuicyjny? Jakie są objawy in-
żesz odczuć frustrację użytkowników: zwy- tuicyjnego interfejsu?
• Organizer nie działa tak, jak trzeba – co konkretnie nie działa? Jakie konkretne czynności
czajnie wyobraź sobie, że przy każdej proś-
wykonujesz? Jakiego efektu się spodziewałeś? Jaki efekt otrzymałeś?
bie o podwyżkę słyszysz: Nie da się! • Sortowanie ma być szybkie – jak długo maksymalnie może trwać sortowanie? Pomiędzy
Zamiast takiej twardej odpowiedzi moż- którymi momentami należy przeprowadzić pomiar?
na zadać kilka pytań:

• Jak ważna jest ta funkcjonalność?


• O ile można przesunąć termin i zwięk-
Uogólnienia
Powstają, gdy na podstawie niewielkiej liczby przesłanek rozmówca przedstawia daleko idą-
szyć budżet projektu, aby ją zaimple- ce ogólne wnioski.
mentować?
• Jak do tej pory radziłeś sobie z tym pro- • Tego się nie da zaimplementować – na jakiej podstawie tak twierdzisz? Co konkretnie spra-
blemem? wia, że się nie da?
• Zawsze trzeba pisać testy jednostkowe – kto tak powiedział? Co się stanie, jeśli w przypad-
ku X lub Y nie napiszę testu jednostkowego? Czy istnieją okoliczności, w których można nie pi-
Cała moc odpowiedniego pytania pole- sać testu jednostkowego?
ga na tym, że nie mobilizuje użytkowni- • Klienci nie wiedzą, czego chcą – którzy klienci? Po czym poznajesz, że nie wiedzą? Po czym
ka do konfrontacji, lecz do zastanowienia poznasz, że już wiedzą?
się nad swoimi oczekiwaniami. Nie chodzi
o to, by ktoś kogoś przechytrzył, lecz o to,
by wspólnie poszukiwać najlepszych roz-
wiązań. Zadawanie pytań pozwala skupić
Zniekształcenia
Powstają wówczas, gdy rozmówca przekazuje informacje, których znaczenie jest niepo-
się na problemie zamiast na słownych prze- prawne.
pychankach.
• Widzę, że się nie rozumiemy – co dokładnie widzisz? W jaki sposób to, co widzisz, oznacza,
W stronę konkretów że się nie rozumiemy?
• Zbieranie wymagań jest zbędne – które konkretnie elementy procesu zbierania wymagań
Gdybyśmy w codziennych rozmowach
uważasz za zbędne? Na jakiej podstawie? Co należałoby w nich zmienić, aby były użyteczne?
chcieli operować na poziomie absolutnych • Przez Ciebie się spóźniliśmy – co takiego zrobiłem? W jaki sposób to, co zrobiłem, wpłynie
i mierzalnych konkretów, to doba musiała- na to, czy się spóźnimy, czy nie? Czy wystąpiły jeszcze jakieś inne czynniki opóźniające pracę?
by trwać o wiele dłużej niż 24 godziny. Do- Który z nich był dominujący?
datkowo w życiu codziennym niedopowie-
dzenia mają swój urok. Tracą go jednak, gdy
mowa o systemach informatycznych, któ-
re trzeba wykonać w ograniczonym czasie
Bądź czujny
Poniżej podajemy przykłady sformułowań, których pojawienie się w rozmowie na temat wy-
i przy ograniczonym budżecie. magań powinno wzbudzać Twoją czujność. Sformułowania te sygnalizują, że właśnie umyka-
W trakcie rozmowy powinniśmy być ją Ci istotne informacje na temat oczekiwań klienta.
świadomi, że brak konkretów wynika ze
sposobu komunikowania się rozmówcy, • dużo, mało, lepiej, szybciej, intuicyjny, ładny, prosty, poprawić, zależy od, kilka, idealnie,
dobrze, zwiększać, zmniejszać, optymalizować, gdy to konieczne, kiedy trzeba, pomię-
a nie z jego złej woli. Powinniśmy być rów-
dzy, taki jak, tak samo jak, wspierać, efektywny, drogi, tani.
nież świadomi nagminnie występujących
zakłóceń:

www.sdjournal.org 75
Efektywność pracy

nia, poproś rozmówcę o zgodę. Tego typu w dół (ang. chunk down). Istnieją również • Klient: Po tym, że trzeba się zalogować,
szczegółowe pytania sprawiają, że rozmów- pytania uogólniające, które prowadzą w od- a w razie awarii komputera nie są traco-
ca musi dokładnie zastanowić się nad od- wrotnym kierunku. Nazywane są one py- ne żadne dane.
powiedzią, musi zastanowić się nad moty- taniami w górę (ang. chunk up). Pytania • Programista [proponuje inny sposób na
wacją swoich oczekiwań. Czasem użytkow- w dół kierują uwagę w stronę konkretów, zapewnienie bezpieczeństwa]: W tech-
nik zdaje sobie sprawę, że nie do końca prze- np.: Co dokładnie? Po czym poznasz? Jak nologii, którą rekomendujemy, stosujemy
myślał swoje oczekiwania lub że są one nie- zmierzysz? Pytania w górę pozwalają od- specjalny bezpieczny moduł logowania.
realistyczne czy niepotrzebne. Nie jest to kryć przyczyny i potrzeby: Dlaczego? Co Jednocześnie możemy wbudować w orga-
zbyt miłe uczucie. Zadbaj zatem o kom- jest w tym ważnego? Finezja w posługiwa- nizer mechanizm kopii bezpieczeństwa.
fort rozmowy i poproś o zgodę na zadawa- niu się pytaniami w górę i w dół (albo tech- Polega on na tym, że przy każdym uru-
nie pytań. niką chunk up / chunk down) polega na chomieniu wszystkie ważne dane są ko-
tym, że gdy pojawia się kwestia sporna na piowane na specjalny serwer bezpieczeń-
Ominąć impas temat szczegółów, to szukamy przyczyny, stwa.
Z pewnością zauważyłeś, że przedstawiony a następnie innego szczegółowego sposobu • Klient: Ok, podoba mi się to rozwiązanie.
sposób na wydobywanie konkretów z infor- wynikającego z tej samej przyczyny. Przy-
macji przekazywanych przez rozmówcę po- kładowy dialog z klientem mógłby przebie- Zauważ, że programista za pomocą py-
zwala tylko na poruszanie się w jedną stro- gać następująco: tań w górę i w dół trafnie zidentyfikował
nę: od ogółu do szczegółu. Co jednak, gdy rzecz ważną dla klienta. Jest nią bezpie-
klient rzuca na stół poważny argument na • Klient: Chcę, żeby mój organizer został czeństwo oprogramowania. Zauważ rów-
dużym poziomie konkretności, np.: Chcę, zaimplementowany w technologii JMS! nież, że proponując inne rozwiązanie niż
żeby mój organizer został zaimplemento- • Programista [pytanie w górę]: Dlaczego technologia JMS, buduje swoją wypo-
wany w technologii JMS! Po krótkim szoku takie ważne jest, aby organizer był wyko- wiedź odkrytej ważnej rzeczy. Kilkukrot-
zaczniesz zastanawiać się, jak z tej sytuacji nany w technologii JMS? nie podkreśla, że nowe rozwiązanie bę-
wybrnąć. Mógłbyś zacząć wyliczać powo- • Klient: Ponieważ słyszałem, że programy dzie bezpieczne. W ten sposób udaje mu
dy, dlaczego w tym konkretnym rozwiąza- w tym napisane są bardzo bezpieczne się ominąć impas w rozmowie. To jest wła-
niu JMS nie jest najlepszym rozwiązaniem. • Programista [szuka rzeczy ważnej dla śnie istota rzeczy: programista omija im-
Z drugiej strony pamiętasz, że bitwa na ar- klienta]: Rozumiem, że bezpieczeństwo pas zamiast go przełamywać. Nie upiera
gumenty w sytuacji gdy strony są na zupeł- oprogramowania jest dla Pana bardzo się przy swoim rozwiązaniu, lub co gorsze
nie innych poziomach merytorycznych, do- ważne? nie krytykuje rozwiązania klienta. Świa-
prowadzi donikąd. Co zrobić w takiej sytu- • Klient: Tak. domie stara się odkryć potrzeby i rzeczy
acji? Oczywiście zadać pytanie! • Programista [pytanie w dół]: Po czym ważne. Poszukuje przyczyn, które spra-
Pytania uszczegóławiające, które oma- konkretnie poznaje Pan, że oprogramowa- wiły, że klient obstaje przy jakimś szcze-
wialiśmy do tej pory, noszą nazwę pytań nie jest bezpieczne? gółowym rozwiązaniu. Gdy już zidentyfi-
kuje i upewni się co do potrzeb, wtedy ma
o wiele szersze pole do działania i może
zaproponować najlepsze jego zdaniem roz-
wiązanie. W przedstawionym przypadku
klient wiedział, czego chciał. Chciał bez-
pieczeństwa. Nie wiedział tylko, czego
konkretnie potrzebował.
Sytuacje podobne do omówionych w ar-
tykule dzieją się każdego dnia. W setkach
firm, na tysiącu spotkań miliony sfrustro-
wanych uczestników wciąż na nowo zadają
sobie te same pytania: Co on mówi? Dlacze-
go mnie nie słucha? O co mu chodzi? Dlaczego
on nic nie rozumie? Gdy rozmawiasz z kimś,
to od Ciebie zależy przynajmniej 50% efek-
tywnej komunikacji. Jak zamierzasz wyko-
rzystać swoje 50%?

MICHAŁ BARTYZEL,
MARIUSZ SIERACZKIEWICZ
Trenerzy i konsultanci w �rmie BNS IT. Badają
i rozwijają metody psychologii programowania,
pomagające programistom lepiej wykonywać ich
pracę. Na co dzień Autorzy zajmują się zwiększa-
niem efektywności programistów poprzez szkole-
nia, warsztaty oraz coaching i trening.
Kontakt z autorami: m.bartyzel@bnsit.pl,
Rysunek 1. Pytania w górę i w dół m.sieraczkiewicz@bnsit.pl

76 03/2010
KLUB PRO
Oferta skierowana dla firm
Jeżeli Twoja firma jest prenumeratorem Software Developer’s Journal za comiesięczną
dopłatą 50 PLN +VAT możesz dodatkowo otrzymać reklamę.
Wystarczy tylko, aby profil Twojej firmy pokrywał się z naszym magazynem.
Wyślij do nas: logo firmy, dane kontaktowe i informację o firmie
Reklama przez 12 kolejnych numerów tylko za 600 PLN +VAT.
Jeżeli nie posiadasz jeszcze prenumeraty możesz ją zamówić w atrakcyjnej cenie.
Dla nowych prenumeratorów specjalna oferta – 690 PLN.

Skontaktuj się z nami:


tel. +48 22 877 20 80
fax: +48 22 877 20 70
software@europress.pl

Opera Software Architektury systemów IT


Opera Software’s vision is to deliver the best In- Twórca frameworków JUVE i serwera aplikacji
ternet experience on any device. We are offering AVAX oferuje usługi, doradztwo, rozwiązania do
browser for PC/desktops and embedded pro- tworzenia nowoczesnych, dużych systemów i roz-
ducts that operates across devices, platforms wiązań informatycznych/internetowych, integrujące
and operating systems. Our browser can deliver architektury ery post-J2EE/.NET, wykorzystujące
a faster, more stable and flexible Internet expe- MDD/MDA dla dziedzin – bankowość, telekomuni-
rience than its competitors. kacja, handel, e-commerce, ERP/Workflow/CRM,
rozwiązania internetowe, portalowe.
http://www.opera.com www.mpsystem.com mpsystem@mpsystem.com

Kei.pl Future Processing


Kei.pl działa na rynku usług hostingowych od 2000 Future Processing to dynamiczna firma technolo-
roku. Do naszych zadowolonych Klientów z du- giczna działająca na globalnym rynku oprogramo-
mą możemy zaliczyć wiele przedsiębiorstw sekto- wania. Jesteśmy zespołem wysokiej klasy specja-
ra MSP, instytucji oraz osób prywatnych. W ofer- listów posiadających wiedzę i doświadczenie nie-
cie Kei.pl znajdują się pakiety hostingowe, a także zbędne do realizacji ambitnych projektów informa-
usługi dla wymagających Użytkowników – platfor- tycznych. Jeśli programowanie to Twoja pasja do-
my e-Biznes oraz serwery fizyczne. łącz do nas! (możliwość pracy zdalnej).

http://www.kei.pl http://www.future-processing.pl

Playsoft WSISiZ w Warszawie


Playsoft jako lider portowania aplikacji na plat- INFORMATYKA ZARZĄDZANIE
formy mobilne wciąż powiększa bazę swo- studia stopnia I i II (stacjonarne i niestacjonar-
ich klientów: EA Mobile, Sega, THQ, Kona- ne) specjalności: inżynierskie, magisterskie
mi. W ramach rozszerzania swojej działalno- i licencjackie. Szczegółowe plany studiów, opi-
ści, poszukujemy doświadczonego programi- sy poszczególnych specjalności – zapraszamy
sty, który byłby odpowiedzialny za tworzenie na stronę uczelni.
aplikacji na platformy Iphone, Windows Mobi-
le, Android.
http:// www.playsoft.fr http://www.wit.edu.pl
KLUB PRO

INFOTEX SP.J TTS Company Sp. z o.o.


Śmietanowski i Wsp. Sprzedaż i dystrybucja oprogramowania komputero-
Dystrybutor XP Unlimited – Serwer Terminali dla wego. Import programów na zamówienie. Ponad 200
Windows XP i VISTA. Program umożliwia łącze- producentów w standardowej ofercie. Chcesz kupić
nie się z dowolnego klienta Windows, Linux z wy- oprogramowanie i nie możesz znaleźć polskiego do-
korzystaniem protokołu RDP. Cena wersji Classic stawcy? Skontaktuj się z nami – sprowadzimy nawet
dla 5 użytkowników - 165€, dla nieograniczonej
liczby - 235€. Ponadto oferujemy opiekę serwiso- pojedyncze licencje.
wą i aplikacje internetowe na zamówienie.

http://www.infotex.com.pl http://www.OprogramowanieKomputerowe.pl

IT SOLUTIONS Softline rozwiązania mobilne


Wdrożenia i szkolenia z zakresu: Wiodący producent systemów mobilnych, do-
• SQL Server stawca aplikacji użytkowych dla biznesu (Sym-
• SharePoint Services bian OS, Windows Mobile, J2ME ) zaprasza do
IT SOLUTIONS • MS Project / Server
• Tworzenie aplikacji w technologii .NET
współpracy. Zostań naszym partnerem. Dołącz
do zespołu.

http://www.itsolutions.biz.pl
marcin.pytlik@itsolutions.biz.pl http://www.softline.com.pl

Proximetry Poland Sp. z o.o. Systemy bankowe, ISOF


Proximetry Poland Sp. z o.o. jest polskim od- HEUTHES istnieje na rynku od 1989 r. Obok
działem amerykańskiej firmy Proximetry Inc. – systemów informatycznych dla banków, ofe-
dostawcy systemów zarządzania sieciami bez- ruje nowoczesne oprogramowanie do obsługi
przewodowymi opartymi na technologiach WiFi
i WiMAX. Naszą misją jest dostarczenie klien- firm. System ISOF jest udostępniany klientom
tom rozwiązań poprawiających jakość usług w trybie SaaS lub licencji. Pracuje na platfor-
(QoS) dostarczanych drogą radiową. Dołącz do mie Linux i zawiera m.in. takie moduły jak
najlepszych i zostań członkiem naszej ekipy! CRM, DMS, Magazyn, Sprzedaż, Logistyka
oraz Rachunkowość.
http://www.proximetry.com http://www.isof.pl
Roczna prenumerata

tylko
256,-
Software Developer’s Journal (poprzednio Software 2.0)
jest miesięcznikiem głównie dla programistów, którzy li-
czą, że dostarczymy im gotowe rozwiązania, oszczędza-
jąc im czasu i pracy. Jesteśmy czytani przez tych, któ- UWAGA!
rzy chcą być na bieżąco informowani o najnowszych osią-
gnięciach w dziedzinie IT i nie chcą, żeby jakiekolwiek
istotne wydarzenia umknęły ich uwadze. Aby zadowolić Zmiana danych
kontaktowych
naszych czytelników, prezentujemy zarówno najnowsze
rozwiązania, jaki starsze, sprawdzone technologie.

Obsługa prenumeraty
Software Wydawnictwo EuroPress
1. Telefon 1. Telefon
(022) 427 37 59 +48 22 877 20 80
2. Fax 2. Fax
(022) 244 24 59 22 877 20 70
3. Online 3. Online
pren@software.com.pl software@europress.pl
4. Adres 4. Adres
Software Wydawnictwo EuroPress Polska Sp. z o.o.
ul. Bokserska 1 ul. Jana Kazimierza 46/54
02-682 Warszawa 01-248 Warszawa
Prenumerujesz
– zyskujesz
l oszczędność
pieniędzy
l szybka dostawa
l prezenty
l bezpieczna płatność
on–line

Zadzwoń
0
+48 22 877 20 8
lub
zamów
mailowo!

Ilość Od
Ilość zama- numeru
Tytuł nume-
rów
wianych pisma
prenu- lub mie-
Cena

merat siąca
Software Developer’s
Journal (1 płyta DVD) 12 256
– dawniej Software 2.0 PLN
Felieton
��������

�����������


������������������������������������������������������ ������������������������������������������������������������
���������������������������������������������������� ��� ����������� �� ������ ���� �������������� ������ ���� ����������
����������������������������������������������������� ���� ������ ������������� ��������� ���� ���������� ���� �������� ��
��������������������������� �������������������
��������������������������������������������������������� �����������������������������������������������������������
�������������������������������������������������������������������� ���������������������������������������������������������������
��������������������������������������������������������������� ���������������������������������������������������������������
���� ������ ������������� ������� ����� ����� ��������������� ���� ������� ����� ������ ������� ������������� �� ����������� ������ ���
������������������������������������������������������������� ��������� ������� �� ������� �������� ������� �������� ���������� ���
�������������������������������������������������������������� �������� ���� ��������� ���� �������� �������������� �� �������� ���
����� ������������ ��������� ������� �������� ������ ���� �������� ���� ���� ������������ ��������� ���������� ���������� ������ ��
�������������������������������������������������������������������� ���������� ��������� ��������������������� ��������� ����
��������������������������������������������������������������� ������� ������� ���� ����������� ����������� �������� ��������������
����������������������������������������������������������������� ��������������
������������������������ ������� �� ��������� ��� ���� ������ ���� ���� ������������ �� ������
����������� ������� ������������ ������� ������� ���� �� ��� ��������������������������������������������������������������
��� ����� �� ����������� ������������ ����������� ��� ������ ��������� ��������������������������������������������������������������
��������������������������������������������������������������������� ��������� ����������� ��� ���������� �������� ���� ������������ ���
������������������������������������������������������������� ���������� ������ ��������������� �������� ���� ���������� �������� ���
��� ���� ������� ����� ������ ����� ���������� �������� ����������� ���� �����������������������������������������������������������������
��� ��������� ��������� ��������� �������� �������� ������ ����������� �������������������������������������������������������������
���� ������������ ������ �������� ������ ���������� ������ ������� ����������������������������������������������������������������
������ ������ �������� �������� ��������� ��������� ������� ������� �����������������������������������������������������������������
�������������������������������������������������������������� �������
������� ���� ������� ������� �������� �������� �������������� �� ������� �������������������������������������������������������������
������������� ������� ������� �� ������������� ������������� ����� ������������������������������������������������������������
������ ������ ����������� �� ��������������� ����������� �� ��������� ���������������������������������������������������������������
���������������������������������������������������������������� �������������������������������������������

�� 03/2010
�������
Jan, Kasia,
Dyrektor Data Center
Finansowy Manager

Robert,
Dyrektor
Techniczny

Bardzo realna wydajność!


Rzeczywista wydajność wirtualnej infrastruktury. Już teraz możesz mieć spójną, wirtualną infrastrukturę IT, która obejmuje zarówno
duże centra danych, jak i stacje robocze użytkowników. Pytanie jest tylko takie, czy słowo „mieć” jest tutaj najlepsze, w końcu
to wszystko jest wirtualne… Wykorzystując Windows Server 2008 R2 z wbudowaną technologią Hyper-V, możesz łatwo pozbyć
się wysokich kosztów zakupu dodatkowego oprogramowania. Dodaj do tego nieograniczone możliwości wirtualizacji SQL Server
2008 Enterprise, a pozbędziesz się szaf z serwerami, które i tak nigdy w pełni nie wykorzystywały swoich mocy obliczeniowych.
Centralnym zarządzaniem całą infrastrukturą w przedsiębiorstwie, aż do poziomu pojedynczych aplikacji, zajmie się System Center.
Co to wszystko oznacza? Posiadasz elastyczną, dynamicznie zarządzaną, wirtualną infrastrukturę IT, za pomocą której
zmaksymalizujesz korzyści ze swoich inwestycji, obniżysz koszty i zapewnisz stabilność swojego biznesu.

Aby dowiedzieć się, jak zwiększyć wydajność infrastruktury IT za pomocą wirtualizacji serwerów,
odwiedź stronę www.itwspierabiznes.pl

3 SDJ MB 203x297.indd 1 1/14/10 4:59 PM

You might also like