P. 1
Software Developers Journal PL 03/2009

Software Developers Journal PL 03/2009

|Views: 1,958|Likes:
Wydawca: hellboy0
Tematy numeru:

* Biblioteka Luabind...
* Spring Java Configuration Project...
* CUDA się zdarzają, czyli programowanie GPGPU...
* Facebook dla programistów...
* Zabezpieczanie systemów IT...
* Praca z zespołem testerów klienta...
* Jakość czy jakoś to będzie?...
* WebAii – testowanie aplikacji ASP .NET...
* Zintegruj się z Internet Explorer 8...
* Weryfikacja przez model z narzędziem SPIN...
* Aby wielu mogło na raz......
* Najpierw cele...
Tematy numeru:

* Biblioteka Luabind...
* Spring Java Configuration Project...
* CUDA się zdarzają, czyli programowanie GPGPU...
* Facebook dla programistów...
* Zabezpieczanie systemów IT...
* Praca z zespołem testerów klienta...
* Jakość czy jakoś to będzie?...
* WebAii – testowanie aplikacji ASP .NET...
* Zintegruj się z Internet Explorer 8...
* Weryfikacja przez model z narzędziem SPIN...
* Aby wielu mogło na raz......
* Najpierw cele...

More info:

Published by: hellboy0 on Aug 06, 2009
Prawo autorskie:Attribution Non-commercial

Availability:

Read on Scribd mobile: iPhone, iPad and Android.
download as PDF, TXT or read online from Scribd
See more
See less

05/11/2014

pdf

text

original

03/2009

SPIS TREŚCI
06 Aktualności
Rafał Kocisz

35 Opis CD
Duży zbiór materiałów od firmy nsoftware

wykorzystać kartę graficzną do obliczeń niekoniecznie związanych z grafiką komputerową. Następnie użyjemy typowych rozwiązań mających na celu znaczne przyspieszenie obliczeń.

36 Facebook dla programistów
Włodzimierz Kozłowski Facebook jest nie tylko klasycznym serwisem społecznościowym, lecz także platformą umożliwiającą tworzenie własnych aplikacji. W artykule pokażemy jak przygotować i opublikować przykładową aplikację dla Facebooka współpracującą z serwisem aukcyjnym Allegro.

BIBLIOTEKA MIESIĄCA
12 Biblioteka Luabind
Rafał Kocisz Lua oraz C++ bardzo ładnie uzupełniają się jako języki programowania; niestety – ich łączenie przy pomocy podstawowego API opartego na czystym C jest delikatnie mówiąc – zniechęcające. Na pomoc przybywa Luabind: nowoczesna biblioteka C++, dzięki której łączenie Lua i C++ staje się proste i przyjemne.

BEZPIECZEŃSTWO
42 Zabezpieczanie systemów IT
Aleksander Jachowicz Coraz więcej słyszymy o ochronie bezpieczeństwa systemów informatycznych. Wynika to z tego, że pojawia się coraz więcej doniesień prasowych o włamaniach na konta klientów banków lub o przypadkach wykradzenia dużej ilości danych osobowych. W artykule Aleksander Jachowicz omawia Adaptive Access Manager firmy Oracle.

PROGRAMOWANIE JAVA
20 Spring Java Configuration Project
Henryk Konsek Twórcy projektu Spring Framework spróbowali zminimalizować ilość konfiguracji XML poprzez przeniesienie źródeł definicji komponentów do plików języka Java. Spring Java Configuration Project to alternatywa dla klasycznego podejścia do zagadnienia konfiguracji aplikacji internetowych, która równocześnie nie narusza wzorca Inversion Of Control oraz ogólnej elegancji architektury naszej aplikacji.

TESTOWANIE OPROGRAMOWANIA
46 Praca z zespołem testerów klienta
Karolina Zmitrowcz Karolina Zmitrowicz w artykule przedstawia studium przypadku dotyczącego procesu testowania systemu bankowego w środowisku klienta. Zostaną przedstawione problemy wynikłe w trakcie organizacji testowania oraz czynności przedsięwzięte w celu ich eliminacji i osiągnięcia satysfakcjonującego poziomu współpracy pomiędzy dostawcą oprogramowania a klientem.

WARSZTATY
28 CUDA się zdarzają, czyli programowanie GPGPU
Jacek Piekarski W artykule dowiemy się co nieco o CUDA z praktycznego punktu widzenia. Na konkretnym przykładzie zobaczymy, jak w prosty sposób

Miesięcznik Software Developer’s Journal (12 numerów w roku) jest wydawany przez Software-Wydawnictwo Sp. z o.o. Dyrektor wydawniczy: Anna Adamczyk Junior Market Manager: Anna Adamczyk Senior Product Manager: Katarzyna Juszczyńska Redaktor naczelny: Łukasz Łopuszański lukasz.lopuszanski@software.com.pl Kierownik produkcji: Marta Kurpiewska marta.kurpiewska@software.com.pl Projekt okładki: Agnieszka Marchocka Skład i łamanie: Monika Grotkowska monika.grotkowska@software.com.pl Wyróżnieni betatesterzy: R. Zacharczyk Nakład: 6 000 egz.

Le périodique hakin9 est publié par Adres korespondencyjny: Software-Wydawnictwo Sp. z o.o. o.o., Bokserska, 02-682 Varsovie, Pologne ul. Bokserska 1, 02-682 Warszawa, Polska Tél.+48 22 427 36 91, fax +48 2222 887 10 11 tel. +48 22 887 10 10, Fax. +48 224 24 59 www.phpsolmag.org cooperation@software.com.pl Directeur de la publication : Jarosław Szumski Dział reklamy: adv@software.com.pl Imprimerie, photogravure : 101 Studio, Firma Tęgi Obsługa prenumeraty: EuroPress Ekonomiczna 30/36, 93-426 Łódź Polska software@europress.pl Imprimé en Pologne/Printed in Poland Abonnement (France métropolitaine, DOM/TOM) : 1 an Dołączoną do magazynu płytę CD przetestowano programem AntiVirenKit firmy (soit 6 numéros) 38 € G DATA Software Sp. z o.o. Dépôt légal : à parution Redakcja dokłada wszelkich starań, by publikowane w piśmie i na towarzyszących mu ISSN : 1731-7037 nośnikach informacje Distribution : MLP i programy były poprawne, jednakże nie bierze odpowiedzialności za efekty wykorzystania ich; nie gwarantuje także Parc d’activités de Chesnes, 55 bd de la Noirée poprawnego działania programów shareware, freeware i public domain. BP 59 F - 38291 SAINT-QUENTIN-FALLAVIER CEDEX (c) 2005 Software-Wydawnictwo, tous les droits réservés

4

03/2009

54 Jakość czy jakoś to będzie?
Zbigniew Zarzycki Odpowiedź na pytanie czy tworzone oprogramowanie jest wystarczająco dobre do uruchomienia produkcyjnego wymaga złożonego procesu decyzyjnego. IBM Rational Quality Manager jest rozwiązaniem, które może podjąć tę odpowiedzialną decyzję w oparciu o wiarygodne dane, dostarczane w czasie rzeczywistym.

nym wykonaniu jest zadaniem wyjątkowo kłopotliwym. Formalna weryfikacja przez model jest jedną z metod mających na celu wykazanie poprawności oraz niezawodności takich systemów.

FELIETON
74 Aby wielu mogło na raz...
Arkadiusz Merta

58 WebAii – testowanie aplikacji ASP .NET
Paweł Wilkosz Przyszłość należy do serwisów internetowych. Ogólna powszechność Internetu, świadczenie usług na odległość czy też rozwój urządzeń mobilnych są argumentami umacniającymi Pawła w przekonaniu, iż to właśnie aplikacje webowe będą najbardziej kojarzone z inżynierią oprogramowania za parę lat.

77 Najpierw cele
Arkadiusz Merta

TECHNOLOGIE INTERNETOWE
62 Zintegruj się z Internet Explorer 8
Bartłomiej Zass Już niedługo premiera kolejnej wersji przeglądarki firmy Microsoft, która otworzy przed programistami zupełnie nowe możliwości tworzenia rozszerzeń. W artykule przedstawione zostały podstawy programowania tzw. akceleratorów, web slice’ów oraz search provider’ów, które pozwalają zintegrować nasze strony z przeglądarką Internet Explorer 8.

NARZĘDZIA
68 Weryfikacja przez model z narzędziem SPIN
Sławomir Maludziński Współczesne programy wykorzystują więcej niż jeden wątek przetwarzania w celu zmniejszenia opóźnień bądź zwiększenia szybkości działania. Niestety, zapewnienie o ich bezbłędnym oraz efektyw-

Rédacteur en chef : Marek Bettman marekb@software.com.pl Uszkodzone podczas wysyłki płyty wymienia redakcja. Rédacteurs : Aneta Cejmańska anetta@software.com.pl Ewa Dudzic ewal@software.com.pl piśmie są własności odpowiednich firm. Wszystkie znaki firmowe zawarte w Préparation du CD : Aurox celach informacyjnych. Zostały użyte wyłącznie w Core Team Maquette : Anna Osiecka annao@software.com.pl Couverture : Agnieszka Marchocka Redakcja używa systemu automatycznego składu Traduction : Iwona Czarnota, Aneta Lasota, Marie-Laure Perrotey, Grazyna Wełna Osoby zainteresowane współpracą prosimy o kontakt: Bêta-testeurs : Thomas Bores, Tony Boucheau, Pascal Foulon, Pascal Miquet, cooperation@software.com.pl Romain Lévy, Augustin Pascual, Julien Poulalion, Alain Ribault Druk: ArtDruk Les personnes intéressées par la coopération sont priées de nous contacter : cooperation@software.com.pl Abonnement : abonnement@software.com.pl Fabrication nakładu Kurpiewska marta@software.com.pl nie udziela pomocy Wysokość : Marta obejmuje również dodruki. Redakcja Diffusion : Monika Godlewska monikag@software.com.pl technicznej w instalowaniu i użytkowaniu programów zamieszczonych na płycie Publicité : dostarczonej razem z pismem. CD-ROM publicite@software.com.pl Si vous êtes intéressé par l’achat de licence de publication de revuescenie niż Sprzedaż aktualnych lub archiwalnych numerów pisma po innej merci de contacter : Monika okładce – bez zgody wydawcy – jest ,działaniem na887 12 wydrukowana na Godlewska monikag@software.com.pl tél : +48 (22) jego 66 fax : i+48 (22) 887 10 11 szkodę skutkuje odpowiedzialnością sądową.

www.sdjournal.org

5

Aktualności
Mniej telefonów z Windows Mobile

Microsoft przewiduje, że w przyszłości coraz mniej telefonów komórkowych będzie wyposażonych w system operacyjny Windows Mobile. W związku z rosnącą konkurencją Microsoft chce przebudować i ulepszyć swój system. Będzie się to wiązało z umieszczaniem WM na mniejszej liczbie telefonów po to, aby móc skupić wysiłki programistów i lepiej dostosować system do wymagań konkretnych urządzeń. Obecnie Windows Mobile można spotkać na 140 modelach telefonów. System ten ma coraz liczniejszą konkurencję. Oprócz Symbiana jest jeszcze Android. Nowy system operacyjny przeznaczony do zastosowań mobilnych, o nazwie WebOS, opracowuje również firma Palm. http://www.nytimes.com/

25 najniebezpieczniejszych błędów programistycznych

P

Microsoft-Yahoo!: reaktywacja?

Temat przejęcia Yahoo! przez Microsoft wydawał się być sprawą zamkniętą, a tymczasem okazuje się, że Microsoft poważnie myśli o dokończeniu transakcji, a przynajmniej o zakupie części firmy związanej z wyszukiwaniem informacji w Internecie. Steve Ballmer powiedział w wywiadzie dla Financial Times, że właśnie teraz jest najlepszy moment na sfinalizowanie tej sprawy. Obie firmy są bowiem w fazie ważnych zmian jeśli chodzi o kadrę zarządzającą. Qi Lu, były szef działu wyszukiwania w Yahoo! pracuje teraz jako dyrektor działań on-line w firmie Microsoft. Yahoo! szuka również nowego dyrektora zarządzającego; główne kandydatki to wywodząca się z Autodesk Carol Barz oraz Susan Decker, aktualna prezydent Yahoo!. Wypowiedź Ballmera może dziwić, zwłaszcza biorąc pod uwagę fakt, że jeszcze całkiem niedawno stanowczo odcinał się on od pomysłów wznawiania oferty przejęcia Yahoo!. http://vnunet.com/

onad 30 organizacji związanych z rynkiem IT połączyło siły, aby pod kierownictwem ekspertów z Agencji Bezpieczeństwa Narodowego USA (U.S. National Security Agency), Departamentu Bezpieczeństwa Krajowego Stanów Zjednoczonych (Department of Homeland Security), firm Microsoft i Symantec, opracować dokument zawierający listę najbardziej niebezpiecznych błędów, jakie popełniają programiści. Na liście znajdziemy takie błędy jak: zostawianie „otwartych drzwi” dla różnych ataków, wysyłanie kluczowych informacji w postaci łatwego do odczytania czystego tekstu, zapisywanie haseł w kodzie programu. Dwa z wymienionych błędów, zdaniem SANS Institute, spowodowały, że ponad 1,5 miliona stron internetowych było wrażliwych na ataki. Celem, który przyświecał twórcom dokumentu, było

dostarczenie minimalnego zestawu wymagań, jakie powinno spełniać oprogramowanie, zanim trafi w ręce użytkowników. Niektórzy widzą w nim również kartę przetargową, której można użyć przy negocjacjach między producentem oprogramowania a nabywcą. Jest to też część większego zestawu dokumentów, który być może będzie używany przez agencje stanowe do certyfikacji oprogramowania. Niestety, na chwilę obecną, perspektywy certyfikacji ograniczają się do projektów wykonywanych na zamówienie i prawdopodobnie oprogramowanie z certyfikatem bezpieczeństwa będzie przywilejem organizacji rządowych. Nie ma na razie mowy o przyznawaniu takich certyfikatów szeroko dostępnym produktom, na przykład systemom Microsoft Windows. http://www.sans.org/

Słabość MD5 poważnym zagrożeniem dla SSL

P

Rok 2009 pod znakiem phishingu

Jak zapowiada serwis ITPro powołując się na raport firmy McAfee, w 2009 roku wzrośnie ilość botnetów zbierających dane wykorzystywane do szantażowania lub sprzedaży na czarnym rynku. Z raportu wynika, że coraz częściej celem ataku stawać się będą przeglądarki jako element najsłabiej zabezpieczony. Praktyki takie jak kradzież własności intelektualnej lub dostęp do danych klientów stają się celem włamywaczy, nie tylko w firmach, ale także w gospodarstwach domowych. Z tego powodu wiele instytucji zmuszonych będzie do zmiany polityk bezpieczeństwa wynikających z naruszania poufnych danych, których kradzieże zwykle bywają próbą zarobku albo ataków. Raport przewiduje ponadto wzrost wyłudzeń wywołany wykorzystywaniem bezrobocia w postaci różnego rodzaju wiadomości z fałszywymi programami szkoleniowymi i certyfikacyjnymi. Podobnie sytuacja ma się w przypadku ofert rekrutacji z prośbami o CV i dane osobowe, rzekomych pożyczek czy pracy w domu. http://www.itpro.co.uk/

odczas odbywającej się w Niemczech 25 edycji Chaos Communication Congress, Alex Sotirov i Jacob Appelbaum zaprezentowali sposób na stworzenie fałszywego certyfikatu SSL wykorzystując słabość algorytmu kryptograficznego MD5. W tym celu wykorzystali moc klastra składającego się z 200 konsol PlayStation 3. Pomyślne wykonanie ataku jest możliwe poprzez wykorzystanie tak zwanej kolizji MD5, która pozwala na identyfikowanie różnych danych przez tą samą sumę kontrolną. Grupa była w stanie wygenerować certyfikat imitujący jeden z tak zwanych root CA - głównych urzędów certyfikacji, których certyfikaty służące do podpisywania innych certyfikatów znajdują się na listach zaufania wszystkich przeglądarek. Umożliwia to wygenerowanie i podpisanie certyfikatu witryny, który będzie nieodróżnialny od oryginalnego. Po wejściu na tak spreparowaną stronę, przeglądarka automatycznie uzna ją za bezpieczną - dane przesyłane będą poprzez połączenie szyfrowane (https), a na pasku stanu wyświetlana zostanie budząca zaufanie kłódka potwierdzająca autentyczność certyfikatu. Według badaczy, połączenie kolizji MD5 z odkrytą parę miesięcy temu luką w systemie nazw DNS może mieć poważne konsekwencje. Użytkownicy będą mogli być przekierowywani na podrobione witryny banków, podczas

gdy przeglądarki nie zwrócą uwagi na ten fakt, gdyż witryny te identyfikować się będą rzekomo prawdziwymi certyfikatami SSL. Zdaniem Sotirova, urzędy certyfikacyjne muszą natychmiast zaprzestać wykorzystywać MD5 na rzecz SHA-1. Szczegóły ataku dostępne są na stronie autorów (http://www.win.tue.nl/ hashclash/rogue-ca/). Bardziej szczegółowe informacje przesłane zostały producentom przeglądarek internetowych. Również Microsoft w odpowiedzi na doniesienia o ataku opublikował biuletyn bezpieczeństwa. Póki co nie odnotowano prób wykorzystania luki, należy mieć jednak na uwadze, że połączenie jej ze wspomnianą luką w systemie DNS może stworzyć bardzo realne i poważne zagrożenie. Na reakcje firm nie trzeba było długo czekać. Dla przykładu, VeriSign, jeden z największych wystawców certyfikatów, ogłosił zaprzestanie korzystania z podważonego przez Sotirova i Appelbauma algorytmu hashującego w swoich certyfikatach na rzecz SHA-1. MD5 był jak dotąd wykorzystywany w certyfikatach RapidSSL. Jak zapewnia VeriSign, były to jedyne certyfikaty tej firmy podatne na atak. Wystawca obiecuje dodatkowo, że certyfikaty wystawione z hashem MD5 zostaną wszystkim klientom RapidSSL nieodpłatnie wymienione na nowe, wykorzystujące algorytm SHA-1. http://www.techit.pl/

6

03/2009

Aktualności

Windows 7 i 2008 R2 Beta dostępne publicznie

Co drugi Polak korzysta z Internetu

Z

godnie z zapowiedziami Microsoft udostępnił publicznie do pobrania wersję beta systemu Windows 7 oraz jego serwerowego odpowiednika: Windows Server 2008 R2. Od 8 stycznia 2009 roku obie bety mogli pobierać posiadacze płatnych subskrypcji TechNet i MSDN oraz zaproszeni przez Microsoft uczestnicy technicznego programu beta. Aktualnie Windows 7 i Windows Server 2008 R2 mogą pobrać wszyscy zainteresowani. Udostępniona kompilacja oznaczona jest numerem 7000.0.081212-1400. Warto więc zauważyć, że jest to identyczny build, który wyciekł jeszcze przed świętami do sieci torrentowych, skompilowany 12 grudnia. Plik obrazu płyty ISO z systemem Windows 7 w wersji 32-bitowej zajmuje 2,43 GB, wersja 64-bitowa jest nieco „cięższa” - waży 3,15 GB. Windows Server 2008 R2 występuje jedynie w wersji 64-bitowej, jego obraz w edycji Standard zajmuje 2,78 GB, w edycji Enteprise 2,45 GB, zaś w edycji Web 2,66 GB. Klucze produktów do aktywacji wersji beta udostępniono na stronie pobierania. Pozwalają one na użytkowanie systemu do 1 sierpnia 2009. W tym miejscu należy podkreślić, że jest to wczesna wersja beta z licznymi, częściowo już znanymi, problemami. W rezultacie nie jest zalecana jej instalacja na komputerach wykorzystywanych do codziennej pracy. Przy okazji wypuszczenia bety Windows 7 pojawiły się nowe informacje odnośnie premiery nowego systemu rodem z Redmont. Microsoft jak dotąd stanowczo zapewniał, że premiera nowych Okienek odbędzie się jeszcze w 2009 roku. Okazuje się jednak, że producent po cichu przygotowuje producentów

sprzętu na to, że wydanie nowego systemu może nastąpić nieco później. Podczas targów CES w Las Vegas Bill Veghte, jeden z menedżerów działu Windows w firmie Microsoft, mówił w wywiadzie dla CNET, że producenci sprzętu są przygotowywani na termin tegoroczny i przyszłoroczny. Wydamy system dopiero wtedy, gdy jego jakość będzie zadowalająca - tłumaczył Veghte. Dał również do zrozumienia, że na moment premiery może mieć wpływ sytuacja ekonomiczna, a konkretnie konieczność zaciskania pasa przez Microsoft i cięcia finansowe w marketingu. Co prawda, jak na razie są to tylko spekulacje i być może żadnych opóźnień nie będzie, aczkolwiek – jeśli takowe się pojawią, to mogą być fatalne w skutkach dla Microsoftu; zwłaszcza rozmowy z producentami sprzętu są w tym przypadku krytyczne. To między innymi na skutek wielokrotnego przekładania premiery Visty producenci sprzętu nie zdążyli na czas z przygotowaniem wielu sterowników, co wywołało falę niezadowolenia ze strony pierwszych użytkowników. http://www.microsoft.com/poland; http://www.cnet.com/

Jak wskazują wyniki badań opublikowanych przez NetTrack przeprowadzonych przez MillwardBrown SMG/KRC, już prawie połowa Polaków (47,1%) posiada dostęp do Internetu. Według badań za okres wrzesień - listopad 2008, 71,9 proc. osób mających dostęp do Internetu korzysta z niego codziennie, 17,5 proc. kilka razy w tygodniu, 5,2 proc. raz na tydzień, a 3,4 proc. kilka razy w miesiącu. Równy 1% badanych korzysta z Internetu raz na miesiąc lub rzadziej. Zdecydowana większość badanych (88 proc.) korzysta z Internetu w domu, jedna czwarta (23,7 proc.) w pracy, 9 proc. w szkole lub na uczelni, 6 proc. u znajomych, a 1 proc. w kawiarence internetowej lub w sklepie komputerowym. Najsilniejszą grupę internautów stanowią niezmiennie osoby w wieku pomiędzy 25 i 39 rokiem życia (36 proc.). Ponad połowa użytkowników (51 proc.) to mężczyźni korzystający z Internetu na ogół powyżej 5 lat poprzez stałe łącze. Najczęściej odwiedzana strona to Google. Ilość osób korzystających z Internetu w badanym okresie wzrosła o nieco ponad cztery punkty procentowe w stosunku do początku 2008 roku, kiedy liczba ta oscylowała w okolicach 45%. Oznacza to, że dynamika wzrostu popularności Internetu spadła, w ciągu 2007 roku wzrosła o ok. 10%. http://www.millwardbrown.com/pl

Jak bardzo Google zanieczyszcza środowisko?

Samsung będzie tworzył oprogramowanie w Warszawie

M

inisterstwo Gospodarki i Samsung Electronics Polska informują o rozpoczęciu wieloletniego programu inwestycyjnego w naszym kraju. Program zakłada powstanie w Warszawie Telekomunikacyjnego Centrum Badań i Rozwoju. Centrum będzie największym i głównym ośrodkiem rozwoju oprogramowania telekomunikacyjnego Samsung Group. Firma zainwestuje w Polsce blisko 25 milionów złotych i zatrudni 250 osób. Prace prowadzone będą głównie z myślą o oprogra-

mowaniu dla telefonów komórkowych typu smartphone i featurephone - znajdzie ono zastosowanie na platformach Windows, Linux i Symbian. Budżet państwa dodatkowo udzieli wsparcia finansowego w wysokości 3,7 mln złotych; Samsung łącznie wyda ponad 42 mln złotych. Szacuje się, iż do końca 2016 roku dzięki realizacji tej inwestycji do polskiego budżetu wpłynie około 23 mln złotych. http://www.mg.gov.pl/

Do ciekawych wniosków doszli autorzy wydanego jakiś czas temu raportu, który dowodził, że Google uwalnia do atmosfery taką samą ilość dwutlenku węgla w dwóch wynikach wyszukiwania, ile jest potrzebne do zagotowania czajnika wody. Jak wyjaśnia Google, zanieczyszczenie środowiska wynika z rosnącego zapotrzebowania na energię elektryczną potrzebną do zasilenia centrów danych. Te są wymagane, aby odpowiedzi na zapytania użytkowników pojawiały się w możliwie jak najkrótszym czasie. W ten sposób przez każdą sekundę połączenia z Internetem produkowanych zostaje 0,2 grama dwutlenku węgla. Typowe wyszukiwanie trwa 0,2 sekundy, zapytanie jest wysyłane i przetwarzane przez serwery w kilka tysięcznych sekundy. Pojedyncze wyszukiwanie zużywa 1kJ (0,0003 kWh), średnia dzienna dla dorosłego człowieka to 8000 kJ. Dla przykładu, ilość dwutlenku węgla emitowana przez samochód pokonujący trasę jednego kilometra - odpowiada tysiącowi zapytań. W 2008 roku Google zainwestowało 45 milionów dolarów na technologie energetyczne, zaś rok wcześniej zainicjowała grupę Climate Savers Computing Initiative zajmującą się cięciem kosztów energii. Na przyszły rok gigant z Mountain View planuje redukcję emisji CO2 o 54 milionów ton rocznie. http://neowin.net/

www.sdjournal.org

7

Aktualności
Microsoft Tag zamieni długie linki na obrazki

Podczas targów CES 2009 Microsoft ogłosił dostępność nowej usługi (na razie działającej w fazie beta): Microsoft Tag. Usługa ta umożliwia dostęp do zawartości on-line nie na podstawie tradycyjnych, długich linków, a specjalnych kodów graficznych. Kod (tag) to niewielki kwadrat z kolorowym wypełnieniem tworzącym unikalny wzór. Sama technika nie jest nowa, a idea funkcjonowania tej technologii jest bardzo prosta - wystarczy uruchomić aplikację skanującą w telefonie lub urządzeniu przenośnym wyposażonym w kamerę i skierować obiektyw na kod. W odpowiedzi, po rozpoznaniu kodu przez aplikację, od razu uruchamiana jest przeglądarka i strona przypisana do zeskanowanego wzoru. Microsoft Tag to jednak coś więcej niż tylko klon już istniejących usług tego typu, na przykład czarno-białych kodów QR. Proponowane przez Microsoft tagi korzystają z kolorowych wzorów i opierają się o bardziej nowoczesną technologię High Capacity Color Barcode, opracowaną notabene przez badaczy z Microsoft Research. Dzięki zastosowaniu kolorów przestrzeń potrzebna do przechowania tej samej informacji jest mniejsza, więc tag można łatwiej zmieścić na stronach gazet, plakatach czy nawet koszulkach lub samochodach. Microsoft Tag może wypróbować każdy; aplikacja na telefon dostępna jest do pobrania bezpłatnie, na tej samej stronie można znaleźć również testowy wzór do zeskanowania. Możliwe jest również stworzenie własnego tagu. W fazie beta komercyjne wykorzystanie tagów jest dozwolone bez żadnych opłat. http://www.microsoft.com/poland

Plany Apple na 2009 rok

P

hil Schiller na konferencji MacWorld Expo wygłosił keynote, w którym nakreślił plany Apple na rok 2009. Główną nowością, o której głośno było w Internecie, jest nowy, 17-calowy MacBook Pro. Nie będzie on co prawda posiadał wymienialnego akumulatora, ale jego wbudowana bateria ma wystarczać na 8 godzin pracy, tudzież na 7 - jeśli wykorzystywany będzie układ graficzny 9600GT zamiast 9400M. Niemożliwość samodzielnej wymiany baterii będzie rekompensowana przez opcję wymiany przez serwis. Nowy MacBook ma posiadać dysk twardy o pojemności 320 GB, 4 GB RAM i procesor 2,66 GHz. Cenę urządzenia ustalono na 2799$. Dostępna jest także wersja z matową matrycą, ostatnimi czasy bardzo rzadko spotykaną w notebookach, a dla wielu osób (szczególnie dla programistów) wygodniejszą od matrycy błyszczących. Kolejna ważna wiadomość to stopniowa rezygnacja z DRM w iTunes. Obecnie już 8 milionów utworów jest dostępnych bez tego zabezpieczenia, do końca marca będzie to ponad 10 milionów. W odpowiedzi na żądania koncernów fonograficz-

nych zdecydowano się też na elastyczne ceny, najtańsze utwory będą dostępne już od 69 centów. Najnowsze utwory mają kosztować 1,29 dolara. Apple ogłosiło także betę serwisu iWork.com, wzorowany na Google Docs. Będzie on dostępny w ramach pakietu iWork 2009 za opłatą, której wysokość zostanie ustalona później. Obecnie iWork 2009 dostępny jest w Apple Store za 79$ oraz w opcji „family pack” za 99$, gdzie nabywa się 5 licencji jednocześnie. Pakiet można też kupić za promocyjną cenę 49$ przy zakupie dowolnego komputera Mac. http://www.apple.com/

Renaissance – nowy interfejs OpenOffice.org

ICANN podsumowuje rok 2008

Organizacja ICANN (Internet Corporation for Assigned Names and Numbers), zajmująca się między innymi przyznawaniem domen internetowych, opublikowała raport na temat swojej działalności w roku 2008. Przygotowany raport koncentruje się na osiągnięciach i postępie organizacji w 2008 roku. Czołowe miejsce zajmuje proces uwalniania domen najwyższego poziomu (TLD) i umożliwienie ich rejestracji. Na dalszych pozycjach uplasowały się: wprowadzenie międzynarodowych nazw domen oraz prace nad zorganizowaniem konsultacji w sprawie mechanizmów zaufania pomiędzy podmiotami. Pozostała część przedstawia szczegóły biograficzne każdego zarządu spółki i najważniejsze plany organizacji. Prócz tego, dołączono raporty z działania departamentów korporacji, zawarto też krótką historię organizacji z podziałem na ponad trzydzieści międzynarodowych publicznych spotkań, jako że ICANN obchodził w ubiegłym roku dziesięciolecie istnienia. Pełna treść raportu jest dostępna na stronach ICANN (http: //icann.org/en/annualreport/annual-report2008-en.pdf) i liczy 133 strony. http://www.icann.org/

P

od koniec 2008 roku Frank Loehmann, lider projektu OOo User Experience, publicznie ogłosił zainicjowanie projektu „Renaissance”, którego celem jest przeprojektowanie interfejsu pakietu OpenOffice.org. W rzeczywistości projekt ten jest nieco starszy, gdyż jego początki sięgają czasów OOoCon’u 2008, które miało miejsce w Pekinie, we wrześniu. Do grupy OO.o UX dołączyli pracownicy firmy RedFlag, ci sami, którzy zaprojektowali interfejs RedOffice’a 4.0. Renaissance jest projektem długoterminowym i raczej niemożliwe jest, aby jakiekolwiek zmiany zauważono w zbliżających się wydaniach. Projekt został podzielony na trzy fazy: badania, projekt i ocena. Aktualnie prace skupione są na pierwszym etapie. By móc lepiej zrozumieć potrzeby użytkowników, OpenOffice.org 3.1 będzie dostarczany wraz z rozszerzeniem „User Feedback”, którego zadaniem jest zapisywanie danych na temat użytkowania aplikacji OO i przesyłanie ich w anonimowej formie do zespołu projektowego. Na razie użytkownicy mogą swoje opinie wyrazić za pośrednictwem internetowej ankiety. Wspomniane rozszerzenie będzie dostępne również dla OpenOffice.org w wersji 3.0.1,

jednak trzeba będzie je doinstalować ręcznie. Od momentu aktywacji dodatek zapisuje wszelkie interakcje użytkownika z programem, takie jak np. wywołania okien dialogowych, opcji menu, a także stosowanie skrótów klawiszowych. W drugim etapie drużyna Loehmanna zajmie się modelowaniem struktury menu, tak by najczęściej używane opcje były bardziej dostępne. Loehmann przy okazji poinformował, iż projekt nie będzie ograniczać się do możliwości technicznych obecnego toolkitu, a że zajmą się stworzeniem listy z wymaganiami (technicznymi i użytkowników), a drużyna odpowiedzialna za rozwój programu od strony wewnętrznej weźmie się za napisanie nowego szkieletu, który powinien w pełni sprostać oczekiwaniom. Misją projektu jest stworzenie takiego interfejsu użytkownika, aby Openoffice.org stał się wyborem użytkownika nie tylko z potrzeby, ale i z pożądania. Wszystkie informacje o postępach projektu mają być udokumentowane na oficjalnym blogu (http://ux.openoffice.org/blog/). Osoby niezadowolone z obecnego interfejsu OpenOffice.org zaproszone są do partycypowania w tym przedsięwzięciu. http://linuxnews.pl/

8

03/2009

Aktualności

Ruby on Rails 3 = RoR 2 + Merb

Windows 7 wydajniejszy niż Vista oraz XP

M

iły prezent przygotowali programistom deweloperzy frameworków Ruby on Rails oraz Merb. Projekty te połączą się w jeden twór, wraz z wydaniem RoR 3.0 w 2009 roku. Optymalizacje i rozszerzenia Merba zostaną przeportowane do Rails. Warto przypomnieć, iż framework Merb został stworzony przez Ezrę Zygmuntowicza mniej więcej dwa lata temu, jako lekka alternatywa dla Rails. Z czasem projekt zaczął się rozrastać, a oba projekty zaczęły dzielić ze sobą coraz więcej kodu. Deweloperzy obu szkieletów programistycznych doszli do wniosku, że razem zdziałają więcej niż osobno i że nie ma sensu powielać prac, gdy można działać razem. Istotą połączenia będzie przeniesienie części funkcji z Merba do Rails. Nie będzie całkowitego przepisania kodu, a raczej spokojne wdrażanie zmian i ulepszanie tego, co w Rails nie jest idealne. Rdzeń Rails pozostanie, jednak programiści połączonych projektów postarają się umożliwić uruchamianie go w uszczuplonej wersji, bez zbędnej funkcjonalności. Również optymalizacje wydajno-

ści z Merb zostaną przeniesione do Rails. Rails stanie się bardziej agnostyczne pod względem wyboru (narzucania użytkownikowi) technologii. Aktualnie stosowane rozwiązania będą wykorzystywane domyślnie (np. Active Record), ale łatwe będzie wymienienie ich na alternatywne odpowiedniki preferowane przez programistę (np. Sequel/Data do mapowania obiektowo-relacyjnego, Mapper czy jQuery dla Ajaksa). Nastąpi też powrót do idei rygorystycznego API. Zbyt wiele wtyczek przestaje działać po aktualizacji, co jest wynikiem słabego zaakcentowania, które części API Rails są stabilne, a które mogą być w najbliższej przyszłości modyfikowane. Samo Rails 3 nie będzie kompatybilne wstecz, aczkolwiek deweloperzy postarają się w miarę możliwości (i rozsądku) ułatwić migrację projektów zbudowanych na straszych wersjach RoR. Bardziej szczegółowe informacje na temat połączenia obydwu frameworków można znaleźć na dedykowanej stronie http://rubyonrails.org/merb. http://linuxnews.pl

Emotikona zastrzeżonym znakiem towarowym

Mimo że licencja dostępnych obecnie wersji beta Windows 7 zabrania wykonywania testów wydajności, pierwsze porównania zaczynają się już pojawiać. Jedno z nich przygotował Adrian Kingsley-Hughes z ZDNet. Na dwóch platformach sprzętowych (AMD Phenom 9700 2.4GHz z kartą ATI Radeon 3850 i 4 GB RAM oraz Intel Dual Core E2200 2.2GHz z kartą GeForce 8400 GS i 1 GB RAM) przeprowadził on dwadzieścia trzy testy wydajności Windows XP, Visty oraz najnowszego biulda Windows 7 o numerze kompilacji 7000. Testy obejmowały typowe scenariusze - od instalacji systemu, przez jego uruchomienie, zamknięcie, przeniesienie różnej wielkości plików między dyskami oraz przez sieć, kompresowanie danych, instalację Office 2007, operacje na dokumentach Word i Excel, wypalanie płyt oraz otwieranie dużych dokumentów PDF. Wynik każdej operacji był mierzony i zestawiany wynikami osiągniętymi na tej samej platformie sprzętowej przez inne systemy. Rezultaty tych testów wypadły bardzo pomyślnie dla Siódemki - niemal w każdej kategorii jej wydajność była większa niż Visty oraz Windows XP. Należy pamiętać że jest to nadal kompilacja testowa, której wydajność niemal zawsze (w przypadku produktów Microsoft) jest gorsza od wydajności finalnego produktu. http://neowin.net/

Microsoft Boku zmieniony na Kodu

O

leg Teterin, rosyjski biznesmen i prezes firmy telekomunikacyjnej Superfone, zarejestrował w rosyjskim urzędzie patentowym znak towarowy w postaci... emotikony uśmiechu, czyli sekwencji znaków dwukropka, łącznika i zamykającego nawiasu: :-). Dlaczego Teterinowi zależało na zastrzeżeniu emotikony? Biznesmen zapewnia, iż nie zamierza ścigać nadawców SMSów i e-maili, czy też użytkowników komunikatorów. Będzie jednak zwracał uwagę, czy firmy nie wykorzystują jego zastrzeżonego znaku do celów komercyjnych. Aby móc posługiwać się emotikoną będzie trzeba zapłacić i nabyć od Teterina roczną licencję. Ile konkretnie będzie taka licencja kosztować - tej informacji niestety biznesmen nie chce jeszcze zdradzić, jak mówi, kwota będzie liczona w dziesiątkach tysięcy dolarów. Warto nadmienić, że zastrzeżone są również znaki pochodne tworzone na podstawie oryginału, czyli takie jak na przykład :) czy ;). Jak nietrudno się domyślić, większość internautów na wiadomość o „przywłaszczeniu” przez Teterina emotikony reaguje z oburzeniem. Podstawy prawne

decyzji urzędu patentowego w tej sprawie są bardzo szeroko podważane przez światowych komentatorów. Faktycznie, trudno uwierzyć, że wykorzystywana od lat przez miliony ludzi na całym świecie sekwencja znaków została teraz własnością jednej osoby. Niektórzy zwracają uwagę, że to niebezpieczny precedens, inni mówią po prostu: absurd. Czas pokaże, czy Teterin będzie w stanie zarobić cokolwiek na swoim kontrowersyjnym pomyśle. Bez względu jednak na to, czy znak emotikony faktycznie należy do rosyjskiego biznesmena, czy nie - za pioniera uśmieszków nadal uważa się Scotta Fahlmana, amerykańskiego naukowca z Carnegie Mellon University, który w 1982 roku po raz pierwszy użył znaku :-) w wysłanej przez siebie wiadomości. http://news.bbc.co.uk/

Pierwsze informacje o projekcie Boku firmy Microsoft pojawiły się w zeszłym roku. Ten język programowania wizualnego przygotowywany przez giganta z Redmond zmienia teraz oficjalnie nazwę na Kodu. Jak ogłasza Microsoft, Kodu wystartuje na kanale Xbox LIVE Community Channel i (w skrócie) da zainteresowanym posiadaczom Xboksów 360 możliwość składania z gotowych klocków (jest ich ponad 200) własnych gier, wszystko przy użyciu standardowego kontrolera do konsoli. Projekt zadebiutować ma na wiosnę bieżącego roku. Kodu określane jest jako gra o sporych możliwościach kreacyjnych. W minut kilka da się przy jego pomocy złożyć całkiem zaawansowany, wyjątkowy świat, a to wszystko przy pomocy ikonkowego interfejsu. Wszystko opiera się na zasadzie akcji i reakcji. Dla bardziej leniwych użytkowników Kodu oferuje możliwość modyfikacji dostępnych poziomów. „Zrobiliśmy wszystko, co możliwe, aby upewnić się, że zabawa z Kodu jest nie tylko łatwa, ale również daje masę frajdy i wciągnie różnych odbiorców, w każdym wieku” - powiedział Matt MacLaurin, w głównej mierze odpowiedzialny za ten projekt. „Poprzez to, że interfejs Kodu jest tak intuicyjny i zapobiega najczęstszym błędom programistycznym, ułatwiamy wszystkim rozkoszowanie się magią tworzenia gier.” http://www.gamikaze.pl/

www.sdjournal.org

9

Aktualności
Android na netbookach

Wygląda na to, że opracowany przez Google dla telefonów komórkowych system operacyjny Android sprawdzi się także na netbookach. Dwóch współpracowników serwisu VentureBeat spędziło cztery godziny kompilując Androida na netbooka Asus EEEPC 1000H. Wynik ich eksperymentu był bardzo dobry. Działały prawie wszystkie urządzenia, w tym karta graficzna, dźwiękowa oraz WiFi. Było to możliwe dzięki temu, że Android jest oparty na Linuksie, który posiada sterowniki do wielu urządzeń. Niedawno także Dima Zavin, programista z Google, ogłosił, że udało mu się przeportować Androida na urządzenie Asus EeePC 701. Doniesienia te spowodowały, że zaczęto głośno mówić o wejściu Androida na rynek nie tylko netbooków, ale także notebooków, a nawet desktopów. Netbooki z Androidem mogłyby się pojawić nawet w ciągu trzech miesięcy. Przewiduje się jednak, że Android zyska większą popularność dopiero w 2010 roku. Pomóc ma mu w tym przeglądarka Google Chrome, mogąca stanowić platformę do uruchamiania wielu aplikacji. http://venturebeat.com/

Microsoft zapłaci 1,5 mld USD za Vista Capable?

P

ółtora miliarda dolarów, tyle może wynosić kara, jaką zapłacić będzie musiał Microsoft w wyniku głośnego procesu dotyczącego kampanii marketingowej Windows Vista Capable. W skierowanym do sądu apelacyjnego wnioskowi przeciwko Microsoft, konsumenci zarzucają, że w ramach rzekomego wprowadzania w błąd klientów dzięki zaniżaniu wymagań sprzętowych systemu certyfikowane były komputery, które raczej nie powinny posiadać loga świadczącego o zgodności sprzętu z najnowszym systemem. Nie umożliwiło to obsługi pozostałych edycji Visty z wyjątkiem Home Basic, między innymi graficznego interfejsu użytkownika Aero. To z kolei Microsoftowi pozwoliło wzbogacić się po-

przez zwiększenie popytu na słabsze konfiguracje. O orientacyjne oszacowanie wysokości dochodów uzyskanych przez Microsoft wskutek wyniku sprzedaży Windows XP na komputerach z logiem Vista Capable zamiast Vista Premium poproszony został Leffler Keith. Uznał, że zysk ten wyniósł 1,505 miliarda USD. Jeśli powodom uda się przekonać sąd, że Microsoft faktycznie wyrządził szkodę w wyniku akcji, może podjąć decyzję o ocenie rzeczywistej szkody współmiernie do wspomnianej kwoty. Inny scenariusz przewiduje nałożenie na firmę kary w wysokości trzykrotności ocenianej kwoty szkód. http://www.theinquirer.net/

Microsoft planuje redukcję zatrudnienia

Wygląda na to, że plotki o tym, jakoby w obliczu globalnego kryzysu Microsoft miał zacząć redukować zatrudnienie, przestają być plotkami - serwis Fudzilla powołując się na wewnętrzne źródła w korporacji informuje, że pracownicy Microsoftu zostali już poinformowani o planowanych na początku 2009 roku zwolnieniach na stosunkowo dużą skalę. Obecnie Microsoft zatrudnia mniej więcej 90 tys. ludzi na całym świecie i z tego co ustalił serwis Fudzilla, zwolnienia mogą objąć aż 15 tys. stanowisk - to niemal 17% całego stanu zatrudnienia, więc zdecydowanie niemało. Póki co nie wiadomo jeszcze, które jednostki organizacyjne lub regiony zostaną najmocniej dotknięte, nieoficjalnie wskazuje się na dział MSN oraz struktury regionu EMEA (Europe, Middle East and Africa), w skład których wchodzi także polski oddział. http://neowin.net/

Nokia wyda Qt 4.5 na licencji LGPL

N

okia podjęła decyzję o złagodzeniu licencjonowania biblioteki Qt. Najbliższe wydanie oznaczone numerem 4.5 będzie dostępne między innymi na licencji LGPL. Rok temu, kiedy Nokia kupiła Trolltech, firmę rozwijającą Qt i czerpiącą zyski z jej wolno-komercyjnej licencji (Qt dostępne było za darmo na GPL, ale tylko dla niekomercyjnych projektów udostępnionych na tej samej licencji, firmy sprzedające software musiały zakupić komercyjną licencję biblioteki), wszyscy zastanawiali się, w jakim kierunku nowy właściciel pokieruje rozwojem Qt. Teraz widać już, że ten kierunek to

otwartość. Nokia planuje wydanie Qt 4.5 na licencji LGPL, w celu zwiększenia zainteresowania tą biblioteką zarówno świata open source, jak i komercyjnego. Licencja LGPL umożliwia używanie kodu do komercyjnych celów bez opłat licencyjnych (choć zastosowanie dodatkowo biblioteki na GPL wymusza stosowanie dla projektu licencji GPL). Krok taki wynika z faktu, iż Nokia nie musi zarabiać na Qt tak, jak musiał robić to Trolltech. W jej interesie leży raczej zwiększenie popularności tej platformy, a zmiana licencji na pewno otworzy dla Qt nowe segmenty rynku. http://linuxnews.pl

30 lat więzienia dla ukraińskiego hakera

Turecki sąd skazał ukraińskiego hakera na 30 lat pozbawienia wolności i grzywnę w wysokości ok. 23 tysięcy dolarów. Maksym Jastremski został skazany za dokonanie serii ataków na dwanaście tureckich banków i liczne malwersacje finansowe. Haker został aresztowany 17 miesięcy temu w Antalii, śródziemnomorskiej prowincji Turcji. Wyrok jest surowy, choć dotyczył wyłącznie czynów popełnionych na terenie Turcji. Jastremski jest jednak dobrze znany nie tylko tamtejszym władzom. Stany Zjednoczone podejrzewają, że to właśnie on stał w 2007 roku za głośnymi atakami na TJX, operatora sieci sklepów w USA, które doprowadziły do ujawnienia danych kart kredytowych klientów. Śledztwo w tej sprawie nadal trwa. http://www.cnet.com/

Szwedzka Partia Piratów w Europarlamencie?

K

iedy ponad trzy lata temu startowała Szwedzka Partia Piratów, większość ludzi traktowała ją jako żart w stylu Polskiej Partii Przyjaciół Piwa. Okazuje się jednak, że czasy się zmieniły - ostatnie badania opinii publicznej pokazują, że 21% Szwedów rozważa głosowanie na Partię Piratów w nadchodzących wyborach do Parlamentu Europejskiego. Wśród młodych ludzi (18-29) wynik ten jest bezprecedensowy - aż 55%. Partia rośnie też w siłę - w ciągu ostatniego kwartału liczba jej członków wzrosła o 50% i przekroczyła liczebność Partii Zielonych, która ma obecnie 19 miejsc w

szwedzkim parlamencie. Bardzo dynamicznie rośnie też zainteresowanie i poparcie dla jej działań, w czym kluczową rolę odgrywa naturalnie Internet. Jak twierdzi lider Partii Piratów, Rick Falkvinge, miejsce w Europarlamencie jest obecnie jak najbardziej w zasięgu - potrzeba do tego 100 tys. szwedzkich głosów. Czy się uda – okaże się w czerwcu 2009 roku. Jeśli tak, będzie to wydarzenie całkowicie bezprecedensowe - po raz pierwszy realna siła polityczna ukształtowałaby się w odpowiedzi na potrzeby społeczności internetowej. http://torrentfreak.com/

10

03/2009

Aktualności

Internet lepszym źródłem aktualności niż prasa

Porządki w licencjonowaniu dla organizacji non-profit

A

merykańska organizacja The Pew Research Center for the People & the Press przeprowadzając ostatnie badania dotyczące czytelnictwa odkryła, że po raz pierwszy Internet wyprzedził prasę drukowaną jeśli chodzi o źródła pozyskiwania aktualności. Badania przeprowadzono między 3 a 7 grudnia 2008 roku na grupie 1489 dorosłych Amerykanów. Większość pytań dotyczyła reakcji na najważniejsze wydarzenia roku, część jednak sprawdzała, skąd respondenci dowiedzieli się o nich. Okazało się, że 40% ludzi aktualności krajowe i światowe czerpała z Internetu - to znaczny skok względem analogicznego badania w roku 2007, kiedy podobnie odpowiedziało jedynie 24% badanych. Niekwestionowanym liderem okazała się nadal telewizja, jednak i dla niej zapaliło się już ostrzegawcze światło - w badaniu ograniczającym grupę respondentów wyłącznie do młodych

ludzi, telewizja znacznie traci już na swoim znaczeniu i jako źródło pozyskiwania informacji pozycjonowana jest już na równi z Internetem. Warto zauważyć, że niektóre komentarze do tych badań ostrzegają, że nie ma z czego się cieszyć. O ile bowiem w oczach wielu ludzi Internet jest idealnym medium szybko i sprawnie identyfikującym najważniejsze wydarzenia, o tyle mało które witryny webowe mają zasoby niezbędne do przeprowadzania wnikliwych dziennikarskich analiz i śledztw, jakie wykonywanie są codziennie przez doświadczonych redaktorów dużych gazet - to, że treści internetowe są za darmo, odbija się niestety na ich jakości. Bez wątpienia jednak media internetowe bardzo szybko uczą się i dzięki rosnącemu znaczeniu jako atrakcyjny nośnik reklamy zyskują odpowiednie środki, by tą jakość poprawiać. http://people-press.org/

Apple, Google i Microsoft pozwani za naruszanie patentu

T

rzej giganci rynku IT, Apple, Google i Microsoft zostali podani do sądu za złamanie patentu firmy Cygnus Systems. Chroniona patentem technologia znajduje się w produktach takich jak: Windows Vista, Internet Explorer 8, Google Chrome, Mac OS X czy iPhone. Firma Cygnus Systems uważa, że wspomniane systemy i aplikacje używają chronionej funkcji podglądu plików, która pozwala użytkownikowi na podgląd zawartości dokumentu bez otwierania go. Spółka obrała sobie za cel liderów rynku informa-

tycznego, sprawdza jednak możliwe naruszanie patentu w produktach innych firm i rozważa skierowanie pozwu także przeciwko nim. Sporny patent został pierwotnie zgłoszony w 2001 roku, ale dopiero teraz Amerykańskie Biuro Patentowe przyznało go firmie. Jeśli sprawa zostanie rozstrzygnięta negatywnie dla Apple, Google i Microsoft, zobowiązani będą zapłacić odszkodowanie i opłaty licencyjne. http://www.edibleapple.com/

Koniec roku, czas więc na podsumowania i porządki - również w firmie Microsoft, która przeprowadza audyt wykorzystania licencji grupowych w obniżonej cenie dla organizacji non-profit, czyli w ramach programu Academic Volume. O skali tych porządków boleśnie przekonały się... domy spokojnej starości w Australii. Microsoft zakwestionował prawo do korzystania z programów licencjonowania Academic przez 1300 instytucji prowadzących 2900 placówek w Australii. Korporacja twierdzi, że tego typu instytucje nie mieszczą się w definicji organizacji uprawnionych do korzystania z programu. Sprawa jest o tyle poważna, że instytucje te z rozwiązań Microsoftu korzystają od lat, nic dziwnego więc, że cała infrastruktura zbudowana jest w oparciu o takie produkty jak Office, SharePoint i SQL Server. Teraz, by dalej z nich korzystać, trzeba zapłacić za licencje komercyjne - cztery razy więcej, niż dotychczas. Jest również dobra wiadomość - Microsoft przygotowuje specjalny program licencjonowania dla organizacji charytatywnych i non-profit, więc jeśli firma stanie na wysokości zadania i upora się szybko z przygotowaniami, być może w przypadku australijskich domów spokojnej starości i innych tego typu instytucji skończy się tylko na dyskusjach. Poza programami licencjonowania grupowego Microsoft systematycznie przekazuje podmiotom non-profit oprogramowanie również w formie zwyczajnej darowizny - w mijającym roku jego wartość wyniosła ponad 22 miliony dolarów. http://www.australianit.news.com.au/

22 korporacje pozwane o naruszenie patentu

Rok 2009 rokiem Linuksa na biurkach?

J

ak donosi serwis Bankier.pl, rok 2009 może się stać rokiem Linuksa. Ktoś może zapytać – a co dziennikarze takiego serwisu jak Bankier.pl mogą wiedzieć o technologii? Na technologii być może się nie znają, ale liczyć potrafią bardzo dobrze. Przyczyną sukcesu Linuksa w 2009 roku mają być netbooki – te małe, nieużyteczne i niedoceniane komputerki sprzedawane w milionach egzemplarzy, na których producenci bardzo często instalują Linuksa. Bankier.pl powołuje się na prognozy sprzedaży netbooków w 2009

roku, które mówią o sprzedaży do 8 milionów sztuk a w roku 2012 ma być sprzedanych ponad 50 milionów netbooków. Sprzedaż netbooków niewątpliwie przyczyni się do popularyzacji Linuksa, ale czy użytkownicy będą chcieli go używać, i czy będą z niego zadowoleni? Z danych udostępnionych niedawno przez firmę MSI wynika, że ma ona czterokrotnie więcej zwrotów netbooków z Linuksem niż z Windows. http://www.bankier.pl

22 korporacje, głównie wydawcy oprogramowania chroniącego przed wirusami i złośliwym oprogramowaniem, zostały pozwane przez Information Protection and Authentication of Texas (IPAT). Według IPAT, produkty pozwanych firm naruszają patenty, których jest właścicielem. Wśród pozwanych znaleźli się tacy giganci jak: Microsoft, Symantec, CA, Kaspersky, Novell, AVG czy Trend Micro. Konkretnie chodzi o dwa patenty: 5311591 zarejestrowany w maju 1994 oraz 5412717 zarejestrowany w maju 1995, oba zgłoszone przez Addisona M. Fischera i następnie kupione przez IPAT. Pierwszy z wymienionych patentów to innowacja dająca użytkownikowi kontrolę nad zachowaniem aplikacji przy neutralizowaniu działania złośliwych programów (malicious software). Drugi dotyczy zastosowania unikalnych identyfikatorów numerycznych (hash) do upewniania się, że działanie aplikacji (na przykład tarczy antywirusowej) nie zostało zablokowane. Jak na razie żadna z pozwanych firm nie odpowiedziała na oskarżenia. Nie wiadomo też, czy IPAT domaga się, poza prawnym nakazem zakończenia działań naruszających patent, odszkodowania lub rekompensaty. http://www.arstechnica.com/

www.sdjournal.org

11

Biblioteka miesiąca

Biblioteka Luabind
Wygodne łączenie języków Lua i C++
Lua oraz C++ bardzo dobrze uzupełniają się jako języki programowania; niestety – ich łączenie przy pomocy podstawowego API opartego na czystym C jest delikatnie mówiąc – zniechęcające. Na pomoc przybywa Luabind: nowoczesna biblioteka C++, dzięki której łączenie Lua i C++ staje się proste i przyjemne.
Dowiesz się:
• W jaki sposób odbywa się łączenie języków Lua i C++ na bazie podstawowego API opartego na czystym C; • W jaki sposób można usprawnić ten proces przy pomocy biblioteki Luabind; • W jaki sposób języka Lua może stanowić dopełnienie języka C++.

Powinieneś wiedzieć:
• Jak programować w języku C++.

Poziom trudności

J

ęzyk C++ jest to niewątpliwie potężny język programowania, aczkolwiek – posiada pewne ograniczenia. Przekonał się o tym zapewne niejeden programista C++, któremu przyszło popracować z bardziej dynamicznymi językami programowania (np. Perl, Python czy Ruby). C++, który oferuje niezwykle bogaty wachlarz mechanizmów abstrakcji operujących na etapie kompilacji (chociażby potężny mechanizm szablonów), pozostawia swoim użytkownikom wyraźny niedosyt w zakresie bardziej zaawansowanych mechanizmów działających w czasie wykonania programu. Brakuje chociażby mechanizmu refleksji czy możliwości wygenerowania i wykonania w locie fragmentu kodu. Trudno powiedzieć, że są to wady C++. Taki stan rzeczy wynika z filozofii języka, a w zamian użytkownicy C++ otrzymują inne, potężne możliwości. Na szczęście, siła języka C++ polega również na tym, iż brak niektórych jego właściwości można sobie zrekompensować korzystając z dedykowanych rozwiązań bibliotecznych. W niniejszym artykule przedstawię w jaki sposób można łączyć C++ ze skryptowym językiem Lua wykorzystując bibliotekę Luabind. Dzięki takiemu zabiegowi przed programistą C++ otwiera się ocean nowych możliwości: może on na etapie wykonania programu uruchamiać skrypty za12

pisane w zewnętrznych plikach, a także generować i wykonywać skrypty zapisane w pamięci. Co więcej, w przypadku Lua istnieje możliwość eksponowania konstrukcji (np. zmiennych, funkcji, czy klas) opisanych w C++ i odwoływanie się do nich z poziomu skryptów. Ogólny zarys tego jakie możliwości i zarazem, jakie zagrożenia wiążą się z wykorzystaniem skryptów przedstawiłem w ramce Skrypty: zastosowania. Struktura niniejszego artykułu jest następująca: na początku zaprezentuję podstawowe mechanizmy integracji obydwu języków (uruchamianie skryptów, eksponowanie konstrukcji) w oparciu o podstawowe API udostępnione w czystym C. W dalszej kolejności zaprezentuję możliwości biblioteki Luabind. Podejście takie zastosowałem z dwóch powodów: po pierwsze – przedstawienie możliwości Luabind na tle mechanizmów podstawowych pozwala wyraźnie wyeksponować siłę tej biblioteki, a po drugie – daje ono pełniejszy obraz tematu, szczególnie dla Czytelników nieobeznanych z tym zagadnieniem. Osoby, które dobrze znają podstawowe mechanizmy integracji Lua i C++, a chciałyby zapoznać się z możliwościami prezentowanej biblioteki, mogą rozpocząć lekturę niniejszego artykułu od podpunktu Luabind nadciąga z odsieczą!

tu Lua, który z kolei uruchomimy z programu napisanego w C++. Pierwszą czynnością, którą należy wykonać, to konfiguracja środowiska pracy. Osoby korzystające z pakietu Visual Studio C++ zapraszam do przestudiowania zawartości ramki Szybki Start: Lua. Użytkownicy alternatywnych środowisk deweloperskich w ramce W sieci znajdą odnośniki do stron, na których można znaleźć odpowiednie instrukcje postępowania odnośnie konfiguracji. Gdy środowisko pracy jest już gotowe, należy wpisać i skompilować program przedstawiony na Listingu 1. Rozważmy krok po kroku, co się dzieje we wspomnianym programie. Na początek, dołączamy odpowiednie nagłówki. Z punktu widzenia integracji naszego programu ze skryptami Lua, uwagę należy zwrócić na nagłówek lua.hpp. Kolejna, interesująca nas instrukcja znajduje się wewnątrz funkcji main():
lua_State* pL = lua_open();

W powyższym wywołaniu tworzony jest obiekt reprezentujący kontekst wywołania naszego skryptu (bądź skryptów), będziemy ją przekazywać do wszystkich funkcji wywoływanych z
�����������������

���

��

���

��

���

��

���

��

Pierwszy skrypt
Zgodnie z tradycją, nasze rozważania rozpoczniemy klasycznym przykładem typu Witaj Świecie! Tym razem postaramy się jednak, aby powitalny komunikat został wyświetlony z poziomu skryp-

���

��

Rysunek 1. Koncepcja indeksowania wirtualnego stosu biblioteki Lua

03/2009

Biblioteka Luabind

biblioteki Lua. W kolejnych pięciu instrukcjach (luaopen _ *) aktywujemy dostęp do standardowych bibliotek języka Lua. Sercem omawianego przykładu jest instrukcja if, w której wywołuje-

my funkcję luaL_dofile(), przekazując do niej dwa parametry: kontekst oraz nazwę pliku, w którym zapisany jest skrypt do uruchomienia. Jeśli wartość zwrócona ze wspomnianej funkcji jest

Skrypty: zastosowania
Skryptowanie (ang. scripting) jest dość modnym tematem wśród programistów C++; szczególnie często słyszy się o nim w kontekście produkcji gier. Czytelnicy, którzy mieli okazję grać w takie tytuły jak Far Cry, Crysis, Grim Fandango, Escape from Monkey Island, Heroes of Might and Magic V, World of Warcraft czy Witcher – chcąc nie chcąc mieli do czynienia ze skryptami Lua. Lista gier wykorzystujących ten, bądź alternatywne języki skryptowe jest bardzo długa. Ze skryptów korzysta też wiele aplikacji użytkowych (np. Adobe Photoshop Lightroom, Celestia, Monotone). W tym miejscu postaram się odpowiedzieć w skrócie na pytanie: dlaczego warto rozważyć wykorzystywanie skryptów w programach – szczególnie w tych, które powstają na bazie kompilowanych języków programowania (takich jak C++)? Kluczem do odnalezienia odpowiedzi na przedstawione wyżej pytanie może być hasło data driven developemnt. Idea tworzenia programowania sterowanego danymi zakłada, iż oprogramowanie powinno być tworzone w taki sposób, aby jego konfiguracja odbywała się możliwie jak najczęściej na bazie danych zapisanych w zewnętrznych, łatwo dostępnych repozytoriach (np. w plikach tekstowych). W myśl tej zasady, wszelkie stałe kontrolujące zachowanie programu oraz wybrane elementy logiki powinny być zdefiniowane poza programem, w taki sposób aby było je można łatwo modyfikować. Podstawowe zalety takiego podejścia to: • • • • • Oszczędność czasu (łatwiej jest modyfikować zachowanie programu; nie trzeba za każdym razem przebudowywać źródeł), Zwiększenie wydajności pracy, Obniżenie kosztów pracy (wyeksponowane aspekty działania programu mogą być dostrajane przez mniej wykwalifikowanych pracowników, np. testerów), Zwiększenie kreatywności (łatwiej i szybciej możne wdrażać i testować nowe pomysły), Zwiększenie rozszerzalności i elastyczności tworzonego oprogramowania,

różna od zera, to oznacza, że uruchomienie skryptu z jakiegoś powodu nie powidło się; w takim przypadku nasz program wypisuje odpowiedni komunikat o błędzie. To czego jeszcze nam brakuje to zawartość skryptu hello.lua., która wygląda następująco:
print( "Hello from Lua!" )

Języki skryptowe pokroju Lua nadają się bardzo dobrze do opisanych wyżej celów; można je w relatywnie prosty sposób łączyć z językami kompilowanymi, są stosunkowo nietrudne do nauki (np. Lua można bez problemu użyć do tworzenia prostych plików konfiguracyjnych), a jednocześnie – gdy zachodzi taka potrzeba – oferują pełną moc języka programowania. Kluczowe jest również tworzenie dwustronnych wiązań pomiędzy językami. Chodzi o to, aby mieć zarówno możliwość wywoływania funkcji zdefiniowanych w skrypcie z poziomu języka kompilowanego, jak i odwrotnie. Np. częstą praktyką przy tworzeniu gier jest eksponowania interfejsów wybranych modułów, tak aby zachowanie rozgrywki można było łatwo kontrolować z zewnątrz. Jak wszystkie narzędzia, również mechanizm skryptowania może być nadużywany. Przy projektowaniu systemu korzystającego ze skryptów trzeba bardzo dokładnie przemyśleć, która część logiki zostanie wyeksponowana. Niestety, często zdarzają się przypadki, kiedy rozentuzjazmowani programiści idą na przysłowiową całość i w rezultacie prawie cała aplikacja tworzona jest w języku skryptowym. To z kolei może odbić się negatywnie na wydajności; skrypty też w większości przypadków o wiele trudniej jest debugować (chociażby w porównaniu do programu pisanego w C++).

Po uruchomieniu opisanego wyżej przykładu, program powita nas przyjaznym komunikatem: Hello from Lua! W tym miejscu należałoby opisać nieco szerzej możliwości języka Lua. Dogłębne przedstawianie tego tematu wykracza poza ramy niniejszego artykułu. Żądnych wiedzy Czytelników zapraszam do przestudiowania treści ramki Lua: przegląd możliwości języka (tutaj można znaleźć podstawowe informacje o składni i konstrukcjach stosowanych w Lua), oraz W sieci – gdzie umieściłem odnośniki do bardziej szczegółowych materiałów edukacyjnych w tym temacie. Gorąco zachęcam Czytelników do poeksperymentowania z językiem Lua; można do tego wykorzystać lekko zmodyfikowaną wersję programu z Listingu 1. Zamiast oryginalnej instrukcji if, należy wpisać:
if ( int error = luaL_dofile( pL, argv[ 1 ] ) != 0 )

Pozwoli to wczytywać dowolne skrypty przez podawanie odpowiednich ścieżek w postaci argumentów wiersza poleceń przy kolejnych wywołaniach programu.
Listing 1. Uruchomienie zewnętrznego skryptu Lua z programu C++
#include <iostream> #include <lua.hpp> int main() { using namespace std;

Szybki start: Lua
• • • • • •

Aby rozpocząć pracę z biblioteką Lua należy wykonać następujące czynności (uwaga: poniższa instrukcja odnosi się do użytkowników pakietu Visual Studio w wersji 7 oraz wyższych): Pobrać binarną dystrybucję biblioteki Lua (patrz: ramka W Sieci) i rozpakować ją do wybranego katalogu (LUA_ROOT), Stworzyć w Visual Studio nowy projekt C++ W ustawieniach projektu (C/C++ -> General) ustawić dodatkowy katalog do wyszukiwania plików nagłówkowych: LUA_ROOT/include, W ustawieniach projektu (Linker -> General) ustawić dodatkowy katalog do wyszukiwania bibliotek: LUA_ROOT. W ustawieniach projektu (Linker -> Input) dodać bibliotekę lua5.1.lib, Skopiować plik LUA_ROOT/lua5.1.dll w miejsce rozpoznawane przez aplikację (np. C:\ Windows\System32).

lua_State* pL = lua_open(); luaopen_base( pL ); luaopen_string( pL ); luaopen_table( pL ); luaopen_math( pL ); luaopen_io( pL );

if ( int error = luaL_dofile( pL, "hello.lua" ) != 0 )

Szybki start: Luabind
Aby rozpocząć pracę z biblioteką Luabind należy wykonać następujące czynności (uwaga: poniższa instrukcja odnosi się do użytkowników pakietu Visual Studio w wersji 7 oraz wyższych): • • • • Wykonać kroki opisane w ramce Szybki start: Lua, Pobrać dystrybucję biblioteki (patrz: ramka W Sieci) i rozpakować ją do wybranego katalogu (LUABIND_ROOT), W ustawieniach projektu (C/C++ -> General) ustawić dodatkowy katalog do wyszukiwania plików nagłówkowych: LUABIND_ROOT, Dodać pliki źródłowe z katalogu LUABIND_ROOT/src do projektu.

{

cout << "\n[C++]: ERROR(" << error << "): Problem with lua << endl;

script file!\n\n"

} }

return 0;

return 1;

www.sdjournal.org

13

Biblioteka miesiąca Wirtualny stos, czyli rozmowy kontrolowane
Lua i C++ jako języki programowania są diametralnie różne, zarówno na poziomie konstrukcji jak i wykorzystywanych typów danych (patrz: ramki Lua: przegląd możliwości języka). W tej sytuacji oczywiste jest, że trudno byłoby zrealizować bezpośredni mechanizm komunikacji pomiędzy nimi. Aby rozwiązać ten problem autorzy biblioteki Lua wprowadzili dodatkowy poziom abstrakcji w postaci wirtualnego stosu, który służy do komunikacji pomiędzy obydwoma językami. Koncepcja komunikacji jest bardzo prosta. Dla przykładu – jeśli z poziomu języka C++ chcielibyśmy wywołać funkcję Lua, to na stos powędruje najpierw obiekt tę funkcję reprezentujący, a później – argumenty. W dalszej kolejności program C++ daje sygnał do biblioteki, że chciałby wywołać funkcję. W tym momencie po stronie Lua ze stosu zdejmowane są parametry i obiekt reprezentujący funkcję, po czym następuje wywołanie. Opisany tu pokrótce proces będzie opisany bardziej szczegółowo w kolejnych podpunktach niniejszego tekstu. Wirtualny stos Lua ma dość ciekawą właściwość. Oprócz standardowych operacji (włożenie nowego elementu na wierzchołek i zdjęcie elementu z wierzchołka) użytkownik ma możliwość odwoływania się do konkretnych elementów stosu przy pomocy indeksów. Co więcej – oprócz zwyczajnego indeksowania liczbami dodatnimi, do elementów stosu można odwoływać się przy pomocy liczb ujemnych (np. liczba -1 reprezentuje wierzchołek stosu). Koncepcja ta jest przedstawiona w sposób wizualny na Rysunku 1.

Listing 2. Dostęp do zmiennych Lua z poziomu programu C++
#include <cassert> #include <string>

#include <iostream> #include <lua.hpp>

using namespace std; int main() {

int run_lua_script( lua_State* pL, const char* name );

Dostęp do zmiennych Lua z poziomu programu C++
Na początek przeanalizujmy najprostszy z możliwych scenariuszy: dostęp do globalnych zmiennych skryptu Lua z poziomu programu napisanego w języku C++. Rozważmy następujący, prosty skrypt:
url = "http://www.sdjournal.org/" id = 17

lua_State* pL = lua_open(); luaL_openlibs( pL ); { } if ( run_lua_script( pL, "vars.lua" ) ) return 1;

lua_settop( pL, 0 );

lua_getglobal( pL, "url" ); lua_getglobal( pL, "id" ); { if ( !lua_isstring( pL, 1 ) ) cout << "[C++]: ERROR: Invalid type! (number expected)\n"; return 1;

Na Listingu 2 pokazany jest przykładowy program, który pobiera wartości zmiennych zdefiniowanych w powyższym skrypcie. Na początek warto zwrócić uwagę na deklarację funkcji:
int run_lua_script( lua_State* pL, const char* name )

}

string url = lua_tostring( pL, 1 ); cout << url << endl; { if ( !lua_isnumber( pL, 2 ) ) cout << "[C++]: ERROR: Invalid type! (number expected)\n"; return 1;

}

int id = ( int )lua_tonumber( pL, 2 ); cout << id << endl; } return 0;

Lua: przegląd możliwości jezyka
Język Lua dość diametralnie różni się do C++. Przede wszystkim jest on dynamicznie typowany. Dzięki temu w skrypcie Lua możemy zapisać następującą sekwencję instrukcji:
name = "Ola" x = 44 x = name

Lua oferuje 8 typów podstawowych: Nil (oznacza, że dana zmienna nie ma żadnego typu), Number (liczba; warto zauważyć, iż wszystkie wartości liczbowe w Lua reprezentowane są jako wartości zmiennoprzecinkowe), String (napis), Boolean (typ logiczny), Function (w Lua funkcja traktowana jest jako pełnoprawny typ; np. można ją przypisać do zmiennej i przekazać ją do innej funkcji), Table (tablica), UserData (pomocnicy typ wspomagający integrację Lua z językami C/C++) oraz Thread (wątek). Oprócz tego Lua oferuje podstawowe operatory oraz instrukcje sterujące. Język ten pozwala również definiować klasy. Przykładowe, proste skrypty Lua można znaleźć w dołączonych Listingach, aczkolwiek pełne przedstawienie możliwości tego języka zdecydowanie wykracza poza ramy niniejszego artykułu. Czytelników, którzy chcieliby nauczyć się języka Lua zapraszam do zapoznania się z dokumentacją oraz samouczkami wskazanymi w ramce W Sieci.

Funkcja ta opakowuje kod odpowiedzialny za uruchomienie skryptu Lua i wyświetlenie komunikatu o błędzie; będziemy ją jeszcze wielokrotnie wykorzystywać w kolejnych przykładach. Definicję funkcji umieściłem na Listingu 3. Rozważmy teraz po kolei co dzieje się w funkcji main() przedstawionej na Listingu 2. Na początku tworzony jest kontekst Lua, dalej – wczytywane są biblioteki (tym razem robimy to przy pomocy pojedynczej funkcji luaL_openlibs()). Następnie wykorzystujemy funkcję run_lua_script() w celu uruchomienia skryptu. Warto w tym miejscu zauważyć, iż tym razem działanie skryptu jest niewidoczne – dzieje się tak, ponieważ rozważany skrypt nie zawiera żadnych operacji wyjścia; w zamian za to, w obiekcie reprezentującym stan pojawiają się dwie zmienne globalne, te do których postaramy się uzyskać dostęp. Aby odwołać się do wspomnianych zmiennych z poziomu języka C++, musimy załadować je na wirtualny stos. Służy do tego funkcja lua_ getglobal(). Zanim to jednak uczynimy, stos powinien być wyczyszczony za pomocą operacji lua_settop( pL, 0 ); dopiero po tym lądują na nim po kolei zmienne: url oraz id. Zanim pobierzemy wartości zmiennych ze stosu, warto upewnić się, czy mają one rzeczywiście taki typ, którego się spodziewamy. Służy to tego
03/2009

14

Biblioteka Luabind

specjalny zestaw operacji (patrz Listing 4). Operacje te odpowiadają poszczególnym typom języka Lua. Na Listingu pokazane jest w jaki sposób można jest wykorzystać w celu weryfikacji typu obiektów umieszczonych na stosie. Wreszcie, przy pomocy funkcji z rodziny lua_to* (patrz Listing 5) można pobrać interesującą nas wartość ze stosu i zachować w zmiennej zdefiniowanej w programie C++. W rozpatrywanym przykładzie wykorzystujemy funkcje lua_tostring() oraz lua_tonumber(). W przypadku tej ostatniej konieczne jest dodatkowe rzutowanie na interesujący nas typ; w Lua wszystkie wartości numeryczne reprezentowane są przy pomocy zmiennych typu double (reprezentację tę można zmienić, w tym celu należy przebudować bibliotekę).

pomocy znajomej funkcji lua _ tostring() – pobrać interesującą nas wartość.

Dostęp do funkcji C++ z poziomu programu Lua
W niniejszym podpunkcie opiszemy przypadek odwrotny do tego, który omówiony został wcześniej: rozważymy eksponowanie funkcji zapisanych w języku C++ dla skryptów Lua. Aby uzyskać tego rodzaju efekt, programista zmuszony jest dostosować eksponowaną funkcję do następującego interfejsu:
int (lua_CFunction*) (lua_State*)

Dostęp do funkcji Lua z poziomu programu C++
Idąc o krok dalej – sprawdzimy teraz w jaki sposób można wywołać funkcję zdefioniowaną w skrypcie Lua z poziomu programu C++. Na początek zdefiniujmy sobie prostą funkcję w Lua, która sumuje wartości z przedziału <a, b> (Listing 7). Program C++ wywołujący tę funkcję przedstawiony jest na Listingu 8. Początek rozważanego przykładu jest identyczny w stosunku do swoich poprzedników, do momentu kiedy umieszczamy na stosie obiekt globalny, reprezentujący interesującą nas funkcję. W dalszej kolejności musimy umieścić na stosie argumenty funkcji:
lua_pushnumber( pL, 1 );

Dostęp do tablicy Lua z poziomu programu C++
Jako kolejny przykład interakcji pomiędzy Lua i C++ rozważymy proces uzyskania dostępu do tablicy Lua z poziomu programu C++. Na początek zapraszam Czytelników do zapoznania się z Listingiem 6. W tym przypadku sprawa jest odrobinę bardziej skomplikowana. Kłopot w tym, że tablice Lua są w rzeczywistości kontenerami asocjacyjnymi (patrz: ramka Lua: przegląd możliwości języka) i aby dostać się do określonego elementu musimy podać właściwy klucz. Na dodatek wspomniany klucz może być dowolnego typu. Na potrzeby rozważanego przykładu, zakładamy iż zawartość skryptu table.lua jest następująca:
user_data = { name="Monika", age=4 }

Najprostszą techniką pozwalającą uzyskać tego rodzaju efekt jest opakowywanie (ang. wrapping). Przykład udostępnienia funkcji C++ dla skryptu Lua pokazany jest na Listingu 9. Funkcja, którą eksponujemy w tym przykładzie ma następującą sygnaturę:
void print_ntimes( const string& str, int n )

lua_pushnumber( pL, 100 );

Kluczowym elementem w tym przykładzie jest wywołanie funkcji lua _ call(). Funkcja ta przyjmuje trzy argumenty: stan, ilość argumentów wywoływanej funkcji oraz ilość zwracanych przez nią elementów. Po jej wywołaniu na wierzchołku stosu pojawiają się wspomniane elementy.
Listing 3. Definicja funkcji run_lua_script()

Jej zadanie jest banalne: n razy wyświetla zadany napis. Aby zrealizować postawione zadanie, definiujemy funkcję opakowującą o następującej sygnaturze:
int print_ntimes( lua_State* pL )

int run_lua_script( lua_State* pL, const char* name ) { if ( int error = luaL_dofile( pL, name ) != 0 ) { cout << "\n[C++]: ERROR( " << error << " ): Problem with lua script file!" return 1; << endl;

Zadaniem programu przedstawionego na Listingu 6 jest odczytanie zawartości komórki tablicy identyfikowanej przez klucz name. W tym celu najpierw należy umieścić wspomnianą tablicę na stosie:
lua_getglobal( pL, "user_data" );

} }

return 0;

Po upewnieniu się iż mamy rzeczywiście do czynienia z tablicą, wrzucamy na stos nazwę interesującego nas klucza przy pomocy funkcji lua _ pushstring() Warto zauważyć, iż tym razem . stos został wykorzystany jako kanał komunikacyjny w drugą stronę: dane zostały wysyłane z programu C++ do skryptu Lua. Dalej mamy następujące wywołanie:
lua_gettable( pL, -2 );

Listing 4. Funkcje sprawdzające typ wartości przechowywanej w określonej komórce stosu
int lua_type( lua_State *pL, int index ); int lua_isnil( lua_State *pL, int index );

int lua_isboolean( lua_State *pL, int index ); int lua_isnumber( lua_State *pL, int index ); int lua_isstring( lua_State *pL, int index ); int lua_istable( lua_State *pL, int index ); int lua_isfunction( lua_State *pL, int index ); int lua_isuserdata( lua_State *pL, int index );

int lua_iscfunction( lua_State *pL, int index );

W tym miejscu dzieje się dość sporo interesujących rzeczy. Wewnątrz funkcji z wierzchołka stosu zdejmowana jest komórka reprezentująca klucz, a następnie z tablicy określonej indeksem przekazanym jako drugi argument funkcji (w naszym przypadku: -2) pobierana jest wartość dla wspomnianego klucza i po czym ląduje ona na wierzchołku stosu. Po wywołaniu tej funkcji warto sprawdzić czy typ pobranego obiektu odpowiada naszym oczekiwaniom, po czym – przy
www.sdjournal.org

Listing 5. Funkcje sprawdzające typ wartości przechowywanej w określonej komórce stosu
int lua_toboolean( lua_State *pL, int index ); lua_Number lua_tonumber( lua_State *pL, int index );

const char* lua_tostring( lua_State *pL, int index ); void* lua_touserdata( lua_State *pL, int index ); void* lua_topointer( lua_State *pL, int index );

lua_CFunction lua_tocfunction( lua_State *pL, int index ); lua_State* lua_tothread( lua_State *pL, int index );

15

Biblioteka miesiąca
Proces definiowania tej funkcji można opisać prostym algorytmem: • Na początku pobieramy rozmiar stosu przy pomocy funkcji lua _ gettop() i sprawdzamy, czy zgadza się ona z wymaganą liczbą argumentów eksponowanej funkcji. • Następnie sprawdzamy czy typy poszczególnych elementów umieszczonych na stosie zgadzają się z typami argumentów funkcji. • Pobieramy argumenty ze stosu i wywołujemy właściwą funkcję. • Jeśli funkcja zwraca jakąś wartość, bądź modyfikuje swoje argumenty to wyniki takowych działań należy umieścić na stosie. Funkcja opakowująca powinna zwracać wartość całkowitą określającą ilość elementów zwróconych z funkcji. W funkcji main() pokazane jest w jaki sposób można zarejestrować funkcję opakowującą w kontekście Lua co w rezultacie czyni ją widoczną dla wszystkich skryptów uruchamianych w tym kontekście:
lua_register( pL, "cxx_print_ntimes", print_ ntimes );

Listing 6. Dostęp do tablicy Lua z poziomu programu C++
#include <cassert> #include <iostream> #include <string>

#include <lua.hpp> using namespace std; int run_lua_script( lua_State* pL, );

const char* name

int main() {

stawowe mechanizmy integracji języków C++ oraz... skutecznie zniechęcić Czytelników do ich wykorzystywania. Trzeba powiedzieć to wprost: stosowanie wspomnianych mechanizmów zmuszają programistę to wykonywania żmudnej, powtarzalnej i podatnej na błędy pracy. Na dodatek większość z potencjalnych błędów manifestuje się dopiero na etapie działania programu, co dodatkowo utrudnia odpluskwianie programów. Tutaj na pomoc przychodzi nam biblioteka Luabind, która – wydawało by się – w magiczny sposób rozwiązuje wymienione wyżej problemy. Na początek rozważmy podobne przypadki, do tych, które zostały przedstawione w pierwszej części artykułu – tyle, że tym razem - z wykorzystaniem Luabind.

lua_State* pL = lua_open(); luaL_openlibs( pL );

Luabind: zaczynamy pracę
W niniejszym punkcie rozważymy w jaki sposób można rozpocząć pracę z biblioteką Luabind. Jeśli chodzi o konfigurację biblioteki, to zapraszam Czytelników do zapoznania się z treścią ramki Luabind: szybki start. W tym miejscu zakładam, że biblioteka jest pomyślnie zainstalowana oraz skonfigurowana i możemy skupić się na programowaniu. Na Listingu 10 przedstawiłem krótki program, który pokazuje jak niewiele pracy potrzeba aby rozpocząć korzystanie z Luabind. Na początek należy dołączyć dwa nagłówki: lua.hpp oraz luabind.hpp. Dalej, tworzymy kontekst Lua przy pomocy znajomej nam lua_ open(), po czym przekazujemy utworzony obiekt do funkcji luabind::open(). I na tym w zasadzie kończy się inicjacja biblioteki. W miejscu zaznaczonym komentarzem z trzema kropkami można już wstawić kod korzystający z dobrodziejstw Luabind. Rozważmy pierwszy scenariusz wykorzystania biblioteki.

if ( run_lua_script( pL, { }

"table.lua" ) )

return 1;

lua_settop( pL, 0 );

lua_getglobal( pL, "user_data" ); if ( !lua_istable( pL, 1 ) ) { cout << "\n[C++]: ERROR: Invalid type! (table return 1;

expected)\n";

Drugi argument przekazywany do funkcji lua _ register() określa symbol reprezentujący zarejestrowaną funkcję w skrypcie. W kontekście rozpatrywanego przykładu skrypt cxx.lua mógłby wyglądać następująco:
print("Hello from Lua");

}

lua_pushstring( pL, "name" ); lua_gettable( pL, -2 ); { if ( !lua_isstring( pL, -1 ) ) cout << "\n[C++]: ERROR: invalid type! (string return 1;

cxx_print_ntimes("Hello from C++", 3); print("Hello from Lua again");

Wyniki działania przykładu zaprezentowanego na Listingu 9 byłyby następujące: Hello from Lua Hello from C++ Hello from C++ Hello from C++ Hello from Lua again

Luabind: Dostęp do funkcji Lua z poziomu programu C++
Do przeanalizowania tego przypadku wykorzystamy zdefiniowaną wcześniej funkcję sum_range() (patrz: Listing 7). Na Listingu 11 pokazane jest, w jaki sposób można uzyskać dostęp do tej funkcji z poziomu programu C++, przy wykorzystaniu Luabind. Zanim przejdziemy do szczegółowej analizy wspomnianego Listingu, warto porównać go z zawartością Listingu 8, w ramach którego realizowaliśmy podobne zadanie – tyle, że z wykorzystaniem podstawowego API do integracji Lua i C++. Z miejsca rzuca się w oczy fakt, iż w przypadku korzystania z Luabind programista nie musi borykać się z takimi niskopoziomowymi szczegółami jak obsługa wirtualnego stosu Lua. Cała procedura wywołania funkcji zdefiniowanej w skrypcie sprowadza się do jednej linijki kodu:
luabind::call_function< int >( pL, "sum_ range", 1, 100 )

expected)\n";

}

string name = lua_tostring( pL, cout << "[C++]: name = " << name << lua_pop( pL, 1 ); } return 0; endl; -1 );

Dostęp do klas C++ z poziomu Lua
Przedstawione powyżej przykłady pokazały, że łączenie języków Lua i C++ nie jest trudne, aczkolwiek wiąże się ze sporym nakładem pracy, która w dużej mierze ma charakter powtarzalny. O ile w przypadku prostych typów danych (zmiennych, tablic czy funkcji) proces ten jest jeszcze znośny, o tyle w przypadku typów złożonych (klas) manualne ich eksponowanie może być prawdziwą katorgą dla programisty. W tym miejscu nie będę nawet pokazywał przykładu takiego procesu – w zamian za to przedstawię rozwiązanie, które znacznie ułatwi nam pracę w tym zakresie. Uwaga, uwaga...

Listing 7. Prosta funkcja zdefiniowana w języku Lua
function sum_range(a, b) sum = 0

for i = a, b, 1 do sum = sum + i

end end;

return sum

Luabind nadciąga z odsieczą!
Mam nadzieję, że w pierwszej części artykułu udało mi się w klarowny sposób zaprezentować pod-

Konstrukcja call _ function< int > jest instancją funkcji szablonowej; wywołując ja musimy przekazać parametr szablonu określający typ
03/2009

16

Biblioteka Luabind

zwracany z funkcji wywoływanej ze skryptu Lua (w naszym przypadku jest to int). Pierwszy parametr przekazywany do call _ function() to stan Lua, drugi to nazwa docelowej funkcji, następnie – argumenty tej funkcji. W naszym przypadku wywołujemy funkcję sum _ range() z parametrami 1 i 100; w wyniku otrzymujemy komunikat: sum_range( 1, 100 ) = 5050 przy czym wartość 5050 została obliczona i zwrócona z funkcji zdefiniowanej w skrypcie Lua. W sytuacji gdyby wywołanie funkcji nie powiodło się z jakiegoś powodu, call_ function() zgłosiłoby wyjątek luabind:: error.

Listing 8. Dostęp do funkcji Lua z poziomu języka C++
#include <cassert> #include <string>

#include <iostream> #include <lua.hpp>

using namespace std; int main() {

int run_lua_script( lua_State* pL, const char* name );

lua_State* pL = lua_open(); luaL_openlibs( pL ); { } if ( run_lua_script( pL, "func.lua" ) ) return 1;

Luabind: Dostęp do funkcji C++ z poziomu programu Lua
Rozważmy teraz przypadek, w którym chcielibyśmy udostępnić zadaną funkcję zdefiniowaną w programie C++ do skryptu Lua. Jako przykład wykorzystajmy ponownie funkcję print_ntimes(), zdefiniowaną na Listingu 9. Listing 12 zawiera program realizujący to zadanie przy pomocy Luabind. W tym przypadku przewaga Luabind nad manualnym mechanizmem eksponowania funkcji C++ do Lua jest wręcz porażająca. Wierzę, iż pierwsza myśl pojawiająca się w głowie niejednego Czytelnika brzmi: jak to działa? Magia Luabind opiera się na ciekawym paradygmacie programistycznym, tzw. metaprogramowaniu na bazie szablonów języka C++ (ang. template metaprogramming). Mówiąc w dużym uproszczeniu – kod podobny do tego, który tworzony jest manualnie w przypadku budowania funkcji opakowującej (patrz: Listing 9) – w przypadku Luabind generowany jest w trakcie kompilacji przy pomocy dedykowanego mechanizmu opartego na szablonach C++. Wszystko to dzieje się w linii:
luabind::module( pL )[ luabind::def( "print_ ) ];

lua_getglobal( pL, "sum_range" ); if ( !lua_isfunction( pL, -1 ) ) {

cout << "\n[C++]: ERROR: Invalid type! (function expected)\n"; return 1;

}

lua_pushnumber( pL, 1 ); lua_call( pL, 2, 1 );

lua_pushnumber( pL, 100 ); int result = static_cast< int >( lua_tonumber( pL, -1 ) ); lua_pop( pL, 1 ); } return 0;

cout << "[C++]: sum_range( 1, 100 ) = " << result << endl;

Listing 9a. Eksponowanie funkcji C++ dla skryptu Lua
#include <iostream> #include <string> #include <lua.hpp>

using namespace std; void print_ntimes( const string& str, int n ) { while ( n-- ) { } cout << str << endl;

ntimes", print_ntimes } {

W tym miejscu, w globalnej przestrzeni nazw umieszczona jest funkcja print _ ntimes(), przy czym jest ona związana (ang. bind) z funkcją o takiej samej nazwie – zdefiniowanej w naszym przykładowym programie. Voila! Zanim przejdziemy do kolejnego podpunktu, warto zwrócić uwagę, iż tym razem – dla odmiany – do uruchomienia testowego skryptu wykorzystałem funkcję luaL _ dostring(). Funkcja ta interpretuje skrypt zapisany w pamięci programu (w naszym przypadku jest to zwyczajna stała tekstowa).

int print_ntimes( lua_State* pL ) int argc = lua_gettop( pL ); if ( argc != 2 ) {

cout << "[C++]: print_ntimes: wrong number of parameters\n"; return 0;

} {

if ( !lua_isstring( pL, 1 ) && !lua_isnumber( pL, 2 ) ) cout << "[C++]: print_ntimes: invalid types passed\n"; return 0;

Luabind: Eksponowanie klas C++ dla skryptów Lua
Widząc jak łatwo przy pomocy Luabind można zrealizować podstawowe zadania związane z łączeniem języków Lua i C++, większość Czytelników domyśla się zapewne, iż wiązanie klas będzie równie proste. I tak właśnie jest w rzeczywistości.
www.sdjournal.org
}

}

string str = lua_tostring( pL, 1 ); print_ntimes( str, n ); return 0;

int n = static_cast< int >( lua_tonumber( pL, 2 ) );

int run_lua_script( lua_State* pL, const char* name );

17

Biblioteka miesiąca
Na Listingu 13 przedstawiona jest przykładowa klasa (point2d) reprezentująca punkt. Z kolei na Listingu 14 pokazane jest jak można uczynić tę klasę widoczną dla skryptów Lua. Rozważmy zawartość tych dwóch Listingów. Szkielet programu przedstawionego na wspomnianym Listingu jest bardzo podobny do tego, który zastosowaliśmy w przykładzie wiązania funkcji. Podstawową różnicą jest zastosowanie szablonu luabind::class_, który służy do eksponowania klas. W kolejnych liniach zawarte są instrukcje odpowiedzialne za generowanie kodu eksponującego dla poszczególnych składników klasy: na początku dwa konstruktory, następnie funkcja print oraz składowe. Przy tych ostatnich warto się na moment zatrzymać. Dla przykładu, linia
.property( "x", &point2d::get_x, &point2d:: set_x )

Listing 9b. Eksponowanie funkcji C++ dla skryptu Lua
int main() { lua_State* pL = lua_open(); luaL_openlibs( pL ); lua_register( pL, "cxx_print_ntimes", print_ntimes ); if ( run_lua_script( pL, "cxx.lua" ) ) { } } return 1;

return 0;

Listing 10. Rozpoczynamy pracę z Luabind
#include <lua.hpp> int main() { #include <luabind/luabind.hpp>

lua_State *pL = lua_open(); // ... luabind::open( pL ); return 0;

}

Listing 11. Dostęp do funkcji Lua z poziomu języka C++, zrealizowany przy pomocy Luabind
#include <lua.hpp> #include <luabind/luabind.hpp> #include <iostream>

definiuje tzw. właściwość klasy (ang. property) z możliwością jego odczytu za pomocą funkcji składowej get_x() oraz zapisu – przy pomoc set_ x(). Dzięki temu w kodzie skryptu możemy napisać następującą instrukcję:
p2.x = p1.y

using namespace std; int main() {

Na wyjściu przykładowego programu przedstawionego na Listingu 14 otrzymamy następujacy wynik: [2,4] [3,3] [4,10]

int run_lua_script( lua_State* pL, const char* name );

lua_State *pL = lua_open(); luabind::open( pL ); { } if ( run_lua_script( pL, "func.lua" ) == 1 ) return 1;

Zaawansowane możliwości Luabind
Przedstawione wyżej przykłady pokazują moc prostoty i elegancji drzemiącą w bibliotece Luabind, aczkolwiek stanowią one jedynie zalążek możliwości tej biblioteki. Języki C++ i Lua różnią się mocno od siebie i przy łączeniu ich razem pojawia się wiele wyzwań (podejrzewam, że co bardziej uważni i dociekliwi Czytelnicy sami zauważyli niektóre z nich, analizując zawartość prezentowanych wyżej Listingów). Luabind dokłada starań aby zaoferować wygodne mechanizmy wspomagające tę niełatwą integrację. Przedstawione powyżej udogodnienia będą zapewne wystarczające dla większości standardowych zastosowań, aczkolwiek prędzej czy później przyjdzie nam sięgnąć do arsenału bardziej zaawansowanych możliwości Luabind. Poniżej zaprezentowana jest pełna lista możliwości tej biblioteki: • Wiązanie wolnych funkcji (włącznie z przeciążaniem) • Eksponowanie klas C++ dla skryptów Lua, • Eksponowanie składowych klas dla skryptów Lua, • Eksponowanie właściwości (ang. properties) klas C++ dla skryptów Lua,
03/2009

cout << "sum_range( 1, 100 ) = " << endl;

<< luabind::call_function< int >( pL, "sum_range", 1, 100 )

}

return 0;

Listing 12. Dostęp do funkcji C++ z poziomu języka Lua, zrealizowany przy pomocy Luabind
#include <lua.hpp> #include <luabind/luabind.hpp> #include <iostream> using namespace std; int main() {

void print_ntimes( const string& str, int n ) { /* ... */ }

lua_State *pL = lua_open(); luabind::open( pL ); [ luabind::module( pL ) luabind::def( "print_ntimes", print_ntimes )

];

luaL_dostring( pL, "print_ntimes( \"Hello from Lua!\", 5 )\n" ); } return 0;

18

Biblioteka Luabind

• Eksponowanie enumeracji C++ dla skryptów Lua, • Eksponowanie funkcji Lua dla programów C++,

• Eksponowanie klas Lua dla programów C++, • Dziedziczenie klas (mechanizm ten działa zarówno z Lua do C++ jak i z C++ do Lua),

Listing 13. Przykładowa, prosta klasa reprezentująca punkt
class point2d { public:

• Przeciążanie funkcji wirtualnych z klas C++ w skryptach Lua, • Rozdzielne rejestrowanie modułów • Polityki wartości zwracanych i parametrów • Obsługa błędów • Obsługa wątków Lua Istota działania większość z wymienionych wyżej mechanizmów jest dość oczywista; w przypadku niektórych warto by pokusić się o dodatkowy opis – niestety, ze względu na ograniczenie długości niniejszego artykułu zmuszony byłem pominąć wspomniane opisy. W zamian za to – zapraszam zainteresowanych Czytelników do lektury materiałów odnoszących się do tych tematów, a dostępnych bezpłatnie w Internecie (patrz: ramka W sieci).

point2d( int x, int y ) : x_( x ), y_( y ) {} point2d( int x ) : x_( x ), y_( x ) {} int get_x() const { return x_; } void set_x( int x ) { x_ = x; } void set_y( int y ) { y_ = y; } void print() { } int get_y() const { return y_; }

cout << '[' << x_ << ',' << y_ << ']' << endl;

Luabind: ograniczenia
Nie ma róży bez kolców: Luabind również posiada pewne ograniczenia. Choć jest to nieco paradoksalne, podstawową wadą biblioteki jest jednocześnie to co stanowi o jej olbrzymiej mocy i użyteczności – mowa tu oczywiście o mechanizmie metaprogramowania bazującego na szablonach. Korzystanie z Luabind powoduje znaczący wzrost czasu kompilacji – zwłaszcza w przypadku projektów, w których rejestracja modułów odbywa się w wielu plikach źródłowych. Sami autorzy biblioteki zalecają zresztą aby (w miarę możliwości) wspomniana rejestracja odbywała się w ograniczonej liczbie plików (najlepiej w jednym). Niestety – problem ten dotyka praktycznie wszystkich bibliotek, które intensywnie korzystają z mechanizmów metaprogramowania opartego na szablonach języka C++.

private:

int x_; int y_;

};

Listing 14. Eksponowanie klasy C++ dla skryptu Lua przy pomocy Luabind
#include <lua.hpp> int main() { #include <luabind/luabind.hpp>

lua_State *pL = lua_open(); luabind::open( pL ); [ luabind::module( pL ) luabind::class_< point2d >( "point2d" )

.def( luabind::constructor< int, int >() ) .def( luabind::constructor< int >() ) .def( "print", &point2d::print )

Podsumowanie
W powyższym artykule przedstawiłem mechanizm integrowania języków Lua i C++ na bazie prostego API opartego na czystym C, pokazałem wady i ograniczenia takiego podejścia oraz zaproponowałem alternatywę w postaci biblioteki Luabind. Rozważając kolejne przykłady pokazałem jak wspomniane rozwiązanie pozwala łatwo i wygodnie łączyć dwa pięknie dopełniające się języki programowania. Gorąco zachęcam Czytelników do wypróbowania tego koktajlu – dzięki Luabind jest on zdecydowanie łatwiejszy do przełknięcia.

.property( "x", &point2d::get_x, &point2d::set_x ) ]; .property( "y", &point2d::get_y, &point2d::set_y )

luaL_dostring( pL,

"p1 = point2d( 2, 4 )\n" "p1:print()\n" "p2:print()\n" "p2.y = 10\n" "p2 = point2d( 3 )\n" "p2.x = p1.y\n" "p2:print()" );

}

return 0;

RAFAŁ KOCISZ
Pracuje na stanowisku Dyrektora Technicznego w firmie Gamelion, wchodzącej w skład Grupy 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 efektywniej wykorzystywać potencjał dwóch szybko rozwijających się producentów oprogramowania – BLStream i Gamelion. Firmy wchodzące w skład grupy specjalizują się w wytwarzaniu oprogramowania dla klientów korporacyjnych, w rozwiązaniach mobilnych oraz produkcji i testowaniu gier. Kontakt z autorem: rafal.kocisz@game-lion.com

W Sieci
• • • • • • http://www.lua.org/ – strona domowa języka Lua; http://luabinaries.luaforge.net/ – stąd można pobrać binarną dystrybucję interpretera i biblioteka języka Lua; http://en.wikipedia.org/wiki/Lua_(programming_language) – podstawowe informacje na temat języka Lua; http://lua-users.org/wiki/TutorialDirectory – samouczki poświęcone językowi Lua; http://www.rasterbar.com/products/luabind.html – strona domowa biblioteki Luabind http://www.rasterbar.com/products/luabind/docs.html – rozbudowany opis możliwości biblioteki Luabind.

www.sdjournal.org

19

Programowanie Java

Spring Java Configuration Project
Alternatywa dla tradycyjnej konfiguracji XML
Twórcy projektu Spring Framework spróbowali zminimalizować ilość konfiguracji XML poprzez przeniesienie źródeł definicji komponentów do plików języka Java. Spring Java Configuration Project to alternatywa dla klasycznego podejścia do zagadnienia konfiguracji aplikacji internetowych, która równocześnie nie narusza wzorca Inversion Of Control oraz ogólnej elegancji architektury naszej aplikacji.
Dowiesz się:
• Jak można konfigurować kontener IOC (Inversion Of Control) Springa za pomocą klas języka Java; • Dlaczego warto posiąść taką umiejętność; • Jak połączyć klasyczną konfigurację XML z innowacyjnym podejściem do tematu oferowanym przez Java Configuration Project.

Powinieneś wiedzieć:
• Podstawowa znajomość języka Java oraz konfiguracji kontenera Inversion Of Control dla Spring Framework 2.x za pomocą plików XML.

Poziom trudności

T

rudno znaleźć użytkownika szkieletu aplikacyjnego Spring Framework, który nie wiedziałby, czym jest XML. Sądzę również, że żaden z takowych nie uniknął w swojej karierze edycji dokumentu XML rozpoczynającego się elementem <beans>. Oczywiście twórcy Springa udostępnili nam na tyle ogólny mechanizm programowej obsługi kontenera IoC (Inversion Of Control), że bez większych problemów możemy dodawać do niego definicje ziaren springowych (znanych również jako beany) zbudowanych w języku Java lub zawartych w plikach properties. Mało tego, możemy nawet przy nadmiarze wolnego czasu napisać samodzielnie implementację interfejsu org.springframework.beans.factory.BeanFactory, który będzie odczytywać definicje naszych komponentów z najbardziej nawet niecodziennych źródeł (bazy danych, dokumentów w formacie JSON, hierarchii systemu plików, etc.). Niezależnie od chwały należnej autorom Springa za elegancję jego architektury, faktem jest, że de facto standardem konfiguracji apli20

kacji internetowych jest XML. Co za tym idzie, wśród projektów opartych na Spring Framework funkcjonują w zasadzie tylko konteksty aplikacji analizujące dokumenty w tym formacie. Czytając dokumentację Springa lub artykuły na jego temat można wręcz odnieść wrażenie, że nie ma innego sposobu na konfigurację aplikacji napisanych z jego użyciem.

Motywacja
XML jest bardzo wygodnym formatem konfiguracji – z tym stwierdzeniem zapewne zgodzi się większość z nas. Niemniej jednak wraz ze wzrostem złożoności projektu nietrudno poczuć subtelne uczucie przytłoczenia rozmiarem dokumentu applicationContext.xml, który na początku wydawał się nam tak zgrabny, minimalistyczny i czytelny. Postanawiamy zatem go odchudzić. Zaczynamy wydzielać wspólne części konfiguracji i tworzymy abstrakcyjne definicje beanów. Decydujemy się na rezygnację z pełnej kontroli nad zależnościami na rzecz automatycznego wiązania (autowiring). Dzielimy plik konfiguracyjny na logiczne moduły, które następnie umieszczamy w osobnych plikach i importujemy do głównej konfiguracji. Wreszcie, zdesperowani, piszemy własny schemat XML i za pomocą własnej przestrzeni nazw redukujemy roz-

miar części konfiguracji charakterystycznej dla naszego projektu. Załóżmy, że kiedy powyższe techniki nie dają nam satysfakcjonującego poziomu zredukowania konfiguracji, decydujemy się na użycie adnotacji. Dla przykładu, zastępujemy konfigurację transakcji dokonywaną za pomocą przestrzeni nazw tx, na adnotacje @Transactional. I to właśnie jest kluczowy moment w naszej opowieści – coś w nas pękło. Po raz pierwszy przełamaliśmy tabu konfiguracji XML i przenieśliśmy część tej odpowiedzialności do kodu aplikacji. Co prawda są to tylko metadane, bo adnotacje to w końcu żaden kod. Załóżmy, że adnotacje nie kłócą się z naszym pojmowaniem wzorca Inversion Of Control. Niestety dalsze przenoszenie odpowiedzialności za konfigurację z XML-a do kodu jakiejkolwiek warstwy aplikacji spowoduje powolną regresję do stanu, któremu Spring wraz ze swoim kontenerem IoC właśnie zapobiegają. Może zatem wypracujemy jakiś kompromis pomiędzy unikaniem XML-a a przenoszeniem konfiguracji do kodu? A gdybyśmy tak np. stworzyli osobny plik języka Java, który pozwoliłby nam na przeniesienie części konfiguracji z dokumentu XML? Taki plik logicznie znajdowałby się poza wszystkimi warstwami aplikacji (zatem nie mieszamy logiki aplikacji z logiką konfiguracji), a jedyną częścią systemu, która byłaby zależna od niego, to kontener IoC (zatem i ten wzorzec pozostanie nienaruszony). Wspominałem wcześniej, że twórcy Springa pozwolili nam na eleganckie rozszerzanie mechanizmu rozpoznawania źródeł definicji komponentów. Kuszącą perspektywą wydaję się więc odczytywanie definicji beanów z odpowiednio napisanej, prostej klasy języka Java. Taką skompilowaną klasę moglibyśmy analizować za pomocą mechanizmu refleksji oraz poprzez rozpoznawanie określo03/2009

Spring Java Configuration Project

nych adnotacji naniesionych na nią lub na jej metody. Fizycznie plik języka Java stanowiłby źródło konfiguracji, ale z punktu widzenia architektury byłby on logicznie tożsamy z plikiem XML (Rysunek 1.). Wizja ciekawa, ale ktoś już nas uprzedził. Twórcy Springa już w 2005 roku rozpoczęli pracę nad projektem Java Configuration (w skrócie JavaConfig) realizującym ten pomysł.

Konfiguracyjny flamewar
Zanim przejdziemy dalej, pragnąłbym zwrócić uwagę na fakt, że zarówno podejście lansowane przez np. Google Guice, Spring Java Configuration Project, jak i jakiekolwiek inne odejście od XML-a na rzecz konfigurowania aplikacji poprzez chociażby adnotacje lub XDoclety (a już w szczególności kod języka Java, analizowany na poziomie wykonywania programu) mają prawo budzić kontrowersje. Kierunek redukowania tzw. XML hell na rzecz czegokolwiek bliższego językowi aplikacji nie jest standardem w świecie aplikacji zdominowanych przez XML. Dla wielu podejście reprezentowane przez Java Configuration jest nie do zaakceptowania i w ich opinii narusza realizację wzorca IoC. Celem tego artykułu nie jest stwierdzenie, że przedstawiona w nim technika konfiguracji jest lepsza lub gorsza od jakiejkolwiek innej. Unikałbym zbędnego wartościowania konfiguracji XML oraz nowszych technik, używanych do jej redukcji. JavaConfiguration to po prostu alternatywa. A już do architekta konkretnego projektu należy decyzja (i związana z nią odpowiedzialność), czy taka opcja wyjdzie na lepsze.

mość możliwości analizowania odpowiednich klas języka Java) oraz post processor służący do zintegrowania istniejących konfiguracji XML z nową konfiguracja JavaConfig. O możliwościach rozwoju tego projektu może świadczyć osobiste zaangażowanie Roda Johnsona (głównego architekta Springa) w rozwój oraz promowanie Java Configuration Project. Jeżeli uznamy intuicję Pana Johnsona za wyznacznik pewnych trendów w programowaniu, to możemy spodziewać się wzrostu znaczenia tej nowej techniki konfiguracji w aplikacjach internetowych.

guracją swojego kontenera IoC. Nasz kontener mógłby zawierać jeden komponent springowy – niech to będzie zwykły string. Kod potrzebny do uruchomienia tej przykładowej aplikacji znajduje się na Listingu 1. W stosunku do konfiguracji kontenera IoC za pomocą XML-a pojawiły się trzy nowości: • oznaczenie klasy, zawierającej konfigurację adnotacją @Configuration, • oznaczenie adnotacją @Bean metody, której wynik ma zostać zarejestrowany w kontenerze jako bean, • użycie kontekstu aplikacji świadomego klas zgodnych z Java Configuration.

Hello World, Bye XML
Chcielibyśmy móc z czystym sumieniem powiedzieć, że kiedyś napisaliśmy coś w Java Configuration. Skonfigurujemy zatem kontener IoC Springa bez jednej linijki XML-a, wyłącznie w czystej Javie. Załóżmy, że chcemy napisać aplikację konsolową, której klasa jest równocześnie konfiListing 1. Najprostszy przykład użycia JavaConfig
package pl.hekonsek;

Hello World z wiązaniem
Od kontenera IoC oczekujemy najczęściej, że będzie w stanie wstrzykiwać zależności. Aby udowodnić, że i Java Configuration nie jest pozbawiony tej funkcjonalności, spróbujmy rozszerzyć nasz

import org.springframework.config.java.annotation.Bean;

import org.springframework.config.java.annotation.Configuration; import org.springframework.context.ApplicationContext; // To jest konfiguracja Java Configuration @Configuration public class Application { /** Tożsame z... * */

import org.springframework.config.java.context.JavaConfigApplicationContext;

JavaConfig
Spring Java Configuration Project (w skrócie nazywany po prostu Spring JavaConfig) to jeden z podprojektów Springa. Dostarcza on nowe źródło konfiguracji dla kontenera IoC, zatem wśród jego zależności możemy znaleźć głównie powiązania ze Spring Core. Java Configuration oferuje m.in.: zbiór adnotacji (używanych do oznaczania klas i ich poszczególnych elementów jako konfiguracji kontenera), nowe implementacje kontekstu aplikacji (rozbudowane o świado���������

* <bean id="myBean" class="java.lang.String"> * </bean> <constructor-arg value="foo"/>

@Bean

public String myBean() { } return "foo";

public static void main(String[] args) {

// Stwórz kontekst świadomy analizy plików Java Configuration // i dodaj do niego klasę zawierającą taką konfigurację. ApplicationContext ac = new JavaConfigApplicationContext( System.out.println(ac.getBean("myBean")); Application.class);

}

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

}

Listing 2. Najprostsze wiązanie w XML
<bean id="wireSth" class"java.lang.String"> </bean> <constructor-arg ref="wireMe" />

<bean id="wireMe" class"java.lang.String">

Rysunek 1. Uproszczony schemat zależności między aplikacją, kontenerem IoC Springa oraz źródłami jego konfiguracji

</bean>

<constructor-arg value="foo />

www.sdjournal.org

21

Programowanie Java
przykład o najprostsze wiązanie. Chcielibyśmy za pomocą JavaConfig uzyskać konfigurację XML, analogiczną do tej z Listingu 2. Odpowiedni wycinek w Java Configuration widać na Listingu 3. – wiązanie odbywa się po prostu przez wywołanie metody oznaczonej adnotacją @Bean.

Szczegółowe przykłady konfiguracji
A czy w Java Configuration tak mogę? Zapewne niektórzy z was zadają sobie już pytanie, czy w JavaConfig można uzyskać każ-

Listing 3. Najprostsze wiązanie w Java Configuration
package pl.hekonsek; import org.springframework.config.java.annotation.Bean;

dą funkcjonalność konfiguracji XML? Czy nie jest to tylko zabawka oferująca najprostszy podzbiór możliwości kontenera konfigurowanego za pomocą XML-a? Otóż nie, nie jest to tylko zabawka, ale w pełni funkcjonalna alternatywa dla tradycyjnej konfiguracji. Na poparcie tych słów pozwolę sobie na rozwianie typowych wątpliwości, pojawiających się na początku przygody z Java Configuration. Cykl życia ziarna springowego w kontenerze Spring oferuje pokaźną listę możliwych wywołań zwrotnych, które pozwalają nam na wstrzelenie się z naszym kodem w różne momenty życia naszej instancji, np. poprzez interfejsy z serii *aware (np. BeanNameAware) lub InitializingBean (Listing 4.). Mam dobra wiadomość – wszystkie one są obsługiwane przez JavaConfig. Wynika to z faktu, że implementacje interface'u ApplicationContext, dostarczane przez Java Configuration, rozszerzają bazowe wersje, istniejące w Spring Core, tak więc mechanika związana z analizą cyklu życia jest realizowana przez oryginalny kod Springa. Cykl życia – przekazywanie nazwy metody A co, gdy chcemy użyć odpowiedników metod wskazanych przez atrybuty init-method lub destroy-method z konfiguracji XML (Listing 5.)? W końcu musimy wpisać je w pliku XML. Oczywiście i tutaj Java Configuration pozwala nam na podanie odpowiedniej nazwy metody, tyle że nie w XML-u. Java Configuration pozwala nam na podanie odpowiedniej nazwy metody w ramach atrybutu initMethodName lub destroyMethodName adnotacji @Bean (Listing 6.). Cykl życia – BeanPostProcessors Co z implementacjami interface'u BeanPostProcessor? Oczywiście spełniają swoją funkcję, jak powinny – ponownie kod, rozszerzany przez implementacje interface'u ApplicationContext deleguje sterowanie do kodu Spring Core odpowiedzialnego za tą funkcjonalność. Zatem PostProcessory zostaną odpalone na zawartości kontenera, nie wnikając w to, czy źródłem zawartych w nim instancji jest plik XML, czy klasa zgodna z Java Configuration. Zasięg instancji Domyślnie instancje, zarejestrowane za pomocą Java Configuration, mają (podobnie jak w konfiguracji XML) zasięg singleton. Aby wybrać inny zasięg, należy podać go jako parametr adnotacji. Parametr scope jest typu string, tak więc możemy podawać również własne zasięgi, o ile zarejestrujemy takowe w kontenerze. Przykłady znajdują się na Listingu 7.
03/2009

import org.springframework.config.java.annotation.Configuration; import org.springframework.context.ApplicationContext; @Configuration public class Application { @Bean

import org.springframework.config.java.context.JavaConfigApplicationContext;

public String wireMe() { } return "foo";

@Bean

public String wireSth() {

// wywołanie metody oznaczonej jako @Bean return new String( wireMe() );

}

public static void main(String[] args) { Application.class);

ApplicationContext ac = new JavaConfigApplicationContext( System.out.println(ac.getBean("wireSth"));

} }

Listing 4. Przykład klasy świadomej swojego cyklu życia w kontenerze
package pl.hekonsek; import org.springframework.beans.factory.BeanNameAware;

import org.springframework.beans.factory.InitializingBean; public class LifeCycleBean implements InitializingBean, BeanNameAware { @Override }

public void afterPropertiesSet() throws Exception {

@Override } }

public void setBeanName(String name) {

Listing 5. Deklaracja metod init-method oraz destroy-method w XML-u
<bean class="com.Foo" init-method="start" destroy-method="close"/>

Listing 6. Deklaracja metod init oraz destroy w JavaConfig
@Bean(initMethodName="start",destroyMethodName="close") public Foo foo() { } return new Foo();

22

Spring Java Configuration Project

Wstrzykiwanie nietypowych zasięgów przez Scoped Proxy Jeżeli w konfiguracji XML chcemy wstrzyknąć do beana typu singleton zależność o zasięgu typu np. session lub request, to musimy odpowiadającą jej definicję oznaczyć jako <aop: scoped-proxy/>. Wynika to z węższego zakresu działania singletona w porównaniu z przekazywanymi (wstrzykiwanymi) obiektami. A ponieważ sesje oraz żądania HTTP zwykły żyć krócej niż aplikacja (wraz ze swoimi singletonami), tak więc naprawdę Spring musi wstrzyknąć do takiego singletona pośrednika, który będzie żył tak długo, jak obiekt, do którego wstrzykuje się zależność (i przekierowywało żądania do odpowiedniej instancji o krótszym zasięgu życia). Oczywiście Java Configuration również udostępnia taką funkcjonalność. Wystarczy spojrzeć na porównanie Listingów 8 oraz 9. Zmiana domyślnych polityk rejestracji instancji Konfiguracja XML pozwala nam na globalne określenie polityki tworzenia instancji zdefiniowanych w pliku XML (patrz Listing 10.). Podobny efekt możemy osiągnąć za pomocą parametryzowania adnotacji @Configuration (patrz Listing 11.). Method injection Poza najbardziej popularnymi sposobami wstrzykiwania zależności tzn. wstrzykiwaniu przez metodę ustawiającą (setter injection) oraz konstruktor (constructor injection) Spring oferuje tzw. metodę wstrzykującą (method injection). Technika ta jest przydatna zwłaszcza w scenariuszu, w którym potrzebujemy, aby bean typu singleton mógł uzyskać nowy egzemplarz beana o zasięgu prototype, zarządzanego przez kontener IoC, za każdym razem, kiedy ów singleton odwołuje się do swojej zależności. Tradycyjne wstrzyknięcie zależności przez konstruktor lub metodę ustawiającą będzie tutaj niewystarczające, gdyż prototypy są tworzone i wstrzykiwane do singletonów tylko w momencie ustawiania zależności tych drugich. Metoda wstrzykująca jest dostępna w Java Configuration w bardzo intuicyjny sposób – poprzez implementację lub nadpisanie żądanej metody w klasie wewnętrznej (najczęściej anonimowej) i odwołanie się do metody tworzącej prototyp. Style użycia metody wstrzykującej klasy z Listingu 12. w XML-u oraz Java Configuration porównują Listingi 13 oraz 14. Ukrywanie definicji beanów Nieco mniej oczywistą, a bardzo ciekawą opcją, oferowaną przez Java Configuration, jest możliwość ukrywania swoich instancji przed innymi kontekstami w hierarchii. Jeżeli zdefiniowww.sdjournal.org

wana przez nas metoda @Bean będzie miała widoczność domyślną lub chronioną (w starszych wersjach JavaConfig również prywatną), to da-

na definicja beana będzie umieszczona w pomocniczym kontekście-potomku i będzie niewidoczna dla innych kontekstów w hierarchii

Listing 7. Przykłady zmiany domyślnego zasięgu instancji w kontenerze
@Bean(scope = DefaultScopes.SINGLETON) public String wireMe() { } return "foo";

@Bean(scope = DefaultScopes.PROTOTYPE) public String wireMe() { } return "foo";

@Bean(scope = "myCustomScope") public String wireMe() { } return "foo";

Listing 8. Scoped Proxy w XML-u
<bean id="cart" class="pl.hekonsek.Cart" scope="session"> </bean> <aop:scoped-proxy/>

<bean id="cartVerifier" class="pl.hekonsek.CartVerifier"> </bean> <property name="cart" ref="cart"/>

Listing 9. Scoped Proxy w Java Configuration
@Bean(scope = DefaultScopes.SESSION) @ScopedProxy public Cart cart() { } @Bean

return new Cart();

public CartVerifier cartVerifier() { cv.setCart(cart()); } return cv;

CartVerifier cv = new CartVerifier();

Listing 10. Konfigurowanie domyślnej polityki tworzenia i wiązania instancji w XML
<beans default-autowire="byName" default-lazy-init="false" ... ></beans>

Listing 11. Konfigurowanie domyślnej polityki tworzenia i wiązania instancji w Java Configuration
package pl.hekonsek; import org.springframework.beans.factory.annotation.Autowire; import org.springframework.config.java.annotation.Bean; import org.springframework.config.java.annotation.Lazy; import org.springframework.config.java.annotation.Configuration;

@Configuration(defaultAutowire=Autowire.BY_NAME,defaultLazy=Lazy.FALSE) public class Application {

@Bean(autowire=Autowire.BY_TYPE) public String wireMe() { } } return "foo";

23

Programowanie Java
niż ten, który ją definiuje. Możemy dzięki temu tworzyć pomocnicze instancje, które nie będą widoczne dla innych poziomów aplikacji. cji XML. Możemy np. dodać do naszej aplikacji skonfigurowanej w XML PostProcessor org.springframework.config.java.process.ConfigurationPostProcessor. Następnie należy dodać definicje naszych klas konfiguracyjnych do kontenera (Listing 15.). Wspomniany przez nas PostProcessor wykryje, że są one oznaczone adnotacją @Configuration i doda znajdujące się w nich definicje do kontenera. Tą metodą możemy cieszyć się możliwościami JavaConfig tylko dla wybranych przez nas fragmentów konfiguracji, podczas gdy większość definicji dalej będziemy trzymać w formacie XML. Co ważne, ConfigurationPostProcessor pozwala nam na płynną migrację konfiguracji z XML-a do JavaConfig. Dzięki temu nie jesteśmy stawiani przed wyborem, którego konsekwencją może być poważna zmiana w architekturze konfiguracji naszej aplikacji. Nadpisywanie definicji Ciekawą opcją oferowaną przez JavaConfig (a przydatną zwłaszcza w kontekście integracji z XML-em) jest możliwość oznaczenia definicji beana parametrem allowOverriding. Dzięki temu zarejestrowanie w konfiguracji XML instancji o tej samej nazwie przesłoni tą zdefiniowaną w JavaConfig. Jest to funkcjonalność przydatna zwłaszcza wtedy, gdy JavaConfig planujemy używać do bardziej ogólnych (a zarazem domyślnych) fragmentów konfiguracji, podczas gdy XML-owi pozostawiamy rolę konfiguracji szczegółowej. Przykład takiego podejścia demonstrują Listingi 16 oraz 17. JavaConfig w aplikacjach internetowych Jedną technikę integracji Java Configuration z aplikacjami webowymi już poznaliśmy. Jest to dodanie do pliku XML naszej konfiguracji PostProcessora org.springframework.config.java.process.ConfigurationPostProcessor. Niezależnie od tej możliwości możemy użyć kontekstu aplikacji dedykowanego JavaConfig i aplikacjom internetowym. Implementacja org.springframework.config.java.JavaConfigWebApplicationContext w zasadzie niewiele różni się od np. tradycyjnego org.springframework.web.context.support.XmlWebApplicationContext. O ile ten drugi jako wartość contextConfigLocation pobiera listę lokalizacji plików XML, to pierwszy wczytuje listę klas języka Java. Przykład użycia kontekstu aplikacji oferowanego przez Java Configuration znajduje się na Listingu 18.

Integracja konfiguracji XML oraz JavaConfig
Dodatek do XML-a Oczywiście Java Configuration nie wymusza od nas całkowitej rezygnacji z konfigura-

Listing 12. Klasy służące do demonstracji metody wstrzykującej
package pl.hekonsek; public abstract class StringHolder { public abstract String getString(); } package pl.hekonsek; import java.util.Date; class DateString { public Date date = new Date(); }

Listing 13. Metoda wstrzykująca w XML-u
<bean id="prototype" class="pl.hekonsek.DateString"/> <bean id="holder" class="pl.hekonsek.StringHolder> </bean>

<lookup-method name="getString" bean="prototype"/>

Listing 14. Metoda wstrzykująca w Java Configuration
@Bean(scope = DefaultScopes.PROTOTYPE) public DateString prototype() { } @Bean return new DateString();

public StringHolder holder() {

Modularyzacja konfiguracji
Wszystko można zapchać Oczywiście konfiguracja w klasach JavaConfig może być po pewnym czasie, wraz z rozrostem aplikacji, równie uciążliwa w utrzymaniu i kontroli, co monolityczny plik XML. Java Configuration oferuje na szczęście szereg mechanizmów służących do podziału klas konfiguracyjnych na mniejsze elementy. Dostęp do instancji z innych klas i źródeł Podstawowym zagadnieniem pojawiającym się podczas modularyzacji klas JavaConfig jest dostęp do metod definiujących instancje z innych klas lub źródeł danych. Jeżeli np. integrujemy Java Configuration z aplikacją zarządzaną za pomocą XML-a (poprzez ConfigurationPostProcessor) to tracimy możliwość od03/2009

return new StringHolder() { @Override

public String getString() { }

return prototype().date.getTime() + "";

}

};

Listing 15. Integracja konfiguracji XML i JavaConfig
<beans ... > <!-- Dodaj konfigurację do kontenera -->

<!-- Lub dodaj do kontenera wszystkie konfiguracje oznaczone jako @Component --> <context:component-scan base-package="pl.hekonsek.*"/> </beans> <bean class="org.springframework.config.java.process.ConfigurationPostProcessor"/>

<bean class="pl.hekonsek.MyConfigurationClass"/>

24

Spring Java Configuration Project

wołania się z poziomu klasy oznaczonej adnotacją @Configuration do instancji zdefiniowanej w pliku XML. Dzieje się tak z prozaicznego powodu – Java jest językiem statycznie typowanym i nie pozwoli nam na wywoływanie w ramach klasy metody o arbitralnej nazwie. Logicznie wiemy, że np. definicja beana o nazwie notDefinedHere znajduje się w kontenerze, ale składnia języka Java nie pozwoli nam na odwołanie się do metody o takiej nazwie (a jak wiadomo, jest to sposób na odnoszenie się innych obiektów w kontenerze za pomocą JavaConfig). Problem ten obrazuje Listing 19. Musimy zatem zdefiniować metodę pomocniczą, która pozwoli nam na odwołanie się do instancji zdefiniowanej poza daną klasą. Metoda taka może być abstrakcyjna (notabene stąd wniosek, że i klasy JavaConfig mogą być abstrakcyjne, oraz że są one proxowane za pomocą biblioteki służącej do dynamicznej generacji kodu) lub konkretna (zostanie ona nadpisana przez JavaConfig) oraz musi być oznaczona adnotacją @ExternalBean. Rozwiązanie problemu z Listingu 19. za pomocą takiej właśnie metody demonstruje listing 20. Analogiczny problem wystąpi podczas rozdzielania klasy konfiguracyjnej na mniejsze, ale bardziej spójne logicznie. Ponownie z pomocą przybywa adnotacja @ExternalBean. Rozbijanie konfiguracji na wiele klas Najprostszą techniką rozbijania konfiguracji jest przeniesienie części metod z klasy konfiguracyjnej do drugiej klasy i dodanie obydwu do kontekstu. Listing 21. pokazuje przykład podziału klasy na dwie mniejsze z zachowaniem wzajemnych referencji za pomocą @ExternalBean. Adnotacja @Import Podobnie jak w przypadku XML-a i jego elementu <import/>, konfiguracja JavaConfig również może importować inne klasy oznaczone adnotacją @Configuration. Aby tego dokonać, wystarczy oznaczyć klasę konfiguracyjną adnotacją @Import({foo.Config1.class,foo .Config2.class}). Wewnętrzne klasy konfiguracyjne oraz zasięg widoczności obiektu Zastosowanie klasy wewnętrznej w JavaConfig spowoduje utworzenie dla niej osobnego kontekstu aplikacji, będącego potomkiem klasy zewnętrznej. Konteksty te podlegają oczywiście zasadom hierarchii kontenerów IoC Springa (co demonstruje Listing 22.).

Listing 16. Definicja domyślna komponentu w JavaConfig
package pl.hekonsek; import org.springframework.config.java.annotation.Bean;

import org.springframework.config.java.annotation.Configuration; @Configuration

public class Application { @Bean(allowOverriding = true) public String username() { } } return "root";

Listing 17. Nadpisywanie domyślnej wartości za pomocą XML-a
<beans ... > <!-- Dodaj konfigurację do kontenera -->

<!-- Nadpisz instancję reprezentującą domyślną nazwę użytkownika --> <bean id="username" class="java.lang.String"> </bean> </beans> <constructor-arg value="hekonsek"/>

<bean class="pl.hekonsek.Application"/>

<bean class="org.springframework.config.java.process.ConfigurationPostProcessor"/>

Listing 18. Konfiguracja internetowego kontekstu aplikacji świadomego javaConfig
<web-app> <!-- Główny kontekst aplikacji. --> <listener> <listener-class>org.springframework.web.context.ContextLoaderListener</ listener-class>

</listener>

<context-param>

<param-name>contextClass</param-name> param-value>

<param-value>org.springframework.config.java.JavaConfigWebApplicationContext</ </context-param> <context-param>

<!-- Lokalizacje klas zamiast plików XML --> <param-name>contextConfigLocation</param-name>

</context-param>

<param-value>pl.hekonsek.ApplicationContext</param-value>

<!-- Główny servlet aplikacji... --> <servlet>

<!-- ...konfigurowany tak samo, jak kontekst powyżej. --> <servlet-name>app</servlet-name> class>

<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet<init-param>

<param-name>contextClass</param-name> t</param-value>

<param-value>org.springframework.config.java.JavaConfigWebApplicationContex </init-param> <init-param>

Specjalnie nie piszę o...
Wsparciu w Spring IDE Spring IDE to znakomity plugin do Eclipse IDE, wspomagający pracę ze Springiem. Ma już opcjonalne wsparcie dla JavaConfig. Szczegóły jego użycia są poza zasięgiem tematycznym tego arwww.sdjournal.org

<param-name>contextConfigLocation</param-name> param-value>

<param-value>pl.hekonsek.AppServletConf,pl.hekonsek.AppServletDaoConf</ </init-param>

</web-app>

</servlet>

25

Programowanie Java
tykułu (jakkolwiek jest ono na tyle intuicyjne, że nikt nie powinien mieć z nim problemów). Kwestii stabilności Aktualna wersja JavaConfig to 1.0.0.m3. Ze względu na fakt, że Java Configuration znajduje się wciąż w fazie rozwojowej, pewne funkcjonalności oferowane przez projekt mogą ulec gruntownej zmianie. Takie newralgiczne fragmenty API zostały przeze mnie umyślnie pomięte, jakkolwiek myślę, że warto o nich wspomnieć w dużym skrócie. @ResourceBundles oraz @ExternalValue @ResourceBundles oraz @ExternalValue to para adnotacji pozwalających na uzyskanie funkcjonalności podobnej do tej oferowanej przez PropertyPlaceholderConfigurer. Pierwsza z nich ładuje pliki z właściwościami, druga zaś pozwala

Listing 19. Problem z kompilacją klasy JavaConfig odnoszącej się do zewnętrznej definicji
package pl.hekonsek; import org.springframework.config.java.annotation.Bean; public StringHolder referencer() { // Compilation error: // The method notDefinedHere() is undefined for the type Application } } return new StringHolder(notDefinedHere());

// Wstrzyknij referencję do beana 'notDefinedHere'

import org.springframework.config.java.annotation.Configuration; @Configuration

public class Application { @Bean

Listing 20. Rozwiązanie problemu z kompilacją klasy JavaConfig odnoszącej się do zewnętrznej definicji
package pl.hekonsek; import org.springframework.config.java.annotation.Bean; } @Bean not be executed.");

import org.springframework.config.java.annotation.Configuration; import org.springframework.config.java.annotation.ExternalBean; @Configuration

public StringHolder referencer() {

// Wstrzyknij referencję do beana 'notDefinedHere' return new StringHolder(notDefinedHere());

public class Application { @ExternalBean }

}

public String notDefinedHere() {

throw new RuntimeException("Assertion - this line must

Listing 21. Rozbicie dużej konfiguracji na dwie mniejsze klasy
Większa klasa public String foo() {

package pl.hekonsek;

import org.springframework.config.java.annotation.Bean; @Configuration

throw new RuntimeException("This line should never be executed.");

import org.springframework.config.java.annotation.Configuration; public class BigConf { @Bean

@Bean

}

public StringHolder fooHolder() { }

return new StringHolder(foo());

public String foo() { } return "foo";

}

Mniejsza klasa nr 2

@Bean

package pl.hekonsek;

public StringHolder fooHolder() { }

import org.springframework.config.java.annotation.Bean; @Configuration

return new StringHolder(foo());

import org.springframework.config.java.annotation.Configuration; class SmallConf2 { @Bean

}

Mniejsza klasa nr 1

package pl.hekonsek;

public String foo() { } return "foo";

import org.springframework.config.java.annotation.Bean;

import org.springframework.config.java.annotation.Configuration; import org.springframework.config.java.annotation.ExternalBean; @Configuration

}

Przykład uruchomienia kontekstu mniejszych klas SmallConf2.class);

public class SmallConf1 { @ExternalBean

new JavaConfigApplicationContext(SmallConf1.class,

26

03/2009

Spring Java Configuration Project

na oznaczenie metody na podobnej zasadzie, co @ExternalBean (tyle że wartość zostanie odczytana z pliku właściwości). Konfiguracjach aspektowych JavaConfig oferuje możliwość oznaczenia klasy konfiguracyjnej jako aspektu AOP (ang. AspectOriented Programming) oraz jej konstrukcję umożliwiającą zastosowanie go do określonych instancji w kontenerze. Dzięki temu możemy np. przechwytywać za pomocą metody zdefiniowanej w pliku konfiguracyjnym określony wyjątek dla wszystkich instancji naszej aplikacji (lub dla wybranych obiektów i metod - jest to jedynie kwestia odpowiedniego zadeklarowania punktu przecięcia).

Podsumowanie
Java Configuration oferuje nam nowatorskie podejście do konfiguracji aplikacji. Twórcy

Springa starają się balansować pomiędzy zachowaniem spójności wzorca Inversion Of Control i równocześnie pozwalają nam na bardziej intuicyjny (przynajmniej dla programistów języka Java) format konfiguracji. Jak na razie starania zespołu Roda Johnsona dają bardzo satysfakcjonujące rezultaty – JavaConfig może być z powodzeniem stosowany nie tylko jako wsparcie dla konfiguracji XML, ale również jako samodzielna metoda konfiguracji kontenera IoC. Jak wspominałem wcześniej, łatwo jest popaść w pułapkę klasyfikowania tego typu rozwiązań binarnie – jako lepszych lub gorszych od konfiguracji poprzez XML. Sądzę jednak, że każdy rozsądny architekt nie będzie starał się forsować na siłę jednej techniki konfiguracyjnej do wszystkich nadzorowanych przez siebie aplikacji i raczej będzie skłon-

ny do spokojnego zastanowienia się co może uzyskać projekt po ewentualnej relaksacji klasycznego podejścia do konfiguracji XML. Wykorzystanie drzemiących w Java Configuration możliwości jest szczególnie wygodne ze względu na możliwość drobnoziarnistej i płynnej migracji definicji zwartych XML na rzecz klas konfiguracyjnych.

HENRYK KONSEK
Autor pracuje na stanowisku projektanta JEE w warszawskiej firmie Artegence. Udziela się również jako administrator serwisu javablackbelt.com. W wolnym czasie interesuje się swoją Anią oraz m.in. psychiatrią oraz dobrymi technologiami. Kontakt z autorem: http://www.hekonsek.pl lub hekonsek@gmail.com.

Referencje
• • • • • • • • Strona projektu Spring Framework – http://springframework.org/javaconfig Strona projektu JavaConfig – http://springframework.org/javaconfig Inne projekty poboczne Springa – http://springframework.org/projects Artykuł Martina Fowlera nt. IoC – http://martinfowler.com/articles/injection.html JavaConfig Reference Documentation – http://static.springframework.org/spring-javaconfig/docs/1.0.0.m3/reference/html JavaConfig API – http://static.springframework.org/spring-javaconfig/docs/1.0.0.m3/apidocs/ Artykuł Roda Johnsona nt. JavaConfig – http://blog.springsource.com/2006/11/28/a-java-configuration-option-for-spring/ Klasyczna konfiguracja XML Springa – http://static.springframework.org/spring/docs/2.5.x/reference/beans.html

Listing 22. Konfiguracje wewnętrzne oraz zależności rodzic-dziecko między nimi
package pl.hekonsek; @Bean

import org.springframework.beans.factory.NoSuchBeanDefinitionE import org.springframework.config.java.annotation.Bean; xception;

public String fromChild() { } return "from child";

import org.springframework.config.java.annotation.Configuration; import org.springframework.config.java.context.JavaConfigApplica import org.springframework.context.ApplicationContext; @Configuration public class Parent { @Bean tionContext;

} public static void main(String[] args) { t(Child.class);

ApplicationContext ac = new JavaConfigApplicationContex

// Pobierz obiekt z kontekstu dziecka // Mamy dostęp do obiektów rodzica i potomka System.out.println(ac.getBean("fromParent")); System.out.println(ac.getBean("fromChild")); // Pobierz obiekt z kontekstu rodzica // Mamy dostęp do obiektów rodzica try { ac = new JavaConfigApplicationContext(Parent.class); System.out.println(ac.getBean("foo")); System.out.println(ac.getBean("fromParent")); System.out.println(ac.getBean("fromChild")); assert false; assert true; System.out.println(ac.getBean("foo"));

public String foo() { } return "parent";

@Bean

public String fromParent() { } return "from parent";

@Configuration

public static class Child { @Bean

} catch (NoSuchBeanDefinitionException e) { // Nie mamy dostępu do obiektów potomka } }

public String foo() { } return "child";

}

www.sdjournal.org

27

Warsztaty

CUDA się zdarzają, czyli programowanie GPGPU
Wprowadzenie do programowania przy użyciu technologii CUDA
W artykule dowiemy się co nieco o CUDA z praktycznego punktu widzenia. Na konkretnym przykładzie zobaczymy, jak w prosty sposób wykorzystać kartę graficzną do obliczeń niekoniecznie związanych z grafiką komputerową. Następnie użyjemy typowych rozwiązań mających na celu znaczne przyspieszenie obliczeń.
Dowiesz się:
• Jak napisać i wykonać obliczenia na GPU; • Jak wykorzystać pamięć współdzieloną i niestronicowaną a także asynchroniczne API.

Powinieneś wiedzieć:
• Średnio zaawansowana wiedza ogólna z zakresu programowania w języku C; • Podstawowa wiedza z zakresu programowania równoległego.

Poziom trudności

mając na myśli pamięć RAM komputera dostępną bezpośrednio dla części kodu wykonywanej na CPU oraz pamięć RAM karty graficznej.

Na Listingu 1. widzimy implementację tego dość prostego problemu w języku C. W konwencji nazewnictwa CUDA Host odnosi się zawsze do kodu wykonywanego po stronie CPU, stąd też nazwa naszej funkcji. Znaczenie parametrów in, out , oraz data_size jest oczywiste, natomiast den pochodzi od denominator, czyli mianownik 1/h. Rysunek 3. przedstawia zależność danych wyjściowych od wejściowych

Opis przykładu numerycznego

Zarządzanie pamięcią
Zanim zaczniemy obliczenia, po stronie GPU musimy w pierwszej kolejności zaalokować oraz skopiować pamięć na naszą kartę graficzną. Alokacja oraz dealokacja są analogiczne do klasycznych malloców w C (Listing 2.) , przy czym używamy do tego oczywiście funkcji z API CUDA. W Listingu 2., jak i w dalszej części artykułu, została przyjęta konwencja dodawania przedrostka h_ dla wskaźników do pamięci dostępnej z poziomu CPU (host) oraz przedrostka d_ dla pamięci GPU (device). Kopiowanie pamięci odbywa się również podobnie jak w języku C (patrz: Listing 3.)

O

statnio coraz częściej mówi się o GPGPU, czyli o obliczeniach dowolnego zastosowania przy użyciu kart graficznych. Temat stał się jeszcze bardziej popularny po pojawieniu się CUDA (ang. Compute Unified Device Architecture) – rozwiązania w znacznym stopniu ułatwiającego tego typu obliczenia. Niniejszy artykuł jest czysto praktycznym wprowadzeniem do tej technologii. Czytelników, którzy chcieliby dowiedzieć się troszkę więcej o GPGPU oraz CUDA, zapraszamy do lektury Ramek Kilka słów o GPGPU , Co to właściwie jest CUDA oraz do materiałów poleconych w Ramce W Sieci. Jako że zawsze dobrze tłumaczy się na przykładzie, to na początku dobierzemy sobie problem numeryczny najlepiej nadający się do takiego wprowadzenia: na tyle prosty, żeby nie zaciemniał szczegółów, ale zarazem na tyle wredny ( a więc typowy ), żeby pozwolił poruszyć najistotniejsze aspekty programowania w CUDA. Wszystkie obliczenia były wykonane na GeForce GTX280 oraz na jednym rdzeniu QuadCora taktowanego zegarem 2.66 Ghz. Często nieformalnie będziemy używać zwrotów w stylu: kopiowanie pamięci ze strony CPU na stronę GPU,
28

Na wstępie dobierzemy sobie przykładowy problem do eksperymentów, by na jego bazie etapowo poznawać kolejne techniki programowania przy użyciu CUDA. Idealne do tego wydaje się być różniczkowanie numeryczne z formułą pięciopunktową: mając na wejściu funkcję (sygnał), daną jako tablicę N liczb rzeczywistych rozmieszczonych ze stałym krokiem h, w celu obliczenia przybliżonej pochodnej tej funkcji stosujemy wzór przedstawiony na Rysunku 1. Wzory z Rysunku 2. stosujemy dla dwóch pierwszych oraz dwóch ostatnich punktów z tablicy.

Szybki start

Oczywiście na początek musimy ściągnąć ze strony Nvidii SDK toolkit oraz drivery dla CUDA. Wszystko znajdziemy np. tu: http://www.nvidia.pl/object/cuda_get_pl.html Rekomendowanym środowiskiem dla programowania CUDA pod Windowsem jest MS Visual C++ 2005. Głównie chodzi o dostarczany w tym pakiecie kompilator. Fragmenty kodu dla części GPU są kompilowane przez Nvidiowe narzędzie, zaś część dla CPU przez zewnętrzny kompilator i niestety nowsza wersja Microsoftowego kompilatora nie jest kompatybilna z Nvidiową. W katalogu, w którym zainstalowaliśmy CUDA SDK, w podkatalogu \doc\syntax_highlighting znajdziemy mały plik readme opisujący, jak włączyć kolorowanie w Visualu dla plików .cu. Takie właśnie rozszerzenie mają pliki z kodem dla CUDA. Pozostaje jeszcze jedna niezbędna rzecz, a mianowicie CUDA Visual Wizard, czyli plugin dla MS Visuala pozwalający nam na łatwą obsługę projektów CUDA. Pakiet instalacyjny znajduje się na http://sourceforge.net/projects/cudavswizard.

03/2009

CUDA się zdarzają, czyli programowanie GPGPU

Argumentami funckji cudaMemcpy są kolejno: wskaźnik pamięci docelowej, wskaźnik pamięci źródłowej, wielkość kopiowanej pamięci oraz kierunek kopiowania. W tym ostatnim mamy dostępne jeszcze dodatkowo dwie opcje: cudaMemcpyHostToHost oraz cudaMemcpyDevic eToDevice. Ich znaczenie wynika z samych nazw.

Pierwszy kernel
Nadszedł moment na zaimplementowanie funkcji wykonywanej po stronie GPU (tzw. jądra, ang. kernel). Na Listingu 4. przedstawiamy pierwszą wersję, bez użycia pamięci współdzielonej. Jest to dość prosta modyfikacja funkcji dla CPU. Pierwsze rzuca się w oczy słowo kluczowe __global__. Funkcje nim poprzedzone będą skompilowane i wykonywane na GPU wielowątkowo, a dokładniej każdy wątek raz wykona taką funkcję. Fakt ten tłumaczy nieobecność pętli w kodzie jądra, w porównaniu z kodem przeznaczonym do wykonywania na CPU. Taki właśnie był nasz cel: zamiast robić obliczenia sekwencyjnie w pętli, chcieliśmy wykonać je wszystkie jednocześnie w sposób równoległy. Index idx identyfikuje wątek, a do znaczenia parametrów blockIdx.x, blockDim.x, threadIdx.x zaraz wrócimy. Zwróćmy uwagę, że wątki o indeksie większym niż liczba danych nie będą wykonywać obliczeń: if(idx >= data_size) return;, zaś wątki o dwóch najmniejszych i dwóch największych indeksach wykonają obliczenia na podstawie formuły dwupunktowej. Rozważmy teraz sposób wywołania takiej funkcji (patrz: Listing 5.). Dość ciekawie wygląda składnia: . Tutaj są podawane parametry dla konfiguracji wywołania jądra: rozmiar siatki bloków (grid) oraz rozmiar każdego bloku. Następnie jest miejsce na podanie argumentów funkcji. Zwróćmy uwagę na użycie typu dim3. Jest to struktura trzech liczb całkowitych ( x, y, z ), używana do określania rozmiarów. Nasz przykład jest jednowymiarowy, więc nie definiowaliśmy pozostałych pól. W tym przypadku zostały one automatycznie zainicjalizowane jako 1. Z eksperymentów wynikło, że najlepsza ze względu na wydajność wartość dla BLOCK_
��������� � ������������� � ������������ ������������������������

to 256 (w przypadku karty Nvidia GeForce GTX280). Ponieważ wielkość bloku i tak jest dość mocno ograniczona ( w przypadku tej karty to 512), bloki te grupujemy jeszcze w siatkę ( tutaj maksymalny rozmiar wynosi już 65535). Mamy zatem skonfigurowane uruchomienie jądra na dokładnie numBlocks * numThreadsPerBlock wątkach. Nietrudno wyliczyć, że występuje tu pewien nadmiar w stosunku do DATA_SIZE, wynikający oczywiście ze sposobu wyliczenia ilości bloków numBlocks. Istotniejszym jednak parametrem, z punktu widzenia szybkości, jest tutaj wielkość bloku numThreadsPerBlock, naWIDTH

wet gdyby miało być nieznacznie więcej wątków ogółem. Wróćmy teraz do sposobu indeksowania wątków w kodzie jądra: W momencie wykonania kodu jądra mamy dostęp do wartości określających:
threadIdx.x; int idx = blockIdx.x*blockDim.x +

• rozmiar bloku – blockDim – jest to zmienna typu dim3 i jak już wcześniej wspomnieliśmy, w naszym przykładzie interesuje nas blockDim.x . Wartość ta jest równa dokładnie skonfigu-

Listing 1. Implementacja przykładu numerycznego
void HostFunction(float* in, float* out, float den, int data_size){ int idx; for(idx = 0; idx<2; idx++);

out[idx] = ( in[idx+1] - in[idx] ) * den;

for(idx=2; idx<data_size-2; idx++){

out[idx] = ( in[idx-2] - 8*in[idx-1] + 8*in[idx+1]

}

-in[idx+2] )*den*0.083333333f; //1/12h;

for(idx = data_size - 2; idx< data_size; idx++) } out[idx] = ( in[idx] - in[idx-1] ) * den;

Kilka słów o GPGPU

GPGPU (ang. General-purpose computing on graphics processing units) to po prostu wykonywanie obliczeń przy użyciu karty graficznej, zamiast procesora komputera. Początkowo technika ta była wykorzystywana głównie do wspierania procesu tworzenia grafiki komputerowej, jak np. proste obliczenia fizyczne. Z czasem karty graficzne zaczęto wyposażać w coraz to większą liczbę coraz szybszych procesorów (obecnie niektóre urządzenia mają ich grubo ponad 100). Dodatkowo rozmiar pamięci zainstalowanej na karcie graficznej zaczął dorównywać rozmiarom standardowego RAMU. W naturalny więc sposób GPGPU wykroczyło poza ramy grafiki komputerowej i znajduje olbrzymią liczbę zastosowań w zasadzie wszędzie tam, gdzie do tej pory CPU było bezkonkurencyjne. W przypadku masowych obliczeń równoległych można nawet śmiało powiedzieć, że obliczenia na CPU już zwyczjanie się nie opłacają, gdyż na GPGPU możemy uzyskać czasem nawet kilkusetkrotne przyspieszenie. Użytkownicy domowi na pewną będą odczuwać coraz więcej korzyści z rozwoju technologii GPGPU. Nawet bardzo tanie karty graficzne już są w stanie wspierać np. obróbkę zdjęć, kodeki audio/wideo, itd. Natomiast wymagający naukowcy mogą sobie zafundować systemy oparte na kilku mega wydajnych kartach uzyskując superkomputer za stosunkowo niewielkie pieniądze.

���

Rysunek 1. Formuła pięciopunktowa dla przybliżonej pochodnej funkcji

Co to właściwie jest CUDA?

���������

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

���������

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

Rysunek 2. Formuły dwupunktowe dla przybliżonej pochodnej funkcji

CUDA (ang. Compute Unified Device Architecture) jest stworzoną przez firmę NVidia architekturą dla obliczeń równoległych z wykorzystaniem karty graficznej. Dzięki API CUDA technika GPGPU jest jeszcze prostsza, nie musimy bowiem odwoływać się do API typowo graficznego, jak np. Shading Language. Dostępne są także gotowe biblioteki dla algebry liniowej, czy transformaty Fouriera. Jako nowość pojawia się szybka pamięć współdzielona, co jeszcze bardziej uatrakcyjnia GPGPU z CUDA. Językiem programowania dla CUDA jest język C, ale istnieją także nakładki dla Fortrana, Pythona czy Javy. Oczywiście technologia ta jest dostępna tylko dla urządzeń wyporodukowanych przez NVidię, a pełną ich listę znajdziemy w linku podanym w ramce W Sieci. Konkurencja też nie śpi i np. AMD rozwija alternatywną technologię o nazwie FireStream. Niedawno powstał nowy standard OpenCL, który jest niezależnym od urządzenia sposobem pisania programów dla obliczeń równoległych, podobnie jak OpenGL dla grafiki 3D.

www.sdjournal.org

29

Warsztaty
rowanej przez nas uprzednio wartości • indeks bloku dla aktualnego wątku – • indeks aktualnego wątku w obrębie bloku, do którego przynależy – threadIdx.x . W naszym przykładzie threadIdx.x przyjmuje wartości od 0 do 256 maksymalnie i jest offsetem, podszas gdy blockIdx.x*blockDim.x jest segmentem. Z punktu widzenia CPU jądro jest wykonywane asynchronicznie. Chcąc na nie poczekać użyliśmy cudaThreadSynchronize();
blockIdx.x; numThreadsPerBlock;

Listing 2. Alokacja i zwalnianie pamięci poprzez funkcje C oraz CUDA
size_t mem_size = DATA_SIZE * sizeof(float); //host memory allocation float* h_in; h_in = (float *) malloc (mem_size); //device memory allocation float* d_in; cudaMalloc( (void **) &d_in, mem_size ); … free(h_in);

cudaFree(d_in);

Debuggowanie i emulacja
W trybie Debug mamy możliwość debugowania tylko części kodu dla CPU. Niestety nie jest możliwe śledzenie kodu bezpośrednio wykonywanego w GPU. Na szczęście istnieją tryby emulacji, w których kod napisany dla GPU wykonuje się na CPU, dając nam możliwość pełnego debuggowania (tryb EmuDebug). Przeważnie chcemy w ten sposób sprawdzić poprawność zaimplementowanego przez nas algorytmu, zwłaszcza gdy stosujemy kolejne optymalizacje. W trybie emulacji wątki (a w tym wypadku raczej pojedyncze uruchomienia kodu jądra ) wykonają się sekwencyjnie, jednak w losowej kolejności. Należy pamiętać, że w tym trybie kod może się wykonywać o wiele dłużej, dlatego na potrzeby takiego debuggowania warto czasem zmniejszyć znacznie rozmiar danych, wielkość bloku czy też siatki bloków. Nawet jeśli mamy tablice o milionowych rozmiarach do przetworzenia, często warto najpierw uzyskać poprawny algorytm w trybie emulacji nawet na tablicach kilkunasto elementowych.

Listing 3. Kopiowanie pamięci w CUDA
cudaMemcpy(d_in, h_in, mem_size, cudaMemcpyHostToDevice); … cudaMemcpy(h_out, d_out, mem_size, cudaMemcpyDeviceToHost);

Listing 4. Implementacja funkcji uruchamianej na GPU
__global__ void CudaKernel(float* d_in, float* d_out, data_size){ int idx = blockIdx.x*blockDim.x + threadIdx.x; if(idx >= data_size) return; if( idx < 2 ){ return;

float den, int

d_out[idx] = ( d_in[idx+1] - d_in[idx] ) * den;

}

if( idx >= (data_size – 2)){ return;

d_out[idx] = ( d_in[idx] - d_in[idx-1] ) * den;

Obsługa błędów i specyfikacja urządzenia
Oczywiście błędy były, są i będą, więc CUDA również dostarcza nam mechanizm ich obsługi. Prosty sposób jego wykorzystania przedstawiony jest na Listingu 6. Wspomnieliśmy wcześniej, że w przypadku karty GTX280 maksymalna wartość dla rozmiaru bloku to 512. W niektórych modelach nawet 256 może być nieosiągalne. Aby nasz kod był bardziej przenośny (z punktu widzenia karty graficznej obsługującej CUDA), powinniśmy parametr BLOCK_WIDTH uzależnić od urządzenia. Na Listingu 7. pokazujemy sposób odczytania maksymalnej wartości rozmiaru bloku (zakładamy tutaj, że jeśli w ogóle, to zainstalowana jest tylko jedna karta graficzna z CUDA). Nazwy użytych tutaj funkcji są dość opisowe, więc nie będziemy wchodzić w szczegóły. Dostępny jest też cały szereg innych informacji o naszym urządzeniu, jak. np. rozmiar pamięci globalnej czy współdzielonej, maksymalne rozmiary dla siatki bloków itd.; wszystkie te wartości można uzyskać w analogiczny sposób.
03/2009

}

d_out[idx] = ( d_in[idx-2]-8*d_in[idx-1];

+ 8*d_in[idx+1] - d_in[idx+2] );

}

*den*0.083333333f; // 1/12h;

Listing 5. Konfiguracja i uruchomienie jądra
#define BLOCK_WIDTH 256 #define DATA_SIZE 10000000 #define DATA_STEP 0.0001f …

int numBlocks = DATA_SIZE/BLOCK_WIDTH + 1; int numThreadsPerBlock = BLOCK_WIDTH; dim3 dimGrid(numBlocks); dim3 dimBlock(numThreadsPerBlock); float denominator = 1.0/DATA_STEP;

CudaKernel<<< dimGrid, dimBlock >>> cudaThreadSynchronize();

(d_in, d_out, denominator, DATA_SIZE);

30

CUDA się zdarzają, czyli programowanie GPGPU

Optymalizacja jądra poprzez użycie pamięci współdzielonej
Pomimo że już na tym etapie uzyskaliśmy niezłą prędkość obliczeń, to nadal istnieje możliwość zwiększenia wydajności jądra. Każde odwołanie do tablicy d_in kosztuje od 400 do 600 cykli, gdyż tablica ta jest ulokowana w pamięci globalnej GPU, a pamięć ta nie jest w żaden sposób buforowana. Co więcej, łatwo zauważyć, że kilka wątków będzie czytać naraz z tej samej lokalizacji. Jest to konsekwencją natury naszego zadania numerycznego: dla wykonania obliczeń dla bieżącego indeksu odczytujemy dwie poprzednie i dwie następne wartości w tablicy. Idealna sytuacja występuje, gdy mamy do czynienia z odczytem jednorodnym (ang. coalesced ), kiedy to na jeden wątek przypada jeden i dokładnie jeden adres tablicy. Niestety nie zawsze możemy zmodyfikować nasz algorytm, aby spełniał ten warunek. Możemy wtedy użyć pamięci współdzielonej, z której to odczyt wynosi tylko 4 cykle. Pamięć ta jest wspólna w obrębie jednego bloku, więc jeśli każdy wątek z bloku wczyta jedną wartość z pamięci globalnej do pamięci współdzielonej, to potem wartości te będą dostępne dla wszystkich wątków w bloku już z poziomu pamięci współdzielonej. Zaimplementujmy jeszcze raz nasze jądro (patrz Listing 8.). Znaczenie pierwszej linijki kodu jądra zaraz omówimy. Zwróćmy uwagę, że teraz jądro jest podzielone na dwie sekcje. W pierwszej odbywa się kopiowanie pamięci z globalnej do współdzielonej. Zanim jednak przejdziemy do obliczeń, a tym samym do odczytu wartości, musimy mieć pewność, że wszystkie wątki zakończyły już to kopiowanie. Właśnie do tej synchronizacji służy __syncthreads(). W drugiej sekcji wykonywane są obliczenia tak jak w pierwszej wersji jądra, z tym, że odczytujemy wartości już z tablicy shared[]. Tablica z danymi wejściowymi jest teraz rozdzielona między fragmenty (Rysunek 4.). Każdemu fragmentowi odpowiada blok wątków, a więc i każdy taki fragment jest wczytywany do odpowiadającej pamięci współdzielonej. Ponieważ jednak nasz wzór numeryczny wymaga dwóch poprzednich oraz dwóch następnych punktów w stosunku do aktualnego, to do tablicy shared[] wczytujemy również dwa poprzedzające fragment danych punkty, jak i dwa następujące po fragmencie (patrz Rysunek 5.). Punkty poprzedzające są wczytywane przez dwa pierwsze wątki w bloku, pod warunkiem, że nie są pierwszymi globalnie. Analogicznie punkty następujące są wczytywane przez dwa ostatnie wątki w bloku, pod warunkiem też, że nie są ostatnimi globalnie. Wpłynęło to też na przesunięcie indeksów w sekcji obliczeniowej w porównaniu z pierwszą wersją jądra. Na Listingu 9. widzimy, jak zmieni się nieznacznie sposób wywołania takiego jądra. Pojawił się trzeci parametr konfiguracji i oznacza on wielkość pamięci współdzielowww.sdjournal.org

nej na każdy blok. Wyjaśnia się teraz znaczenie pierwszej linii w kodzie jądra: rozmiar taListing 6. Obsługa błędów w CUDA
cudaError_t error = cudaGetLastError(); if( cudaSuccess != error) {

blicy shared[] w pamięci współdzielonej jest ustalany w momencie uruchamiania jądra, co

fprintf(stderr, "Cuda error: %s.\n", exit(-1);

cudaGetErrorString( error ) );

}

Listing 7. Przykład odczytania specyfikacji karty graficznej
int maxThreadsPerBlock; int deviceCount;

if ( deviceCount > 0 ) { cudaDeviceProp deviceProp;

cudaGetDeviceProperties(&deviceProp, 0); }

maxThreadsPerBlock = deviceProp.maxThreadsPerBlock;

Listing 8. Implementacja funkcji uruchamianej na GPU z użyciem pamięci współdzielonej
__global__ void CudaKernel_sharedmem( float* d_in, { float* d_out, float den, int data_size)

extern __shared__ float shared[];

int idx = blockIdx.x * blockDim.x + threadIdx.x; if(idx >= (data_size)) return;

if( (threadIdx.x < 2) && (idx >= 2) ) { }

shared[threadIdx.x] = d_in[idx – 2];

if( (threadIdx.x>=(blockDim.x-2))&&(idx<(data_size-2))){ } shared[threadIdx.x + 4] =d_in[idx + 2];

shared[threadIdx.x + 2] = d_in[idx]; __syncthreads(); if(idx<2){

d_out[idx] =(shared[threadIdx.x+3] return;

}

else if( idx >= (data_size – 2)){

d_out[idx] =(shared[threadIdx.x+2] return;

- shared[threadIdx.x+1] )*den;

}

d_out[idx] =(shared[threadIdx.x]

+ 8*shared[threadIdx.x+3] *den*0.083333333f;

- 8*shared[threadIdx.x+1] - shared[threadIdx.x+4])

}

31

Warsztaty
uzyskujemy poprzez użycie słowa kluczowego extern. Oczywiście, można też ręcznie ustalić wielkość tablicy w pamięci współdzielonej, należy jednak pamiętać o ograniczeniach jej wielkości.

Listing 9. Konfiguracja uruchomienia jądra z pamięcia współdzieloną
int sharedMemSize = (numThreadsPerBlock+4)*sizeof(float);; CudaKernel_sharedmem<<< dimGrid, dimBlock, sharedMemSize>>>;

(d_in_1, d_out_1, den, DATA_SIZE);

Listing 10. Treść pliku cuda_profile.log
method,gputime,cputime,occupancy; method=[ memcopy ] gputime=[ 11782.849 ] ;

Profilowanie i porównanie czasów wykonania
Chcielibyśmy teraz zobaczyć różnicę między dwiema wersjami naszego jądra ze względu na prędkość wykonania, najlepiej przy użyciu jakiegoś profilera. Na stronie Nvidii dostępny jest CUDA Visual Profiler, posiadający proste GUI, którego nie będziemy tu jednakże opisywać. Jego działanie jest podobne do metody, którą użyjemy bezpośrednio. Mianowicie, po pierwsze musimy włączyć profilowanie. Otwieramy w tym celu właściwości projektu w MS Visualu i w sekcji Debugging w polu Environment wpisujemy CUDA_PROFILE=1;. Dzięki temu, po uruchomieniu naszego programu, powinien pojawić się plik cuda_profile.log o treści przypominającej tę z Listingu 10. W nawiasach kwadratowych podane są czasy w mikrosekundach. Łatwo zauważyć (parametr gputime), iż rzeczywiście zoptymalizowane jądro wykonuje się mniej więcej dwa razy szybciej. Widać również, że raczej wąskim gardłem jest tutaj kopiowanie pamięci do i z GPU (gputime dla metod memcopy). Profiler posiada cały szereg dodatkowych opcji i parametrów. Zainteresowanych odsyłamy do dokumentacji CUDA, do pliku CUDA_Profiler_2.0.txt. Podobne wnioski można wyciągnąć, gdy ręcznie zmierzymy w naszym programie czasy wykonania. I tak, czas wykonania algorytmu na CPU wyniósł 0.15160 sekundy, pierwsza wersja jądra: 0.04360, zaś wersja zoptymalizowana: 0.04062, przy czym w dwóch ostatnich przypadkach jest sumowany czas skopiowania danych na GPU, wykonanie kodu jądra oraz ponowne skopiowanie danych wynikowych na stronę CPU. Pomiary te są bliższe stanu faktycznego, gdyż wynik profilera nie uwzględnił czasu CPU poświęconego kopiowaniu danych. W obu przypadkach ustawiliśmy DATA_SIZE = 10000000.

method=[ __globfunc__Z10CudaKernelPfS_fi ] gputime=[ 2552.960 ] cputime=[ 6.681 ]; method=[ memcopy ] gputime=[ 12483.425 ] ; method=[ memcopy ] gputime=[ 11782.017 ] ; occupancy=[ 1.000 ];

method=[ __globfunc__Z20CudaKernel_sharedmemPfS_fi ] gputime=[ 1292.928 ]; cputime=[ method=[ memcopy ] gputime=[ 11780.385 ] 6.459 ] occupancy=[ 1.000 ];

Listing 11. Alokacja i dealokacja w pamięci niestronicowanej
//host memory allocation cudaMallocHost( (void**) &h_in, mem_size); cudaFreeHost(h_in);

Listing 12. W funkcji HostFunction dodajemy pętlę aby zasymulować więcej obliczeń
for(idx=2; idx<data_size-2; idx++); for(int i=0; i<200; i++); out[idx] =(in[idx-2]-8*in[idx-1]; +8*in[idx+1]–in[idx+2];

�����

�����

�����

�����

�����

���

������

������

������

���

���

�������

�������

�����

�������

�������

����

��� ��������

������

�������� ���

Rysunek 3. Zależność danych wyjściowych od wejściowych

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

��� �������

�������

�����

�������

�������

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

���������

���������

���������

�������

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

��� ��������

������

�������� ���

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

����������

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

Rysunek 4. Fragment danych. Odczyt może być spoza fragmentu

32

03/2009

CUDA się zdarzają, czyli programowanie GPGPU

Nasz problem numeryczny nie był zbyt skomplikowany obliczeniowo w tym sensie, że jeden wątek (jedno przekręcenie pętli) nie wykonywał zbyt wielu operacji. Z otrzymanych tutaj wyników można wysnuć śmiało wniosek, iż wysiłek włożony w optymalizację jądra może nie zawsze się opłacać. Oczywiście o wiele łatwiej jest napisać kod jądra nie używając pamięci współdzielonej i może to czasami być wystarczające. Nietrudno jednak wyobrazić sobie sytuację, gdy obliczenia są o wiele bardziej skomplikowane lub gdy kod jądra jest intensywnie wykonywany bez kopiowania danych (np. generacja tekstury, złożone symulacje w pętli).

Na bazie naszego przykładu zrealizujemy powyższy scenariusz i wykonamy kolejne eksperymenty, porównując z czasem wykonania na CPU. Aby zasymulować większą złożoność obliczeniową, formuły wynikowe powtórzymy, powiedzmy, ze 200 razy w HostFunction (patrz Listing 12.). i analogicznie w kodzie jądra CudaKernel_ sharedmem. Na Listingu 13. widzimy kod, jaki wykonamy po stronie CPU, zaś na Listingu 14. odpowiadającą mu adaptację dla GPU z użyciem asynchronicznego API.

Najpierw tworzymy identyfikatory dla dwóch strumieni. Strumień jest ciągiem sekwencyjncyh operacji, ale dwa strumienie są wobec siebie asynchroniczne. Do utworzenia i zamknięcia strumienia służą odpowiednio: cudaStreamCreate oraz cudaStreamDestroy, zaś funkcja cudaStreamSynchronize wstrzymuje program, aż wszystkie operacje w strumieniu się nie zakończą. Aby kopiowanie danych było asynchroniczne, musimy po pierwsze użyć funkcji cudaMemcpyAsync za-

Listing 13. Dziesięciokrotne wywokonanie HostFunction dla dwóch tablic
for(int i=0;i<10;i++){; if(i%2 == 0); else; } HostFunction(h_in_1,h_out_1,den,DATA_SIZE);; HostFunction(h_in_2,h_out_2,den,DATA_SIZE);;

Pamięć niestronicowana
CUDA posiada bardzo ciekawy mechanizm pozwalający na użycie pamięci niestronicowanej (ang. page-locked). Z grubsza wystarczy nam tutaj takie rozróżnienie, że pamięć zaalokowana w pamięci stronicowanej, czyli przy użyciu standardowego malloc'a, w pierwszej kolejnośći jest kopiowana do pamięci niestronicowanej, a dopiero w drugiej kolejności poprzez DMA, do pamięci GPU. W przypadku pamięci niestronicowanej mamy do czynienia tylko z tym drugim etapem. Aby zastosować tę dogodność, zmodyfikujemy część kodu z Listingu 2. do kodu z Listingu 11. Po tej modyfikacji mierzymy ponownie czasy wykonania i otrzymujemy odpowiednio dla obu wersji jądra: 0.02628 oraz 0.02526 sekundy. Zatem wąskie gardło dało się trochę rozszerzyć. Trzeba jednak pamiętać, że pula pamięci niestronicowanej jest o wiele mniejsza niż stronicowanej i nie należy przesadzać z tego typu alokacjami.

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

� �������

� �������

� �����

� �������

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

� ���������

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

��� �������

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

� ������

���

���

����� ������

�����

�����

�����

�����

Obliczenia asynchroniczne
Wspomnieliśmy wcześniej, że jądro jest wykonywane asynchronicznie z punktu widzenia CPU. Dodatkowo kopiowanie z pamięci niestronicowanej nie obciąża CPU. CUDA korzysta z tych faktów udostępniając asynchroniczne API, dzięki któremu da się wykonać następujący scenariusz: • dane są kopiowane do pamięci GPU; • następnie na tych danych jest wykonywany kod jądra, a w tym samym czasie trwa kopiowanie kolejnych danych; • dane wynikowe z 1. są kopiowane z GPU, a w tym czasie na drugich danych wykonuje się kod (być może innego) jądra; • powrót do kroku 1. Co więcej, w tym samym czasie da się jeszcze czasami wcisnąć jakieś obliczenia na CPU, gdyż operacje na CPU, GPU oraz kopiowanie pomiędzy nimi wykonywane są niezależnie względem siebie.
www.sdjournal.org

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

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

� ������

���

���

���

���������

���������

�������

���������

���������

� ������

���

���

�����

�����

�����

�����

�����

��������

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

Rysunek 5. Schemat bloków wątków i odpowiadających im pamięci współdzielonych

33

Warsztaty
miast cudaMemcpy, podając dodatkowo jako ostatni argument identyfikator strumienia, a po drugie pamięć po stronie CPU musi być zaalokowana w pamięci niestronicowanej. Jeśli o tym zapomnimy, to niestety kompilator tego nie wykryje i błąd pojawi się dopiero w trakcie wykonania programu – i to zakładając, że sami przechwytujemy te błędy. Czyli najbezpieczniej jest po prostu po każdej operacji przy użyciu API CUDA sprawdzić ostatni błąd. Jest to dość żmudne i raczej psuje czytelność kodu, dlatego też we wszystkich listingach pomijaliśmy obsługę błędów. Za to w tym momencie dajemy przykład na to, że lekceważenie tego problemu może sprawić przykre niespodzianki. Wracając do Listingu 13. zwracamy jeszcze uwagę, że identyfikatory strumieni pojawiają się także jako ostatni parametr konfiguracji jądra.

Podsumowanie
W podsumowaniu podajemy rezultaty czasowe ostatniego eksperymentu: dla CPU było to 62.86327 sekund, zaś dla GPU 1.29735. Można by rzec, że wyniki mówią same za siebie. Czy są imponujące, pozostawiamy do subiektywnej oceny. Panuje opinia, że GPU liczy coś tam, coś tam setki razy szybciej niż CPU. W niektórych zastosowaniach, a zwłaszcza w takich, gdzie nie mamy do czynienia z kopiowaniem dużej ilości danych pomiędzy CPU i GPU, takie wyniki są jak najbardziej osiągalne. Jeśli jednak mówimy o GPGPU w pełni tego słowa znaczeniu, to nie możemy zapominać o wąskim gardle. Co więcej, operacje dzielenia i mnożenia na liczbach całkowitych jak na razie są beznadziejnie wolne w porównaniu z ich odpowiednikami dla liczb zmiennoprzecinkowych, a te z kolei kosztem szybkości są pozbawione czasami należytej dokładności. No cóż, w końcu karty graficzne zostały stworzone do grafiki. Na pewno jednak GPU wraz z CUDA jest świetnym poszerzeniem możliwości obliczeniowych oferowanych przez CPU. Najlepiej jednak wykorzystywać oba równocześnie, gdyż nie zawsze CUDA będzie w stanie czynić cuda.

Listing 14. Adaptacja do wersji CUDA kodu z Listingu 13
cudaStream_t stream_one, stream_two; cudaStreamCreate(&stream_one); cudaStreamCreate(&stream_two); for(int i=0;i<10;i++) { if(i%2 == 0){ cudaMemcpyHostToDevice,stream_one);

CudaKernel_sharedmem<<< dimGrid, dimBlock,

cudaMemcpyAsync(h_out_1,d_out_1,mem_size, }

(d_in_1, d_out_1, den, DATA_SIZE);

sharedMemSize, stream_one >>>

cudaMemcpyDeviceToHost,stream_one);

else{

cudaMemcpyAsync(d_in_2,h_in_2,mem_size,

CudaKernel_sharedmem<<< dimGrid, dimBlock,

cudaMemcpyHostToDevice,stream_two);

cudaMemcpyAsync(h_out_2,d_out_2,mem_size, }

(d_in_2, d_out_2, den, DATA_SIZE);

sharedMemSize, stream_two >>>

cudaMemcpyDeviceToHost,stream_two);

JACEK PIEKARSKI
Pracuje na stanowisku programisty w firmie BLStream wchodzącej w skład Grupy BLStream. Grupa BLStream powstała, by efektywniej wykorzystywać potencjał dwóch, szybko rozwijających się producentów oprogramowania – BLStream i Gamelion. Firmy wchodzące w skład grupy specjalizują się w wytwarzaniu oprogramowania dla klientów korporacyjnych, w rozwiązaniach mobilnych oraz produkcji i testowaniu gier. Kontakt z autorem: jacek.piekarski@blstream.com

}

cudaStreamSynchronize(stream_one); cudaStreamSynchronize(stream_two); cudaStreamDestroy(stream_one); cudaStreamDestroy(stream_two);

Bibliografia
• •

W zasadzie literatura papierowa do CUDA jeszcze nie istnieje, ale zachęcamy do lektury następujących: NVIDIA_CUDA_Programming_Guide_1.1.pdf – po zainstalowaniu CUDA dokument dostępny w katalogu docs/; http://sites.google.com/site/cudaiap2009/materials-1/cuda-textbook – panowie David Kirk oraz Prof. Wen-mei Hwu udostępnili nam fragmenty książki, którą przygotowują.

W Sieci
• • • • • • • http://www.nvidia.pl/object/cuda_what_is_pl.html – strona firmowa CUDA; http://www.nvidia.pl/object/cuda_learn_products_pl.html – lista urządzeń wspierających CUDA; http://sarathc.wordpress.com/2008/09/26/how-to-integrate-cuda-with-visual-c/ – alternatywny sposób integracji CUDA z Visualem C++; http://en.wikipedia.org/wiki/CUDA – ogólnie o CUDA; http://www.ddj.com/architect/207200659 – cykl świetnych artykułów wprowadzających do programowania z CUDA; http://heim.ifi.uio.no/~knutm/geilo2008/seland.pdf – wprowadzenie do CUDA w formie prezentacji; http://www.gpgpu.org/ - strona poświęcona GPGPU nie tylko z CUDA.

34

03/2009

Opis CD

UIQ 3.3 Beta SDK
UIQ SDK to zestaw narzędzi UIQ, Symbiana i innych. SDK to zestaw narzędzi kontrolowanych przez skrypty Perl. Nowości w interfejsie to: pełne wykorzystanie możliwości Opery Mobile 9 (szybkie ładowanie stron, usprawnienie Zoomu), wprowadzenie obsługi usługi Widget za pomocą specjalnie przygotowanego pulpitu, usprawnienie obsługi Opery za pomocą szybko dostępnych funkcji, ujednolicony system wiadomości oraz obsługa Java JSR 248 MSA.

cji. IP*Works! Secure SNMP wspiera pełny zakres możliwości zarządzania siecią, łącznie z rozszerzonymi właściwościami bezpieczeństwa SNMPv3, opracowanie pułapek, i kompilację ASN-1 MIB.

IP*Works! Zip
Zestaw łatwych, szybkich i efektywnych komponentów, który daje informatykom możliwość dodawania funkcji kompresji do swoich aplikacji. IP*Works! Zip umożlwia szybka integrację funkcji kompresji i rozpakowywania do aplikacji, wykorzystując do tego standardy kompresji Zip, Tar, Gzip lub Jar.

IP*Works! SSL
Do IP*Works! dodano bezpieczeństwo SSL i zarządzanie certyfikatami cyfrowymi. IP*Works! SSL – to wszechstronny zestaw komponentów ze wsparciem SSL w celu zapewnienia bezpiecznej pracy wszystkich protokołów internetowych.

Inne
Trialowe wersje kilkunastu produktów firmy nsoftware

IP*Works! Secure SNMP
IP*Works! Secure SNMP to wszechstronne narzędzie do tworzenia bezpiecznych agentów SNMP i menadżerów aplikaRedakcja nie udziela pomocy technicznej w instalowaniu i użytkowaniu programów zamieszczonych na płytach CD-ROM dostarczonych razem z pismem.

Jeśli nie możesz odczytać zawartości płyty CD, a nie jest ona uszkodzona mechanicznie, sprawdź ją na co najmniej dwóch napędach CD. W razie problemów z płytą, prosimy pisać pod adres: cd@softtware.com.pl

www.sdjournal.org

35

Warsztaty

Facebook dla programistów
Przygotuj własną aplikację dla użytkowników serwisu Facebook
Facebook jest nie tylko klasycznym serwisem społecznościowym, lecz także platformą umożliwiającą tworzenie własnych aplikacji. W artykule pokażemy jak przygotować i opublikować przykładową aplikację dla Facebooka współpracującą z serwisem aukcyjnym Allegro.
Dowiesz się:
• jak stworzyć i opublikować aplikację dla platformy Facebook, • w jaki sposób wykorzystać Facebook API, FBML i FQL, • jak wykorzystać metody Allegro WebAPI.

Powinieneś wiedzieć:
• znać podstawy tworzenia aplikacji webowych (PHP, HTML, CSS), • znać podstawy programowania obiektowego, • znać podstawy języka SQL, • wiedzieć czym jest WebService i protokół SOAP.

Rozpoczynamy pracę
Tworzenie każdej aplikacji dla platformy Facebook należy rozpocząć od jej zarejestrowania i wygenerowania kluczy. Służy do tego dostępna dla każdego zarejestrowanego w serwisie użytkownika aplikacja o nazwie Twórca aplikacji (ang. Developer). Po wybraniu przycisku Set Up New Application zostaniemy przeniesieni do okna tworzenia nowej aplikacji. Mimo iż jedynymi wymaganymi polami są nazwa aplikacji (ang. Application Name) oraz potwierdzenie zapoznania się z regulaminem usługi, warto w tym miejscu od razu skonfigurować pola Callback URL oraz Canvas Page URL, które umożliwią nam szybkie uruchomienie testowej aplikacji. Pierwsze z nich jest adresem, pod którym fizycznie będzie dostępna nasza aplikacja (np. http://www.kozlowscy.org/facebook/ allegro), drugi parametr określa unikalną nazwę, która posłuży do konstrukcji adresu, pod którym będzie widoczna nasza aplikacja (np. http://apps.facebook.com/allegro). Oczywiście wszystkie ustawienia aplikacji możemy później edytować. Do pierwszego uruchomienia naszej aplikacji pozostało nam tylko kilka kroków. Po pierwsze do katalogu aplikacji na naszym serwerze musimy skopiować pliki oficjalnego klienta Facebooka (ang. official PHP Client Library) oraz plik index.php, który możemy wygenerować automatycznie, korzystając z linka Get started quickly with some example code! Jeśli wywołamy teraz naszą aplikację, powinniśmy ujrzeć listę naszych znajomych w serwisie (dokładniej listę ich identyfikatorów). Nasza aplikacja nie musi być oczywiście tworzona z wykorzystaniem wyżej wspomnianej biblioteki i języka PHP. Facebook API jest interfejsem opartym o wywołania REST zwracającym wyniki w formacie XML
03/2009

Poziom trudności

F

acebook (www.facebook.com) jest serwisem społecznościowym, dzięki któremu, jak piszą o nim jego autorzy, miliony użytkowników na całym świecie każdego dnia mogą odszukiwać swoich znajomych, przesyłać nieograniczoną liczbę zdjęć, udostępniać linki i pliki wideo i dowiadywać się coraz więcej o poznanych tam ludziach, a wszystko po to, żeby świat był coraz bardziej otwarty i połączony. Projekt został uruchomiony 4 lutego 2004 roku przez studenta Uniwersytetu Harvard – Marka Zuckerberga i obecnie posiada ponad 120 mln aktywnych użytkowników na całym świecie. Według rankingu Forbes Magazine z 2008 roku Zuckerberg został najmłodszym miliarderem świata. Z punktu widzenia programisty Facebook jest tym bardziej interesujący, że umożliwia tworzenie i publikowanie własnych aplikacji dla tej platformy. Dzięki temu możemy zrealizować zasadę: jeśli brakuje Ci funkcjonalności dostarczonej przez twórców serwisu, rozbuduj go o to, co potrzebujesz i jeśli masz taką ochotę,
36

udostępnij efekty swojej pracy innym członkom społeczności. Katalog aplikacji podzielony jest na kilkadziesiąt kategorii, w których można znaleźć zarówno eksperymentalną aplikację do weryfikacji teorii o sześciu stopniach separacji – Six Degrees, jak i aplikację umożliwiającą komponowanie nowych potraw i ocenę ich smaku przez własnych znajomych.

Jak działają aplikacje Facebooka
Schemat działania każdej zewnętrznej aplikacji Facebooka przedstawiony jest na Rysunku 1. Za każdym razem, kiedy użytkownik dokonuje interakcji z naszą aplikacją (1) jego żądanie poprzez jeden z serwerów serwisu społecznościowego przekazywane jest do serwera, na którym hostowana jest nasza aplikacja (2). W odpowiedzi na to żądanie aplikacja przygotowuje odpowiedź w formacie FBML, którą przekazuje do serwera Facebooka (5). Jednym z kroków przygotowania takiej odpowiedzi może być dodatkowa komunikacja z serwerami platformy poprzez wywołanie jednej z metod API lub zapytanie FQL. W kolejnym kroku nasza odpowiedź FBML tłumaczona jest do HTML i w takiej postaci przesyłana jest do przeglądarki użytkownika (6).

Facebook dla programistów

lub JSON, a wynikiem wywołania naszej aplikacji zwracanym do serwerów Facebook jest kod FBML. Możemy więc wykorzystać biblioteki dostępne dla innych języków (choćby facebook-java-api http://code.google.com/p/ facebook-java-api/) lub zdać się na własną implementację.

Wykorzystane technologie i narzędzia
Facebook API Facebook API jest sieciową usługą opartą o REST udostępniającą kilkadziesiąt metod w kilku grupach tematycznych.

Listing 1. Przykładowy szkielet naszej aplikacji wygenerowany automatycznie z Twórcy aplikacji
<?php // // Application: test // File: 'index.php' // // require_once 'facebook.php'; $appapikey = '0f88cc125f2c08e351541ae2ecabc985'; $appsecret = 'e7ada359998797e35f9422b2b960a2da'; $user_id = $facebook->require_login(); // Greet the currently logged-in user! $facebook = new Facebook($appapikey, $appsecret); This is a sample skeleton for your application.

Facebook Markup Language (FBML) FBML jest zbiorem znaczników umożliwiającym integrację aplikację z platformą Facebooka. Składa się z podzbioru znaczników HTML oraz znaczników specyficznych dla Facebooka, np. fb:photo czy fb:dialog. Zwróćmy uwagę, że w zbiorze znaczników FBML nie ma np. znacznika body. Próba jego użycia w naszej aplikacji spowoduje wystąpienie błędu ładowania strony i wyświetlenie komunikatu w rodzaju:
Wystąpiły błędy podczas ładowania strony Błędy składniowe: aplikacji

// Copyright 2007 Facebook Corp.

All Rights Reserved.

FBML Error (line 184): illegal tag "body" under "fb:canvas".

echo "<p>Hello, <fb:name uid=\"$user_id\" useyou=\"false\" />!</p>"; // Print out at most 25 of the logged-in user's friends, // using the friends.get API method echo "<p>Friends:"; $friends = $facebook->api_client->friends_get(); $friends = array_slice($friends, 0, 25); foreach ($friends as $friend) { } echo "<br>$friend";

Komunikat taki pojawi się tylko w przypadku używania aplikacji przez jej programistów, dla pozostałych użytkowników niedozwolone znaczniki zostaną po prostu zignorowane. Podglądając źródła stron prezentowanych w przeglądarce przez naszą aplikację, możemy zobaczyć, w jaki sposób tłumaczone są strony FBML do HTML. Jeśli jesteś programistą używanej aplikacji, w komentarzach możesz także zobaczyć źródłowy FBML, który może okazać się przydatny w procesie debugowania. Facebook Query Language (FQL) FQL umożliwia dostęp do tych samych danych, które możemy uzyskać za pomocą wywołań metod API, ale w stylu podobnym do zapytań języka SQL. Tak naprawdę użycie sporej części metod API sprowadza się do wykonania określonych za-

echo "</p>"; ?>

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

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

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

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

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

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

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

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

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

Rysunek 1. Schemat działania aplikacji Facebooka

Rysunek 2. Struktura i lista plików aplikacji

www.sdjournal.org

37

Warsztaty
pytań FQL. Wykorzystując zapytania FQL, możemy zarówno ograniczyć liczbę niezbędnych żądań w porównaniu z wykorzystaniem tradycyjnego API, jak i stosować złożone kryteria wyszukiwania. Poniżej przykładowe zapytanie zwracające nam identyfikator, nazwę oraz datę urodzin wszystkich naszych znajomych.
SELECT uid, name, birthday FROM user WHERE uid IN (SELECT uid2 FROM friend WHERE uid1 = $fb_uid).

mi wywołań metod API i zwracanymi formatami danych, zapytań FQL i poprawnością wykorzystania znaczników FBML w poszczególnych elementach aplikacji. Allegro WebAPI Jak piszą sami autorzy, Allegro WebAPI to usługa umożliwiająca wymianę informacji między zewnętrznymi aplikacjami a serwisem. Dzięki niej można tworzyć programy ułatwiające m.in. zarządzanie transakcjami. Aby rozpocząć pracę z usługą, należy być użytkownikiem Allegro i wystąpić o klucz aktywacji WebAPI-Key. Obecnie korzystanie z pakietu podstawowego, który zawiera około 70 metod jest bezpłatne, nie są także naliczane żadne opłaty za poszczególne wywołania. Szczegółowy opis usługi udostępniany jest za pomocą pliku WSDL (ang. Web Services Description Language) dzięki czemu możemy ją wykorzystać w każdym języku wspierającym obsługę protokołu SOAP.

go w zależności od wartości parametru menu dołączane są funkcją include odpowiednie skrypty. Struktura i lista wszystkich plików pokazana jest na Rysunku 2. Kilka słów o bezpieczeństwie Musimy pamiętać, że zgodnie z architekturą przedstawioną na Rysunku 1. skrypty aplikacji wykonywane są na naszym serwerze, i to na nas spoczywa zapewnienie jej bezpieczeństwa. Z tego też względu wprowadzona jest kontrola wartości parametru menu, żeby zapobiec próbie nieuprawnionego dostępu lub wykonania plików spoza naszej aplikacji, dodatkowo w katalogu include umieściliśmy plik .htaccess z wpisem
<FILES ~ ".php$"> Deny from all </FILES>

Typowe wywołanie zapytania FQL będzie wyglądać następująco:
$query = "...";

$result = $facebook->api_client->fql_ query($query);

Narzędzia dla programistów Strona dla programistów Facebooka udostępnia między innymi narzędzia API Test Console i FBML Test Console. Z ich wykorzystaniem możemy przeprowadzać eksperymenty z parametraListing 2. Główny plik aplikacji index.php
<?php

Budujemy naszą aplikację
Głównym plikiem aplikacji jest index.php, przez który przechodzą wszystkie wywołania i do które-

dzięki czemu próba bezpośredniego wywołania dowolnego pliku PHP z tego katalogu zakończy się błędem.

// plik konfiguracyjny // klient Facebooka // klasa Allegro );

array('auction', 'Aukcja', false), array('test', '@Test', false)

require_once 'config.php'; require_once 'facebook.php'; require_once 'allegro.php';

array('watch', 'Dodaj do obserwowanych', false),

for($i = 0; $i < count($items); $i++) { if($items[$i][2]) { $selected = ($menu == $items[$i][0]);

// zestaw funkcji pomocniczych }

require_once 'functions.php'; // utworzenie instancji klienta Facebooka $facebook = new Facebook($config['facebook']['api-key'], // korzystanie z naszej aplikacji wymaga wcześniejszego zalogowania // utworzenie instancji pomocniczej klasy obsługi serwisu Allegro ?> $allegro = new Allegro($config); $fb_uid = $facebook->require_login(); $config['facebook']['secret']); ?> }

echo "<fb:action href=\"?menu={$items[$i][0]}\ ">{$items[$i][1]}</fb:action>";

<fb:create-button href="?menu=friends">Powiadom znajomych</ fb:create-button>

</fb:dashboard> <!-- include --> <div> <?php

<style>

$step = nvl($_REQUEST['step'], 1); foreach($items as $item) /* $pages[] = $item[0];

<?php echo htmlentities(file_get_contents('css/styles.css', true)); ?>

</style> <!-- dashboard --> <fb:dashboard> <?php

* kontrola czy wartość parametru * jest jedną z dopuszczalnych */ if(!in_array($menu, $pages)) try { die('Próba wywołania niepoprawnej opcji!'); include('./include/' . basename($menu) . '.php'); echo '<fb:error><fb:message>Błąd</fb:message>' . $e>getMessage() . '</fb:error>';

$menu = nvl($_REQUEST['menu'], 'my_auctions'); $items = array( array('my_auctions', 'Moje aukcje', true), array('search', 'Szukaj', true), array('login', 'Zaloguj', true),

array('friends_auctions', 'Aukcje znajomych', true), array('friends', 'Znajomi', true), array('about', 'Informacja', true),

} catch(Exception $e) {

?>

}

</div>

38

03/2009

Facebook dla programistów

Konsumowanie usługi Allegro
Użycie zdecydowanej większości metod Allegro WebAPI wymaga wcześniejszego zalogowania się do serwisu. Służą do tego metody doLogin lub doLoginEnc. W naszej aplikacji wybraliśmy tę drugą ze względu na sposób przesyłania hasła użytkownika. Porównanie danych przesyłanych do serwera w wyniku wywołania metody logowania dla użytkownika pwgdrk, który podał hasło ngtrx znajduje się na Listingu 5. Oprócz oczywistych parametrów, jakimi są nazwa user-login i hasło użytkownika userpassword metody wymagają podania kodu kraju użytkownika country-code (1 – dla Polski), wartości klucza WebAPI webapi-key oraz aktualnego numeru wersji komponentów localversion. Numer ten zmienia się wraz ze zmianami dokonywanymi w udostępnianej przez Allegro usłudze i może być wykorzystywany do weryfikacji zgodności wersji aplikacji klienckiej z interfejsem WebAPI. Jeśli podana przez nas wartość tego parametru będzie różnić się od aktualnej wersji serwisu, to próba logowania zakończy się błędem i zwróceniem komunikatu Niepoprawna wersja kategorii lub pól sprzedaży. Proszę sprawdzić lokalne wersje i uaktualnić oprogramowanie! Aktualną wartość tego parametru możemy uzyskać, wykorzystując panel użytkownika serwisu Allegro (opcja Allegro> Moje Allegro>Ustawienia>WebAPI>Informacje) lub wywołując metodę doQuerySysStatus, doQueryAllSysStatus lub doGetSitesInfo. Do komunikacji z usługą wykorzystamy w naszej aplikacji pomocniczą klasę Allegro pokazaną na Listingu 3. Klasa zawiera pole api będące instancją klasy SoapClient, za pomocą którego będziemy odwoływać się poszczególnych metod API. W wyniku poprawnego zalogowania do serwisu zwracany jest uchwyt (identyfikator) sesji, który jest parametrem wejściowym do wszystkich metod wymagających wcześniejszego zalogowania. Każdy użytkownik może mieć równocześnie otwartych do pięciu sesji, a ważność trwania sesji wynosi 3 godziny. Dla celów demonstracyjnych wartość tego identyfikatora zapisujemy w cookies z wykorzystaniem metody Facebook API
data.setCookie: $facebook->api_client->data_setCookie($fb_ 'AllegroSession', $session, (time() + 3 * HOUR), null); uid,

kownika Facebook fb _ uid ,identyfikator użytkownika Allegro a _ uid , dzięki czemu będziemy mogli zrealizować funkcjonalność prezentacji wystawionych aukcji naszych znajomych.

Funkcjonalność naszej aplikacji
Przykładowy widok naszej aplikacji w działaniu wraz z jej menu głównym pokazany jest na Rysunku 3.

Opcja Moje aukcje (my_auctions.php) odpowiada części funkcjonalności dostępnej w panelu użytkownika serwisu Allegro w opcji Moje Allegro>Aukcje. Do realizacji zakładek wykorzystaliśmy znacznik fb:tab-item. Aukcje znajomych (friends_auctions.php) to lista sprzedawanych przedmiotów w serwisie aukcyjnym przez naszych znajomych z serwisu społecznościowego. W pierwszym kroku zapy-

Rysunek 3. Przykładowy widok naszej aplikacji prezentujący informacje o wybranej aukcji

a kontrolę aktualności logowania wykorzystując zapytanie FQL:
$cookies = $facebook->api_client->fql_query WHERE uid = $fb_uid AND name = time());.

Rysunek 4. Wyślij zaproszenie do znajomych jako przykład wykorzystania znaczników FBML

("SELECT name, value, expires FROM cookies 'AllegroSession' AND expires > " .

Każde pomyślne logowanie skutkuje także zapisaniem w bazie danych pary identyfikator użytwww.sdjournal.org

Rysunek 5. Przykładowy efekt wykorzystania funkcjonalności Udostępnij

39

Warsztaty

Listing 3. Klasa Allegro
<?php $this->config['allegro']['webapi-key'], // identyfikator (uchwyt) sesji return $session; $doGetSitesInfoResponse['ver-key']);

class Allegro{ /*

private $config; * pole będące instancją klienta SOAP, * które umożliwia nam dostęp do metod interfejsu Allegro WebAPI * (http://webapi.allegro.pl) */ public $api; function __construct($config) { // utworzenie instancji klienta SOAP $this->api = new SoapClient("http://webapi.allegro.pl/ } /* * nawiązanie połączenia z bazą danych */ private function connect() { mysql_connect($this->config['database']['host'], $this->config['database']['user'], $this->config['database']['password']); } uploader.php?wsdl"); $this->config = $config; } /*

$session = $doLoginEncResponse['session-handle-part'];

* metoda kodowania hasła */ private function enc($password) { } /* * zapisuje powiązanie między kontami Facebook i Allegro * (identyfikatory użytkowników w obu serwisach) */ public function doSaveUser($fb_uid, $a_uid) { $this->connect(); $query = "REPLACE INTO fba_users SET fb_uid = $fb_uid, mysql_query($query) a_uid = $a_uid"; return base64_encode(hash('sha256',$password,true));

or die(mysql_error());

} /*

mysql_select_db($this->config['database']['name']);

public function doGetUsers($fb_uids){

$query = 'SELECT * FROM fba_users WHERE fb_uid in (' . $this->connect(); implode(',', $fb_uids) . ')';

* zalogowanie do serwisu Allegro */ public function doLogin($login, $password) { // pobranie aktualnej wartości local-version $doGetSitesInfoResponse = $this->api->doGetSitesInfo(1, // szyfrowane logowanie $this->config['allegro']['webapi-key']); }

$result = mysql_query($query); $users[] = $row;

while($row = mysql_fetch_assoc($result)) { } }

return $users;

$doLoginEncResponse = $this->api->doLoginEnc( $login, $this->enc($password), 1,

?>

Świat jest mały

W 1967 r. Stanley Milgram – amerykański socjolog z uniwersytetu Yale przeprowadził ciekawy eksperyment. Poprosił losowo wybrane osoby z Nebraski o przesłanie listu do pewnego maklera giełdowego w Bostonie. Oczywiście jego adres pocztowy nie został ujawniony, a uczestnicy doświadczenia musieli dotrzeć do adresata, wykorzystując jedynie sieć swoich znajomych. Część listów dotarła i okazało się, że średnia liczba ogniw w łańcuchu drogi listu wyniosła sześć. Stąd wzięła się nazwa paradygmatu o sześciu stopniach separacji (and. six degrees of separation) i teorii tzw. małych światów (ang. small world). Okazuje się, że własność tę posiadają także modele innych sieci rzeczywistych. Powstające serwisy społecznościowe stały się naturalnym polem do ponownej weryfikacji wspomnianej teorii.

Metody Allegro WebAPI
• • • • • • • •

Przykładowe metody usługi Allegro WebAPI wykorzystane w naszej aplikacji:
doShowItemInfo – pozwala uzyskać informacje o aukcji o określonym identyfikatorze, doGetBidItem2 – pozwala uzyskać informacje o ofertach kupna złożonych w danej aukcji, doGetUserID – pozwala uzyskać unikalny identyfikator użytkownika na podstawie jego nazwy (login) lub adresu email, doMyAccount2 – pozwala uzyskać informacje o aukcjach użytkownika (Licytuję, Sprzedaję, Wygrałem itp.), doSearch – pozwala na wyszukiwanie aukcji o zadanych parametrach, doAddWatchList – pozwala dodać określoną aukcję do listy aukcji obserwowanych, doGetSitesInfo – pozwala uzyskać podstawowe informacje o dostępnych serwisach aukcyjnych, doLoginEnc – metoda szyfrowanego logowania do serwisu.

40

03/2009

Facebook dla programistów

taniem FQL pobieramy listę znajomych, którzy już dodali naszą aplikację:
SELECT uid FROM user WHERE is_app_user = 1 AND uid IN (SELECT uid2 FROM friend WHERE uid1 = $fb_uid)

a następnie z wykorzystaniem metody doGetUsers klasy Allegro pobieramy powiązanie pomiędzy kontami użytkownika w obu serwisach. Mając te dane, możemy już uzyskać listę aukcji każdego użytkownika. Zamiast jego nazwy wykorzystaliśmy znacznik fb:profile-pic wyświetlający jego profilowe zdjęcie. Szukaj (search.php) to prosta wyszukiwarka z formularzem opartym na znaczniku fb:editor.

W opcji Znajomi (friends.php) wykorzystując znaczniki fb:request-form i fb:multifriend-selector możemy wysłać zaproszenie do znajomych, którzy nie używają jeszcze naszej aplikacji. Nasza aplikacja nie musi ograniczać się jedynie do swojego głównego okna (ang. Canvas Page). W widoku aukcji (auction.php) zastosowaliśmy znacznik fb:share-button, który umożliwia nam współdzielenie zasobów z innymi użytkownikami poprzez wysłanie do nich wiadomości lub publikację informacji na stronie naszego profilu. Przykładowy efekt wykorzystania znacznika pokazany jest na Rysunku 5. Dodatkowo wykorzystaliśmy metodę API profile.setFBML, za pomocą której ustawiamy informację o ostat-

nio oglądanej przez nas aukcji w widoku Pola naszego profilu.

Katalog aplikacji
Kiedy uznamy, że nasza aplikacja jest już gotowa i posiada co najmniej pięciu użytkowników, możemy wysłać ją do Katalogu aplikacji wykorzystując opcję w Twórcy aplikacji. Cały proces sprowadza się do wypełnienia krótkiego formularza. Aby nasza aplikacja nie została odrzucona, musimy pamiętać o tym, że jej nazwa nie może zawierać słów fb i face (np. nasza przykładowa aplikacja otrzymała nazwę Yaama jako akronim od słów Yet Another Allegro Manager), a opis musi być w języku angielskim. Po pozytywnym przejściu weryfikacji nasza aplikacja stanie się łatwo dostępna dla milionów użytkowników serwisu.

Podsumowanie
Pokazaliśmy w jaki sposób utworzyć przykładową aplikację działającą na platformie Facebook. Oczywiście wykorzystaliśmy tylko wycinek możliwości zarówno mechanizmów oferowanych przez tę platformę, jak i interfejsu serwisu aukcyjnego. Mamy jednak nadzieję, że spojrzenie na serwis społecznościowy nie od strony użytkownika, lecz od strony programisty, uczyni go atrakcyjnym polem eksperymentów dla tych drugich.

WŁODZIMIERZ KOZŁOWSKI
Rysunek 6. Przykładowy widok aplikacji w zakładce Pola naszego profilu Absolwent Wydziału Elektrycznego Politechniki Poznańskiej, obecnie doktorant na Wydziale Matematyki i Informatyki Uniwersytetu im. Adama Mickiewicza. Pracuje jako projektant i programista w firmie ABG S.A. (Grupa Asseco). Jest laureatem Truveo Developers Challenge 2008 (za aplikację 3Styler for Facebook) oraz konkursu na przygotowanie dokumentacji z przykładami dla usługi Allegro WebAPI. Kontakt z autorem: wlodzimierz@kozlowscy.org

W Sieci
• • Strona dla programistów Facebooka http://developers.facebook.com/ Dokumentacja usługi Allegro WebAPI http://webapi.allegro.pl/

Listing 4. Skrypt tworzący tabelę przechowującą powiązanie kont użytkowników Facebooka i Allegro
CREATE TABLE IF NOT EXISTS `fba_users` (

`fb_uid` bigint(20) NOT NULL COMMENT 'identyfikator użytkownika Facebook', PRIMARY KEY (`fb_uid`)

`a_uid` bigint(20) NOT NULL COMMENT 'identyfikator użytkownika Allegro.pl', );

Listing 5. Porównanie przesyłanych danych dla obu metod logowania
<!-- fragment koperty SOAP dla wywołania metody doLogin --> <ns1:doLogin soapenv:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" xmlns:ns1="urn:AllegroWebApi"> <user-login xsi:type="xsd:string">pwgdrk</user-login> <user-password xsi:type="xsd:string">ngtrx</user-password>

</ns1:doLogin>

...

<!-- oraz analogiczny fragment dla tych samych danych użytkownika przesyłanych w wyniku wywołania metody doLoginEnc --> <ns1:doLoginEnc soapenv:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" xmlns:ns1="urn:AllegroWebApi"> <user-login xsi:type="xsd:string">pwgdrk</user-login> <user-hash-password xsi:type="xsd:string">tKa+M+Ur0WT4ggDq5cOUQfmqt3+Wo+7eGDTQL2/LR0Y=</user-hash-password>

</ns1:doLoginEnc>

...

www.sdjournal.org

41

Bezpieczeństwo

Zabezpieczanie systemów IT
Adaptive Access Manager firmy Oracle
Coraz więcej słyszymy o ochronie bezpieczeństwa systemów informatycznych. Wynika to z tego, że pojawia się coraz więcej doniesień prasowych o włamaniach na konta klientów banków lub o przypadkach wykradzenia dużej ilości danych osobowych.
Dowiesz się:
• Jak można zabezpieczyć aplikację WWW; • Jak można chronić użytkownika przed „phishingiem”.

Powinieneś wiedzieć:
• Jak działa protokół HTTP; • Wskazana znajomość działania JavaScript.

Poziom trudności

N

ie są to jednak w większości przypadków takie włamania, jakie znamy z historii o hakerach, gdzie wykorzystywane są luki, czy może techniczne niedociągnięcia systemów IT. Obecnie największym zagrożeniem są ataki typu phishing czy pharming. Niepowołane osoby nie łamią zabezpieczeń systemu, one po prostu zdobywają w nielegalny sposób informacje potrzebne do prawidłowego logowania i je wykorzystują. Większość instytucji posiada już zabezpieczenia typu firewall, które chronią systemy IT przed niepowołanym dostępem, ale takie zabezpieczenia w dzisiejszych czasach nie wystarczają. Jak w takim razie radzić sobie z nowym rodzajem przestępczości komputerowej? Odpowiedzią na to jest nowa generacja systemów ochrony. Jednym z wiodących produktów w tej kategorii jest Oracle Adaptive Access Manager (OAAM). W artykule opiszemy zasadę działania tego rozwiązania. Trzeba zwrócić uwagę na dwa aspekty korzystania przez użytkownika z aplikacji webowych: uwierzytelnienie użytkownika w aplikacji, ale też uwierzytelnienie systemu IT u użytkownika, a także zachowanie użytkownika w systemie.

Uwierzytelnianie
Uwierzytelnianie użytkownika w systemie IT jest obecnie całkiem dobrze rozwinięte – począwszy od konta i hasła, przez hasła jednora42

zowe i tokeny, a skończywszy na certyfikatach i smartkartach. Nieco gorzej wygląda sytuacja jeśli chodzi o zapewnienie użytkownika, że strony, które wyświetlają się w jego przeglądarce, pochodzą rzeczywiście z tych źródeł, z których sądzi on, że powinny pochodzić. Fakt uwierzytelnienia sprowadza się w tym przypadku do zmiany małej ikonki w dolnym rogu ekranu (w nowszych wersjach przeglądarek jest to już dosyć wyraźnie wyszczególnione). Doświadczona i świadoma zagrożenia osoba zauważy próbę wyłudzenia danych (phishing), ale przeciętny Kowalski może zostać łatwo oszukany, co widać zresztą w treści publikacji prasowych. Dużym krokiem w kierunku zwiększenia bezpieczeństwa jest w tym przypadku personalizacja. OAAM rozdziela stronę wpisywania identyfikatora użytkownika i hasła. Najpierw zostaniemy poproszeni o podanie naszego identyfikatora. Hasło wpisujemy na kolejnej stronie, która będzie już spersonalizowana przez system, bo on już wie, kto się loguje. Personalizacja polega na wybraniu przez użytkownika dedykowanego dla niego obrazka, który zawsze będzie tłem modułu wpisywania danych typu hasło, czy odpowiedzi na pytania kontrolne. Takiego wyboru użytkownik dokonuje w trakcie rejestracji. Jednocześnie, dla ochrony przez keyloggerami, użytkownik może wybrać bezpieczniejszy moduł wpisywania danych, za pomocą którego dane wprowadzane są nie z klawiatury, ale za pomocą myszki, a więc nie mogą zostać przechwycone. Również w trakcie rejestracji użytkownik podaje odpowiedzi na kilka pytań kontrolnych. Taka dodatkowa weryfikacja może zostać użyta przez system w momencie zwiększonego ryzyka

transakcji. To zabezpiecza użytkownika i znacznie utrudnia utratę przez niego danych pozwalających na zalogowanie się niepowołanej osobie i dokonanie nieautoryzowanych transakcji. A co, jeśli jednak dojdzie do takiej utraty danych? System musi rozpoznać, że osoba zalogowana do aplikacji i wykonująca pewne akcje nie jest prawdziwym użytkownikiem, ale włamywaczem. To zadanie jest podstawową funkcją systemu OAAM. Jak jest ona realizowana? Przede wszystkim realizowany jest tak zwany device fingerprinting gdzie przez device rozumie się urządzenie, z którego loguje się użytkownik. Chodzi tu jednak nie tylko o komputer w sensie dosłownym, ale także o daną instancję przeglądarki. OAAM korzysta z wielu dostępnych atrybutów w celu tworzenia odcisku urządzenia – są to między innymi dedykowane pojedyncze cookies, obiekty flash oraz zaawansowane techniki samo-uczenia się.

Zbieranie odcisku urządzenia
Tzw. fingerprinting odbywa się przy pierwszym kontakcie użytkownika z systemem, zanim jeszcze przeprowadzane są jakiekolwiek działania autoryzacyjne. Dzięki temu informacje zebrane w ten sposób są dostępne do określenia ryzyka w dowolnym momencie – np.: przed autoryzacją, po autoryzacji, czy w trakcie sesji przed wykonaniem transakcji. Pierwsza strona do logowania zawiera kilka linijek statycznego html’a. Ten kod zawiera obiekt flash’owy i tag <IMG>, które służą do zbierania szczegółowych danych o urządzeniu. Kod flash’owy odwołuje się do serwera aplikacyjnego wysyłając do niego zebrane dane. OAAM generuje unikalne szyfrowane ciasteczka (cookies) dla każdej sesji i sprawdza, czy konkretny cookie istnieje przy kolejnym logowaniu użytkownika z tego urządzenia. Oczywiście, ten cookie jest ważny tylko podczas danej sesji z danego urządzenia. Cookies są pobierane od użytkownika za pośrednictwem różnych metod:
03/2009

Zabezpieczanie systemów IT

• Tag <IMG> – specjalny tag jest umieszczany na stronie i przeglądarka wysyła żądanie w celu jego pobrania. W trakcie tego zadania plik cookie jest przesyłany do systemu. Takie tagi mogą być również wykorzystane do badania przepustowości sieci urządzenia oraz prędkości działania samego urządzenia. Te informacje również mogą być użyte do tworzenia odcisku; • Request HTTP – w przypadku blokady znaczników <IMG>, OAAM może pobrać cookie z pierwszego żądania o stronę do logowania. Stosowanie różnych technik ma na celu zapewnienie zebrania jak największej ilości danych w różnych konfiguracjach urządzenia użytkownika. Biblioteki, które przetwarzają te dane, są udostępniane z kodem źródłowym, więc istnieje możliwość ich modyfikacji w trakcie wdrożenia.

ją już jakieś z sesji poprzedniej. W czasie takiego przetwarzania zbierane są również inne dostępne dane: • System operacyjny wraz z wersją i wgranymi patchami; • Przeglądarka z jej wersją; • Możliwość uruchamiania JavaScript. W trakcie zbierania informacji przez obiekty flashowe można uzyskać dalsze dane o środowisku użytkownika: • • • • • • • Rozdzielczość ekranu; Dane o kolorach; Czy jest zainstalowana karta dźwiękowa; Czy jest zainstalowana drukarka; Czy jest mikrofon; Czy są jakieś kodeki audio i video; Czy jest wsparcie dla MP3.

Modele
Posiadając już odpowiednią ilość informacji, możemy zacząć je przetwarzać. Głównym zadaniem systemu jest wygenerowanie liczby (risk score) określającej ryzyko związane z aktualnie wykonywaną przez użytkownika akcją. Takie obliczenia odbywają się oczywiście on-line w wybranych w trakcie instalacji miejscach w chronionej aplikacji (np. przed wygenerowaniem zlecenia przelewu). Na podstawie wartości risk score mogą zostać wykonane akcje (blokada konta, email do administratora, dodatkowa weryfikacja klienta pytaniami kontrolnymi) lub wartość ta może być przekazana do chronionej aplikacji, aby ona sama podjęła dalsze kroki. Generowanie risk score odbywa się na podstawie reguł zebranych w modele, które z kolei zgrupowane są w polityki. Standardowo system posiada ponad 200 szablonów reguł. Polityki podzielone są ze względu na zastosowanie: • Polityka bezpieczeństwa – używa standardów do wykrywania fraudowego zachowania. Typowe reguły bezpieczeństwa to: blokowanie użytkowników z listy zabronionych urządzeń, blokowanie użytkownika działającego z różnych krajów w ustalonej jednostce czasu, blokowanie dostępu z urządzenia, z którego nastąpiło kilka błędnych logowań, blokowanie dostępu z urządzenia, z którego nastąpił dostęp ustalonej liczby użytkowników w tym samym czasie, blokowanie logowania użytkownika, który zalogował się z miejsc odległych geograficznie w czasie krótkiego czasu, itd. • Polityki transakcji – zawierają reguły bazujące na parametrach biznesowych, używane do zmniejszenia ryzyka operacji. Używane do monitorowania działań w trakcie sesji.

Dane dla cookies
Jak wspomniałem, pliki cookie są generowane dla każdej sesji i system sprawdza, czy istnie-

Informacje o IP
Kolejną grupą informacji, jaki zbiera OAAM, są dane związane z IP i protokołem. To wszystko ma na celu uniemożliwienie podszycia się pod użytkownika. Dane zbierane na temat protokołu IP o użytkowniku to: • Sam adres IP; • Lokalizacja geograficzna wyliczona na podstawie danych geolokacyjnych (dane o mapowaniu IP na lokalizacje geograficzne kupuje się od firm zewnętrznych); • Typ i prędkość połączenia; • Typ routingu IP; • Flaga ISP; • ASN; • Nazwa ISP; • Nazwy domen poszczególnych poziomów; • Lista proxy anonimizujących; • Rutery i nazwy maszyn.

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

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

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

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

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

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

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

Rysunek 1. Moduły wpisywania danych

Rysunek 2. „Odcisk palca” urządzenia

www.sdjournal.org

43

Bezpieczeństwo
• Polityki workflow – używają znanych wzorców zachowania użytkownika do wykrywania transakcji, w których to zachowanie jest inne niż zapamiętane. Wykorzystują metody analizy behawioralnej, wykrywania wzorców, analizy temporalnej i danych historycznych.
���������������� �����������������������
���������������������������� ���������������������������� ���������������������������� ������������������������ ���������������������������� ���������������������������� ���������������������������� �����������������

• Dane zewnętrzne – Możliwa jest także integracja z danymi dostarczanymi przez systemy zewnętrzne. Generowanie risk score jest stosunkowo proste. Kiedy pojawia się żądanie, system uruchamia po-

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

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

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

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

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

szczególne modele, skonfigurowane do działania dla danej transakcji. Każda z reguł zwróci risk score (przykładowo, jeśli użytkownik łączy się ze znanego urządzenia, wówczas wynikiem jest 0 -, w przeciwnym przypadku 100). Dla modelu wylicza się wynik biorąc pod uwagę wagi. Następnie taki sam algorytm stosuje się na poziomie wyżej aż do osiągnięcia wartości końcowej. Na podstawie tak wygenerowanego wyniku można podejmować już pewne konkretne działania biznesowe, jak np. wydanie pozwolenia na przelew lub nie. Zaletą OAAM jest możliwość zastosowania dodatkowej weryfikacji użytkownika za pomocą pytań kontrolnych. Logika rozmyta stosowana przy ewaluacji odpowiedzi może być tematem na oddzielny artykuł i pozwala na zaawansowaną autoryzację przy jednoczesnym niewielkim obciążeniu samego użytkownika. Nie musi on dokładnie pamiętać odpowiedzi na pytania kontrolne. Stopień dokładności zależy od nas samych. Na zakończenie prezentuję całościowy przykład działania systemu OAAM: (Rysunek 4)

�����

�����

����������

ALEKSANDER JACHOWICZ
Enterprise Solution Architect w obszarze Identity Management, Oracle Polska

Rysunek 3. Obliczanie „Risk Score”

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

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

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

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

���

���

���

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

���

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

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

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

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

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

Rysunek 4. Działanie pakietu Adaptive Access Manager

44

03/2009

Testowanie oprogramowania

Praca z zespołem testerów klienta
Zwiększanie efektywności testów przeprowadzanych przez klienta
Niniejszy artykuł przedstawia studium przypadku dotyczącego procesu testowaniasystemubankowegowśrodowiskuklienta.Zostanąprzedstawione problemy wynikłe w trakcie organizacji testowania oraz czynności przedsięwzięte w celu ich eliminacji i osiągnięcia satysfakcjonującego poziomu współpracy pomiędzy dostawcą oprogramowania a klientem.
Dowiesz się:
• Jakich reguł przestrzegać, aby testowanie nie doprowadziło do katastrofy; • Jak poprawić proces testowy, gdy jest już w trakcie realizacji a rezultaty są dalekie od ideału.

Powinieneś wiedzieć:
• Podstawowa wiedza z zakresu testowania funkcjonalnego; • Podstawowa wiedza z zakresu zarządzania projektem informatycznym.

Poziom trudności

P

ierwsza część artykułu opisuje podstawowe rodzaje testów zwykle przeprowadzanych przez klienta. W następnej kolejności zostaną przedstawione zalety i wady udostępnienia aplikacji zespołowi klienta z punktu widzenia dostawcy oprogramowania. Trzeci rozdział artykułu jest subiektywną próbą stworzenia pewnego ogólnego schematu postępowania podczas organizacji testowania w środowisku klienta – przedstawia pewne zasady, które powinny być przestrzegane zarówno przez dostawcę, jak i klienta, aby uniknąć w przyszłości potencjalnych problemów. Ostatnia część artykułu to studium przypadku opisujące, w jaki sposób zorganizowano proces testowy w projekcie realizowanym dla zagranicznej instytucji bankowej. Po zapoznaniu się z treścią artykułu, czytelnicy zdobędą wiedzę, w jaki sposób można czerpać korzyści z udostępnienia systemu klientowi oraz zwiększyć efektywność testowania, a także zaufanie klienta zarówno do produktu, jak i samego producenta oprogramowania.
46

Podejmując się realizacji usługi wytworzenia systemu informatycznego, dostawca IT zobowiązuje się do wypełnienia pewnych określonych czynności. Nie tylko musi dostarczyć gotowy produkt w założonym terminie i w ramach określonego budżetu, zagwarantować niezbędne wsparcie przy wdrożeniu systemu i przeszkoleniu użytkowników, ale i powinien przedstawić gwarancję niezawodności i poprawnego działania systemu. Warunkami spełnienia takiej gwarancji są na ogół kryteria wejścia / wyjścia stosowane dla poszczególnych etapów testowania wytwarzanej aplikacji. Dla każdego etapu testowania powinny zostać spełnione nieco inne kryteria. Zapewniają one, iż pewien etap implementacji systemu został ukończony, a jego rezultat zweryfikowany z pozytywnymi wynikami. Mimo obaw i sprzeciwów, związanych z ujawnieniem kondycji aplikacji przed czasem jej oddania do oficjalnych testów akceptacyjnych, wytwórcy oprogramowania coraz częściej godzą się na przeprowadzanie testów aplikacji przez zespół klienta. Zwykle dzieje się tak na życzenie klienta, który pragnie mieć stały wgląd w postęp prac deweloperskich i stan ukończenia systemu. Informacja taka ułatwia planowanie i podejmowanie decyzji dotyczących np. budżetu, daty oddania systemu na produkcję itd. Czasem rozstrzyga też o kwestii

być albo nie być – kontynuować projekt, czy go zawiesić ze względu na mniejsze niż zakładano postępy prac. Niniejszy artykuł przedstawia przykładowy proces testowania przez klienta oraz pokazuje trudności, które można napotkać wspomagając taki proces. Z drugiej strony zostaną ukazane korzyści takiego podejścia i jego możliwy pozytywny wpływ na powodzenie przedsięwzięcia IT.

Z punktu widzenia dostawcy oprogramowania…
Nierzadko pierwszą reakcją wytwórcy oprogramowania na prośbę umożliwienia testowania aplikacji przez testerów klienta jest gwałtowny sprzeciw i wynajdywanie mnóstwa przeciwwskazań. Wynika to głównie z obawy przed ujawnieniem przed przyszłym nabywcą oprogramowania błędów i usterek systemu. Często też pragnie się ukryć mniejszy niż zakładano postęp w pracach deweloperskich lub testowych. Producent oprogramowania wychodzi z założenia, iż dopiero w pełni zaimplementowany i gruntownie przetestowany system może zostać poddany testom klienta. Udostępnienie nie w pełni zaimplementowanego i nieprzetestowanego przez zespół wewnętrzny systemu może w oczach dostawcy wpłynąć negatywnie na opinię klienta o postępach w pracach projektowych. Takie podejście ma często realne uzasadnienie. Klient, zobaczywszy część systemu, jest rozczarowany słabymi w jego pojęciu postępami i niespokojny o możliwość ukończenia całej aplikacji w zakładanym czasie. Pojawia się napięcie i naciski ze strony udziałowców projektu – bądź to, aby położyć większy nacisk
03/2009

Praca z zespołem testerów klienta

na testowanie systemu, bądź by przyspieszyć prace deweloperskie. Często bywa też tak, iż testerzy klienta nie są wystarczająco zaznajomieni z funkcjonowaniem aplikacji by dać poprawne wyobrażenie o jakości działania systemu. Wprowadza to nieporozumienia i konflikt – ponieważ dostawca pewny jest swoich racji, a klient swoich. W takiej sytuacji łatwo może dojść do pogorszenia stosunków pomiędzy udziałowcami projektu ze strony dostawcy i klienta. Są jednak – i to wcale nierzadko – pozytywne aspekty oddania systemu do testowania klientowi. Najistotniejszym z nich jest fakt, iż testerzy klienta – zwykle pracownicy danej instytucji tymczasowo oddelegowani do prac testerskich – najlepiej wiedzą, jak powinien działać system, aby w pełni realizował swoją rolę i usprawniał pracę ludzi. Testerzy ci mogą bardzo pomóc programistom i analitykom dostarczając wskazówek i sugestii pozwalających usprawnić funkcjonowanie aplikacji. Mogą też, co równie ważne, sprawdzić, czy zaprojektowany system sprawdza się w kategoriach użyteczności – czy praca z nim jest wystarczająco intuicyjna, jak szybko zwykły użytkownik może nauczyć się jego obsługi itp. Informacje tego typu, uzyskane jeszcze w fazie implementacji mogą być bardzo przydatne – ponieważ w razie konieczności można jeszcze dokonać pewnych zmian w projekcie i zaimplementować je znacznie mniejszym kosztem i przy mniejszym ryzyku niż jakby to miało miejsce w fazie np. wdrożenia lub końcowych testów akceptacyjnych. Inną zaletą testowania przez zespół klienta jest możliwość wykrycia błędów pominiętych przy testowaniu wewnętrznym – ponieważ takie testowanie jest bliższe rzeczywistemu użytkowaniu systemu i realnych interakcjach z użytkownikiem.

wsparcie ze strony zespołu klienta może być szczególnie istotne dla dalszych prac programistycznych. Często podczas testów funkcjonalnych przeprowadzanych przez klienta wynajdywane są braki lub nieścisłości w projekcie aplikacji – takie jak błędne lub pominięte wymagania biznesowe. Jako przykład niech służy projekt przedsięwzięty na zlecenie instytucji bankowej, w którym testerzy klienta (pracownicy banku) przeprowadzali testy funkcjonalne równolegle z testami wewnętrznymi. Podczas pracy z systemem testerzy wykryli wiele błędów wynikających z niekompletnej analizy biznesowej – np. dokumentacja analityczna nie przewidywała i nie opisała scenariusza interakcji użytkownika (kasjera w banku) z kasą w przypadku używania monet. Udokumentowane i zaprojektowane było jedynie operowanie na banknotach. W rezultacie system błędnie przetwarzał operacje finansowe dokonywane w małych kwotach (poniżej wartości najmniejszego nominału banknotu) lub kwotach obejmujących część ‘groszową’. Transakcje takie były poprawnie zapisywane w systemie, lecz nie w rejestrze kasy – urządzenia bankowego połączonego z aplikacją. Urządzenie takie nie operuje na monetach, więc transakcje monetarne były obsługiwane niepoprawnie – np. w przypadku wypłaty gotówkowej na kwotę 20,50 zł urządzenie wypłacało 20 zł, po czym system wyświetlał komunikat o błędzie – ponieważ nie ‘wiedział’ jak interpretować 0,50 zł. Testy użyteczności Testy użyteczności pozwalają ocenić stopień zadowolenia użytkownika końcowego z pracy z aplikacją. Na użyteczność składa się prostota nauki obsługi systemu, wygoda i szybkość użytkowania, wydajność. Zwykle testowana jest ergonomia układu strony, rozmieszczenie pól, sekcji, przycisków, intuicyjność położenia elementów na stronie oraz szybkość i efektywność przepływu procesu biznesowego. Użytkownik pragnie, aby aplikacja umożliwiała mu jak najprostsze i najbardziej wydajne przeprowadzanie operacji. Nie ma tu miejsca na czasochłonne szkolenia i naukę obsługi systemu – aplikacja powinna dać się poznać w najkrótszym możliwym czasie. Optymistyczny wariant zakłada, iż krótka demonstracja oraz niezbyt rozbudowany podręcznik użytkownika powinien wystarczyć do zapoznania się z działaniem i założeniami aplikacji. Możliwe jest to tylko wów-

czas, gdy system został zaprojektowany tak, by być nieskomplikowany w użytku i jak najbardziej intuicyjny. Podczas testów użyteczności użytkownicy weryfikują, czy projekt aplikacji odpowiada ich potrzebom, preferencjom i nawykom oraz czy system sprawdzi się podczas pracy na produkcji. Testy użyteczności – jeśli przeprowadzane są odpowiednio – mogą pomóc ulepszyć aplikację skłaniając do modyfikacji UI zgodnie z sugestiami użytkowników, co z kolei zwiększa komfort pracy z systemem i satysfakcję odbiorcy oprogramowania. Ponadto, przyjazny i intuicyjny interfejs użytkownika umożliwia minimalizację nakładów przeznaczonych na zapewnienie szkoleń i usług help desk, ponieważ system jest prosty w obsłudze i nauka nie wymaga szczególnego treningu. Testy akceptacyjne Testy akceptacyjne przeprowadza się w celu ostatecznej weryfikacji funkcjonalności systemu przed wdrożeniem na produkcję. Testy te z reguły wykonuje wybrana grupa użytkowników końcowych na podstawie opracowanych scenariuszy end to end. Celem jest stwierdzenie, czy dany system działa w pożądany sposób oraz czy poprawnie i bez usterek współpracuje z zależnymi systemami lub urządzeniami. Często w testach akceptacyjnych uczestniczą również specjaliści z branży danego biznesu (np. analitycy biznesowi) – celem ostatecznego potwierdzenia poprawności systemu. W związku z powyższym, testowanie akceptacyjne często rozdziela się na dwa rodzaje – FAT (ang. Functional Acceptance Testing) i BAT (ang. Business Acceptance Testing). Testy FAT przeprowadzane są zazwyczaj przez wybraną reprezentację użytkowników końcowych (lub testerów klienta wyposażonych w specjalnie opracowane scenariusze testowe); testy BAT wykonywane są przez przedstawicieli biznesu – analityków, specjalistów branżowych. Testy akceptacyjne muszą być przeprowadzane w oficjalny sposób – zgodnie z założeniami i planem. Konieczne jest sporządzenie raportu końcowego, który jest podstawą do podjęcia decyzji o wdrożeniu oprogramowania na produkcję.

Rodzaje testów przeprowadzanych przez klienta
W zależności od przyjętego podejścia i wymagań projektu klient wykonuje testy na kilku poziomach. Zazwyczaj testowanie takie obejmuje testy funkcjonalne, użyteczności i testy akceptacyjne. Testy funkcjonalne Zwykle aplikacja oddawana jest klientowi do testów funkcjonalnych po zaimplementowaniu i wstępnym przetestowaniu przez wewnętrzny zespół testerów pewnego modułu lub zbioru funkcjonalności. Testy takie mają na celu sprawdzenie czy aplikacja spełnia założone wymagania – innymi słowy, czy umożliwia poprawne wykonanie wszystkich pożądanych i ujętych w ramach kontraktu operacji i funkcji. Testy takie mogą się odbywać równocześnie z dalszym rozwijaniem aplikacji przez zespół deweloperski – wtedy
www.sdjournal.org

Zalety i wady testowania przez zespół klienta
Wyobraźmy sobie, że jesteśmy producentem oprogramowania. Otrzymujemy zlecenie wy-

Rysunek 1. Struktura testów wewnętrznych

47

Testowanie oprogramowania
tworzenia aplikacji dla instytucji bankowej zajmującej się obsługą klienta indywidualnego i firm (transakcje, kredyty itp.). Załóżmy, że nasza firma zajmuje się nie tylko usługami programistycznymi, ale i oferuje kompleksowe usługi Quality Assurance. Jak w takim przypadku odnieść się do życzenia klienta, który żąda umożliwienia mu wglądu w stan aplikacji i możliwości przeprowadzenia swoich własnych testów po każdej fazie implementacji? Jakie korzyści możemy z tego uzyskać, a jakie straty ponieść? W pierwszej kolejności rozpatrzmy wady i niedogodności takiego podejścia. Wady • Dodatkowa infrastruktura testów Planując testy klienta często pojawia się konieczność stworzenia odpowiedniej infrastruktury dla potrzeb testów klienta. Należy zorganizować środowisko testowe, odpowiednie oprogramowanie wspierające testowanie i raportowanie. Zwykle środowisko testowe dla testów klienta jest organizowane w jego siedzibie – i zazwyczaj to dostawca oprogramowania proszony jest o przygotowanie i skonfigurowanie sprzętu, integracji itp. Czynności te wymagają zaplanowania i zaalokowania odpowiedniej ilości zasobów – ludzkich, czasowych, czasem sprzętowych. Dostawca systemu czasem traktuje to jako niepotrzebną stratę czasu i pieniędzy i z niechęcią pomaga w realizacji zadania, mocno akcentując, że czyni to ze szkodą dla planowanego przebiegu projektu. • Większe wymagania odnośnie zasobów ludzkich Organizacja i zarządzanie testami klienta wymaga zapewnienia dostępności dodatkowych zasobów ludzkich wspierających instalację i konfigurację systemu, testowanie i wykonywanie poprawek błędów w środowisku klienta. Instalacja testowego systemu, konfiguracja jego ustawień, sprawdzenia, czy system startuje itp. zwykle wymaga poświęcenia jej trochę czasu. W dodatku, środowisko klienta często różni się od środowiska testów wewnętrznych, co również powoduje nieco komplikacji i potrzebę uprzedniego poznania środowiska. Zainstalowaną aplikację należy poddać testom dymnym, aby upewnić się, że dalsze testowanie jest możliwe i system odpowiednio stabilny. To również oznacza konieczność alokacji pewnej liczby zasobów ludzkich (o ile do testów dymnych nie stosuje się narzędzi automatycznych, co jednak nie należy do częstych praktyk). • Zmiany w planowaniu Zachodzą zmiany w planie projektu. Harmonogram dewelopmentu i testowania należy przeanalizować pod kątem wymagań związanych z testami klienta – czasem oznacza Dość często jedną z najważniejszych przeszkód dla testowania klienta jest perspektywa problemów wynikających z różnej specyfiki i kultury pracy – np. odmienny sposób rozwiązywania problemów czy informowania o wynikach pracy, inne podejście do organizacji pracy. Częstym przypadkiem jest zgłaszanie przez testerów klienta rzeczywistych lub 'urojonych' problemów bezpośrednio kierownictwu projektu i podnoszenie stosunkowo drobnych kwestii jako wysokie ryzyko projektowe – co w efekcie powoduje konflikty i nieporozumienia. Innym przykładem jest organizacja pracy – problem szczególnie widoczny w przypadku projektów międzynarodowych – np. przeprowadzanie testów przez tydzień czy dwa, notowanie defektów niezależnie od systemu śledzenia błędów, po czym zgłaszanie ich dopiero po ukończeniu cyklu testów. W praktyce oznacza to, że: • programiści przez tydzień są bezczynni, nie mając żadnych defektów do naprawy; • czas przeznaczony na poprawki drastycznie się zmniejsza – ponieważ obejmuje tylko czas od zakończenia cyklu testów do wydania następnej wersji systemu, a nie np. od momentu znalezienia pierwszych defektów – co z kolei budzi frustrację i sprzeciwy zespołu deweloperskiego; • często zgłaszane są defekty nieprawdziwe lub nieodtwarzalne – znalezio03/2009

to potrzebę zmiany planu, aby dostosować się do preferencji klienta (np. kolejność implementacji modułów itp.) • Dodatkowe szkolenia Zgoda na przeprowadzenie testów przez zespół klienta oznacza dodatkową pracę niezbędną dla przeszkolenia testerów klienta w zakresie funkcjonalności systemu oraz procedur i narzędzi służących do wykonywania i zarządzania testami. Odpowiedzialność ta zwykle spada na dostawcę oprogramowania – niezbyt często zdarza się, aby zespół klienta potrafił w odpowiedni sposób przygotować się do przeprowadzania testów, raportowania ich wyników oraz zarządzania zgłoszonymi defektami. Nie wynika to ze złej woli, ale raczej z braku profesjonalnego przygotowania i kwalifikacji testerskich. Wyjątkiem są sytuacje, w których klient zleca całość testowania zewnętrznemu zespołowi, wynajętemu od profesjonalnej firmy IT. Jednak nawet i w takim przypadku może zaistnieć konieczność przeszkolenia testerów z zakresu funkcjonalności systemu oraz obsługi specyficznych narzędzi wspierających testowanie. • Różna specyfika pracy i kultura

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

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

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

������ ����

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

������

������

������

������ ����

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

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

���������

Rysunek 2. Środowiska testowe i podział zadań testowych i odpowiedzialności

48

Praca z zespołem testerów klienta

ne tuż po instalacji nowego systemu, kiedy aplikacja bądź środowisko nie są jeszcze w pełni stabilne. • Niskie kwalifikacje zespołu klienta. Dość częstym problemem w testowaniu przez zespół klienta jest brak wymaganych kwalifikacji i umiejętności testerskich. Sytuacja taka ma miejsce zwłaszcza wtedy, kiedy testerzy są po prostu pracownikami danej instytucji, tymczasowo alokowanymi do wykonywania testów. Rodzi to nieporozumienia wynikające z braku profesjonalnego przygotowania testerów – niewłaściwego podejścia do testowania, zgłaszania nieprawdziwych defektów – co wynika z niezrozumienia funkcjonowania aplikacji, braku wystarczającego opisu problemu (zbyt ogólne opisywanie błędów, brak wszystkich danych koniecznych do reprodukcji i naprawy problemu) etc. Innego rodzaju czynnikiem powodującym niechęć do testów klienta jest ujawnienie przed klientem kondycji aplikacji przed ukończeniem jej rozwijania. Czasami dostawca oprogramowania nie chce pokazywać klientowi aplikacji, która nie jest jeszcze w pełni ukończona i przetestowana obawiając się paniki w przypadku odkrycia krytycznych błędów i wzbudzenia niepokoju o utrzymanie zakładanych terminów Zalety Udostępnienie aplikacji testerom klienta to nie tylko problemy i dodatkowa praca. Korzyści są następujące: • Większe pokrycie testów Aplikacja poddana testowaniu przez więcej niż jeden zespół jest przetestowana głębiej i staranniej, wykonanych jest więcej scenariuszy i przypadków testowych – aplikację testuje zespół wewnętrzny oraz zewnętrzny (testerzy klienta), co minimalizuje ryzyko pominięcia błędów. Można tu stosować dwa podejścia: • testerzy dzielą się pracą i zakresem funkcjonalności, skupiając się na maksymalnie dokładnym przetestowaniu swojej części aplikacji; • obie grupy testerów pracują równolegle – celem takiego podejścia jest dokładne sprawdzenie aplikacji przez dwie grupy testerów, częściowo niezależnych od siebie i stosujących różne metody pracy, tak by błędy były znalezione nawet jeśli jedna grupa je pominie. • Wyższa efektywność testów Niezaprzeczalną zaletą udostępnienia aplikacji testom klienta jest zwiększenie efekwww.sdjournal.org

tywności testowania oraz możliwość ulepszenia systemu na stosunkowo wczesnym etapie. Testowanie jest bardziej efektywne – podzielenie pracy na dwa zespoły pozwala na lepszy podział zadań czy też testowanych aspektów (np. zespół wewnętrzny wykonuje testy integracyjne i ogólne testy dymne, zespół klienta koncentruje się na testach funkcjonalności, logiki biznesowej i użyteczności). Dobrze zorganizowana współpraca pomiędzy oboma zespołami może przełożyć się na o wiele lepsze pokrycie i głębokość testów niż w przypadku wykonywania prac testowych tylko przez testerów dostawcy oprogramowania. Pracownicy klienta – testerzy i analitycy – mogą dostarczyć cennych wskazówek odnośnie wytwarzanego oprogramowania. Jako że znają oni specyfikę danej organizacji, wymogi biznesowe jakie muszą być spełnione przez system, nawyki i przyzwyczajenia docelowych użytkowników systemu najlepiej ocenią funkcjonalność aplikacji. Ich testy są pod pewnym względem korzystniejsze od testów wewnętrznych, ponieważ symulują pracę z systemem w docelowym środowisku i z docelowymi odbiorcami. Zespół wewnętrzny nie zawsze jest w stanie opracować i zrealizować wszystkie tego typu scenariusze testowe. • Ulepszanie aplikacji Udostępnienie aplikacji klientowi daje możliwość dokonywania zmian w projekcie aplikacji na stosunkowo wczesnym etapie wytwarzania systemu, jeśli służy to poprawie użyteczności, co wiąże się ze znacznie niższymi kosztami niż gdyby to miało miejsce np. na etapie testów akceptacyjnych (przed wdrożeniem na produkcję). Również modyfikacje wymagań wynikające ze zmian w biznesie (np. zmiana przepisów prawnych) mogą być zaplanowane i wdrożone wcześnie, jako że zarówno testerzy, jak i analitycy biznesowi klienta, mają wgląd w aplikację i mogą do-

starczyć wskazówek co do sposobu rozwiązania danej kwestii. • Lepszy poziom komunikacji Klient, informowany na bieżąco o postępie prac – lub ewentualnym opóźnieniu – jest w stanie odpowiednio szybko reagować na zaistniałą sytuacje i adaptować swoje plany zgodnie z bieżącym stanem rzeczy. Przejrzystość ta pozwala zwiększyć komfort pracy, efektywność planowania i podejmowania decyzji biznesowych. Minimalizuje też ryzyko konfliktów, które mogłyby się pojawić w momencie, kiedy klient – przekonany o dobrym postępie prac – nagle dowiaduje się o opóźnieniu.

Zasady współpracy z zespołem klienta
Godząc się na udostępnienie systemu zespołowi klienta, należy uzgodnić plan i organizację procesu testowego. W szczególności dotyczy to harmonogramowania oraz zakresu zadań testowych – ponieważ inne podejście należy przyjąć, gdy testy klienta odbywają się sporadycznie, a inne, kiedy regularnie. Zespół klienta może przystąpić do pracy równocześnie z testerami producenta oprogramowania lub też dopiero po ukończeniu pewnego etapu testów wewnętrznych. Dobrą praktyką jest jednoznaczne określenie następujących kwestii: • Kto jest osobą odpowiedzialną za testowanie w środowisku klienta – pracownik klienta, członek zespołu projektowego dostawcy oprogramowania czy też osoba z całkowicie niezależnej organizacji. Osoba taka będzie stanowić tzw. punkt kontaktu dla wszelkiego typu kwestii związanych z testowaniem klienta – organizacji procesu testowego, planowania i alokacji zasobów, realizacji i raportowania zadań; • Rodzaj narzędzia stosowanego do raportowania wyników testów (system śledzenia defektów) – ważne jest ustalenie, czy

Rysunek 3. Organizacja testów

49

Testowanie oprogramowania
testerzy klienta będą używać tego samego narzędzia, co zespół dostawcy oprogramowania, czy też defekty raportowane będą we własnym systemie klienta. Raportowanie defektów w systemie klienta będzie się wiązać z koniecznością eksportu znalezionych problemów do wewnętrznego narzędzia dostawcy oprogramowania, a następnie z zarządzaniem owymi defektami – kontrolowaniem, które zostały odrzucone, które przekazane do naprawy oraz naprawione. Informacje te będą musiały z kolei zostać przekazane zespołowi klienta. Wszystkie te czynności wymagają dodatkowych zasobów, co należy uwzględnić w planowaniu testów; • Harmonogram testów – należy określić, kiedy zespół klienta może rozpocząć testowanie, czy będzie się ono odbywać równocześnie z testami wewnętrznymi, czy też w osobnych fazach. Inne podejście stosuje się w przypadku, gdy testowanie ma odbywać się regularnie w dłuższym okresie czasu, a inne, kiedy zespół testowy pracuje jedynie od czasu do czasu, wyrywkowo sprawdzając działanie aplikacji. Testowanie regularne oznacza konieczność synchronizacji prac testowych zespołu testerów klienta i dostawcy oprogramowania, tak aby starać się nie duplikować wykonywanej pracy i nie wprowadzać chaosu organizacyjnego. Dobrym rozwiązaniem jest podział zadań lub skupienie się na innych aspektach testowania. Harmonogram testów powinien uwzględniać również prace deweloperskie niezbędne do naprawienia błędów znalezionych przez testerów – ponieważ dopiero po zakończeniu jednego cyklu testowania i naprawie błędów można rozpocząć kolejny cykl testów; • Zakres testów – planując testowanie w środowisku klienta należy zdefiniować, co będzie przedmiotem testowania, a co nie. Pozwoli to uniknąć nieporozumień i niepotrzebnych konfliktów – np. jeśli testy dotyczyć będą użyteczności czy logiki biznesowej, testerzy nie powinni zgłaszać defektów związanych z wydajnością systemu; • Zasady raportowania defektów. Ważne jest przyjęcie pewnych wspólnych wytycznych i zasad zgłaszania błędów. W organizacji klienta mogą istnieć wewnętrzne standardy raportowania, nie odpowiadające potrzebom i przyzwyczajeniom zespołu deweloperskiego dostawcy oprogramowania. Z drugiej strony mogą nie istnieć żadne standardy – w przypadku, gdy np. odbiorca systemu nie utrzymuje własnego działu testów lub korzysta z zewnętrznych usług testerskich. Popraw50

ne zgłaszanie błędu znacznie skraca czas analizy problemu i naprawy usterki – ponieważ deweloper rozumie opis defektu i wie, jak go zreprodukować.

Studium przypadku
Przykład procesu organizacji procesu testowego, w którym uczestniczy zespół klienta, prześledzimy na podstawie międzynarodowego projektu IT, mającego na celu wyprodukowanie oprogramowania na potrzeby bankowości. System miał zastąpić dotychczas używany w oddziałach banku system, zintegrowany z kilkoma innymi aplikacjami i bazami danych oraz urządzeniami bankowymi. Bezwzględnym wymogiem klienta (banku) było dopuszczenie jego zespołu do przeprowadzania testów – i to jeszcze przed rozpoczęciem testów akceptacyjnych, po ukończeniu pewnego etapu rozwijania aplikacji i zbudowaniu wybranych modułów i funkcjonalności. Testowanie wewnętrzne, przeprowadzane przez zespół testerów dostawcy oprogramowania, odbywało się od momentu stworzenia pierwszych stabilnych wersji modułów aplikacji. Testy podzielono na etapy: • Stream – testy polegały na testowaniu pojedynczych funkcjonalności, bez sprawdzania integracji i poprawności biznesowej przebiegu procesu; • Build – testowanie obejmowało kilka funkcjonalności zintegrowanych w stabilną paczkę. Częściowo testowano integrację – na tyle, na ile pozwalał zakres dostarczonej paczki; • Release – testowanie Release obejmowało większą część aplikacji – kilkanaście modułów i funkcjonalności zintegrowanych w aplikację, która mogła już spełniać wybrane funkcje biznesowe. Testy obejmowały zarówno poprawność funkcjonalną, jak i integrację pomiędzy modułami aplikacji. Strukturę testów w ramach jednej ‘iteracji’ przedstawia Rysunek 1. W ramach jednego podejścia testów Stream oddawano kolejno trzy pakiety funkcjonalności (‘Streamy’ po kilka funkcji), głównie do podstawowych testów funkcjonalności i Look & feel. Po zakończeniu tego etapu testów były tworzone paczki funkcjonalności, dostarczane jako Build. Obejmowały one zintegrowane funkcje, dotąd przetestowane w ramach poprzednich testów. Testom poddawano kolejno trzy takie paczki. Końcowym produktem jednej iteracji była wersja Release aplikacji, obejmująca wszystkie dotychczas przetestowane funkcje i moduły zintegrowane w jedną, stabilną aplikację. Testowanie wewnętrzne obejmowało 3 iteracje. Następnie – gdy kondycja aplikacji oraz

zakres funkcjonalności umożliwiał włączenie do testów zespołu klienta – organizacja procesu testowego została zmieniona. Testy wykonywały równocześnie dwa zespoły – wewnętrzny (wewnętrzne środowisko testowe / SIT) i klienta (SIT / UAT). Testowanie dotyczyło już tylko wersji Release aplikacji – przy czym wersja systemu, którą testował zespół wewnętrzny była nowszą o 2 wersje od wersji oddanej do testów pracownikom klienta. Takie podejście umożliwiało zarówno znalezienie poważniejszych błędów i ich poprawienie zanim system zostanie przekazany do testowania klientowi, jak i zagwarantowanie, że testerzy klienta będą pracować na aplikacji wolnej od poważnych błędów i skupią się na testowaniu funkcjonalności, logiki biznesowej i użyteczności.

Środowiska testowe
Zależnie od etapu i celu testów, testowanie przeprowadzano w innych środowiskach. Testy wewnętrzne odbywały się w udostępnionym testerom środowisku dostawcy oprogramowania, ubogim w dane testowe i pozbawionym integracji z zależnymi systemami zewnętrznymi i urządzeniami. Ich celem było znalezienie błędów powstałych w trakcie wytwarzania oprogramowania i przygotowanie aplikacji do kolejnego poziomu testów – integracyjnych i akceptacyjnych. W trakcie testów wewnętrznych wszystkie punkty integracji zastąpiono zaślepkami i sztucznymi danymi testowymi, współpraca z urządzeniami była natomiast symulowana przez oprogramowanie. Laboratoria SIT oraz UAT były stworzone w siedzibie klienta - i połączone z odpowiednimi testowymi bazami danych, systemami zewnętrznymi i urządzeniami typu drukarki, czytniki kart, kasy. W pierwszej kolejności przygotowano środowisko SIT (System Integration Testing) – którego celem było przetestowanie działania systemu zintegrowanego z systemami i urządzeniami zewnętrznymi, przy użyciu testowych danych, kart bankowych, czeków itp. Za tą weryfikację odpowiedzialny był zespół testerów klienta, przy wymaganym wsparciu testerów wewnętrznych. Po uzyskaniu odpowiedniego stopnia jakości aplikacji (ocenianej jako ilość otwartych błędów o określonej krytyczności), system zainstalowano w środowisku UAT I. UAT (User Acceptance Testing) było oficjalnym testem akceptacyjnym, wykonywanym przez testerów klienta. Dwa miesiące przed planowanym terminem wdrożenia systemu na produkcję, aplikację poddano testom UAT II – wykonywanym przez pracowników placówek banku. Mieli oni sprawdzić, czy gotowy system wypełnia wszystkie pożądane funkcje i jest gotowy by zastąpić dotychczas używaną w oddziałach banku aplikację. Schemat organizacji środowisk testowych przedstawia Rysunek 2.
03/2009

Praca z zespołem testerów klienta

W organizacji i konfiguracji środowiska testów wewnętrznych przyjęto następujące założenia: • Dostęp do środowiska ma jedynie zespół testerów dostawcy oprogramowania; • Test dymny (Smoke test) jest pierwszą czynnością po udostępnieniu nowej wersji aplikacji. Test ten musi zostać wykonany z pozytywnymi rezultatami zanim rozpocznie się jakiekolwiek testowanie. Dopuszczalne jest przyjęcie aplikacji do dalszych, regularnych testów, jedynie gdy: • nie ma defektów krytycznych i blokujących dalsze testowanie; • istnieją defekty krytyczne, lecz mogą zostać szybko naprawione za pomocą hotfixu lub innego rodzaju szybkiej poprawki. W tym przypadku warunkiem koniecznym po zastosowaniu hotfixu jest rozpoczęcie testów od sprawdzenia, czy poprawka działa i umożliwia dalsze testowanie aplikacji. Hotfix może dotyczyć zarówno błędów w samej aplikacji, jak i defektów środowiska – konfiguracji sprzętu, baz danych itp; • Defekty znalezione w testach wewnętrznych są zgłaszane w osobnej (wewnętrznej) bazie danych i nie są udostępniane klientowi ani jego testerom; • Końcową czynnością testów jest sporządzenie raportu opisującego kondycję aplikacji, liczbę i ważność znalezionych defektów oraz poprawek, zweryfikowanych i potwierdzonych jako działające w pożądany sposób; • Zakończeniem testowania wewnętrznego jest upewnienie się, że aplikacja jest stabilna, działa poprawnie i jest gotowa do testowania zewnętrznego – przez zespół klienta. Decyzja ta jest podjęta na podstawie raportu z testowania oraz dyskusji kierowników zespołów testowych i kierownictwa projektu. Organizacja środowiska SIT przedstawiała się następująco: • Dostęp do środowiska mają testerzy dostawcy oprogramowania – w celu przepro-

wadzenia testu dymnego oraz reprodukcji zgłoszonych defektów – oraz testerzy klienta – dla wykonywania regularnych testów w fazie poprzedzającej testy UAT oraz dla przeprowadzania testów dymnych w fazie testowania UAT; Test dymny (Smoke test) jest pierwszą czynnością po udostępnieniu nowej wersji aplikacji. Test ten musi zostać wykonany z pozytywnymi rezultatami zanim rozpocznie się jakiekolwiek testowanie. Podobnie jak w przypadku testów wewnętrznych, dopuszczalne jest przyjęcie aplikacji do dalszych, regularnych testów, jedynie gdy nie ma defektów krytycznych i blokujących lub jeśli istnieje co najwyżej jeden defekt krytyczny, ale może zostać naprawiony w przeciągu 1 dnia za pomocą hotfixu lub re-instalacji systemu; Defekty znalezione w testach SIT są zgłaszane w oddzielnym, udostępnionym klientowi systemie śledzenia błędów (‘zewnętrzna’ baza danych błędów). Dostęp do tej bazy danych mają wybrane osoby z zespołu klienta (Test Leader) oraz analitycy biznesowi i Test Leader zespołu dostawcy oprogramowania; Końcową czynnością testów jest sporządzenie raportu zawierającego liczbę i określenie krytyczności znalezionych defektów oraz liczbę poprawek, zweryfikowanych i potwierdzonych jako działające w pożądany sposób; Zakończeniem testowania SIT jest upewnienie się, że aplikacja jest stabilna, działa poprawnie i jest gotowa do testowania UAT – w środowisku bardziej zbliżonym do produkcyjnego pod względem danych testowych. Testy UAT wykonują testerzy oraz analitycy klienta. Decyzja ta jest podjęta na podstawie raportu z testowania oraz dyskusji kierowników zespołów testowych i kierownictwa projektu.

tem przydatności i poprawności w działaniu operacyjnym oraz ergonomii. Środowiska UAT charakteryzowały się następującymi cechami: • Dostęp mają jedynie zespoły klienta; • Defekty znalezione podczas testowania zgłaszane są w wewnętrznym systemie klienta. Manager QA po stronie dostawcy oprogramowania ma dostęp do tego systemu i jest odpowiedzialny za przetransferowanie defektów dotyczących aplikacji do wewnętrznej bazy defektów producenta oprogramowania; • Zakończenie cyklu testów UAT kończy się sporządzeniem raportu przedstawiającego stan aplikacji – do wglądu Komitetu Sterującego. Pozytywne wyniki testów i subiektywna ocena udziałowców projektu są podstawą do podjęcia decyzji o wdrożeniu na produkcję. Organizacja pracy zespołów testerskich W trakcie dewelopmentu i początkowych etapów testowania, testy wykonywał tylko zespół wewnętrzny. W tym czasie testerzy klienta zapoznawali się z funkcjonalnością systemu na podstawie dokumentacji projektowej oraz organizowali środowisko pracy. Po zakończeniu pierwszego etapu testów i upewnieniu się, że dana wersja systemu jest gotowa do testów integracyjnych i udostępnienia go zespołowi klienta, aplikację zainstalowano w środowisku SIT. SIT było początkowo środowiskiem dostępnym jedynie zespołowi klienta, testerzy wewnętrzni nie mieli do niego dostępu. Podczas gdy zespół wewnętrzny kontynuował swoje testy i weryfikował kolejne wersje aplikacji, pracownicy klienta otrzymali pierwszą – już przetestowaną wewnętrznie – wersję systemu do testowania. Swoje pierwsze testy przeprowadzali bez jakiegokolwiek wsparcia ze strony dostawcy oprogramowania, opierając się na własnym rozumieniu systemu i dostępnej dokumentacji projektowej. Testy odbywały się w cyklu tygodniowym, przy czym zgłaszanie znalezionych defektów następowało dopiero po zakończeniu cyklu. Komunikacja z zespołem producenta oprogramowania ograniczała się do roz-

Środowiska UAT służyły do oficjalnych testów akceptacyjnych. Zorganizowano dwa laboratoria UAT – jedno dla zespołu testerskiego klienta, drugie dla zespołu pracowników banku z różnych oddziałów, mających sprawdzić funkcjonowanie systemu pod ką-

Pojęcia
• • • • • UAT (User Acceptance Testing) – Testy akceptacji użytkowników mające na celu sprawdzenie, czy aplikacja spełnia wymagania użytkowników pod względem funkcjonalności oraz użyteczności. SIT (System Integration Testing) – Testowanie integracji systemu weryfikujące poprawność działania wszystkich modułów systemu zintegrowanych w całość i połączonych z zależnymi systemami zewnętrznymi. Smoke test (Sanity test) – Test dymny – podstawowy test wykonywany po instalacji nowej wersji systemu mający na celu stwierdzenie, czy aplikacja działa i może być poddana dalszym, głębszym testom Back end – Aplikacja pośrednio wspierająca pracę systemu frony end – np. przez komunikowanie się w celu pobrania informacji / danych wykorzystywanych bezpośrednio przez użytkownika aplikacji front-end Front end – Aplikacja, z którą użytkownik pracuje bezpośrednio

www.sdjournal.org

51

Testowanie oprogramowania
mów telefonicznych lub e-konferencji (raz w tygodniu) dotyczącej rezultatów testów i ogólnego postępu prac. Takie podejście od początku doprowadziło do problemów i sytuacji konfliktowych. Po pierwsze, brak odpowiedniej komunikacji i wsparcia spowodował, iż zespół testowy skazany był na siebie. Problemy z konfiguracją systemu, integracją z systemami zewnętrznymi lub urządzeniami itp. wstrzymywały testowanie i powodowały nieprawdziwe wyniki testów, ale nie były identyfikowane i komunikowane odpowiednim osobom. I tak na przykład awaria połączenia z zewnętrznym systemem, która uniemożliwiała wykonanie transakcji bankowych, została zgłoszona jako krytyczny błąd w aplikacji, bez upewnienia się, że integracja z back endem działa. Dalsze testowanie wstrzymano odrzucając wersję systemu jako niestabilną, mimo że – jak się okazało później – przywrócenie połączenia z back endem zajęło 0.5 godziny. Powtarzające się problemy i konflikty doprowadziły w końcu do zmiany podejścia do testowania – do siedziby klienta wysłano testerów dostawcy oprogramowania oraz programistów, którzy mieli wspierać testowanie aplikacji i naprawę błędów bezpośrednio korzystając ze środowiska docelowego. Początkowo zespół wewnętrzny korzystał ze środowiska SIT jedynie w celu przeprowadzania testów dymnych oraz reprodukcji defektów, które nie były reprodukowane w wewnętrznym środowisku testowym. W rzeczywistości oznaczało to, że programiści i testerzy dostawcy oprogramowania byli zmuszeni czekać, aż zespół klienta zakończy prace, aby mieć dostęp do SIT i móc rozpocząć analizę zgłoszonych błędów. Aby wyeliminować to ograniczenie i umożliwić bezproblemową pracę obu zespołów, klient zorganizował drugie środowisko testowe – UAT. Testerom dostawcy udostępniono środowisko SIT, natomiast testerzy klienta rozpoczęli prace w środowisku UAT, przy czym wstępny test dymny realizował zespół dostawcy. Harmonogram i organizacja testów SIT odbywała się według wspólnego schematu (Rysunek 3.). Procedura testów przedstawiała się następująco: • Po instalacji nowa wersja systemu zostawała poddawana testom dymnym. Wykonywał je najpierw zespół dostawcy oprogramowania w środowisku SIT. W razie pozytywnych wyników testu, aplikację instalowano w środowisku UAT i oddawano testerom klienta; Test dymny wykonywany przez klienta miał na celu stwierdzić, czy aplikacja jest gotowa do dalszych, głębszych testów. Wszystkie krytyczne przypadki testowe musiały być zakończone z oczekiwanym wynikiem; W czasie, gdy zespół klienta zajmował się testem dymnym, testerzy wewnętrzni wykonywali testy regresji. Pozwalało to zweryfikować dokonane poprawki błędów i znaleźć ewentualne nowe błędy jeszcze przed rozpoczęciem kolejnego etapu testów klienta. Tym sposobem programiści otrzymywali szybką informację zwrotną i mogli skupić się na kolejnych pracach; Po zakończeniu testów dymnych zespół klienta rozpoczynał testy regresji, aby stwierdzić, czy poprawki dla uprzednio zgłoszonych przez nich błędów działają w odpowiedni sposób i nie wywołują dalszych błędów; Zespół dostawcy rozpoczynał testowanie regularne jeszcze w trakcie testów regresji – przypadki testowe zostały zaprojektowane w taki sposób, aby umożliwiać jednoczesną weryfikację poprawek i przeprowadzanie normalnych testów. Wyniki testów – błędy – były raportowane na bieżąco w wewnętrznym systemie obsługi błędów dostawcy oprogramowania; Zespół klienta rozpoczynał regularne testy po wykonaniu testów regresji, analizie ich wyników oraz przygotowaniu zadań do zrealizowania podczas testowania. Testy klienta wykonywane były według procedury obowiązującej w banku, pod nadzorem i przy wsparciu zespołu dostawcy, który udzielał niezbędnych wyjaśnień co do wdrożonych poprawek oraz zakresu zmian dokonanych w funkcjonalności systemu; Po ukończeniu cyklu testów zespół klienta opracowywał wyniki testów (tworzył raporty błędów) i przekazywał je do swojego Kierownika Testów, który po dyskusji z Kierownikiem Testów ze strony dostawcy zgłaszał znalezione błędy do systemu obsługi błędów; • Równocześnie z rozpoczęciem cyklu testowania przez zespół klienta, programiści przystępowali do naprawy błędów: • zgłoszonych w trakcie testów wykonywanych przez testerów dostawcy oprogramowania; • zgłoszonych przez testerów klienta po ukończeniu ich cyklu testów. Plusem takiej organizacji pracy było zwiększenie interakcji i komunikacji pomiędzy zespołami, co w widoczny sposób polepszyło efektywność testowania i zmniejszyło ilość popełnianych przez testerów pomyłek. Ponadto testy przeprowadzane podwójnie – przez oba zespoły – pozwalały znaleźć więcej błędów i zminimalizować ryzyko pominięcia istotnych błędów. Poprawiła się także efektywność poprawiania błędów, ponieważ nowe błędy zgłaszane były z wystarczającym opisem i już zweryfikowane jako prawdziwe błędy – programiści nie musieli więc tracić czasu na analizowanie i weryfikację poprawności. Udostępnienie środowiska UAT oznaczało jeszcze większe zwiększenie efektywności testowania z racji tego, że zawierało więcej danych i urządzeń testowych i było bardziej niż SIT zbliżone do środowiska docelowego. Z tego powodu testy umożliwiały symulację pracy w środowisku docelowym. Kolejnym etapem było udostępnienie aplikacji pracownikom oddziałów banku w celu ostatecznej weryfikacji funkcjonalności i użyteczności aplikacji. System testowy zainstalowano w osobnym środowisku UAT II będącym niemal dokładną kopią środowiska produkcyjnego. Pracownicy banku realizowali testy posługując się własnymi metodami i procedurami, które obowiązywały w oddziałach banku. Operacje wykonywane przez nich symulowały rzeczywiste procesy biznesowe i czynności w banku. Pracę testerów z oddziałów banku nadzorowali analitycy biznesowi klienta oraz Kierownik Testów ze strony dostawcy oprogramowania. Służyli oni wyjaśnieniami w przypadku pytań i niejasności dotyczących funkcjonalności systemu oraz weryfikowali ewentualne błędy (które następnie zgłaszano do systemu obsługi błędów projektu). Wszelkie uwagi i wnioski pracowników banku były notowane i rozpatrywane na cotygodniowych zebraniach kierownictwa projektu,

W Sieci
• • • • http://articles.techrepublic.com.com/5100-10878_11-1044625.html – Krótkie wprowadzenie do pojęcia testów akceptacyjnych; www.xpuniverse.com/2001/pdfs/Testing05.pdf – Artykuł dotyczący wymagań i przeprowadzania testów akceptacyjnych; http://www.usability.gov/refine/learnusa.html – Wprowadzenie do testów użyteczności – cele, metody i koszty testów; www.webcredible.co.uk/user-friendly-resources/web-usability/usabilty.testing.shtml – Osiem wskazówek dotyczących planowania, realizacji i analizy wyników testów akceptacyjnych.

52

03/2009

Praca z zespołem testerów klienta

które następnie decydowało, jakie uwagi i sugestie rzeczywiście mogą usprawnić działanie aplikacji i będą wdrażane jako Żądania Zmian. Analizowano również błędy wykryte podczas testów UAT II – stosunkowo często błędy te pojawiały się tylko w środowisku UAT II, nie występowały w UAT i SIT. W takich przypadkach naprawa błędów wymagała dostępu do UAT II – błąd reprodukowano oraz brano odpowiednie logi systemu, aby następnie przystąpić do poprawiania błędu na maszynie programisty. Zatrudnienie pracowników banku do testowania systemu przed wdrożeniem na produkcję umożliwiło wykrycie i poprawę istotnych dla poprawnego funkcjonowania systemu błędów oraz wdrożenie kilku zmian ułatwiających sprawną i szybką pracę z aplikacją. Wyniki Dzięki usprawnionej współpracy z zespołami klienta i kooperacji w prowadzeniu prac testowych osiągnięto wymierne korzyści: • większa liczba błędów wykrytych i naprawionych przed wdrożeniem systemu na produkcję; • większe pokrycie testów dzięki wykonywaniu testów przez dwa zespoły, uzupełniające się nawzajem; R

• lepsza komunikacja w projekcie, szybsze i efektywniejsze rozwiązywanie problemów; • wzrost zaufania klienta do dostawcy oprogramowania. Oraz oczywiście – sprawdzenie funkcjonowania systemu w środowisku docelowym (UAT II) i w użytkowaniu przez użytkowników końcowych. Dodatkowo połączenie sił i wspólna praca nad systemem umożliwiła zespołowi klienta dogłębne poznanie funkcjonalności tworzonego systemu, jak również powiązań z systemami zewnętrznymi, co usprawniło pracę organizacji klienta.

rozwiązywania problemów, jeśli ma wgląd w bieżący stan aplikacji. Niewątpliwym plusem jest możliwość maksymalizacji efektywności prac testowych – wykrycie jak największej liczby błędów w jak najkrótszym czasie oraz możliwość sprawdzenia działania systemu podczas działania z użytkownikami zbliżonymi do użytkowników końcowych systemu. Dlatego też warto rozważyć większe zaangażowanie klienta w prace projektowe – obie strony – i dostawca, i klient – mogą na tym wiele skorzystać.

KAROLINA ZMITROWICZ
Pracuje na stanowisku Analityka biznesowego w firmie BLStream, wchodzącej w skład Grupy BLStream. Karolina specjalizuje się obecnie w modelowaniu wymagań biznesowych. Wcześniej pracowała jako Manager Quality Assurance w projektach informatycznych w sektorze finansowo – bankowym. Grupa BLStream powstała by efektywniej wykorzystywać potencjał dwóch, szybko rozwijających się producentów oprogramowania – BLStream i Gamelion. Firmy wchodzące w skład grupy specjalizują się w wytwarzaniu oprogramowania dla klientów korporacyjnych, w rozwiązaniach mobilnych oraz produkcji i testowaniu gier. Kontakt z autorem: karolina_zmitrowicz@wp.pl

Podsumowanie
Praca z testerami klienta nie zawsze jest prosta i przyjemna. Czasami wymaga poświęcenia stosunkowo dużych nakładów czasu na przeszkolenie zespołu klienta i zorganizowania dodatkowego środowiska testowego oraz reorganizacji planu i założeń projektu. Współpraca z klientem wymaga dobrej organizacji pracy i chęci współdziałania, ale rezultaty mogą być bardzo dobre i mieć zasadniczy wpływ na sukces projektu. Klient nabiera zaufania do dostawcy oprogramowania i z większym zaangażowaniem podchodzi do E K L A M

A

www.sdjournal.org

53

Testowanie oprogramowania

Jakość czy jakoś to będzie?
Czyli jak Rational Quality Manager może wesprzeć profesjonalne zarządzanie procesem testów
Odpowiedź na pytanie czy tworzone oprogramowanie jest wystaczająco dobre do uruchomienia produkcyjnego wymaga złożonego procesu decyzjnego. IBM Rational® Quality Manager jest rozwiązaniem, które może pomóc podjąć tą odpowiedzialną decyzję w oparciu o wiarygodne dane dostarczane w czasie rzeczywistym.
Dowiesz się:
• Jak oprogramowanie wspiera proces zarządzania testami; • Jak rozpocząć prace z Rational Quality Manager .

Powinieneś wiedzieć:
• Jak wygląda proces testów w Twoich projektach.

Tworzenie nowego użytkownika
Utworzenie konta dla nowego użytkownika wymaga następujących czynności: • Zalogowanie do systemu w roli administratora (domyślne konto to user name: ADMIN; password: ADMIN). • Następnie z menu aplikacji wybieramy Admin i Jazz User Administration (Rysunek 1.) • Na ekranie User Management wybieramy polecenie Create User. Niezbędne dane do wprowadzenia to name (nazwa użytkownika), user ID (login użytkownika i adres e-mail oraz konieczne jest wybranie właściwych uprawnień licencyjnych, przykład na Rysunku 2. Następnie przycisk Save zakończy operację, która będzie potwierdzona komunikatem (tak jak na Rysunku 3.) Uwaga: Nowy użytkownik ma nadawane hasło takie same jak nazwa konta (User Id) Po pierwszym zalogowaniu użytkownik powinien ustalić sobie inne hasło.

Poziom trudności

J

ego zadaniem jest maksymalizacja efektów pracy zespołów projektowych, zmniejszenie liczby defektów oraz skrócenie czasu dostarczania produktów. To ludzie, a nie organizacje, tworzą dobre oprogramowanie. Aby proces produkcji oprogramowania był ściśle związany z zapewnieniem jakości, zespoły muszą współpracować, wykorzystywać automatyzację, która przyspiesza realizację prac, wymieniać informacje oraz widzieć wskaźniki postępu testów umożliwiające lepsze zarządzanie projektami. Proces produkcji oprogramowania sterowany jakością rozszerza definicję jakości poza tradycyjne testowanie. Obejmuje kluczowe aspekty produkcji oprogramowania — od definiowania wymagań i zarządzania projektem, po zarządzanie defektami.

Jakie zadania może Rational Quality Manager wykonać za Ciebie?
Lista funkcji realizowanych przez Rational Quality Manager jest długa. Nie było w ofercie IBM Rational podobnego produktu do tej pory. Oto krótkie podsumowanie kluczowych cech: Postulaty te są jasne i w każdym projekcie powinny być przestrze54

gane. Praktyka jednak mówi inaczej. Np. współdzielenie informacji w zespole. Przecież informacje w każdym projekcie są rozsyłane do wszystkich zainteresowanych! Czy na pewno tak jest? Przestrzeganie wszystkich tych zadań może się wiązać z koniecznością wykonania dodatkowych prac niż konkretne zadania projektowe, a w efekcie czasem doprowadzamy do drobnych zaniedbań, które mają tendencje do przekształcania się w poważne problemy projektowe. Np. brak informacji o wykorzystaniu laboratorium testowego może spowodować spiętrzenie się testów wymagających specyficznych zasobów w pewnych okresach czasu (zwykle tuż przed końcem projektu), a bezproduktywne utrzymywanie go w innych. Takie przykłady można mnożyć. Zwykle wytłumaczeniem jest brak czasu na zadania niezwiązane ściśle z projektem, takie jak raportowanie czy uzupełnianie dokumentacji. Ważne jest więc zapewnienie automatyzacji jak największej ilości czynności, aby postulaty takie jak wgląd w stan realizacji projektu w czasie rzeczywistym mogły być spełnione. Jak więc wygląda praca z Rational Quality Manager i jak rzeczywiście wypełnia on postawione przed nim zadania? Ze strony http://www.ibm.com/developerworks/ downloads/r/rqm/ można ściągnąć 60 dniową wersję próbną Rational Quality Manager, aby we własnym środowisku przekonać się o możliwościach tego narzędzia. Aby ułatwić pierwsze kroki, kilka przykładów działania użytkowników.

Planowanie testów
Plan testów to jedna z tych cznności, które są kluczowo ważne dla sprawnego procesu testów, ale bardzo często prowadzona jest tylko na ogólnym poziomie, a typowym wytłumaczeniem jest, że planowanie zabiera dużo czasu, który może być wykorzystany na bardziej konkretną pracę.

Rysunek 1. Menu administratora 03/2009

Jakość czy jakoś to będzie?

Dzięki Rational Quality Manager plan testów może być stworzony szybko, może wykorzystywać sprawdzone wcześniej procedury i być aktualizowany na bieżąco, zgodnie ze zmieniającymi się potrzebami projektu. W Rational Quality Manager plan testów obejmuje co najmniej cel i zakres testów, poszczególnych etapów testów oraz kryteria zakończenia. Pozwala to na: • Śledzenie przeglądów, akceptacji i bieżącego statusu planu;

• Tworzenie i zarządzanie przypadkami testowymi w powiązaniu z zakresem zdefiniowanym w planie; • Importowanie i wiązanie wymagań projektu z przypadkami testowymi czy bezpośrednio z planem dla zapewnienia właściwego pokrycia testami; • Planowanie i wiązanie z przypadkami i elementami planu środowisk do przeprowadzania testów (np. przeglądarki, bazy danych, systemy operacyjne), co ułatwia przygotowanie właściwych konfiguracji testo-

wych i śledzenie stanu w rozbiciu na istotne cechy konfiguracji; • Określenie potrzebnych zasobów, czasu i innych wysiłków do zrealizowania właściwych testów na każdym z etapów projektu; • Zdefiniowane i komunikowanie w całym zespole celów biznesowych, przedmiotów testów, kryteriów jakości i innych artefaktów. Plan składa się zwykle z kilku szablonów, dostosowywanych do własnych potrzeb organizacji. Jeśli w standardowych szablonach są elementy nieprzydatne do Twojego procesu, można je usunąć, jeśli jakiś brakuje, można je utworzyć. Tak utworzony szablon może być podstawą w następnym projekcie, pozwalając tym samym na przeniesienie sprawdzonych praktyk i przyspieszenie pracy. Kluczowe kroki przy tworzeniu nowego planu testów ze standardowego szablonu: • Zaloguj się do Rational Quality Manager jako użytkownik. • W lewym panelu nawigacyjnym wybierz ikonę Plannig i polecenie Create Test Plan • Następnie podaj nazwę planu testów, a w polu Template wybierz Default Test Plan Template • Przycisk Save utworzy Twój plan testów, efekt powinien być analogiczny do widocznego na Rysunku 4. Domyślny plan testów składa się z trzech głównych sekcji: • * Nagłówek (pokazy na Rysunku 4.); • * Spis treści (czyli elementy planu); • * Sekcja opisu elementu. Domyślnie sekcje znajdujące się w szablonie nie są utworzone, tak więc w każdą potrzebną w projekcie należy zainicjować poprzez naciśnięcie przycisku Work Item Create i wypełnienie danych niezbędnych danej sekcji, Np. w sekcji Summary musimy wybrać właściciela (Owned By) i planowaną datę zakończenia (Due), tak jak to pokazane jest na Rysunku 5. Jako że zadaniem testów jest sprawdzenie spełnienia wymagań, najczęściej kolejnym krokiem jest dołączenie opisów wymagań do przetestowania. Jeśli wymagania są zgromadzone w systemie zarządzania wymaganiami takim jak RequistePro możemy je powiązać do Rational Quality Manager. Wymagania zapisane w dokumentach możemy zaimportować przez format XML, a dla naszego ćwiczenia utworzymy wymaganie wprost w Rational Quality Manager. Wybieramy z panelu sterowania ikonę Requirements i polecanie Create Requirement.

Rysunek 2. Tworzenie nowego użytkownika

Rysunek 3. Potwierdzenie utworzenia nowego konta

Rysunek 4. Zapisany plan testów Tabela1. Podsumowanie kluczowych cech Rational Quality Manager Współdzielenie informacji w zespole Zarządzanie w cyklu życia projektu Wsparcie współpracy w rozproszonych zespołach dzięki interfejsowi Web 2.0; Centralne repozytorium przechowuje wersje zasobów testowych i szablonów do wielokrotnego wykorzystania; Obsługa zespołów małych, średnich i dużych (do 250 osób). Elastyczne środowisko definiowania procesów pozwalające na włączenie sprawdzonych praktyk w miarę ich nabywania; Plan testów dla wszystkich etapów projektu określający role uczestników, proces, odpowiedzialnych za efekty i automatyzujący przepływ zasobów i informacji; Współdzielony dostęp i śledzenie stanu zasobów w całym cyklu życia. Opisywanie kroków testowych z formatowaniem RichText, obrazami i zestawami danych testowych zapewniające precyzję opisu i wykonania; Proceduralizacja tworzonych testów zapewnia przyspieszenie pracy, wielokrotne wykorzystanie tworzonych elementów oraz dostęp dla wszystkich zainteresowanych w zespole. Terminarze wykonania testów zapewniają możliwość optymalnego wykorzystania środowisk testowych; Zarządzanie laboratoriami testowymi pomaga użytkownikom śledzić zapotrzebowanie i maksymalizować wykorzystanie posiadanych zasobów zarówno tych dostępnych fizycznie, jak i tworzonych wirtualnie. Automatyczne zbieranie danych; Wizualizacja aktualnego statusu projektu dzięki personalnym widokom wskaźników; Stała aktualizacja danych.

Zarządzanie testami ręcznymi

Automatyzacja skracająca czas projektu Metryki projektu ułatwiające podejmowanie decyzji

Rysunek 5. Tworzenie sekcji Summary 55

www.sdjournal.org

Testowanie oprogramowania
W oknie dialogowym, które się pokazuje, wpisujemy tytuł (pole summary) i możemy określić inne parametry (tylko waga jest obowiązkowa, ale ma wartość domyślną, więc też możemy pozostawić bez zmiany). Obowiązkowe jest naciśnięcie Save aby wysłać dane do bazy. Przykładowo wypełnione wymaganie jest pokazane na Rysunku 6. Kolejne dane wprowadzamy do opisu przypadku testowego. Wybieramy sekcję przypadków testowych (Table of Contents->Test Cases) i z panelu nad tabelą operację Add New Test Case Przy użyciu domyślnego szablonu (Default Test Case Template) wszystkie pola poza nazwą i wagą są opcjonalne. Ich wypełnienie pozwala łatwo wyszukiwać potrzebne elementy i zestawy elementów. Warto jest zwrócić uwagę na pole waga (Weight). Teoretycznie wszystkie przypadki testowe są równie ważne, ale jak wiadomo, niektóre są ważniejsze. Dobra skala oceny pozwala w krytycznych sytuacjach wybrać kluczowo ważne. Zatwierdzenie danych przyciskiem OK tworzy szablon i wracamy do listy przypadków testowych, podobnej do tej z Rysunku 8. Kliknięcie na elemencie listy przypadków testowych otworzy nową kartę z szablonem możliwych do wprowadzenia danych. W odpowiednich sekcjach możemy utworzyć link do wymagań innych przypadków testowych czy dołączyć dowolne dokumenty, które powinny być związane z tym przypadkiem testowym. Wszystkie te informacje pomogą nam określić,jak wykonać test na rzecz wybranego przypadku testowego. Na koniec tego artykułu stworzymy i uruchomimy test. cisk OK tworzy skrypt, następnie naciskamy Save i klikamy nazwę skryptu, co otwiera nową kartę, w której możemy wprowadzić kroki skryptu. Każdy tworzony krok testu jest domyślnie akcją do wykonania. W liście wyboru po lewej stronie opisu kroku można zmienić rodzaj z akcji na punkt weryfikacji bądź punkt raportowania. Opisując kroki testu można tekst formatować zgodnie z formatem RFT, dodawać obrazy i listy danych do wykorzystania w trakcie danego kroku. Przycisk Save kończy edycję i nasz skrypt jest gotowy do wykonania.

Tworzenie i wykonywanie przypadków testowych
Kluczowym elementem przypadku testowego jest opis testu. Znajduje się on w sekcji skryptów (Test Scripts). Sekcja pozwala na stworzenie listy skryptów związanych z przypadkiem testowym. Skrypty mogą być wpisane do ręcznego wykonania w Rational Quality Manager albo też powiązane z narzędziami automatyzujące pracę takimi jak: • • • • IBM® Rational® Functional Tester, IBM® Rational® Manual Tester, IBM® Rational® Performance Tester, IBM® Rational® Service Tester for SOA Quality, • IBM® Rational® Appscan i innymi. Interfejs komunikacji jest w pełni udokumentowany, więc w razie potrzeby można zbudować połączenie do innych rozwiązań wspierających pracę testera. W ramach tego artykułu stworzymy najprostszy kilkukrokowy skrypt do testów ręcznych. Wybieramy sekcję Test Scripts i ikonę dodaj nowy skrypt (Add New Test Script). Podajemy nazwę skryptu i wypełniamy inne opcjonalne pola (pole Type nie może być zmienione, jeśli nie są zainstalowane interfejsy do narzędzi automatyzacji). Przy-

Wykonanie skryptu
W prawym górnym rogu przypadku testowego, niezależnie od wybranej sekcji, jest przycisk uruchomienia skryptu Run Test Case. Po wybraniu wypełniamy metrykę testu (kto, kiedy, jaki skrypt, jakie środowisko itp.), i otwiera się okno wykonania takie jak na Rysunku 11. Następnie wykonujemy pokazane kroki testu raportując kolejno ich wykonanie oraz sprawdzając punkty testowe i określając wynik. Przejście przez ostatni punkt bądź wybranie negatywnego zakończenia testu (Fail) powoduje wyświetlenie statusu realizacji takie jak na Rysunku 12. Na tym ekranie mamy do dyspozycji przycisk Save – zapisanie wyników testu lub też zgłoszenie

Rysunek 7. Opisany przypadek testowy

Rysunek 8. Lista przypadków testowych

Rysunek 9. New Test Script dialog

Rysunek 6. Wypełnione wymaganie

Rysunek 10. Kroki skryptu

56

03/2009

Jakość czy jakoś to będzie?

błędu. Nie da się ukryć, że tester czuje się usatsfakcjonowany, jeśli błąd znajduje, co w jakimś stopniu może opóźnić dostarczenie produktu, ale taka jest natura ludzka. Następny krok staje się więc bardzo ważny – zakomunikowanie faktu, że aplikacja nie jest taka dobra jak się wydawało do tej pory w zespole. Nie darmo powstały określenie krytyka i krytyka konstruktywna. Ta druga forma wskazania błędów zakłada, że nie tylko podamy informację, że jest źle, ale również podpowiemy, co trzeba zrobić/osiągnąć, aby stan uległ poprawie. Dzięki Rational Quality Manager wraz z werdyktem testu przesyłane są w czasie rzeczywistym wszystkie inne dostępne informacje: • skrypt testu pokazujący kroki, jakie zostały wykonane; • dane testowe, które doprowadziły do błędu; • czas wykonania; • opis konfiguracji serwera i klienta; • wymagania, które zostały niespełnione. Mając takie informacje znacznie łatwiej jest znaleźć i usunąć przyczynę błędu niż tylko na podstawie informacji, że jest źle. Zebrane w jednym centralnym serwerze wszystkie informacje o testach znacznie ułatwiają wielokrotne wykorzystanie tych samych skryptów, danych, czy osób, co zapewnia krótszy czas i większą precyzję pracy. Przy tym dzięki temu, że Rational Quality Manager jest zbudowany w Javie przy użyciu technologii Web 2.0, dotarcie i wykorzystanie informacji nie jest trudniejsze niż użycie przeglądarki WWW. Rational Quality Manager jest środowiskiem zarówno dla testerów, jak i dla osób podejmujących decyzje projektowe. Wszystkie dane, jakie wprowadziliśmy w trakcie tworzenia i wykonania testu, mogą posłużyć powzięciu właściwej decyzji czy to o skierowaniu produktu do rzeczywistego działania, czy o dalszych pracach rozwojowych. Ekran główny (Home) pokazuje (być może trzeba nacisnąć przycisk Refresh) wyniki właśnie wykonanych testów, w formie graficznej czy tekstowej. Podejmowanie trafnych decyzji na podstawie twardych danych staje się znacznie łatwiejsze. Wygląd ekranu głównego i dostępne raporty mogą być dowolnie zmieniane i rozszerzane o potrzebne organizacji wskaźniki, zestawienia czy inne formy raportu. Przykładowy raport można zobaczyć na Rysunku 13. Zapraszam na stronę ibm.com/developerworks/ rational, gdzie w sekcji Rational Quality Manager znajdziesz artykuły na temat tworzenia własnych raportów, wskaźników, integracji z narzędziami automatyzacji. Artykuły są publikowane zarówno w formie tekstów, jak i filmów. Można dołączyć się do forum użytkowników wymieniających informacje na temat Rational Quality Manager i innych produktów rodziny Rational poświęconych jakości oprogramowania.

Rysunek 11. Wykonanie testu

Rysunek 12. Podsumowanie wykonania skryptu

Rysunek 13. Przykładowy wykres automatycznie generowany przez Rational Quality Manager

ZBIGNIEW ZARZYCKI
IBM Rational Technical Consultant

www.sdjournal.org

57

Testowanie oprogramowania

WebAii
Testowanie aplikacji ASP .NET
Przyszłość należy do serwisów internetowych – tego typu sformułowanie słyszałem już niejednokrotnie i być może jakiś gram prawdy w nim jest. Ogólnodostępność, interaktywność czy też współdzielenie zasobów są argumentami umacniającymi mnie w przekonaniu, iż to właśnie aplikacje webowe będą najbardziej kojarzone z inżynierią oprogramowania za parę lat.
Dowiesz się:
• Czym jest WebAii i jaka jest jego rola w procesie testowania stron ASP .NET; • Jak krok po kroku stworzyć szablon testów.

Powinieneś wiedzieć:
• Czym są testy jednostkowe; • Posiadać podstawową wiedzę z zakresu biblioteki NUnit.

Poziom trudności

J

ak twierdzi Stephen H. Kan: jakość oprogramowania przestała być zaletą systemów informatycznych. Stała się warunkiem koniecznym dla firm poważnie myślących o zakończeniu projektów sukcesem. Dlatego wychodząc naprzeciw tym problemom, chciałbym zaprezentować czytelnikowi artykuł na temat technik testowania systemów webowych opartych na silniku ASP.NET oraz frameworku WebAii.

stów. Istnieje możliwość uruchomienia programu testowego na dwa sposoby: w środowisku NUnit bądź we własnej aplikacji typu standalone (błędy wykonania można raportować w pliku zewnętrznym, obsługiwanym przez obiekt Log). Swoje rozważania chciałbym skupić na pierwszym sposobie. Po dodaniu referencji do bibliotek zewnętrznych, możemy rozpocząć pracę z implementacją pierwszego testu. Na początku zdefiniujmy nową klasę. W tym celu w Visual Studio z menu Project>Add New Item wybieramy WebAiiNUnitTest (Shared Manager). W tym momencie utworzyliśmy gotowy szablon składający się z następujących standardowych metod: • – utworzenie instancji obiektu Manager, wykorzystywanego podczas testów. Jeżeli nie istnieje obiekt konfiguracyjny (Settings) bądź został zniszczony, tworzona jest jego nowa instancja. Wszystkie pola ustawiane są na wartości domyślne. • MyTestInitialize – określenie wartości początkowych, wykonywanych przed każdym testem. • TestClassTearDown (CleanUp) – tzw. metoda sprzątająca, kończy pracę obiektu Manager oraz zamyka uruchomioną przy starcie przeglądarkę interetową.
TestClassInitialize

miejscu chciałbym się zatrzymać nad metodą MyTestInitialize . W niniejszym przykładzie wykorzystywane są ustawienia domyślne – czyli weryfikacja poprawności oceniania będzie w środowisku Internet Explorer. Aby zmienić przeglądarkę na Firefox, wystarczy jako parametr wywołania metody LaunchNewBrowser podać typ przeglądarki, zgodnie z Listingiem 1.

Pierwszy test
Załóżmy, iż przedmiotem naszej weryfikacji będzie prosta strona ASP.NET, która zawiera formularz logowania użytkownika do systemu (Rysunek 1.). W pierwszym teście będziemy chcieli sprawdzić, czy wszystkie elementy, które zostały określone w specyfikacji, znajdują się na podstawowym widoku. Znając ich numery ID metodę testującą można zakodować w następujący sposób (Listing 2.). Ponadto framework WebAii pozwala na wyszukiwanie elementów na stronie po dowolnym parametrze, według którego będzie w stanie odróżnić kontrolki. Wśród nich do bardziej użytecznych można zaliczyć: • •
Find.ByName

WebAii – wprowadzenie
WebAii jest darmowym zestawem bibliotek wspierającym tworzenie testów automatycznych, uruchamianych dla podstawowych przeglądarek internetowych (Microsoft Internet Explorer, Mozilla Firefox). Niniejszy framework dostarcza rozbudowanego zestawu narzędzi do tworzenia asercji dla stron WWW związanych ze sprawdzaniem dostępności i widoczności kontrolek HTML/ASP.NET, śledzenia renderingu elementów strony, wsparciem dla testów struktury DOM oraz JavaScript czy też widoków zależnych od kaskadowego arkusza stylów (CSS). Sercem środowiska WebAii jest obiekt Manager, który odpowiedzialny jest m.in. za uruchomienie przeglądarki, połączenie z klientem oraz sterowanie procesem te58

– wyszukiwanie po nazwie

pontrolki.

W dalszych krokach jedyne co musimy zrobić to zakodować poszczególne metody, które będą odpowiedzialne za weryfikację poprawności naszej aplikacji webowej. W tym

– wyszukiwanie kontrolki/zbioru kontrolek wg zawartości np. • Manager.ActiveBrowser.Find.ByCon tent("<div id=RegionId>"); Opcja ta akceptuje również wyrażenia regularne. • Find.ByAttributes /Find.AllByAttributes – jako parametr wywołania metoda przyjmuje tablicę znaków interpretowaną jako parę [name, value], np. Manager.ActiveBrow
ser.Find.ByAttributes(new "class", "TextArea _ Class" });. string[] {

Find.ByContent /Find.AllByContent

03/2009

WebAii –Testowanie aplikacji ASP .NET

Find.ByXPath/Find.AllByXPath

– zwraca kontrolkę/zbiór kontrolek dopasowanych do wyrażenia XPath, np. pobranie wszystkich elementów div ze strony:
Find.AllByXPath("/descendant::

W następnym kroku odnajdujemy i klikamy przycisk Log In:
HtmlInputSubmit button = Manager.ActiveBro

IList<Element> allDivs =

wser.Find.ById<HtmlIn putSubmit>("Button");

node()[starts-with(@id, 'div')]");.

button.Click();

Drugi test – ustawianie wartości dla poszczególnych kontrolek
W kolejnym etapie testowania naszego formularza spróbujemy sprawdzić zachowanie systemu podczas autoryzacji użytkownika. Załóżmy, iż w przypadku udanej próby klient zostanie przekierowany do strony http: //localhost/WebAiiTest/StartPage.aspx, na której będzie znajdowała się tylko jedna etykieta z wartością Hello [login użytkownika]. Na początek spróbujmy wypełnić wartości login i hasło poprawnymi danymi:
loginTxt.Text = "admin"; passwdTxt.Text = "admin";

Na koniec sprawdzamy, czy zostaliśmy przekierowani do prawidłowej strony z wymaganymi elementami:
string url = Manager.ActiveBrowser.Url; HtmlSpan label = Manager.ActiveBrowser.Find.ById<HtmlSpan >("Hello_Label_id");

sząc się chociażby do naszej przykładowej aplikacji, jednym ze sposobów przenoszenia nazwy użytkownika pomiędzy stronami, jest umieszczenie wartości login właśnie w takim pliku. WebAii dostarcza pełnego wsparcia w dziedzinie obsługi plików cookie. Dostęp do niego odbywa się poprzez obiekt CookieManager. Do podstawowych funkcji malipulacji na obiekcie tego typu można zaliczyć: • – usunięcie wszystkich ciasteczek – opcja szczególnie przydatna, gdy podczas testowania aplikacji w środowisku produkcyjnym chcemy się uchronić przed cache'owaniem niektórych wartości. • GetCookies – pobranie zbioru plików Cookie spod podanego adresu URL. • SetCookie – utworzenie nowego ciasteczka.
DeleteCookie

string labelValue = label.InnerText;

Pełny zapis metody prezentuje Listing 3.

Pliki cookie
Programowanie WWW nierozerwalnie wiąże się z obsługą plików cookie (ciasteczek). Odno-

Wywoływanie funkcji JavaScript
W ostatnim etapie testowania naszego przykładowego formularza odniesiemy się do procesu integracji strony ze skryptami JavaScript. Za pomocą metody InvokeScript możemy wywołać dowolną funkcję JS, przekazując jej nazwę jako parametr. Załóżmy, iż formularz nie zostanie wysłany do serwera, dopóki użytkownik nie wprowadzi wartości w pola wymagane (w naszym przypadku loginu oraz hasła). Błąd zostanie zasygnalizowany w formie etykiety zawierającej napis koloru czerwonego Fill all required fields.

Listing 1. Ustawienie domyślnej przeglądarki na Mozilla Firefox
[SetUp]

public void MyTestInitialize() { if (Manager.Browsers.Count == 0) { } Manager.LaunchNewBrowser(BrowserType.FireFox);

}

Listing 2. Metoda testująca dostępność elementów wymaganych na formularzu
[Test] { public void ControlVisibility() // Nawigacja do strony podlegającej weryfikacji Manager.ActiveBrowser.NavigateTo( "http://localhost/WebAiiTest/Default.aspx");

// Element ogólny Element loginLabel = Manager.ActiveBrowser.Find.ById("Login_Label"); Element passwordLabel = Manager.ActiveBrowser.Find.ById("Password_Label");

Rysunek 1. Przykładowy formularz logowania

// Korzystając już z konkretnego typu Html Input HtmlInputText loginTxt = n_TextBox"); Manager.ActiveBrowser.Find.ById<HtmlInputText>("Logi

HtmlInputPassword passwdTxt = Manager.ActiveBrowser.Find.ById<HtmlInputPassword>(" Passwd_TextBox");

Rysunek 2. Widok po poprawnej autoryzacji

HtmlInputSubmit button = ");

Manager.ActiveBrowser.Find.ById<HtmlInputSubmit>("Button

Assert.IsNotNull(loginLabel); Assert.IsNotNull(loginTxt); Assert.IsNotNull(button);

Assert.IsNotNull(passwordLabel); Assert.IsNotNull(passwdTxt); }

Rysunek 3. Walidacja z wykorzystaniem JavaScript

www.sdjournal.org

59

Testowanie oprogramowania
Proces walidacji przeprowadzimy w następujących krokach: • Przed kliknięciem: etykieta validate posiada styl display:none – nie jest widoczna na stronie. Deklaracja: • <span id="validate" style=
"display:none">Fill all required fields</span>

Listing 4. prezentuje propozycję przeprowadzenia testów integracji JavaScript z naszą aplikacją.

Test Regions
Strona www zazwyczaj składa się z wielu części np. nagłówka, stopki, wydzielonych bloków, paska nawigacyjnego itp. Framework WebAii umożliwia grupowanie elementów wchodzących w skład danego segmentu strony i przeprowadzenia procesu weryfikacji poprawności dla jej fragmentu. Korzyści płynące z tego zabiegu to m.in.: • zmniejszenie kosztów i złożoności testów poprzez ich ukierunkowanie na dany obszar,

• oznaczanie fragmentów stałych zmian w kodzie podlegających szczególnej analizie, • luźne połączenie testów z kodem produktu • w przypadku pracy z praktyką Test Driven Development – ostrzeganie programistów o potencjalnym złamaniu zasad automatyzacji testów. WebAii oferuje pełną elastyczność w przypadku tworzenia oznaczeń dla regionów. Można zapisać je za pomocą dowolnego języka znaczników (html, xml, xhtm) zawierającym tag testregion oraz numer id (np. dla widoku ASP .NET: <testregion
id=”regionid”> testregion>).

• Po kliknięciu przycisku Log In, etykieta validate zmieni kolor na czerwony oraz styl na display:inline . • Deklaracja: <span id="validate"
style="display:inline">Fill required fields</span>

all

Listing 3. Testowanie procesu uwierzytelniania użytkownika
[Test] {

public void ValidFormLogIn() HtmlInputText loginTxt = "Login_TextBox"); Manager.ActiveBrowser.Find.ById<HtmlInputText>(

W kodzie metody testującej odwołanie do wyznaczonego fragmentu uzyskujemy za pomocą metody Region obiektu ActiveBrowser (np. TestRegion reg =
Manager.ActiveBrowser.Regions[„region id”];)

region

content

</

Podsumowanie
Prezentowane w artykule techniki testowania dynamicznych stron WWW są jedynie kroplą w morzu możliwości frameworka WebAii. Pozostałe rozszerzenia odnoszą się również do testowania m.in. aplikacji Microsoft Silverlight, Ajax, ASP.NET local server, .NET Page DOM czy też popularnego w systemach WEB 2.0 wsparcia dla dynamicznych elementów typu Drag And Drop. Testowanie części FrontEndowej strony jest dość problematyczne, natomiast zarówno rynek komercyjny, jak i opensource'owy nadal pozostaje ubogi w kwestii doboru narzędzi tworzenia testów automatycznych dla witryn internetowych. Dlatego, wg mnie, warto zapoznać się z frameworkiem WebAii.

HtmlInputPassword passwdTxt = Manager.ActiveBrowser.Find.ById<HtmlInputPassword>( "Password_TextBox");

loginTxt.Text = "admin";

passwdTxt.Text = "admin"; HtmlInputSubmit button = Manager.ActiveBrowser.Find.ById<HtmlInputSubmit>("But

ton");

button.Click(); string url = Manager.ActiveBrowser.Url; HtmlSpan label =

Manager.ActiveBrowser.Find.ById<HtmlSpan>("Hello_Label_id");

string labelValue = label.InnerText; Assert.AreEqual(url, “http://localhost/WebAiiTest/StartPage.aspx/”); Assert.IsNotNull(label); } Assert.AreEqual(labelValue, "Hello admin");

Bibliografia
• • • • Stephen H. Kan, Metryki i modele w inżynierii jakości oprogramowania, Wydawnictwo Naukowe PWN, 2006 J. Newkirk, Test Driven Development In .NET, Microsoft Professional 2004 A. Hunt, D. Thomas, Pragmatic Unit testing in C# with NUnit, O’Reilly 2007 Dokumentacja techniczna frameworka WebAii dostępna pod adresem: http: //www.artoftest.com/Resources/WebAii/ Documentation/topicsindex.aspx

Listing 4. Testowanie elementów zależnych od CSS i JavaScript
[Test] { public void RequiredFields() Manager.ActiveBrowser.NavigateTo(

"http://localhost:1293/WebAiiAsp/Default.aspx");

HtmlSpan span = Manager.ActiveBrowser.Find.ById<HtmlSpan>("validate"); Assert.AreEqual("none", span.Styles[0]);

PAWEŁ WILKOSZ
Pracuje na stanowisku Software Quality Engineer w firmie Making Waves Polska. Ma również doświadczenie w tworzeniu aplikacji .NET oraz SQL Server. Jest aktywnym członkiem Polish SQL Server User Group w Krakowie. Prywatnie pasjonat muzyki alternatywnej z lat ’60 – ’90 oraz squasha. Kontakt z autorem: pawel.wilkosz@gmail.com

// Wywołanie metody JavaScript CheckForm() Manager.ActiveBrowser.Actions.InvokeScript("CheckForm(this)"); Assert.AreEqual(Color.Red, span.GetComputedStyle("color").ToColor()); } Assert.AreEqual("inline", span.Styles[0]);

60

03/2009

Soware Development GigaCon
– budowanie aplikacji biznesowych
23 - 24 marca 2009 Warszawa, Hotel Novotel Airport

Tematyka konferencji: Blok zarządzanie projektami:

WST

TNY - zarządzanie portfelem projektów - zarządzanie wymaganiami - zarządzanie zmianą - outsourcing projektów IT - nowoczesne metodyki projektowania systemów informatycznych - metodyki „lekkie” (agile, xp) w konstrukcji systemów informatycznych - problematyka analizy wymagań w projektach wdrożeniowych
Blok technologiczny:
- cloud computing – NOWOŚĆ! - bazy danych - Java - zarządzanie treścią w internecie (narzędzia do tworzenia aplikacji web, oprogramowania portalowe) - RIA - rich internet application - środowiska programistyczne -- pakiety Case i Rad - rozwiązania oparte na technologiach XML i Web Services - platformy integracyjne - budowanie aplikacji mobilnych - budowanie aplikacji BPM - budowanie aplikacji SOA - narzędzia do testowania oprogramowania - narzędzia wspomagające prowadzenie projektów programistycznych

ĘP B

EZP Ł

A

Blok jakości i testowania
- jakość systemów informatycznych. - planowanie jakości - zapewnianie jakości - kontrola jakości - normy i standardy dotyczące jakości oprogramowania - jakość w różnych fazach procesu budowy oprogramowania: jakość w wymaganiach, analizie, projektowaniu itp. - konstrukcja i testowanie oprogramowania

Więcej informacji:
http://sdevelopment.gigacon.org

Kontakt:
Marta Paprowicz Specjalista ds.organizacji konferencji i szkoleń mail: marta.paprowicz@software.com.pl tel: +48 22/ 427 36 75

Główny sponsor konferencji:

Technologie internetowe

Zintegruj się z Internet Explorer 8
Czyli jak stworzyć Akcelerator, Web Slice i Search Provider
Już niedługo premiera kolejnej wersji przeglądarki firmy Microsoft, która otworzy przed programistami zupełnie nowe możliwości tworzenia rozszerzeń. W niniejszym artykule przedstawione zostały podstawy programowania tzw. akceleratorów, web slice’ów oraz search provider’ów, które pozwalają zintegrować nasze strony z przeglądarką Internet Explorer 8.
Dowiesz się:
• Jakie nowe możliwości rozszerzeń będą dostępne w Internet Explorer 8; • Jak zintegrować Twoją stronę z przeglądarką; • Jak stworzyć search provider, akcelerator i web slice.

Powinieneś wiedzieć:
• Znajomość podstawowych pojęć z zakresu HTML, CSS, RSS, Javascript; • Podstawowe informacje na temat protokołu HTTP.

Poziom trudności

W

raz z rosnącą popularnością Internetu rosną również oczekiwania użytkowników w stosunku do możliwości oferowanych przez przeglądarki internetowe. Internet Explorer 8 (w chwili pisania artykułu wchodzący w fazę RC1) będzie oferował 3 nowe typy rozszerzeń: zintegrowaną wyszukiwarkę (o bogatszych możliwościach niż w Internet Explorer 7), tzw. Akceleratory (przyspieszające odnajdowanie informacji w sieci) oraz Web Slice’y (do monitorowania często zmieniających się treści stron). Wszystkie mechanizmy bazują na standardach XML oraz HTML – możemy odetchnąć z ulgą, tym razem zintegrowanie strony z przeglądarką Microsoftu będzie naprawdę prostym zadaniem. A kiedy już coś zrobimy, warto się tym podzielić z innymi użytkownikami – każdy może zgłosić swoje rozszerzenie do publicznej galerii polskich dodatków do IE 8 (http://ieaddons.com/pl/).

Zintegrowana wyszukiwarka
Zarówno przeglądarka Internet Explorer od wersji 7, jak i Firefox od wersji 2 w prawym górnym rogu udostępniają niewielkie pole tekstowe umożliwiające użytkownikom szybkie przesła62

nie zapytania do wybranej wyszukiwarki internetowej. W dolnej części okna rozwijającego się po wpisaniu słów kluczowych możemy wybrać silnik, który ma zostać w danym momencie wykorzystany. Praktycznie każda strona z zaimplementowanymi mechanizmami wyszukiwania może zintegrować się w ten sposób z przeglądarką. Na rynku dostępne są już wyszukiwarki integrujące się np. z Wikipedią, serwisem Amazon czy wyszukiwarkami Windows Live oraz Google. W Polsce warto zwrócić uwagę m.in. na rozwiązanie stworzone przez serwis GoldenLine (patrz Rysunek 1.) z uwagi na fakt, iż wykorzystuje ono najnowsze mechanizmy zintegrowanej wyszukiwarki – automatycznie pojawiające się sugestie ze zdjęciami i opisami. Od strony technicznej każdy search provider reprezentowany jest przez niewielki plik XML będący zgodny z tzw. specyfikacją OpenSearch. Została ona zaprojektowana przez firmy Amazon.com oraz A9 i wprowadzona na rynek w roku 2005. Obecnie OpenSearch wykorzystują zarówno Firefox 2+, jak i Internet Explorer 7+. Najprostszy provider zgodny z tą specyfikacją prezentuje Listing 1. Wystarczy w znaczniku ShortName określić nazwę wyszukiwarki, w znaczniku Image adres reprezentującej ją ikony oraz w elemencie Url szablon adresu, pod który przeglądarka ma wysyłać zapytania. Najistotniejszy w sekcji Url jest parametr {searchTerms} – reprezentuje on słowo kluczowe wpisane przez użytkow-

nika do wyszukiwarki. Na przykładzie z Listingu 1., po wysłaniu słowa test do tak zdefiniowanej wyszukiwarki użytkownik trafi na stronę http://example.com/?query=test. Nieco więcej pracy wymagać będzie od nas dodanie do wyszukiwarki funkcjonalności podpowiedzi dla wprowadzanych słów kluczowych. Aby były one wspierane, musimy stworzyć stronę (np. http://suggestions.example.com/?q=slowo_ kluczowe), która będzie wysyłała odpowiednio sformatowane odpowiedzi w formacie XML lub JSON (Javascript Object Notation). Będą one w rzeczywistości interpretowanymi przez przeglądarkę podpowiedziami do przekazanego w parametrze slowo_kluczowe zapytania. W zależności od tego czy serwer zwraca odpowiedzi w formacie JSON, czy XML, do sekcji OpenSearchDescription musimy dodać jedną z dwóch linijek prezentowanych na Listingu 2. Przykład podpowiedzi w formacie JSON, jaką mógłby zwracać serwer po wpisaniu przez użytkownika zapytania XBOX, prezentuje Listing 3. Jak widzieliśmy na Rysunku 1., podpowiedzi mogą również zawierać obrazy oraz opisy. Listing 4. prezentuje przykładową odpowiedź serwera w formacie XML, która spowoduje wyświetlenie tych elementów. Opisy zamieszczamy w elementach Description, adresy obrazów w sekcjach Image. Podpowiedzi mogą być również oddzielone od siebie separatorami definiowanymi przez elementy Separator. Na podstawie otrzymanej od serwera odpowiedzi z Listingu 4., przeglądarka wyświetliłaby jeden separator o nazwie My Visual Suggestions na samej górze okna. Po stworzeniu pliku XML definiującego wyszukiwarkę nie pozostaje nam nic innego, jak dodanie mechanizmów umożliwiających zain03/2009

Zintegruj się z Internet Explorer 8

stalowanie jej przez użytkowników portalu. Mamy tu do dyspozycji dwie możliwości. Pierwszą z nich jest zamieszczenie na stronie specjalnego linku, który odpowiednim wywołaniem funkcji JavaScript spowoduje zainstalowanie wyszukiwarki. Przykładem może być link:
<a href="#"

onclick="window.external.AddSearch

które spowodują automatyczne wykrycie wyszukiwarki. Po wejściu na stronę zawierającą takie znaczniki, Internet Explorer 8 wyświetli żółtą strzałkę obok pola wyszukiwarki. Umożliwi ona instalację search provider’a. To wszystko, co musieliśmy zrobić, aby użytkownicy mogli cieszyć się zintegrowanym z przeglądarką mechanizmem wyszukiwania treści na naszym portalu.

Provider('http:

//www.example.com/ Add Search Provider Example</a> provider.xml')">

Tworzenie akceleratorów
Czy nie zdarzyło Ci się nigdy kopiowanie adresu pocztowego do portalu nawigacyjnego? A ile razy znajdowałeś na stronie interesujący zwrot, który kopiowałeś do schowka, by wkleić go za chwilę w oknie wyszukiwarki internetowej? Akceleratory mają na celu przyspieszyć niektóre operacje, któ-

który zainstaluje wyszukiwarkę zdefiniowaną w pliku provider.xml. Drugim sposobem jest dodanie do strony specjalnych nagłówków np.:
<link title="My Provider" rel="search" +xml"

re robimy w Internecie – wyeliminować konieczność nieustannego kopiowania i wklejania, ręcznego przenoszenia interesujących nas słów kluczowych ze strony do strony. Są one dodatkowymi opcjami pojawiającymi się w menu kontekstowym po zaznaczeniu tekstu i kliknięciu go prawym przyciskiem myszy (lub wybraniu specjalnej ikony akceleratora). Przykładowymi akceleratorami mogą być np.: wyślij zaznaczony tekst mailem, znajdź zaznaczony tekst, przetłumacz wybrany tekst, znajdź zaznaczone słowo kluczowe w portal.pl, itp. Interesującym przykładem może być korzystający z serwisu Live Maps akcelerator, prezentujący mapę zaznaczonego adresu pocztowego – bez konieczności ręcznego wklejania go na stronach portalu (Rysunek 2.).

type="application/opensearchdescription href="http://www.example.com/

provider.xml">

Rysunek 1. Zintegrowana wyszukiwarka udostępniana przez serwis GoldenLine
Listing 1. Najprostszy Search Provider
<?xml version="1.0" encoding="UTF-8"?>;

Rysunek 2. Przykładowy akcelerator – mapa z Live Maps

<OpenSearchDescription xmlns="http://a9.com/-/spec/opensearch/1.1/">; <Url type="text/html" template="http://example.com/?query={searchTerms}&amp;source=IE"/>; </OpenSearchDescription> <Image height="16" width="16" type="image/icon">http://example.com/mycustom.ico</Image>; <ShortName>My Custom Search</ShortName>;

Listing 2. Definiowanie adresu zwracającego podpowiedzi
<Url type="application/x-suggestions+json"; template="http://suggestions.example.com/?query={searchTerms}"/>; <Url type="application/x-suggestions+xml"; template="http://suggestions.example.com/?query={searchTerms}"/>

Listing 3. Przykładowa odpowiedź serwera w formacie JSON
["xbox",; ["Xbox 360", "Xbox cheats", "Xbox 360 games"]]

www.sdjournal.org

63

Technologie internetowe
Jak widać, akcelerator po podświetleniu myszką potrafi wyświetlić niewielkie okno podglądu – możemy w nim znaleźć np. wyniki wyszukiwania, tłumaczenie zaznaczonego zwrotu, definicję z wikipedii, itp. Z technicznego punktu widzenia akcelerator jest po prostu plikiem XML (tzw. OpenService Description Format), podobnie jak search provider. Do zrobienia najprostszych akceleratorów (tzw. Codeless Accelerators) wystarczy dosłownie kilka linijek kodu (patrz Listing 5.). Najważniejszymi elementami formatu OpenService są: •
homePageUrl – określa domenę, w ramach

której ma działać akcelerator; • display – definiuje wygląd akceleratora (nazwa, ikona); • activity – określa funkcjonalności. Dodatkowymi parametrami, które możemy zdefiniować są: • Kategoria (category) – kategoria, w której akcelerator wyświetlać się będzie użytkownikowi. Można skorzystać z pre-

definiowanych: Add , Blog, Define , Map, Translate lub stworzyć własną; • Typ treści, dla której działa (context) – może być to cała strona (jeśli wywołujemy akcelerator z menu Page), zaznaczenie (selection) lub hiperłącze; • Szablon adresu strony, do której przekazywane są dane kontekstu (execute); • Informacja o kodowaniu znaków. Listing 5. prezentuje niektóre z tych parametrów w praktyce. Jednym z bardziej istotnych elementów akceleratora jest sekcja execute . Określa ona szablon strony, do której zostaniemy przekierowani po kliknięciu opcji reprezentującej dany akcelerator. Może on zawierać określone zmienne – np. na przykładzie z Listingu 5. wykorzystujemy parametr {selection}, który definiuje zaznaczony przez użytkownika tekst. Tabela 1. prezentuje inne parametry, które możemy wykorzystać w naszych szablonach adresów. Parametr możemy również oznaczyć jako opcjonalny, poprzez dodanie znaku zapytania po identyfikatorze zmiennej (np. {documentUrl?}). W odróżnieniu od zaprezentowanego na Listingu 5. przekazywania parametrów metodą GET, można je również przekazywać metodą POST. Listing 6. prezentuje przykład tego drugiego podejścia. Omawiane dotychczas akceleratory nie oferowały jednak bardzo wygodnej funkcjonalności, jaką jest podgląd wyników (wyświetlany po podświetleniu akceleratora). W praktyce jest to najzwyklejsza strona HTML, osadzona w niewielkim okienku podglądu. Musimy zatem ją stworzyć. Listing 7. prezentuje kod akceleratora zaprojektowanego przez serwis Ebay. Dzięki elementowi preview w sekcji activity, po podświetleniu akceleratora myszką wyświetli on podgląd (kod HTML zwracany ze strony http: //ie8.ebay.com/activities/preview/index.php). Podgląd może zawierać kod Javascript (ograniczony do domeny akceleratora) oraz kontrolki ActiveX – o ile zostały przez użytkownika zaakceptowane dla danej domeny. Okno podglądu ma stały rozmiar 320 x 240, wszystko poza nim jest ucinane. Nie zaleca się stosowania w nich pasków przewijania. Kiedy nasz akcelerator jest już gotowy, wystarczy dodać do strony mechanizm umożliwiający użytkownikom zainstalowanie go. Podobnie jak w przypadku search provider’ów dokonujemy tego z poziomu kodu Javascript, np.: <button onc
lick=”window.external.AddService(‘htt p://maps.live.com/GetMap.xml’)”>Dodaj akcelerator</button>.

Listing 4. Przykładowa odpowiedź serwera w formacie XML
<?xml version=”1.0”?>; <SearchSuggestion>; <Section>; <Item>; <Query>xbox</Query>; <Separator title="My Visual Suggestions" />; <Text>Xbox 360 Game Consoles</Text>;

<Description>Game console systems and packages at a great deal.</Description>; <Image source="http://www.example.com/xboxconsole.jpg" alt="Xbox 360 Consoles" <Url>http://www.example.com/</Url>; width="75"; height="75"/>;

</Item>; <Item>;

<Text>Xbox 360 Wireless Controller</Text>;

<Image source="http://www.example.com/xboxcontroller.jpg" alt="Xbox 360 Wireless </Item>; <Item>; Controller" width="75" height="75"/>;

<Text>Xbox 360 Live Games</Text>;

<Image source="http://www.example.com/live.jpg" alt="Xbox 360 Live Games" <Url>http://www.example.com/games.aspx?q="Xbox 360"</Url>; width="75"; height="75"/>;

</Item>;

</Section>;

</SearchSuggestion>

Listing 5. Przykładowa implementacja prostego akceleratora
<?xml version="1.0" encoding="UTF-8"?>; <openServiceDescription; xmlns="http://www.microsoft.com/schemas/openservicedescription/1.0">;

<homepageUrl>http://www.portal.pl</homepageUrl>; <display>; <name>Wyszukaj w Portal.pl</name>;

</display>;

<icon>http://www.portal.pl/ikonka-act.ico</icon>;

<activity category="find">;

<activityAction context="selection">; method="get"/>;

<execute action="http://www.portal.pl/search.aspx?string={selection}"

</openServiceDescription>

</activity>;

</activityAction>;

Listing 6. Przekazywanie parametrów metodą POST przez akcelerator
<execute method=”post” action=”http://www.portal.pl/search.aspx“>; <parameter name=”selection” value=”{documentUrl}” />; <parameter name=”title” value=”{documentTitle}” />;

</execute>

Dodajmy, że możliwe jest również programowe sprawdzenie, czy dany akcelerator nie został wcześniej zainstalowany – kod analogiczny do: window
maps.live.com/GetMap.xml, „map”);.

.external.isServiceInstalled(http://

64

03/2009

Zintegruj się z Internet Explorer 8

Na koniec warto wspomnieć, iż akceleratory mogą również integrować się z aplikacjami działającymi na komputerze poprzez COM (tzw. Code-based Accelerators), ale nie są one przedmiotem tego artykułu.

użytkownikom na monitorowanie jego zawartości poprzez Web Slice. Aby Web Slice był wykrywany na stronie, musimy jej fragment oznakować specjalnymi znacznikami: • Klasa hslice . Przypisanie klasy hslice nie wyklucza wykorzystania również innych klas CSS;

Web Slice’y
Web Slice’y są budzącą wśród użytkowników wiele entuzjazmu nową koncepcją, która pozwala zasubskrybować kawałek strony internetowej i monitorować jej zawartość. Można je porównać do wizualnych, HTML-owych informacji RSS, do których dostęp mamy zawsze w przeglądarce, pod paskiem adresu. Przykłady zastosowań znajdziemy wszędzie tam, gdzie często szukamy aktualizacji – nowe wiadomości e-mail w internetowej skrzynce odbiorczej, najnowsze informacje ze świata, aktualne kursy walut, zmiany statusów znajomych na portalu społecznościowym, itp. Rysunek 3. prezentuje Web Slice do monitorowania skrzynki odbiorczej dostępny dla użytkowników portalu GoldenLine. Aby sprawdzić czy mamy nowe wiadomości, nie musimy za każdym razem wchodzić na stronę – wystarczy rozwinąć Web Slice. Ten nowy mechanizm wspiera wszystkie popularne typy zabezpieczeń (w tym SSL, Cookies, Basic Authentication). Użytkownicy po zalogowaniu do portalu i zaznaczeniu opcji zapamiętaj (zostawiającej ciasteczko z ticketem uwierzytelniającym) będą mogli monitorować stan swojej skrzynki z poziomu Web Slice’u – korzystają one z tych samych, zapisanych już na dysku, ciasteczek. Ogromną zaletą Web Slice’ów jest informowanie o wszelkich zmianach w monitorowanej części portalu. Kiedy tylko zmieni się część zasubskrybowanej przez nas zawartości, przeglądarka poinformuje nas o tym wizualnie. Nie bez znaczenia są tu skojarzenia z RSS. Wszystkie aktualizacje Web Slice’ów kontroluje Windows RSS Platform. Ponadto zasubskrybowanie Web Slice’u skutkuje również dodaniem go do wszystkich czytników RSS wykorzystujących tę platformę. Przyjrzyjmy się, jakim modyfikacjom należy poddać portal, aby pozwalał

• Atrybut id – dla tego samego elemetu, do którego przypisana jest klasa hslice. Musi być unikalny w obrębie całej strony; • Klasa entry-title – określa tytuł Web Slice’u. Jeśli zostanie przypisana do kilku elementów (np. div oraz span), tytuł powstanie ze złączenia ich. Element można ukryć stosując np. style=”visibility: hidden;” .

Listing 7. Akcelerator oferujący podgląd aukcji Ebay
<?xml version="1.0" encoding="UTF-8" ?>;

<openServiceDescription xmlns="http://www.microsoft.com/schemas/ <homepageUrl>http://ie8.ebay.com</homepageUrl>; <display>; <name>Find with eBay Search</name>; </display>; openservicedescription/1.0">

<icon>http://ie8.ebay.com/resources/images/favicon.ico</icon>; <activity category="Find"> <activityAction context="selection">;

<preview action="http://ie8.ebay.com/activities/preview/index.php?query={select <execute method="get" action="http://ie8.ebay.com/index.php?query={selection}" ion}" />; />;

</openServiceDescription>

</activity>;

</activityAction>;

Listing 8. Najprostszy Web Slice
<div class="hslice" id="1">; <div class="entry-title">Slice Title</div>; <div class="entry-content">Content</div>;

</div>

Listing 9. Strona Basic.htm (dodawanie Web Slice’u)
<div class="hslice" id="auction">; <span class="entry-title">Web Slice Test</span>;

</div>

<a rel="feedurl" href="update.htm#slice-test" style="display:none;"></a>;

Listing 10. Strona Update.htm (aktualizowanie Web Slice’u)
<div class="hslice" id="slice-test">; <h2 class="entry-title">Web Slice Test</h2>;

</div>

<div class="entry-content">Web Slice content</div>

;

Tabela 1. Parametry wykorzystywane w akceleratorach Parametr {documentUrl} {documentTitle} {documentDomain} {documentHost} {selection} {link} {linkText} {linkRel} {linkType} {linkDomain} {linkHost} Kontekst Dowolny Dowolny Dowolny Dowolny selection link link link link link link Opis Adres dokumentu Tytuł dokumentu Domena dokumentu W pełni kwalifikowana nazwa hosta Aktualnie zaznaczony tekst href zaznaczonego linku Inner Text zaznaczonego linku Rel zaznaczonego linku Typ zaznaczonego linku (jeśli dostępny) Domena wybranego linku W pełni kwalifikowana nazwa hosta linku

www.sdjournal.org

65

Technologie internetowe
Wszystkie powyższe znaczniki możemy przypisać do dowolnych elementów HTML (np. div, span , tabela). Listing 8. prezentuje fragment strony, który zostanie rozpoznany jako Web Slice. Przeglądarka umożliwi zasubskrybowanie go poprzez specjalną opcję w menu (patrz Rysunek 4.) lub ikonę pojawiającą się po najechaniu myszką na tak oznaczony element div. Web Slice będzie automatycznie aktualizowany przez Windows RSS Platform. Kiedy tylko zmieni się jego zawartość, użytkownik zostanie o tym powiadomiony. Opcjonalnymi elementami istotnymi dla tworzenia Web Slice’ów są: • Klasa entry-content – oznacza zawartość Web Slice’u. Może być łączona z kilkoma innymi tak oznaczonymi elementami (jak w przypadku klasy entry-title). Wielkość Web Slice’u określa rozmiar tego elementu; • rel=”feedurl” – adres strony, z której aktualizowana będzie zawartość Web Slice’u. Może to być feed RSS lub inna strona zawierająca znaczniki hslice (w takim wypadku na końcu adresu powinniśmy dodać znak hash oraz identyfikator Web Slice’u – np. http://test.com/sliceupdate.htm#Slice1); • Klasa ttl – pozwala określić, jak często (w minutach) Internet Explorer 8 ma odświeżać zawartość Web Slice’u. Może on być przypisany do dowolnego elementu strony (np. <span class=”ttl”>5</span> ; • Klasa endtime – data ważności Web Slice’u. Po jej upływie Web Slice będzie uznawany za nieaktywny. Przestanie być aktualizowany i zostanie specjalnie oznaczony przez przeglądarkę. Bardzo często dochodzi do sytuacji, w której chcielibyśmy po dodaniu Web Slice’u aktualizować go z innych źródeł niż strona, na której został wykryty. Jest to korzystne, jeśli zależy nam np. na odciążeniu strony głównej portalu od zapytań wysyłanych automatycznie przez przeglądarkę. Aby to zrobić, określamy tzw. Alternative Update Source, wykorzystując konstrukcję rel=”feedurl” (Listing 9.). Listing 10. prezentuje stronę, która będzie wykorzystywana do pobierania aktualizacji. Do projektowania zawartości Web Slice’ów można wykorzystywać style CSS (zarówno zagnieżdżone w kodzie, jak i zawarte w zewnętrznych plikach). Istnieje także możliwość korzystania z kodu JavaScript, Flash czy Silverlight – takie Web Slice’y muszą być jednak odpowiednio zaprojektowane (z wykorzystaniem tzw. Alternative Display Source). Strona zawierająca interaktywne elementy powinna zostać wydzielona ze stron odpowiedzialnych za aktualizowanie zawartości Web Slice’u i wskazana konstrukcją <a
rel="entry-content" style="display:none;"></a>, zamiast tradyhref="Display.htm"

cyjnego elementu entry-content. Na koniec warto dodać, że Web Slice’y mogą być również dodawane z poziomu kodu JavaScript. Konstrukcja analogiczna do: <button onclick="javascript:windo
Rysunek 3. Web Slice prezentujący aktualny stan skrzynki odbiorczej GoldenLine
/auction.microsoft.com/item#1', button> $66.00', 'slice')">Add WebSlice</ 'Item

w.external.addToFavoritesBar('http:/

spowoduje zasubskrybowanie ele-

mentu.

Podsumowanie
Przeglądarka Internet Explorer nigdy dotąd nie umożliwiała tak prostego pisania rozszerzeń integrujących ją ze stronami internetowymi. O ich przydatności może świadczyć fakt, iż przenikają stopniowo także do innych przeglądarek. Najnowszy Firefox wspiera już nie tylko standard OpenSearch, ale również Web Slice’y (na razie w postaci add-inu). Nie pozostaje nic innego, jak tylko stworzyć własne rozszerzenie – a kiedy już to zrobimy, zgłośmy je do polskiej galerii dodatków Internet Explorer 8 (http: //www.ieaddons.com/pl/), aby inni użytkownicy mogli je zobaczyć!
Rysunek 4. Dodawanie wykrytego Web Slice’u

BARTŁOMIEJ ZASS
Bartłomiej Zass pracuje w dziale Developer & Platform Group polskiego oddziału Microsoft. Zajmuje się współpracą z producentami oprogramowania w zakresie najnowszych technologii dla programistów. Szczególnie interesuje się technologiami internetowymi, programowaniem urządzeń mobilnych oraz zagadnieniami konstrukcji interfejsu użytkownika. Kontakt z autorem: bzass@microsoft.com

W Sieci
• • • • Polska galeria dodatków do Internet Explorer 8 http://ieaddons.com/pl/; Specyfikacje OpenSearch http://www.opensearch.org; Szczegóły specyfikacji OpenService Accelerators http://msdn.microsoft.com/en-us/library/ cc287851(VS.85).aspx; Dokumentacja Web Slice’ów http://msdn.microsoft.com/en-us/library/cc196992(VS.85).aspx#_ preview

66

03/2009

Narzędzia

Weryfikacja przez model z narzędziem SPIN
Wprowadzenie do języka PROMELA oraz narzędzia SPIN
Współczesne programy wykorzystują więcej niż jeden wątek przetwarzania w celu zmniejszenia opóźnień bądź zwiększenia szybkości działania. Niestety, zapewnienie o ich bezbłędnym oraz efektywnym wykonaniu jest zadaniem wyjątkowo kłopotliwym. Formalna weryfikacja przez model jest jedną z metod mających na celu wykazanie poprawności oraz niezawodności takich systemów.
Dowiesz się:
• Czym jest weryfikacja przez model; • W jaki sposób modelować systemy w języku PROMELA; • Jak specyfikować własności poprawności; • Jak przeprowadzić weryfikację oraz interpretować otrzymane wyniki; • Jakie są zalety oraz wady przedstawionej metody.

Powinieneś wiedzieć:
• Co to jest wątek; • Jakie problemy występują podczas przetwarzania współbieżnego.

Poziom trudności

pretującego język PROMELA. Jego w pełni automatyczne działanie oraz zwiększające się zastosowania tej metody weryfikacji sprawiają, iż warto przyjrzeć im się bliżej.

W

Wzajemne wykluczenie
Wykonanie nawet najprostszego programu współbieżnego może prowadzić do powstania nietrywialnych, trudnych do wykrycia błędów. W tym celu przedstawiamy prosty problem pokazujący, w jaki sposób może dojść do błędnego zachowania. Przez ów przykład wprowadzamy Czytelnika w podstawy języka PROMELA służącego do opisu modelu systemów współbieżnych oraz własności poprawności, jakie mają być spełnione. Model ten jest następnie poddawany weryfikacji przy użyciu narzędzia SPIN, które może pokazać, w jaki sposób dana własność poprawności zostaje złamana. W poniższym przykładzie przedstawiono dwa procesy dokonujące współbieżnej modyfikacji zmiennej dzielonej. Ich równoczesne działanie prowadzi do niepoprawnego stanu systemu. Na Listingu 1. prezentujemy przykład systemu, w którym dostęp do zmiennej dzielonej total jest realizowany przez dwa procesy credit oraz debit. Ich inicjalizacji dokonuje-

ytwarzanie programów współbieżnych jest zadaniem wyjątkowo trudnym. Co więcej, zauważenie możliwych błędów w projekcie lub implementacji jest niejednokrotnie czynnością bardzo pracochłonną i wymagającą wiele uwagi. Formalna weryfikacja przez model jest techniką, która umożliwia zbadanie wszystkich wykonań systemu współbieżnego. W przypadku wykrycia sekwencji instrukcji, które prowadzą do niepoprawnego stanu, pozwala na wygenerowanie kontrprzykładu świadczącego o takiej sytuacji. Dodatkowo możliwe jest badanie systemów, których wykonanie nigdy się nie kończy. Język PROMELA pozwala na specyfikację systemów, w których dochodzi do komunikacji kilku wątków wykonania programu współbieżnego. Komunikację możemy przedstawiać przy pomocy wymiany wiadomości oraz zmiennych dzielonych, a przez to badać własności takich programów. Informację tą uzyskuje się przy pomocy narzędzia SPIN inter68

my w specjalnym procesie init, wykonywanym zawsze na początku działania systemu. Wspomniane procesy dokonują odpowiednio zwiększenia oraz zmniejszenia wartości zmiennej określającej wysokość środków na pewnym koncie bankowym. Czynności te realizowane są z użyciem zmiennej tymczasowej temp. Powoduje to, że w przypadku przeplotu instrukcji może dojść do sytuacji, gdzie po zakończeniu wspomnianych procesów stan konta nie będzie odpowiadał wysokości zdeponowanych oraz wypłaconych środków. Zapewnienie o ich poprawnej wysokości realizujemy przez instrukcję assert. Ze względu na współbieżne działanie procesu init wraz z procesami credit oraz debit, koniecznie jest poczekanie na ich zakończenie. Stąd w specyfikacji systemu wprowadzamy dodatkową zmienną pc. Po przyjęciu przez nią wartości 0, proces init wykona instrukcję assert. Na podstawie utworzonego modelu weryfikator SPIN generuje program, który poddaje analizie wszystkie możliwe wykonania systemu. Aby uzyskać taki weryfikator, wywołujemy program SPIN z odpowiednimi opcjami oraz kompilujemy otrzymany kod. W następnym kroku uruchamiamy weryfikator i po zauważeniu komunikatu o złamaniu assercji, dokonujemy analizy kontrprzykładu. Komendy, które służą do wykonania tych czynności, znajdują się poniżej.
spin -a bankaccount.pml ./pan

gcc -w -DSAFETY -o pan pan.c spin -t -p bankaccount.pml

Na Listingu 2. możemy prześledzić typowy wynik działania weryfikatora. Najważniej03/2009

Weryfikacja przez model z narzędziem SPIN

szą informacją jest ta o złamaniu własności poprawności, którą specyfikowaliśmy przy pomocy instrukcji assert . Pozostałe linie informują nas o wersji programu, zastosowanych optymalizacjach, rodzajach sprawdzanych własności poprawności oraz o wielkości przestrzeni stanów, jaka została rozpatrzona. Przyjrzyjmy się teraz Listingowi 3., przedstawiającemu wygenerowany kontrprzykład. Informuje nas o sekwencji instrukcji, które doprowadziły do błędu. Jego uważne prześledzenie wskazuje, iż problem ten pojawia się w przypadku dokonania jednoczesnych obliczeń przy pomocy zmiennej tymczasowej temp przez oba procesy (linie 3-4 oraz 5-6). Przypisanie wyniku obliczeń (linie 7 i 10) do zmiennej dzielonej powoduje, iż tak obliczona wartość jest niepoprawna. Aby uniknąć tego błędu, należy wykonać obliczenia niepodzielnie przez obydwa procesy. Język PROMELA dostarcza takie rozwiązanie. Na Listingu 1. została zakomentowana instrukcja atomic. Lista instrukcji wewnątrz bloku opatrzonego tym słowem kluczowym zostanie wykonana niepodzielnie, bez przeplotu z innymi procesami. W ten sposób unikniemy przedstawionego problemu. Po usunięciu komentarzy i powtórnym wykonaniu komend, nie zostanie wygenerowana informacja o błędzie. Oznacza to, iż dla wszystkich możliwych wykonań procesów assercja będzie spełniona. Przedstawiony przykład prezentuje kilka elementów potrzebnych do weryfikacji systemów. Po pierwsze, sam model systemu podlegającego weryfikacji. Jest on uproszczeniem i abstrakcją prawdziwego systemu – pominięto w nim wszystkie zbędne elementy. Składa się on jednak z najważniejszych procesów oraz akcji w weryfikowanym systemie. Następnym składnikiem jest specyfikacja własności poprawności, jakie mają zachodzić. W tym przypadku własność taka została określona przez słowo kluczowe assert. Kolejnymi czynnościami jest weryfikacja systemu oraz analiza otrzymanych rezultatów, zaś w przypadku wykrycia błędu – jego usunięcie oraz powtórne sprawdzenie poprawności.

Weryfikacja przez model
Wykorzystanie możliwości współczesnych procesorów w programach komputerowych odbywa się poprzez wprowadzenie kilku wątków wykonania. Dzięki ich współbieżnemu działaniu możliwe jest osiągnięcie trzech podstawowych celów. Pierwszym z nich jest zredukowanie opóźnień podczas przetwarzania, dzięki zwiększeniu szybkości wykonania pewnych obliczeń. Drugim celem jest ukrycie samego faktu wykonywania długotrwałych obliczeń poprzez pozwolenie na kontynuację pracy całego systemu. Wreszcie ostatnim jest podwyższenie przepustowości systemu przez zwiększenie ilości obliczeń, które mogą być wykonanie w jednostce czasu. Niestety pozytywne efekty, jakie przynosi wprowadzenie kilku wątków przetwarzania, okupione są większym stopniem skomplikowania takich programów. W ogólności pojawiają się problemy związane z dostępem do wspólnych zasobów. Musi następować odpowiednie ograniczenie kolejności wykonania wątków podczas ich odczytu oraz zapisu. Kolejnymi jest nadwyrężenie zasobów w trakcie pracy kilku wątków. Wynika stąd konieczność przypisania odpowiednich priorytetów wątkom oraz zapewnienie ich uszeregowania w dostępie do procesora. Wreszcie okazuje się, iż sekwencyjne algorytmy, które dobrze działają z jednym wątkiem wykonania, są bardzo trudne do stworzenia dla kilku wątków. Często nie uzyskuje się oczekiwanych rezultatów związanych z przyspieszeniem działania. Weryfikacja przez model jest w pełni automatyczną metodą, pozwalającą na stwierdzenie poprawności wykonania systemów współbieżnych. Wykorzystuje się ją do weryfikacji urządzeń elektronicznych, protokołów, a ostatnio nawet programów komputerowych. Jej głównym zadaniem jest udzielenie odpowiedzi na temat bezpieczeństwa oraz żywotności takich systemów. Są to dwie duże klasy własności poprawności, których spełnienie świadczy o poprawnym działaniu. W ramach własności bezpieczeństwa weryfikuje się zachodzenie niezmienników, brak zakleszczeń oraz występowanie sekwencji instrukcji prowadzących do niepoprawnego zachowania. Żywotność z kolei oznacza spraw-

dzanie zakończenia wykonywania procesów, możliwość odpowiedzi na nadchodzącą wiadomość oraz brak nieskończonych pętli instrukcji, które prowadzą do niepoprawnego zachowania. Specyfikacji tych własności dokonuje się przy pomocy instrukcji assert, odpowiednich etykiet oraz formuł logicznych. Narzędzia do weryfikacji przez model analizują wszystkie możliwe wykonania systemu współbieżnego. W przypadku zauważenia sekwencji zdarzeń, które prowadzą do złamania własności poprawności, generowany jest kontrprzykład. Umożliwia on prześledzenie, w jaki sposób dochodzi do jej złamania. W kolejnym przykładzie prezentujemy możliwości specyfikacji oraz badania klasycznego problemu czytelników i pisarzy. Posłuży nam on do dokładniejszego zapoznania się z elementami języka PROMELA oraz sposobu sprawdzania poprawności rozwiązania. Przedstawiona jest również weryfikacja własności bezpieczeństwa oraz żywotności.

Czytelnicy i pisarze
W problemie czytelników i pisarzy dwie grupy procesów (wątków) posiadają dostęp do wspólListing 1. Przeplot instrukcji prowadzący do błędu
int total = 1500; byte pc = 2; int temp; /* stan rachunku */ /* bariera */

proctype credit(int amount) { //atomic { temp = total; total = temp; temp = temp + amount; //} }

pc = pc – 1

proctype debit(int amount) { // atomic { temp = total; total = temp; temp = temp - amount; // } } int temp;

pc = pc – 1

init {

run credit(1000); run debit (1000); /* czekamy na zakonczenie procesow */ do :: pc > 0 -> skip; od;

Semafor

Semafor jest nieujemną zmienną naturalną, dla której określono dwie operacje: P oraz V. Dla danego semafora s, operacja P(s) jest blokowana aż s > 0, a następnie zostaje wykonane s = s – 1. Sprawdzenie wartości zmiennej s oraz jej zmniejszenie jest wykonywane niepodzielnie. Z kolei V(s) wykonuje s = s + 1 jako niepodzielną instrukcję. Pojęcie semafora zostało przedstawione przez Holendra Edsgera Dijkstrę. Stąd też wzięły się nazwy operacji P i V. P jest pierwszą literą słowa passeren, które oznacza mijać, przechodzić. V pochodzi od słowa vrygeven oznaczającego zwolnienie lub uwolnienie. W toku dalszych badań uświadomiono sobie, iż lepszym określeniem dla P będzie prolagen, powstałe z połączenia słów roberen (próbować) oraz verlagen (zmniejszać). Uznano również, że bardziej odpowiednim słowem dla V, jest verhogen oznaczające zwiększanie. W literaturze angielskojęzycznej operacja P oznaczana jest przez słowo wait, a operacja V – przez signal.

:: pc == 0 -> break; assert (total == 1500);

printf ("bank account total %d\n", } total);

www.sdjournal.org

69

Narzędzia
nego zasobu. Zasobem tym może być baza danych, plik, zmienna lub też czytelnia w bibliotece. Czytelnicy oraz pisarze wykonują różne czynności względem zasobu. W ogólności w tym samym czasie dostęp do niego może posiadać wielu czytelników. W przypadku zaś pisarzy, dostęp do zasobu może mieć tylko jeden z nich. Problem ten można rozszerzać o kolejne założenia dotyczące działania tych procesów, na przykład wykluczenia czytelników, gdy pisarz zechce modyfikować zasób. Na Listingu 4. znajduje się kompleksowe rozwiązanie omawianego problemu z użyciem seListing 2. Działanie weryfikatora
pan: assertion violated (total==1500) (at depth 13) pan: wrote bankaccount.pml.trail Warning: Search not completed (Spin Version 4.3.0 -- 22 June 2007) + Partial Order Reduction

maforów. Oprócz realizacji odpowiedniego dostępu czytelników i pisarzy, zapewnia ono wykluczenie czytelników, gdy pisarz próbuje uzyskać dostęp do czytelni. W następnych paragrafach postaramy się w kolejnych krokach przedstawić zastosowane podejście jak i sam język specyfikacji. Specyfikacja w języku PROMELA składa się z kilku elementów: deklaracji stałych, zmiennych dzielonych, kanałów komunikacyjnych oraz procesów. Dodatkowo określane są zastrzeżenia stanowiące o poprawności takiego modelu.

Full statespace search for: never claim assertion violations cycle checks invalid end states

- (none specified) + + - (disabled by -DSAFETY)

State-vector 40 byte, depth reached 16, errors: 1 48 states, stored 27 states, matched 0 atomic steps

75 transitions (= stored+matched) hash conflicts: 0 (resolved) 2.622 memory usage (Mbyte)

Listing 3. Kontrprzykład
Starting :init: with pid 0 Starting credit with pid 1 Starting debit with pid 2 2: proc 3: proc 4: proc 5: proc 6: proc 7: proc 8: proc 10: proc 11: proc 13: proc 2 (debit) line 2 (debit) line 1: proc 0 (:init:) line 0 (:init:) line 29 state 1) [(run credit(1000))] 30 (state 2) [(run debit(1000))]

20 (state 1) [temp = total]

1 (credit) line 1 (credit) line 2 (debit) line 2 (debit) line 1 (credit) line 1 (credit) line 0 (:init:) line

21 (state 2) [temp = (temp-amount)] 10 (state 2) [temp = (temp+amount)] 9 (state 1) [temp = total]

22 (state 3) [total = temp] 24 (state 4) [pc = (pc-1)]

9: proc 2 terminates

11 (state 3) [total = temp] 13 (state 4) [pc = (pc-1)] 35 (state 5) [((pc==0))]

12: proc 1 terminates spin: line 14: proc

spin: text of failed assertion: assert((total==1500)) spin: trail ends after 14 steps #processes: 1 total = 2500 pc = 0 0 (:init:) line

38 "bankaccount.pml", Error: assertion violated 38 (state 10) [assert((total==1500))]

3 processes created

14: proc

0 (:init:) line

40 "bankaccount.pml" (state 11)

W rozpatrywanym przykładzie zostały zdefiniowane dwie stałe wait oraz signal. Posłużą one do realizacji semafora binarnego poprzez kanały komunikacyjne mutex, roomEmpty oraz turnstile . Kanały te, zadeklarowane w kolejnych liniach, mają zerową pojemność. Oznacza to, iż może poprzez nie dochodzić do synchronizacji procesu wysyłającego oraz odbierającego wiadomość. Proces wysyłający jest wstrzymywany do czasu odbioru wiadomości i na odwrót - proces odbierający wiadomość jest zatrzymywany do czasu nadania komunikatu. W ten sposób określa się spotkanie procesów (rendez-vous). W prezentowanym przykładzie proces semaphor będzie kolejno oczekiwał na wiadomości zawierające stałą wait lub signal. W ten sposób procesy wysyłające wiadomości wait i signal będą miały wyłączny dostęp do fragmentów kodu. Po wysłaniu komunikatu wait, inne procesy zostaną wstrzymane do czasu nadania wiadomości signal. W ten sposób specyfikuje się semafor binarny. Posłuży on nam w kolejnych liniach modelu. Procesy deklarowane są przy pomocy słowa kluczowego proctype. Uruchomienie instancji procesu następuje przy pomocy słowa kluczowego run. W obrębie danego procesu mogą zostać zadeklarowane zmienne lokalne lub kanały komunikacyjne. W naszym przykładzie interesujące są procesy reader oraz writer. Poprzez odpowiednie użycie semaforów następuje ograniczenie dostępu do sekcji krytycznych. Jak zostało powiedziane wcześniej, w sekcji krytycznej może znajdować się tylko jeden pisarz bądź dowolna liczba czytelników. Sekcje te zostały oznaczone przez etykietę cs. Posłuży ona do sformułowania własności poprawności dotyczącej tego obostrzenia. Ograniczenie dotyczące wykonania całego systemu jest zdefiniowane przez słowo kluczowe never. W przypadku jego spełnienia, zostanie wygenerowane odpowiednie ostrzeżenie oraz przedstawiony kontrprzykład. Jego spełnienie następuje w chwili, gdy zostanie osiągnięty nawias zamykający deklarację. W danym modelu może się znajdować tylko jedna jego deklaracja, stąd na listingu 4. pierwsze z nich zostało zakomentowane. Obostrzenie to jest warunkiem bezpieczeństwa i dotyczy wzajemnego wykluczenia czytelników oraz pisarzy. Jego zajście byłoby widoczne po prawie całkowitym usunięciu linii specyfikacji odnoszących się do semaforów w procesach reader lub writer . Dodatkowego wytłumaczenia wymaga linia reader[3]@cs && writer[5]@cs -> break; . Oznacza ona, iż jeśli instancje procesów reader o numerze 3 oraz writer o numerze 5 znajdą się w sekcji krytycznej, ma zostać przerwana pętla, a
03/2009

70

Weryfikacja przez model z narzędziem SPIN

co za tym idzie – wygenerowane ostrzeżenie o błędzie. Powróćmy na chwilę do problemu czytelników i pisarzy. W szczególnym przypadku może dojść do sytuacji, gdy czytelnicy dokonają aktu sabotażu na pisarzach. Zaraz po wyjściu z czytelni (sekcji krytycznej) będą do niej powracać. W ten sposób żaden z pisarzy nie uzyska dostępu do czytelni. W konsekwencji dojdzie do ich zagłodzenia. Aby zapobiec takiemu zdarzeniu, należy odpowiednio sformułować własność poprawności oraz ją zbadać. Drugi z warunków poprawności zawiera kod, który służy temu zadaniu. Może on zostać sklasyfikowany jako warunek żywotności, gdyż dotyczy poszukiwania nieskończonych pętli akcji, prowadzących do niepoprawnego zachowania. Warunek poprawności został wygenerowany przy pomocy formuły logiki temporalnej.
Listing 4. Czytelnicy i pisarze
mtype = { wait, signal }; byte readers = 0;

Formuła [](en -> <>cs) mówi nam, iż zawsze [] jeśli -> proces znajdzie się przy wejściu do sekcji krytycznej en, w końcu uzyska do niej dostęp <>cs. Jej weryfikacja będzie odbywała się przy pomocy deklaracji never (nigdy). Ponieważ jednak ma ona być zawsze spełniona, więc musimy ją zanegować. Odpowiedni kod uzyskuje się automatycznie przez polecenie spin -f '!([](en -> <>cs))'. Wygenerowanie weryfikatora oraz jego uruchomienie doprowadzi do pokazania pętli, w której czytelnicy nieustannie wchodzą do sekcji krytycznej. Rozwiązaniem, które usuwa ten problem, jest zastosowanie dodatkowego semafora turnstile. Miejsca jego użycia są pokazane przy pomocy komentarza /* 2 */. Po jego zastosowaniu nie będzie dochodziło do błędnego działania systemu, spowodowanego zagłodzeniem pisarzy. Otrzymanie tych rezul-

tatów musi odbyć się z innymi parametrami weryfikatora.
spin -a readerswriters-nostarve.pml gcc -w -o pan pan.c ./pan -a -n

spin -t -p bankaccount.pml

Aby uczynić opis języka PROMELA kompletnym, należy wspomnieć o samych instrukcjach. W przeciwieństwie do innych języków programowania, takich jak C czy Pascal, są one przedzielane, a nie kończone, znakami średnika oraz strzałki w prawo. Ze względu na czytelność specyfikacji, średnika używa się do oddzielenia dwóch instrukcji. Zwyczajowo po prawej stronie strzałki umieszcza się instrukcję, która ma zostać wykonana, gdy warunek znajdujący się po lewej stronie zostanie spełniony. Jednak nie jest to niezbędne. Oznacza to, iż na przykład instrukcja (a && b) zosta-

do

:: skip; en:

chan mutex = [0] of { mtype };

turnstile!wait;

/* 2 */

chan roomEmpty = [0] of { mtype };

roomEmpty!wait;

chan turnstile = [0] of { mtype }; /* 2 */ proctype semaphore(chan sem) { do od :: sem?wait -> sem?signal }

/* sekcja krytyczna pisarzy */ cs: skip; printf("%d writes\n", _pid); /* 2 */

turnstile!signal; roomEmpty!signal; od skip;

proctype reader() { do :: skip;

}

/* never { do /* 2 */ /* 2 */ :: reader[3]@cs && writer[5]@cs -> break; :: else -> skip od } */ never { /* !([](en -> <>cs)) */ if T0_init:

turnstile!wait; mutex!wait; if

turnstile!signal;

readers = readers + 1; :: (readers == 1) -> roomEmpty!wait; :: else fi;

mutex!signal; /* sekcja krytyczna czytelnikow */ cs: skip; printf("%d reads\n", _pid); mutex!wait; if }

:: (1) -> goto T0_init fi; if

:: (!writer@cs && writer@en) -> goto accept_S4 accept_S4: :: (!writer@cs) -> goto accept_S4 fi;

readers = readers - 1; :: (readers == 0) -> roomEmpty!signal; :: else fi;

init {

run semaphore(mutex);

run semaphore(roomEmpty); run semaphore(turnstile); run reader(); run reader(); } run writer();

}

od

mutex!signal;

proctype writer() {

www.sdjournal.org

71

Narzędzia
nie wstrzymana aż do spełnienia warunku. Czasami konieczne jest wykonanie instrukcji pustej, dlatego też stosuje się słowo kluczowe skip. Instrukcje do oraz if również posiadają odmienne znaczenie. Składają się z jednej lub kilku sekwencji instrukcji zaczynających się od znaku ::. Pierwsza z instrukcji znajdujących się za dwukropkiem pełni funkcję warty (guard), czy też warunku wykonania takiej sekwencji. W przypadku spełnienia jednej z nich, zostają wykonane następujące po nim instrukcje. Gdy spełnionych jest równocześnie kilka warunków, wybór sekwencji instrukcji następuje niedeterministycznie. W przypadku zaś niespełnienia żadnego, cała instrukcja do lub if jest blokowana. Aby jednak uniknąć blokady, wprowadzono słowo kluczowe else. Instrukcje występujące po nim są wykonywane, gdy żadna inna sekwencja instrukcji nie może być wykonana. Oczywiście instrukcja if kończy się po wykonaniu jednej z sekwencji. W przypadku instrukcji do, jej działanie wraca od początku. Pętlę tą można przerwać przez użycie słowa kluczowego break. Ostatnimi instrukcjami jest wysłanie oraz odbiór wiadomości. Wysłanie wiadomości następuje poprzez wyszczególnienie kanału oraz jej treści. Do wysłania stosuje się wykrzyknik. Odbiór następuje poprzez oznaczenie kanału oraz znak zapytania. Poszczególne pola wiadomości mogą być oddzielone przecinkami. Do przesłania komunikatu dochodzi, gdy dopasowane zostaną stałe występujące po stronie nadającej i odbierającej. Możliwe jest również zmienianie kolejności wiadomości w kanale komunikacyjnym oraz ich odczyt, bez usunięcia ich z kanału. Dodatkowo udostępnione są funkcje umożliwiające na sprawdzenie, czy kanał komunikacyjny jest pusty lub pełny. W języku PROMELA istnieje możliwość specyfikacji kanałów komunikacyjnych o zadanej pojemności. W takim przypadku nadanie i odbiór wiadomości zależy od ilości komunikatów w kanale. W przypadku odpowiedniej ilości dostępnego miejsca bądź istnienia wiadomości w kanale, procesy odpowiednio kontynuują bądź wstrzymują działanie.

Podsumowanie
Dzięki weryfikacji przez model możliwe jest badanie zachowania systemów współbieżnych, których wykonanie nigdy się nie kończy. Uzyskane w ten sposób rezultaty mogą służyć do zapewnienia poprawności ich działania bądź usunięcia zauważonych błędów. Weryfikacja przez model nie gwarantuje a priori poprawności, zwiększa jednak rozumienie funkcjonowania systemów poprzez odkrywanie niespójności, niejednoznaczności i niekompletności, które w innym przypadku mogłyby pozostać nie zauważone. Znaczącym ograniczeniem stosowania tej metody jest wykładniczo rosnący rozmiar systemu, jaki musi zostać zbadany, wraz ze zwiększającą się liczbą procesów. Dzięki rozwojowi tej metody w ostatnim czasie, uzyskuje ona jednak coraz większe zastosowanie w praktyce. Poniższy artykuł miał za zadanie zaznajomienie Czytelnika z weryfikacją przez model, a w szczególności z językiem PROMELA oraz narzędziem SPIN. Omawia on tylko najważniejsze elementy tych rozwiązań poprzez pokazanie prostych przykładów. Intencją autora było jedynie zasygnalizowanie dostępności tej metody weryfikacji oraz zachęcenie do samodzielnego studiowania.

Listing 5. Pętla prowadząca do zagłodzenia procesów pisarzy
289: 291: 292: 294: 296: 298: proc proc proc proc proc proc 5 (writer) line 4 (reader) line 5 (writer) line 4 (reader) line 3 (reader) line 56 39 46 18 18 (state 6)[(1)] 11 (state 2)

1 (semaphore) line

(state 19)[mutex!signal] (state 1)[(1)] (state 1)[(1)] (state 1)[(1)]

[sem?signal]

Never claim moves to line 64 Never claim moves to line 68

[((!((writer._p==cs))&&(writer._p==en)))] [(!((writer._p==cs)))]

<<<<<START OF CYCLE>>>>> 300: 301: 303: 305: 307: 308: 310: 311: 313: 313: 315: 316: 318: 320: 322: 323: 325: 326: 328: proc proc proc proc proc proc proc proc proc proc proc proc proc proc proc proc proc proc proc 4 (reader) line 4 (reader) line 4 (reader) line 4 (reader) line 21 22 24 24 (state 2)[mutex!wait] (state 1)

1 (semaphore) line

11

(state 3)[readers = (readers+1)] (state 4)[((readers==1))] (state 5)[roomEmpty!wait] (state 1)

[sem?wait]

2 (semaphore) line 4 (reader) line 4 (reader) line 4 (reader) line 4 (reader) line 4 (reader) line 4 (reader) line 4 (reader) line

11

[sem?wait]

1 (semaphore) line

27 30 31 33 34 36 36

11

(state 9)[mutex!signal] (state 10)[(1)] (state 2)

[sem?signal]

4 reads

(state 11)[printf('%d reads\\n',_pid)] 11 (state 12)[mutex!wait] (state 1) [sem?wait]

1 (semaphore) line

(state 13)[readers = (readers-1)] (state 14)[((readers==0))]

W Sieci
• • • http://spinroot.com/spin/whatispin.html, http://www.spinroot.com/spin/Man/ promela.html, http://bcook.cs.georgiasouthern.edu/ promela.htm.

2 (semaphore) line 4 (reader) line 4 (reader) line

11

(state 15)[roomEmpty!signal] (state 2)

[sem?signal]

1 (semaphore) line

39 18

11

(state 19)[mutex!signal] (state 1)[(1)] (state 2)

[sem?signal]

spin: trail ends after 328 steps

SŁAWOMIR MALUDZIŃSKI
Jest doktorantem informatyki AGH. Specjalizuje się w metodach formalnych oraz systemach agentowych. Posiada kilkuletnie doświadczenie zawodowe w czołowych placówkach naukowych oraz firmach softwarowych. Kontakt z autorem: slawomir.maludzinski@gmail.com

Procesy oraz wątki

W teorii metod formalnych nazwa proces ma inne znaczenie niż to znane z systemów operacyjnych. W ten sposób oznacza się pojęcie mogące realizować pewne akcje i posiadać dostęp do zmiennych dzielonych oraz kanałów komunikacyjnych. Proces odpowiada więc wątkowi wykonania programu, znanego z języków programowania.

72

03/2009

Felieton

Aby wielu mogło na raz...
Cloud computing przedstawiane jest jako cudowny lek na kryzys w IT. Czy za tym terminem kryje się rzeczywisty sposób na stawienie czoła recesji? A może jest to jedynie sprytna sztuczka na sprzedanie starych idei w nowym, marketingowym opakowaniu?

L

udowe porzekadło przekonuje, że mała rewolucja od czasu do czasu jeszcze nikomu nie zaszkodziła. Podobnie jest w warunkach wolnego rynku – krótkotrwałe wstrząsy mogą przynieść wiele dobrego. Powodują wahania równowagi konkurencyjnej tworząc możliwości pojawienia się na rynku nowych graczy czy produktów. Jeżeli jednak zamieszanie będzie za duże, a jego konsekwencje zbyt rozległe, to powstałe deregulacje przyniosą jedynie pozorne korzyści. W dłuższym okresie czasu doprowadzą do zjawisk bardziej niebezpiecznych, niż sam kryzys (por. [1]). Nikt już nie wątpi, że dzisiejsza gospodarka znalazła się na takim właśnie zakręcie. A już na pewno nikogo nie zaskoczy, gdy IT na tym ucierpi. Przedsmak tego odnajdujemy w prognozach na 2009 rok (dane IDC, Gartnera, Forrestera oraz ISuppli, [2]): • Sprzedaż komputerów stacjonarnych ma wzrosnąć jedynie o 4% (zamiast wcześniej prognozowanych przez ISuppli prawie 12%, według IDC odpowiednio 2.4%, zamiast 6%), ale za to laptopów – aż o 15%; Wzrost wydatków na IT na świecie ma wynieść jedynie 2,6%, zamiast spodziewanych wcześniej 5,9%; Rynek serwerów fizycznych będzie rósł średnio o 4% rocznie, ale za to serwerów wirtualnych przybywać będzie już 55% rocznie (zob. [3]); Najbardziej dynamicznie rozwija się rynek serwerów wieloprocesorowych (bazujących na x86), sprzedaż maszyn jednoprocesorowych odnotowuje znaczące spadki; Rynek outsourcingu IT ma rosnąć o około 5% w latach 2009-2010.

• •

booki, smartphony itp.), oznacza przesunięcie środka ciężkości przetwarzania w stronę większych centrów obliczeniowych (również tych oferowanych przez zewnętrznych partnerów). Tendencje te potwierdza Gartner, umieszczając wirtualizację oraz cloud computing na czołowych miejscach listy technologii strategicznych w 2009 ([4]). Termin cloud computing (pol. chmura obliczeniowa) odwołuje się do dostarczania usług realizowanych przez wirtualne zasoby za pomocą standaryzowanych protokołów. Wirtualizacja jest tu rodzajem silnika organizującego i napędzającego oferowane zasoby. Sedno tej idei polega na przeniesieniu odpowiedzialności na barki wyspecjalizowanych dostawców odpowiednich usług w zakresie: tworzenia i utrzymywania infrastruktury (komputerów, sieci), aspektów jej działania (np. współdzielenia zasobów, kontroli dostępu, tworzenia kopii zapasowych, zarządzania awariami) i funkcjonalności (aplikacji). Biznes może się wtedy skoncentrować na procesach będących bezpośrednio jego przedmiotem, na akcie tworzenia, dostarczania i konkurowania – a nie na działaniach jedynie to umożliwiających. Wynika z tego, że cloud computing nie jest żadną konkretną technologią, a pewnym wielowarstwowym modelem. Poszczególne warstwy tego modelu odzwierciedlają poziomy specjalizacji oferowanych usług. Na najniższym poziomie oferuje się czystą infrastrukturę. Najwyższy poziom stanowią wyspecjalizowane aplikacje. W szczególności wyróżnia się następujące warstwy ([5]): • • • dSaaS (ang. data-Storage-as-a-Service), która oferuje usługi przechowywania danych (np. Amazon/S3, Microsoft Live Workspace); IaaS (ang. Infrastructure-as-a-Service), która oferuje wirtualne serwery (Amazon/EC2, IBM Blue Grid, Sun Grid); PaaS (ang. Platform-as-a-Service), oferuje środowisko do tworzenia i wykonywania aplikacji (system operacyjny, zestaw wymaganego oprogramowania, dedykowane bazy danych, np. Google App Engine); SaaS (ang. Software-as-a-Service), oferuje konkretne aplikacje (np. Google Docs, Salesforce CRM).

Z powyższych danych wyłania się obraz wyzwań, jakie staną przed IT. Przyszłe miesiące to przede wszystkim konieczność ograniczenia tempa wydatków, rozwijanie systemów w oparciu o słabsze, ale bardziej mobilne stacje klienckie oraz tańsze, ale wieloprocesorowe serwery. Ograniczenia finansowe szybciej wymuszą optymalizację wykorzystania istniejącej infrastruktury, niż jej rozszerzanie. Pojawi się potrzeba rozwiązań bardziej wydajnych oraz lepiej skalowalnych zarówno w górę (obsługa pików przetwarzania), jak i w dół (przestoje). Taka elastyczność umożliwi szybkie tworzenie otoczenia dla implementacji i wdrażania produktów. Powinno to wspomagać konieczność skrócenia tych etapów, co jest wymagane w obliczu zaostrzonej konkurencji. Wreszcie, zastępowanie stacji roboczych laptopami i innymi urządzeniami mobilnymi (tablety internetowe, PDA, net74

W takim modelu do zakresu obowiązków pracowników pionu IT należy poszukiwanie partnerów, którzy dostarczą usługi odpowiadające potrzebom firmy. Za to partnerzy – dostawcy pobierać będą opłaty. Z drugiej strony IT rozlicza dostawców z jakości oferowanych usług, dotrzymywania uzgodnionych parametrów użytkowych oraz zapewnionego poziomu bezpieczeństwa. W tym zakresie dostawcy będą konkurować ze sobą.
03/2009

Felieton
Należy tu zauważyć, że w obrębie wymienionych warstw wykorzystuje się znane i sprawdzone technologie, takie jak wirtualizacja, Web 2.0, interpretery języków (np. Python dla Google Apps). Również idea wykorzystania Internetu jako medium dostępu do usług także nie jest specjalnie nowa (por. ang. Web services). Z drugiej strony, w prawie każdej publikacji na temat przyszłości IT wspomina się o cloud computing (przynajmniej pośrednio). Co stało się powodem takiej eksplozji popularności tego modelu? Myślę, że podstawowym katalizatorem jest kryzys finansowy. Nawet jeżeli jego korzenie nie wiążą się bezpośrednio z rynkiem IT (jak to było przy krachu dotComów w 2001 roku), to firmy nauczone bolesnym doświadczeniem, od razu zaczęły rozglądać się za potencjalnymi oszczędnościami. Możliwość obniżenia kosztów budowania i obsługi infrastruktury oferowana przez chmurę wydaje się bardzo na czasie. Zwłaszcza gdy nie odbywa się to kosztem istniejących wdrożeń. Można uniknąćw ten sposób np. kosztownych problemów z zachowaniem kompatybilności. Kryzys to kurczenie się rynków zbytu. Szacuje się, że moce obliczeniowe
Tabela 1. Wybrani gracze na rynku cloud computing (zob. [16], [17]) Firma/Produkt Amazon/ Amazon Web Services Model biznesowy Udostępnianie przestrzeni dyskowej (Simple Storage Service - S3:dSaaS), serwery wirtualne (Elastic Compute Cloud - EC2: IaaS), kolejki wiadomości oraz baza danych (SimpleDB) Hosting aplikacji napisanych w Pythonie (PaaS: dostęp do przestrzeni dyskowej, serwerów ale również środowisko programistów). SaaS: procesor tekstu, arkusz kalkulacyjny, tworzenie prezentacji, klient pocztowy, kalendarz (plus przestrzeń dyskowa) SaaS: On-line CRM Przykładowe ceny 15 centów/1 GB powierzchni/ miesiąc 10-80 centów/godzinę pracy serwera Ilość użytkowników 370 tyś.

przedsiębiorstw z branży e-commerce wykorzystywane są jedynie w 85%. Patrząc na lata 2004-2007 w 25 krajach EU, liczba dostępnych łączy typu broadband zwiększyła się z około 10 do prawie 90 milionów. W tym samym czasie liczba gospodarstw domowych z szerokopasmowym dostępem do Internetu wzrosła jedynie o około 28 milionów (dane szacowane na podstawie Eurostat). Cloud computing obiecuje możliwość zyskownego zagospodarowania takich rezerw. Kryzys to również skłonność do poszukiwania tańszych alternatyw. Dla przykładu, już dziś w Polsce więcej osób korzysta z przeglądarek innych niż Internet Explorer (głównie Firefox). Kompleksowość usług dostarczanych przez model chmury obliczeniowej może się okazać zaletą. Według mnie, ostatecznym katalizatorem jest szerzące się na świecie piractwo. To zjawisko osiągnęło taką skalę, że walka z nim jest bardzo trudna. Co więcej – część beneficjentów praw autorskich przedkłada agresywne sposoby dochodzenia swoich roszczeń (na sali sądowej) nad elastyczność. Przynosi to mizerne zyski finansowe i powoduje wiele negatywnych emocji. Decydując się na przeniesienie swoich

Google/ Google App Engine (również Android) Google/ Google Apps (również Gmail/Postini) Google/ Salesforce: Salesforce CRM Salesforce: Force.com

15 - 18 centów/1 GB powierzchni/ n/a miesiąc (do 0.5 GB za darmo) 10-12 centów/godzinę pracy serwera Za darmo lub 50$ rocznie za usługi premium $10/miesiąc Nawet 6 milionów (docs+spreadsheets) użytkowników, ale jedynie 4 (docs) - 6 minut (spreadsheet) spędzanych on-line (dane: www.compete.com) n/a

PaaS: platforma aplikacji Web; Relacyjna baza danych, interfejs użytkownika, logika biznesowa, środowisko programistyczne, udostępnianie aplikacji (AppExchange) PaaS: Oprogramowanie plus usługi (np. MS Word do tworzenia dokumentów i MS Live Workspace do zapisywania ich on-line). PaaS: wirtualny desktop linuxa

n/a

1.1 miliona

Microsoft: Office Online, Live Workspace, Hotmail (w przygotowaniu: Azure) Ulteo Desktop

n/a

Około 0.5 milina unikalnych użytkowników witryny officelive.com (dane: www.compete.com)

Darmowy (community edition) lub płatne wsparcie

Około 6 tysięcy unikalnych użytkowników miesięcznie (dane: www.compete.com), ponad 140 tyś. sesji w ciągu ostatnich kilku miesięcy (w/g Ulteo)

Spektakularne wycieki danych w latach 2007-2008
• • • • • Niemcy: wyciekły dane 21 milionów kont bankowych. Źródłem przecieku były najprawdopodobniej zewnętrzne firmy dostarczające usługi księgowe i finansowe. Kilka miesięcy wcześniej ujawniono wyciek danych 17 milionów klientów operatora T-Mobile, o czym opinia publiczna dowiedziała się dopiero ponad 1.5 roku po fakcie ([7], [8]); Wielka Brytania: na laptopie zakupionym na eBay znaleziono dane kilku milionów klientów Royal Bank of Scotland, Natwest oraz American Express ([9]); Rok wcześniej wyciekło nawet 90 milionów numerów kart kredytowych klientów sieci T.J. Maxx ([12]); Polska: dane osobowe (w tym numery kont bankowych) chętnych na zakup biletów na Euro2008 były dostępne przez kilka godzin. PZPN twierdzi, że jedyną odpowiedzialność ponosi prywatny operator [10]; Polska: wyciekły życiorysy 3 tysięcy osób kandydatów do pracy w Pekao SA. Według ekspertów powodem były nieodpowiednie zabezpieczenia zastosowane przez firmę, której Pekao zleciło wykonanie strony ([11]); USA: podczas przewożenia taśmy z back-up'em skradziono dane 12,5 miliona klientów New York Mellon Bank, GE Money stracił w podobny sposób dane 650 tyś. klientów; Szpital Uniwersytecki Utah: 2.2 mln danych medycznych pacjentów zostało skradzionych z samochodu serwisanta systemów archiwizacji, podczas gdy ten był u innego klienta; Countrywide Financial: 2 mln danych kredytobiorców zostało ukradzionych i sprzedanych przez pracownika firmy, który łączył się zdalnie do sieci korporacyjnej ([12]);

www.sdjournal.org

75

Felieton
produktów do chmury, producenci uzyskują całkowitą kontrolę nad tym kto, jak często i w jakim zakresie ich używa. Problem piractwa przestaje istnieć. O ile jestem zdecydowanym przeciwnikiem piractwa (w końcu sam korzystam z tantiem za swoją pracę), to podobny stopień kontroli jest dla mnie problematyczny. Dyskomfort wiąże się przede wszystkim z koniecznością zaufania zewnętrznemu dostawcy. Łatwiej o takie zaufanie, kiedy mówimy o sklepie mięsnym za rogiem. Wiem, że pracującej tam pani Basi zależy na klientach. Zbyt wiele podobnych sklepików jest w okolicy, aby mogła pozwolić sobie na sprzedanie mi nieświeżego towaru. Czy tak samo będzie zależeć na mnie (mojej firmie) korporacji, która obsługuje miliony podobnych klientów? Powtarzając za Greenspanem tłumaczącym przyczyny kryzysu finansowego: uwierzyłem, że banki są w stanie wykonać właściwe posunięcia by zabezpieczyć interesy ich akcjonariuszy i klientów. Myliłem się. Wydaje się, że to poziom bezpieczeństwa będzie warunkował popularność usług cloud computing. Jak dotychczas usługi świadczone za pomocą Internetu trudno było uznać za bezpieczne. Przypadki ujawnienia danych niepowołanym osobom zdarzają się niemal na porządku dziennym (zob. Ramka Spektakularne wycieki danych w latach 2007-2008). Ponieważ zaufanie będzie kluczową kwestią, można spodziewać się, że dostawcy nie będą zinteresowani nagłaśnianiem swoich wpadek. Dodatkowo, dowiedzenie ewentualnej winy dostawcy stanie się bardziej skomplikowane, niż w przypadku systemów lokalnych – również ze względu na trudności w określeniu zasięgu chmury. Biorąc pod uwagę ryzyko, jakie przejmują na siebie dostawcy, poziom bezpieczeństwa nie będzie traktowany jako parametr usługi (np. usługi składowania danych), ale jako kolejna osobno płatna usługa (podobnie transfer, szybkość operacji, itd.). Udzielane gwarancje będą uzależnione od wartości opłacanego abonamentu (np. wysokość odszkodowania za straty wynikłe z utraty lub upublicznienia danych, przestojów systemu). Kolejną kwestią wartą rozważenia jest niekompatybilność chmur. Oczywiście, wielu z dostawców zaproponuje własne standardy dostępu (protokoły, interfejsy). Istnieją więc duże szanse, że znowu będziemy świadkami scysji podobnej do tej między ODF i OOXML (zob. [13]). Brak porozumienia doprowadzi do typowego vendor lock-in: przeniesienie danych między dostawcami stanie się na tyle trudne, że nie zrekompensuje potencjalnych zysków tytułem niższych opłat u innego dostawcy. To ograniczy presję konkurencyjną. Przydatność chmury do wymiany informacji między klientami różnych dostawców może być ograniczona. Przecież nie chodzi o to, żeby załączyć dokumenty do e-maila. Z drugiej strony może się okazać, że takich dostawców nie będzie znowu aż tak wielu. Nawet jeśli sami stworzą rozwiązania odpowiednio funkcjonalne i skalowalne, ilu z nich zostanie obdarzonych odpowiednim kredytem zaufania? Którym zdecydujemy się powierzyć tajemnice niejednokrotnie warunkujące istnienie naszego biznesu? Progiem wejścia na taki rynek jest nie tylko infrastruktura, know-how, ale aspekty czysto emocjonalne, jak np. zaufanie do marki. Wątpliwości dotyczą również firm powiązanych z klientami za pomocą produktów. Czy będą one w stanie przestawić się na model dostawca-usługobiorca (zob. [14])? Czynniki te mogą sprawić, że powstanie monopol kilku-, kilkunastu dostawców, czy korporacji o międzynarodowym zasięgu i renomie. Ograniczy to wpływ problemów z przenośnością, ale czy rzeczywiście tak powinien funkcjonować wolny rynek? Bańkę spekulacyjną nadmuchała chciwość. Zagrożenie, jakie się wiąże z udzieleniem kolejnego kredytu subprime, było nieistotne. Większą wagę miała ilość zawartych umów, bo od tego zależała miesięczna premia. Jaka jest pewność, że podobna sytuacja się nie powtórzy? Niektóre z oferowanych usług będą przecież bardziej popularne niż inne. Dostawcy chętniej zainwestują w ich rozwój, bo to one przyciągną klientów i przyniosą największe zyski. Może to doprowadzić do sytuacji, w której pakiety usług staną się zunifikowane i przykrojone do najczęstszych potrzeb. Presja konkurencji przestanie się liczyć, ponieważ zysk będzie pochodną ilości, a nie specyficzności. Oczywiście na usługach niszowych dostawca będzie mógł zarobić wielokrotnie więcej. Tylko czy małe i średnie firmy, do których cloud computing jest w pierwszym rzędzie adresowany, będzie na to stać? Raczej dostosują się do oferowanych usług, co przyniesie efekt dokładnie odwrotny do obiecywanego przez marketing. Czy właśnie to ma na myśli Sun pod eufemistycznym określeniem important tradeoffs (zob. [15])? Chmura to chwytliwy i bardzo obrazowy slogan. Dobrze współbrzmi z Internetem, którego clue to decentralizacja. Z drugiej strony – chmura jest synonimem pewnej nieokreśloności, rozmytości, a istotą chmury obliczeniowej jest konsolidacja i centralizacja zasobów. Podobnie niejednoznaczne są moje odczucia. Z jednej strony nęci mnie obietnica uzyskania pewnego komfortu psychicznego (zrzucenia na kogoś choćby części odpowiedzialności związanej z infrastrukturą), możliwości kształtowania infrastruktury według potrzeb, przebierania w usługach (zamiast ich mozolnego tworzenia we własnym zakresie). Z drugiej strony jednak studzi mnie brak przejrzystości reguł i długofalowych skutków. Ciekawy jestem co wygra? Artykuł wyraża prywatne poglądy autora, które niekoniecznie odzwierciedlają stanowisko Silicon & Software Systems Ltd. (S3)

Bibliografia
• • • • • • [1] Doktryna Szoku, Naomi Klein, Muza, październik 2008; [2] Branża technologiczna nie poległa... Na razie, NetWord Online, listopad 2008; [3] Wirtualizacja 2.0 – trend czy standard? Prognozy rynku rozwoju technologii, Jarek Smulski, IDC Polska, 2007; [4] Dziesięć strategicznych technologii 2009 roku, IDG.pl, padziernik 2008; [5] Cloud computing with Linux, M.Tim. Jones, wrzesień 2008; [6] Dane Dow Jones: Google Finance; dane wyszukiwań: Google Trends; dane odwiedzin domeny docs.google.com: Compete; wszystkie znormalizowane do % maksymalnej wartości w okresie październik 2007 – listopad 2008; [7] Niemcy: 21 milionów kont bankowych do kupienia, Dziennik Internautów,6 grudnia 2008; [8] Niemcy: Wyciekly dane 17 milionów klientów, Dziennik Internautów, 5 październik 2008; [9] Wyciek danych – nowa specjalnosc Brytyjczyków?, Dziennik Internautów, sierpień 2008; [10] Wyciek danych polskich kibiców, Dziennik Internautów, luty 2008; [11] Wyciek danych z Pekao to nie atak hakerów, Dziennik Internautów, lipiec 2008; [12] Banking's Data Security Crisis, Andy Greenberg, Forbes, listopad 2008; [13] Zagadnienia procesu normalizacji OOXML opisywane były w SDJ numer 6/2008, 8/2008 oraz SDJ Extra! Numer 25; [14]The Risks and Rewards of Cloud Computing, Gartner Voice, lipiec 2008; [15] Demystifying Cloud Computing, Sun Inner Circle – Newsletter, listopad/grudzień 2008; [16] Demystyfying the Cloud, Information Week Research & Reports, June 2008; [17] Handicapping cloud computing, Larry Dignan, grudzień 2008;

• • • • • • • • • • •

ARKADIUSZ MERTA
Autor od 10 lat zajmuje się zagadnieniami projektowania i realizacji oprogramowania. Aktualnie jest pracownikiem Silicon & Software Systems Polska zatrudnionym na stanowisku menadżera projektów. Kontakt z autorem: arkadiusz.merta@s3group.com

76

03/2009

Felieton

Najpierw cele

C

el nie powinien byc postrzegany jako punkt. Kazda decyzja podejmowana w projekcie moze do niego przyblizac lub oddalac. Dlatego cele nalezy rozpatrywac w kategoriach dazenia w wybranym kierunku. Pamiętam jedno opowiadanie Lema z serii Dzienników Gwiazdowych [1]. Jego bohater Ijon Tichy, nie mogąc w pojedynkę poradzić sobie z naprawą statku kosmicznego, postanowił zapętlić czas, tak aby zwielokrotnić samego siebie. Uzyskane w ten sposób dodatkowe ręce do pracy, miały pomóc w wyjściu z opresji. Niestety już po pierwszym rozmnożeniu okazało się, że brakuje zapasowego skafandra. Po kilku powtórzeniach procesu, gdy liczba klonów bohatera gwałtownie wzrosła (zamierzenie lub jako efekt uboczny), chaos pogłębiał się a rakieta dryfowała coraz dalej w nieznane. Na pierwszy rzut oka może się wydawać, że problemy Ijona są tak wydumane, że nadają się jedynie na niedzielne czytadło. Spróbujmy jednak pomyśleć o podróży bohatera jako o pewnym projekcie. Przeszkody, które pojawiły się w czasie jego realizacji (uszkodzenia statku), okazują się na tyle trudne, że powodzenie misji staje pod znakiem zapytania. Mamy tu do czynienia z poważnie zagrożonym projektem i desperacką próbą uratowania go. Nasz bohater decyduje się rozwiązać problem poprzez zwiększenie ilości zasobów. Metoda taka (jak i jej wynik) jest dokładną ilustracją prawa Brooksa (sformułowanego jakieś 10 lat po wydaniu wspomnianego opowiadania – przypadek?). Prawo to mówi, że dodawanie kolejnych zasobów do spóźnionego projektu, czyni go jeszcze bardziej spóźnionym. Problem polega na tym, że im większy jest zespół, tym więcej czasu trzeba poświęcić na wewnętrzną komunikację. Im później ludzie dołączają do projektu, tym więcej czasu potrzebują na wdrożenie (tzn. tym później będą w stanie efektywnie wspomagać projekt, zob. [2]). Boleśnie tego doświadczył Ijon, kiedy próbował ustalić, który klon jest kim, po co się pojawił i jaki ma sposób na rozwiązanie sytuacji. Zamiast pracować nad osiągnięciem celu, uwikłał się w męczące spory, dyskusje i rozważania. A czas uciekał... Podobne historie przydarzyły się już wielu projektom. Goniące terminy, nieprzewidziane wydarzenia kradnące czas i zasoby, niedoszacowane zadania – to wszystko sprawia, że zaczynamy panikować. Ściągamy dodatkowe zasoby, nerwowo żonglując zadaniami między nimi – zgodnie ze wskazaniami ścieżki krytycznej. Zarywamy weekendy (o nadgodzinach nie wspominając). W zespole zaczyna robić się gęsto od nerwów. Niektórzy nie wytrzymują tempa i awantura gotowa. Nie myślcie, że nie nachodziły mnie takie pomysły. Jednak mój szef produktu, na prośbę przydzielenia dodatkowych ludzi w celu dopięcia terminów, odmówił. Uzasadnił to krótko: bo chcę, żeby Ci się udało. Czy chodziło mu jedynie o prawo Brooksa? Źródłem problemów Ijona była jego ślepa koncentracja na celu. Tak bardzo nastawił się na jego osiągnięcie, że przysłoniło mu to wszystkie inne, w jego pojęciu poboczne, aspekty – jak np. ilość skafandrów, miejsce czy zapasy pożywienia dla rosnącej załogi. Postrzegał problem w ograniczony sposób i źle ukierunkował działania. Osiągnięte rezultaty nie poprawiały

Bibliografia
• • • • [1] Dzienniki Gwiazdowe: Podróż siódma, Stanisław Lem, Wydawnictwo Literackie, 1966 [2] The Mythical Man-Month, Essays on Software Engineering, Peter F. Brooks, Addison-Wesley, 1995 [3] Mądre życie, A. Roger Merrill, Rebecca Merril, Bertlsmann Media, Warszawa 2004 [4] Praktyka zarządzania, Peter F. Drucker, MT Biznes, 2008

sytuacji. Okazana krótkowzroczność prowadziła do niechybnej zguby. Postrzeganie jest inspiracją dla działania (zob. [3]). Jeżeli będzie zakłócone, fałszywe, podyktowane nieobiektywnymi czy doraźnymi przesłankami – podjęte na jego podstawie akcje mogą przynieść więcej szkody niż korzyści. Powstaje zatem pytanie, czy jesteśmy w stanie poprawnie postrzegać (a więc i definiować) cele? Powtarzając za Druckerem: to, co klient uważa za wartość, jest tak skomplikowane, że na pytanie o nią tylko on sam może odpowiedzieć. Zarząd firmy nie powinien nigdy nawet próbować tego zgadywać. Powinien zawsze i systematycznie szukać odpowiedzi u klienta [4]. Firma funkcjonuje tak długo, jak długo potrafi zarabiać pieniądze. Aby zapewnić stały dopływ środków, musi dotrzymywać swoich zobowiązań. Realizacja zadanych celów to podstawowe zadanie. Rolą liderów jest zapewnienie tego. Trzeba jednak dokładnie rozumieć na czym polega biznes. Czy chodzi o dostawę, czy raczej spełnienie oczekiwań (potrzeb) klienta? Czy chodzi o sztukę, czy o produkt? Czy chodzi o tysiące linii kodu, czy o postęp? Należy również zdać sobie sprawę z faktu, że cele (potrzeby) klienta nie są stałe w czasie. Gdy dostarczamy np. proof-of-concept (dowód, że projekt jest wykonalny), klienta będą interesować jak najniższe koszty i najkrótszy czas wykonania (tzn. minimalna strata w przypadku niemożności realizacji). Z drugiej strony zadaniem podobnego prototypu jest przedstawienie, wizualizacja koncepcji przyszłego produktu, tak aby klient zdecydował się na realizację. Dostarczenie podobnej projekcji pozostawia pole do kompromisu w zakresie kompletności i jakości. Oczywiście w miarę postępu prac nad projektem, pole manewru ulegnie znacznemu ograniczeniu. Nadal jednak świadome i odpowiedzialne balansowanie czasem, kosztami i zakresem może umożliwić osiągnięcie sukcesu – nawet w przypadku zagrożonych projektów. Sztuczka polega na tym, aby cel postrzegać w kategorii dążenia, codziennego kursu i jego korekt, a nie tylko pojedynczego punktu w czasie. Wszystkie doraźne działania należy ważyć w kategorii zysków i strat, które będą przybliżać lub oddalać sukces. Brak długofalowej analizy wyników takich działań (nawet tych pozornie błahych) może skutkować dryfem, a nie podążaniem w określonym kierunku. Refleksja na temat potencjalnych efektów nie może być rozpatrywana jedynie w kontekście celu postawionego przed projektem. Konieczne jest uwzględnienie wszelkich dodatkowych faktów, które mogą zaistnieć w wyniku podejmowanych decyzji. Przykładowo, planowe dostarczenie projektu było okupione wzmożonym wysiłkiem zespołu. W dłuższym okresie może to prowadzić do spadku zaangażowania i kreatywności – a więc i wydajności. Cele należy osiągać – to podstawa egzystencji firmy – ale trzeba być świadomym drogi, która prowadzi do ich realizacji. Wszystkie decyzje podejmowane w tym czasie trzeba rozpatrywać względem szerszego horyzontu późniejszych skutków. Zaniedbanie przewidywania może się wkrótce zemścić, i to w całkowicie nieprzewidziany sposób. PS. Nie zdradzę zakończenia opowiadania – zachęcam do lektury. Powiem jedynie, że rozwiązanie leżało nie tyle w ilości, ile w składzie zespołu i jego odpowiednim zaangażowaniu w rozwiązanie problemu. Artykuł wyraża prywatne poglądy autora, które niekoniecznie odzwierciedlają stanowisko Silicon & Software Systems Ltd. (S3).

ARKADIUSZ MERTA
Autor od 10 lat zajmuje się zagadnieniami projektowania i realizacji oprogramowania. Aktualnie jest pracownikiem Silicon & Software Systems Polska zatrudnionym na stanowisku menadżera projektów. Kontakt z autorem: arkadiusz.merta@s3group.com

www.sdjournal.org

77

KLUB PRO
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.

Oferta skierowana dla firm

sdj@software.com.pl tel. 22 427 36 91 pren@software.com.pl http://buyitpress.com
Opera Software
Opera Software’s vision is to deliver the best Internet experience on any device. We are offering browser for PC/desktops and embedded products that operates across devices, platforms and operating systems. Our browser can deliver a faster, more stable and flexible Internet experience than its competitors. http://www.opera.com

Skontaktuj się z nami:

Architektury systemów IT

Twórca frameworków JUVE i serwera aplikacji AVAX oferuje usługi, doradztwo, rozwiązania do tworzenia nowoczesnych, dużych systemów i rozwiązań informatycznych/internetowych, integrujące architektury ery post-J2EE/.NET, wykorzystujące MDD/MDA dla dziedzin – bankowość, telekomunikacja, handel, e-commerce, ERP/Workflow/ CRM, rozwiązania internetowe, portalowe. www.mpsystem.com mpsystem@mpsystem.com

FRONTLINE STUDIOS

Frontline Studios – amerykańsko-polski twórca gier konsolowych oraz PC – szuka utalentowanych koderów (bardzo dobra znajomość C/C++; Java, Delphi, UML), doświadczonych grafików (2D, 3D) oraz zespołów developerskich. Oferujemy długoterminową pracę nad poważnymi projektami. Nie przegap tej okazji! kadry@frontstudios.com

Future Processing

Future Processing to dynamiczna firma technologiczna działająca na globalnym rynku oprogramowania. Jesteśmy zespołem wysokiej klasy specjalistów posiadających wiedzę i doświadczenie niezbędne do realizacji ambitnych projektów informatycznych. Jeśli programowanie to Twoja pasja dołącz do nas! (możliwość pracy zdalnej). http://www.future-processing.pl

Kei.pl

Kei.pl działa na rynku usług hostingowych od 2000 roku. Do naszych zadowolonych Klientów z dumą możemy zaliczyć wiele przedsiębiorstw sektora MSP, instytucji oraz osób prywatnych. W ofercie Kei.pl znajdują się pakiety hostingowe, a także usługi dla wymagających Użytkowników – platformy e-Biznes oraz serwery fizyczne. http://www.kei.pl

WSISiZ w Warszawie
INFORMATYKA ZARZĄDZANIE
studia stopnia I i II (stacjonarne i niestacjonarne) specjalności: inżynierskie, magisterskie i licencjackie. Szczegółowe plany studiów, opisy poszczególnych specjalności – zapraszamy na stronę uczelni. http://www.wit.edu.pl

KLUB PRO
StatConsulting TTS Company Sp. z o.o.

StatConsulting to firma o znaczącej pozycji na rynku usług analitycznych oraz Data Mining. Nasza oferta obejmuje m.in. modele scoringowe, rozwiązania Fraud Detection oraz modelowanie ryzyka. Tworzymy także własne rozwiązania informatyczne na potrzeby projektów Data Mining, Data Quality, zarządzania ryzykiem itd. http://www.statconsulting.com.pl

Sprzedaż i dystrybucja oprogramowania komputerowego. Import programów na zamówienie. Ponad 200 producentów w standardowej ofercie. Chcesz kupić oprogramowanie i nie możesz znaleźć polskiego dostawcy? Skontaktuj się z nami – sprowadzimy nawet pojedyncze licencje. http://www.OprogramowanieKomputerowe.pl

Transition Technologies S.A.

Firma w branży high-tech od 1991. Producent oprogramowania dla przemysłu (ponad 350 referencji z instalacji na całym świecie). Usługi z zakresu: hurtownie danych i Business Intelligence, rozwiązania eBusiness, optymalizacja, integracja danych, aplikacji oraz procesów biznesowych, portale korporacyjne, consulting i outsourcing usług IT, zaawansowana automatyka cyfrowa. http://www.tt.com.pl

EPRO

Naszą misją jest projektowanie najwyższej jakości dedykowanych systemów IT, które cechuje wysoka niezawodność, wydajność, ergonomiczność i intuicyjność w obsłudze oraz administracji. Głównym elementem oferty EPRO jest oprogramowanie sklepu internetowego oraz identyfikacja wizualna. tel. 085 743 66 38 http://www.epro.com.pl

IT SOLUTIONS

IT SOLUTIONS

Wdrożenia i szkolenia z zakresu: • SQL Server • SharePoint Services • MS Project / Server • Tworzenie aplikacji w technologii .NET http://www.itsolutions.biz.pl marcin.pytlik@itsolutions.biz.pl

Softline rozwiązania mobilne

Wiodący producent systemów mobilnych, dostawca aplikacji użytkowych dla biznesu (Symbian OS, Windows Mobile, J2ME ) zaprasza do współpracy. Zostań naszym partnerem. Dołącz do zespołu. http://www.softline.com.pl

Proximetry Poland Sp. z o.o.

Proximetry Poland Sp. z o.o. jest polskim oddziałem amerykańskiej firmy Proximetry Inc. – dostawcy systemów zarządzania sieciami bezprzewodowymi opartymi na technologiach WiFi i WiMAX. Naszą misją jest dostarczenie klientom rozwiązań poprawiających jakość usług (QoS) dostarczanych drogą radiową. Dołącz do najlepszych i zostań członkiem naszej ekipy! http://www.proximetry.com

SWD Software Sp. z o.o

System operacyjny czasu rzeczywistego RTOS QNX. Oficjalny dystybutor w Polsce. Zakres działalności: lokalizacja produktów QNX, dostawy sprzętu i oprogramowania, doradztwo przedsprzedażowe, wsparcie techniczne, certyfikowane szkolenia, opracowania na zamówienie. http://www.swdsoft.pl

Systemy bankowe, ISOF

HEUTHES istnieje na rynku od 1989 r. Obok systemów informatycznych dla banków, oferuje nowoczesne oprogramowanie do obsługi firm. System ISOF jest udostępniany klientom w trybie SaaS lub licencji. Pracuje na platformie Linux i zawiera m.in. takie moduły jak CRM, DMS, Magazyn, Sprzedaż, Logistyka oraz Rachunkowość. http://www.isof.pl

Roczna prenumerata

250,Software Developer’s Journal (poprzednio Software 2.0) jest miesięcznikiem głównie dla programistów, którzy liczą, że dostarczymy im gotowe rozwiązania, oszczędzając im czasu i pracy. Jesteśmy czytani przez tych, któ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ć naszych czytelników, prezentujemy zarówno najnowsze rozwiązania, jaki starsze, sprawdzone technologie.

tylko

UWAGA! Zmiana danych kontaktowych

Obsługa prenumeraty
1. Telefon 2. Fax

+48 22 877 20 80 +48 22 877 20 70
2. Online

3. Adres

EuroPress Polska Sp. z o.o. ul. Jana Kazimierza 46/54 01-248 Warszawa

software@europress.pl

Zamówienie prenumeraty
Prosimy wypełniać czytelnie i przesyłać faksem na numer: 00 48 22 877 20 70 lub listownie na adres: EuroPress Polska Sp. z o.o. ul. Jana Kazimierza 46/54 01-248 Warszawa Polska E-Mail: software@europress.pl Przyjmujemy też zamównienia telefoniczne: 00 48 22 877 20 80 Jeżeli chcesz się dowiedzieć o formach płatności, wejdź na stronę: www.europress.pl lub napisz na e-mail: software@europress.pl

Imię i nazwisko ............................................................................... Nazwa firmy..................................................................................... Dokładny adres .............................................................................. .........................................................................................................

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

Zadzwoń

Telefon ............................................................................................ E–mail ............................................................................................. ID kontrahenta ................................................................................ Numer NIP firmy ............................................................................. Fax (wraz z nr kierunkowym) .........................................................

□ automatyczne przedłużenie prenumeraty

Prenumerujesz – zyskujesz
l

l l l

oszczędność pieniędzy szybka dostawa prezenty bezpieczna płatność on–line

Tytuł
Software Developer’s Journal (1 płyta CD) – dawniej Software 2.0

Ilość Od Ilość zama- numeru nume- wianych pisma rów prenume- lub mierat siąca

Cena

12

250 PLN

W NASTĘPNYM NUMERZE SOFTWARE DEVELOPER’S JOURNAL 4/2009 (172)

Numer będzie poświęcony

Rich Internet Application
W magazynie: • • • JavaFX Silverlight Adobe Flex

A także wiele innych interesujących artykułów z dziedziny programowania urządzeń mobilnych, testowania oprogramowania, języków programowania itp.

W sprz eda po łow ży w drugie ie mar ca j

Redakcja zastrzega sobie możliwość zmiany zawartości pisma.

You're Reading a Free Preview

Pobierz
scribd
/*********** DO NOT ALTER ANYTHING BELOW THIS LINE ! ************/ var s_code=s.t();if(s_code)document.write(s_code)//-->