You are on page 1of 84

05/2010 (185)

SPIS TREŚCI
17 Opis DVD 32 Plone – Zbuduj firmowy intranet
Radosław Jankiewicz
Wybierając narzędzie mające zapewnić bezpieczną i sprawną
komunikację wewnątrz-firmową, warto zwrócić uwagę na Plo-
BIBLIOTEKA MIESIĄCA ne – otwarty system CMS oferujący szeroki zakres możliwości
dysponujący wieloma dodatkowymi produktami, które pozwa-
6 Przetwarzanie obrazów za pomocą OpenCV lają dopasować go do własnych potrzeb. W poniższym artyku-
Igor Kupczyński le przedstawione zostało zastosowanie Plona w roli firmowe-
Przetwarzanie obrazu jest też częstym motywem w filmach scien- go intranetu.
cie-fiction. Bohaterowie za pomocą swoich komputerów potrafią
wskazać na obrazie niewidoczne gołym okiem detale, wyostrzyć 40 Python 3...
rozmyte napisy; roboty namierzają wrogów na polu bitwy, a sys- czyli co nowego w trzeciej edycji języka
tem ochronny wpuszcza do budynku tylko tych, których rozpozna Łukasz Langa
na podstawie obrazu z kamery. Łukasz przeprowadzi Cię przez nowości w najświeższej edycji ję-
zyka programowania Python i pokaże, w jaki sposób wpływają
na sposób tworzenia programów.

KLUB TECHNICZNY 46 Testy wydajnościowe z Funkloadem


Andrzej Mleczko
12 Eclipse IDE Masz problemy z wydajnością swojej aplikacji? Nie wiesz gdzie leży
Tomasz Maćkowiak problem? A może po prostu chcesz wiedzieć czy twoja konfiguracja
Dla języka Python istnieje wiele edytorów. Poczynając od konso- wytrzyma prawdziwe obciążenie? W dodatku szukasz rozwiązania
lowych, takich jak vim, przez dedykowane, jak IDLE, kończąc na OpenSource? Przeczytaj koniecznie ten artykuł...
wielo-językowych platformach programistycznych, jak Netbeans
lub Eclipse. Niniejszy artykuł prezentuje wykorzystanie popular- 50 Django – Doświadczenia z pracy
nego Eclipse do rozwoju aplikacji w Pythonie. z frameworkiem
Łukasz Langa
O ile dokumentacja Django i blogosfera obfitują w zachęcają-
ce tutoriale i przewodniki dla początkujących, dość rzadko zna-
NARZĘDZIA leźć można artykuły wykraczające poza przysłowiowy „pierwszy
blog w 15 minut”.
18 Buildout – Narzędzie automatyzujące budowę
i zarządzanie aplikacjami w języku Python
Wojciech Lichota
W trakcie rozwoju aplikacji ilość zależnych bibliotek stopniowo
się zwiększa. Ręczne zarządzanie projektem staje się mało wy-
BAZY DANYCH
godne, a instalacja oprogramowania na nowej maszynie wy- 54 Krótki wstęp do ZODB
dłuża się. Użycie narzędzia Buildout pozwoli zautomatyzować Michał Węgrzynek
większość tych czynności i ułatwi pracę programistom i admi- Prawie każda aplikacja, z wyjątkiem najprostszych skryptów,
nistratorom. musi w jakiś sposób gromadzić przetwarzane dane. Może je
zapisywać bezpośrednio w plikach, w relacyjnych bazach da-
nych czy w jednej z modnych ostatnio baz NoSQL, takich jak Co-
uchDB czy MongoDB.
PROGRAMOWANIE 58 Sieć dziś i jutro – Rozpowszechnienie Internetu
22 Django – Szybkie tworzenie serwisów Web 2.0 zmieniło na zawsze sposób, w jaki pracujemy,
Paweł Mandes odpoczywamy i komunikujemy się ze sobą
Jeśli cenisz sobie prostotę, elegancką architekturę i zwięzły kod, Paweł Korzec, Krzysztof Wysocki
a jednocześnie potrzebujesz zaawansowanych funkcjonalności Po pierwszej rewolucji Internetu przyszła jej kolejna faza: Web
i do tego gonią Cię terminy – framework Django jest dla Ciebie. 2.0 i dzięki powstaniu serwisów społecznościowych wciągnęła
Powstał na potrzeby redakcji on-line, gdzie szybkość reakcji na do sieci miliony nowych użytkowników. Co przyniesie ze sobą
ciągłe zmiany jest kluczowa. trzecia fala? Zapraszamy do czytania.

4 05/2010
APLIKACJE BIZNESOWE
Miesięcznik Software Developer’s Journal (12 numerów w roku)
62 Wdrożenia SAP – droga przez mękę? jest wydawany przez Software Press Sp. z o.o. SK
Co może się nie udać?
Karolina Zmitrowicz
Redaktor naczelny:
Wdrażanie systemu SAP jest przedsięwzięciem wymagających Łukasz Łopuszański lukasz.lopuszanski@software.com.pl
ścisłej współpracy ze strony firmy wdrożeniowej i klienta. Roz-
Redaktor prowadzący:
wiązania typu SAP posiadają z reguły gotową funkcjonalność Maciej Dziergwa
podstawową ogólną lub dedykowaną dla danej branży.
Warsztaty Projekt okładki: Agnieszka Marchocka

Skład i łamanie:
70 C++ Qt 4.5 – Podstawy budowy aplikacji przy Tomasz Kostro www.studiopoligraficzne.com
użyciu biblioteki Qt
Łukasz Klejnberg Kierownik produkcji:
W artykule zostanie zaprezentowana budowa bardzo prostej Andrzej Kuca andrzej.kuca@software.com.pl
aplikacji okienkowej w oparciu o bibliotekę Qt – będzie to zwy-
Dział produkcji i kolportażu:
kły kalkulator z prostymi wyrażeniami arytmetycznymi. Alina Stebakow alina.stebakow@software.com.pl

EFEKTYWNOŚC PRACY Nakład: 6 000 egz.

Adres korespondencyjny:
78 Na kiedy? – Planowanie zadań Software Press Sp. z o.o. SK,
programistycznych ul. Bokserska 1, 02-682 Warszawa, Polska
tel. +48 22 427 36 91, fax +48 22 224 24 59
Michał Bartyzel, Mariusz Sieraczkiewicz
www.sdjournal.org cooperation@software.com.pl
Z opracowywaniem zadań programistycznych wiążą się dwa
kluczowe pytania: ile to zajmie? oraz na kiedy? Pierwsze pyta-
nie dotyczy szacowania zadań, czyli określania w jednostkach
czasu, jak długo potrwają prace. Drugie pytanie dotyczy plano- Dział reklamy: adv@software.com.pl
wania – czyli osadzania oszacowanych czynności w kalendarzu.
Obsługa prenumeraty: EuroPress Polska
W artykule zajmujemy się tym drugim pytaniem. software@europress.pl

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


AntiVirenKit firmy G DATA Software Sp. z o.o.

Redakcja dokłada wszelkich starań, by publikowane w piśmie


i na towarzyszących mu nośnikach informacje i programy były
poprawne, jednakże nie bierze odpowiedzialności za efekty
wykorzystania ich; nie gwarantuje także poprawnego działania
programów shareware, freeware i public domain.

Uszkodzone podczas wysyłki płyty wymienia redakcja.

Wszystkie znaki firmowe zawarte w piśmie są własności


odpowiednich firm.
Zostały użyte wyłącznie w celach informacyjnych.

Redakcja używa systemu automatycznego składu

Osoby zainteresowane współpracą prosimy o kontakt:


cooperation@software.com.pl

Druk: Artdruk www.artdruk.com

Wysokość nakładu obejmuje również dodruki. Redakcja nie


udziela pomocy technicznej w instalowaniu i użytkowaniu
programów zamieszczonych na płycie CD-ROM dostarczonej
razem z pismem.

Sprzedaż aktualnych lub archiwalnych numerów pisma po


innej cenie niż wydrukowana na okładce – bez zgody wydawcy
– jest działaniem na jego szkodę i skutkuje odpowiedzialnością
sądową.

www.sdjournal.org 5
Biblioteka miesiąca

Przetwarzanie obrazów
za pomocą OpenCV
Przetwarzanie obrazu jest też częstym motywem w filmach sciencie-
fiction. Bohaterowie za pomocą swoich komputerów potrafią wskazać
na obrazie niewidoczne gołym okiem detale, wyostrzyć rozmyte napisy;
roboty namierzają wrogów na polu bitwy, a system ochronny wpuszcza do
budynku tylko tych, których rozpozna na podstawie obrazu z kamery.
obecnie jest dostępna na licencji BSD, co
Dowiesz się: Powinieneś wiedzieć: oznacza, że jest darmowa zarówno do użyt-
• W jaki sposób zainstalować i wykorzystać • Podstawy programowania w języku Python; ku naukowego , jak i komercyjnego. Funk-
bibliotekę OpenCV; • Podstawowe informacje o tym, jak kompu- cjonalność biblioteki opisano w ramce „Za-
• Poznasz podstawowe techniki przetwarza- ter reprezentuje przechowywane obrazy. awansowane możliwości OpenCV”.
nia obrazów; 31 września 2009 została wydana wer-
• Nauczysz się przetwarzać strumień wideo; sja 2.0 biblioteki. Oprócz wielu usprawnień
• Jak wykorzystać techniki uczenia maszyno- i nowych funkcji w kodzie biblioteki dodane
wego do wykrywania twarzy. zostały także nowy interfejs programistycz-
ny w C++ oraz, co bardziej interesujące dla
czytelników, nowy interfejs dla języka Py-
pisy; roboty namierzają wrogów na polu bi- thon (ramka „OpenCV i Python”).
twy, a system ochronny wpuszcza do budyn- Skrót CV pochodzi od angielskiego ter-
Poziom ku tylko tych, których rozpozna na podsta- minu Computer Vision, który oznacza
trudności wie obrazu z kamery. dyscyplinę zajmującą się głównie przetwa-
Okazuje się jednak, że do wielu operacji rzanie obrazów, ale też rozpoznawaniem
związanych z przetwarzaniem obrazu nie obiektów znajdujących się na nich, mode-
potrzeba ani kosmicznych technologii, ani lowaniem otoczenia oraz interakcją mię-

Z
przetwarzaniem i analizą strumie- drogiego oprogramowania. W artykule zo- dzy środowiskiem a systemami kompute-
nia wideo na co dzień ma do czy- stanie przedstawiona biblioteka OpenCV, rowymi.
nienia każdy z nas. W komputerze która umożliwia wykonanie wielu operacji Biblioteka jest stabilna i dojrzała oraz
przechowujemy zdjęcia z wakacji, ogląda- na obrazach statycznych oraz na strumie- ma za sobą wsparcie ważnego gracza na
my filmy publikowane przez internautów niu wideo. Biblioteka oferuje interfejs pro- rynku IT, jakim jest Intel, co w połącze-
na popularnych serwisach, a komunikatory gramistyczny w języku Python, co dodatko- niu z otwartą licencją czyni z niej dosko-
internetowe umożliwiają wideokonferen- wo ułatwia pisanie programów z jej wyko- nałą kandydatkę do wykorzystania we wła-
cje między uczestnikami z całego świata. rzystaniem. Czytelnik zapozna się z pod- snym projekcie z zakresu przetwarzania
Jednak motorem napędowym tej dzie- stawowymi koncepcjami programowania obrazów.
dziny jest przemysł, który potrzebuje au- z wykorzystaniem tej OpenCV oraz stwo- Adresy internetowe oprogramowania
tomatycznych metod analizy obrazów rzy system wykrywający twarze w obrazie wymienionego w tekście można znaleźć
w procesach kontroli jakości czy wykry- z kamery lub pliku wideo. Artykuł opisu- w ramce „W Sieci”. Biblioteka OpenCV
wania defektów materiałowych. Wiele ba- je krok po kroku, w jaki sposób uzyskać kil- jest oprogramowaniem typu Open So-
dań finansowanych jest także przez sek- ka ciekawych efektów za pomocą OpenCV urce i niezależnie od wybranej platfor-
tor usług medycznych – wspomaganie ; zawiera tylko niezbędne minimum teo- my można ją zbudować ze źródeł, prost-
diagnozowania poprzez klasyfikację zdjęć rii – ma natomiast pozwolić czytelniko- szym wyjściem jest jednak skorzystanie
rentgenowskich czy obrazów mikrosko- wi rozpocząć przygodę z przetwarzaniem z przygotowanych paczek binarnych.
powych tkanek pozwoliłoby na obniże- obrazów.
nie kosztów leczenia oraz zwiększenie je- Podstawowe
go skuteczności. Biblioteka – wykorzystanie OpenCV
Przetwarzanie obrazu jest też częstym informacje wstępne Na początek, aby sprawdzić, czy bibliote-
motywem w filmach sciencie-fiction. Boha- OpenCV jest wieloplatformową biblioteką ka została zainstalowana poprawnie zade-
terowie za pomocą swoich komputerów po- oferującą zbiór funkcji do przetwarzania ob- monstrujemy konwersję obrazu do innego
trafią wskazać na obrazie niewidoczne go- razów statycznych oraz video. Jej rozwój zo- formatu. W bibliotece OpenCV format ob-
łym okiem detale, wyostrzyć rozmyte na- stał zapoczątkowany w firmie Intel, jednak razu jest rozpoznawany na podstawie roz-

6 05/2010
Przetwarzanie obrazów za pomocą OpenCV

szerzenia pliku. Kod przedstawiono na li-


stingu 1. Listing 1. Wczytywanie modułu OpenCV
# Wczytanie modułu OpenCV
Przetwarzanie jednopunktowe import cv
Obraz w OpenCV przechowywany jest jako # Załadowanie obrazka do zmiennej src
zbiór pikseli; z każdym pikselem skojarzone src = cv.LoadImage("budynek.bmp")
może być kilka kanałów – w modelu RGB # Ponowne zapisane, tym razem w innym formacie
jest to kanał czerwony, zielony oraz niebie- cv.SaveImage("budynek.png", src)
ski. Piksel jest krotką zawierającą wartości ja-
sności poszczególnych kanałów, z przedziału
<0, 255>. Obiekt obrazu daje też dostęp do Listing 2. Przetwarzanie jednopunktowe
różnych jego parametrów, takich jak rozmiar
czy ilość kanałów. ON = (255, 255, 255) # Elementy czerwone zaznaczymy na biało
Najprostszą formą przetwarzania obra- OFF = (0, 0, 0) # reszta pozostanie czarna
zu jest przetwarzanie jednopunktowe – za-
wartość piksela w obrazie wynikowym za- src = cv.LoadImage("auto.bmp")
leży tylko i wyłącznie od jego zawarto-
ści w obrazie źródłowym. Oprogramowa- # Przygotowanie obrazu wynikowego
nie przetwarzania obrazu w tym modelu # src.depth pozwala pobrać głębie kolorów obrazu wejściowego, a
jest dość proste. Należy iterować po kolej- # src.nChannels – liczbę jego kanałów
dst = cv.CreateImage(cv.GetSize(src), src.depth, src.nChannels)

# Iteracja po kolejnych pikselach obrazu


for y in xrange(0, src.height):
for x in xrange(0, src.width):
# Warto zwrócić uwagę na odwrotną kolejność kanałów
b, g, r = src[y, x] # Pobranie wartości jasności piksela

Rysunek 1a. Oryginalny obraz # Kiedy piksel jest czerwony? Gdy wartość jasności koloru
# czerwonego jest wyższa od pozostałych o co najmniej
# pewien próg, tutaj dobrany na 30
DELTA = 30
if r > b + DELTA and r > g + DELTA:
dst[y, x] = ON # Ustaw wartość piksela w obrazie
# wynikowym
else:
dst[y, x] = OFF
Rysunek 1b. Elementy czerwone # Erozja jest efektem pozwalającym wygładzić uzyskany obraz
cv.Erode(dst, dst)
# Wreszcie zapisujemy wyjście do pliku
cv.SaveImage("out_auto_czerwony.bmp", dst)

Listing 3. Wyodrębnienie kanału zielonego

src = cv.LoadImage("budynek.bmp")
# wyodrębnienie poszczególnych kanałów
czerwony = cv.CreateImage(cv.GetSize(src), src.depth, 1)
zielony = cv.CreateImage(cv.GetSize(src), src.depth, 1)
niebieski = cv.CreateImage(cv.GetSize(src), src.depth, 1)
Rysunek 2a. Oryginalny obraz
cv.Split(src, czerwony, zielony, niebieski, None)

# wyzerowanie kanałów innych niż zielony


cv.Zero(czerwony)
cv.Zero(niebieski)

# Ponowne połączenie w obraz


dst = cv.CreateImage(cv.GetSize(src), src.depth, src.nChannels)
cv.Merge(czerwony, zielony, niebieski, None, dst)
cv.SaveImage("budynek_zielony.bmp", dst)

Rysunek 2b. Kanał zielony

www.sdjournal.org 7
Biblioteka miesiąca

nych punktach (pikselach) w obrazie. Dla wykorzystano także efekt erozji, który deli- przedstawiono efekt wyszukiwania elemen-
każdego punktu można obliczyć jego ja- katnie wygładza krawędzie obiektów znaj- tów czerwonych.
sność na poszczególnych kanałach w obra- dujących się na obrazie. Przetwarzanie jednopunktowe pozwala
zie wyjściowym. Nawet taki prosty model OpenCV zapamiętuje wartości pikseli na przykład na manipulowanie rozkładem
jak przetwarzanie jednopunktowe pozwala w kolejnych komórkach tablicy. Są one prze- jasności danego koloru czy modyfikowanie
rozwiązać wiele ciekawych problemów. Na chowywane wierszami, dlatego ze wzglę- kontrastu obrazu, a także wyliczanie pew-
listingu 2 przedstawiono przykład wykry- du na wydajność, warto przeglądać ob- nych statystyk, takich jak histogramy.
wania w obrazie elementów czerwonych. raz w sposób przedstawiony na Listingu Oprócz przetwarzania jednopunktowego
Oprócz przetwarzania jednopunktowego 2 – wiersz po wierszu. Na Rysunku 1a, b wykorzystano także efekt erozji, który deli-
katnie wygładza krawędzie obiektów znaj-
Listing 4. Przetwarzanie wielopunktowe dujących się na obrazie.
Na Rysunku 2a,b przedstawiono efekt
src = cv.LoadImage(nazwa_zrodla, 1) działania kodu z Listingu 3

# Wykrywanie krawędzi – można do tego celu zastosować operator


# Laplace'a
dst = cv.CreateImage(cv.GetSize(src), cv.IPL_DEPTH_16S, 3)
cv.Laplace(src, dst)
cv.SaveImage("out_budynek_krawedzie.bmp", dst)

# Erozja
dst = cv.CreateImage(cv.GetSize(src), src.depth, src.nChannels)
cv.Erode(src, dst)
cv.SaveImage("out_budynek_erozja.bmp", dst)

# Rozmycie – metoda cv.Smooth Rysunek 3a. Oryginalny obraz


dst = cv.CreateImage(cv.GetSize(src), src.depth, src.nChannels)
# CV_BLUR – rodzaj rozmycia, a kolejne liczby to współczynniki
# im większe tym efekt bardziej intensywny
cv.Smooth(src, dst, cv.CV_BLUR, 9, 7, 3, 1)
cv.SaveImage("out_budynek_rozmycie.bmp", dst)

# Konwersja do skali szarości i normalizacja histogramu


dst = cv.CreateImage(cv.GetSize(src), 8, 1)
dst2 = cv.CreateImage(cv.GetSize(src), 8, 1)
cv.CvtColor(src, dst, cv.CV_BGR2GRAY)
cv.EqualizeHist(dst, dst2)
cv.SaveImage("out_budynek_szary1.bmp", dst) # Skala odcieni szarości Rysunek 3b. Wykryte krawędzie
cv.SaveImage("out_budynek_szary2.bmp", dst2)# Dodatkowa normalizacja
# histogramu

# Skalowanie – metoda cv.Resize


dst = cv.CreateImage((128, 128), src.depth, src.nChannels)
# Metoda ta skaluje obraz źródłowy do wymiarów obrazu wynikowego
cv.Resize(src, dst)
cv.SaveImage("out_budynek_miniaturka.bmp", dst)

# Dodanie prostego znaku wodnego


# Obraz, na którym zostanie umieszczony tekst
wmark = cv.CreateImage(cv.GetSize(src), src.depth, src.nChannels)
Rysunek 3c. Erozja
dst = cv.CreateImage(cv.GetSize(src), src.depth, src.nChannels)
# Wyzerowanie tablicy ze znakiem wodnym
cv.Zero(wmark)
# Inicjalizacja czcionki
font = cv.InitFont(cv.CV_FONT_HERSHEY_DUPLEX,2,2,0,1);
# Umieszczenie tekstu na obrazie
cv.PutText(wmark, "Watermark", (400, 80), font, \
cv.CV_RGB(100, 100, 100))
# Suma ważona obrazu źródłowego i znaku wodnego
cv.AddWeighted(src, 1.0, watermark, 1.0, 0.0, dst)
cv.SaveImage("out_budynek_znak_wodny.bmp", dst)

Rysunek 3d. Rozmycie

8 05/2010
Przetwarzanie obrazów za pomocą OpenCV

Przetwarzanie wielopunktowe
Przetwarzanie jednopunktowe jednak jest Listing 5. Przetwarzanie sekwencji wideo
często niewystarczające i do określenia ja-
sności piksela wyjściowego wymagane jest # Pobranie sekwencji z pliku
uwzględnienie wartości innych pikseli ob- # sequence = cv.CaptureFromFile("video.avi")
razu. Tego typu operacji można dokonać
ręcznie lub wykorzystać jedną z wielu wbu- # Pobranie sekwencji z kamery
dowanych w OpenCV funkcji. Przykła- sequence = cv.CaptureFromCAM(0) # argument jest numerem kamery
dem takiej funkcji jest erozja wykorzysta-
# Gdy coś pójdzie nie tak, to sequence == None
if not sequence:
print u"Nie udało się uruchomić kamery"
sys.exit(1)

while 1:
# Pobierz aktualną ramkę z kamery
frame = cv.QueryFrame(sequence)

# Koniec transmisji
if frame is None:
break
Rysunek 3e. Skala szarości
# Kamera daje domyślnie obraz po odbiciu lustrzanym
cv.Flip(frame, None, 1)

# Zrób coś z ramką


# doSomething(frame)

# Oczekiwanie na klawisz
klawisz = cv.WaitKey(10) # Czas w milisekundach

# 'q' = (ASCI) 0x71


if klawisz == 0x71:
print u"Wciśnięto 'q', kończę"
Rysunek 3f. Normalizacja histogramu
break

Instalacja OpenCV 2.0


W przypadku korzystania z systemu Linux prostym rozwiązaniem jest skorzystanie z pakie-
tów znajdujących się w repozytorium dystrybucji (ta metoda jest specyficzna dla danej dys-
trybucji i dlatego nie zostanie tu opisana). W przypadku systemu Windows warto skorzystać
z instalatora:

• Przed instalacją OpenCV należy zainstalować najnowszą wersję interpretera Python


(OpenCV wspiera gałąź 2.x języka), pod adresem http://www.python.org/download/ do-
stępny jest instalator dla Windows.
• Należy pobrać oraz zainstalować OpenCV w wersji 2.0, również korzystając z instalatora
dla systemu Windows, url: http://sourceforge.net/projects/opencvlibrary/
• Trzeba także uaktualnić odpowiednie zmienne systemowe (przyjęto, że OpenCV znajdu-
je się w katalogu C:\OpenCV2.0), można to zrobić we właściwościach systemu (kliknięcie
Rysunek 3g. Skalowanie prawym klawiszem na „Mój komputer”, wybranie opcji właściwości) w zakładce „Zaawan-
sowane”, po wybraniu opcji zmienne środowiskowe. Do zmiennej PATH należy po średni-
ku dopisać C:\OpenCV2.0\bin. A do zmiennej PYTHONPATH C:\OpenCV2.0\Python2.6\Lib\
site-packages

Budowanie ze źródeł
Zbudowanie OpenCV ze źródeł jest dobrym rozwiązaniem wtedy, gdy chcemy mieć dokład-
ną kontrolę nad modułami, które wchodzą w jej skład lub wtedy, gdy nasza dystrybucja sys-
temu Linux nie oferuje tej biblioteki wcale lub w satysfakcjonującej nas wersji. Biblioteka ma
wiele zależności i jej kompilacja może przysporzyć pewnych problemów. Opis kompilacji, jak
i skryptu konfiguracyjnego znajdziemy na stronie OpenCV (http://opencv.willowgarage.com/
wiki/InstallGuide).
Rysunek 3h. Znak wodny

www.sdjournal.org 9
Biblioteka miesiąca

na w wykrywaniu elementów czerwonych.


Listing 6. Wykrywanie twarzy w obrazie z kamery Na Listingu 4 przedstawionych zostało kil-
# Wczytanie modułów ka innych efektów.
import cv Rysunek 3 przedstawia efekt działania
import sys programu.
Inną przydatną metodą może być
# Lokalizacja pliku z parametrami klasyfikatora cv.Filter2D, która pozwala zastoso-
PARAMS = 'C:\OpenCV2.0\data\haarcascades\' + \ wać filtr o dowolnej masce, przekazy-
'haarcascade_frontalface_alt.xml' wanej jako argument. Model w któ-
rym do określenia wynikowej jasności pik-
# Funkcja zaznaczająca twarze w obrazie sela wykorzystuje się wartości jasności pik-
def detect_faces(src): seli znajdujących się w sąsiedztwie został
# Klasyfikatorowi wystarczy wersja w skali szarości nazwany przetwarzaniem lokalnym. Me-
gray = cv.CreateImage(cv.GetSize(src), 8, 1) toda cv.Filter2D jako argument przyj-
cv.CvtColor(src, gray, cv.CV_BGR2GRAY) muje maskę zawierającą wagi, określają-
ce wpływ sąsiadów na wartość jasności
# Poprawienie kontrastu piksela wynikowego. Ta wartość to suma
cv.EqualizeHist(gray, gray) jasności poszczególnych sąsiadów prze-
# Uruchom kaskadę Haara, mnożona przez ich wagi w masce, a na-
# na wejściu należy podać plik z parametrami klasyfikatora, stępnie znormalizowana (poprzez po-
# znajduje się on w dystrybucji OpenCV. dzielenie przez sumę wag wszystkich są-
haarParams = cv.Load(PARAMS) siadów).
faces = cv.HaarDetectObjects(gray, OpenCV zawiera też metody pozwalają-
haarParams, ce rysować figury geometryczne na obrazie
cv.CreateMemStorage(0), wynikowym, a także dokonywać przekształ-
1.2, 3, ceń całego obrazu. Dzięki temu technikę za-
cv.CV_HAAR_DO_CANNY_PRUNING) stosowaną do stworzenia znaku wodnego
# Wreszcie narysuj prostokąty dokoła znalezionych twarzy można także wykorzystać do wygenerowa-
if faces: nia captcha. Każdą literkę można obrócić
for (x, y, w, h), n in faces: o pewien kąt (na przykład za pomocą metod
cv.Rectangle(src, (x, y), (x + w, y + h), cv.2DRotationMatrix oraz cv.WarpAffine)
cv.CV_RGB(255, 0, 0), 3) czy poddać innym zniekształcającym mo-
dyfikacjom; dodatkowo można utrudnić
# Inicjalizacja kamery i okna do wyświetlenia wyniku odczytanie obrazu wynikowego przez za-
print "Naciśnij 'q' aby zakończyć" stosowanie takich metod jak cv.Line czy
cv.DrawContours, które wytworzą na obra-
# Stwórz okno do wyświetlenia wyniku zie dodatkowe artefakty.
cv.NamedWindow('Faces', cv.CV_WINDOW_AUTOSIZE) Przedstawione tu przykłady mają zachę-
cić czytelnika do własnych eksperymentów
cam = cv.CaptureFromCAM(0) z biblioteką, jednak z pewnością nie wy-
if not cam: czerpują możliwości OpenCV, dlatego war-
print "Nie można otworzyć kamery" to też zajrzeć do dokumentacji (patrz ramka
sys.exit(1) „W Sieci”). Zobacz też ramkę „Zaawansowa-
ne możliwości OpenCV”.
# Pętla powtarzająca wykrywanie twarzy dla kolejnych ramek
while 1: Przetwarzanie sekwencji wideo
frame = cv.QueryFrame(cam) OpenCV udostępnia strumienie wideo
if frame is None: w formie kolejnych klatek (ang. frame).
break Każda z nich jest takim samym obiektem
cv.Flip(frame, None, 1)

# Właściwe wykrywanie twarzy


detect_faces(frame)

# Wyświetl obraz z kamery


cv.ShowImage('Faces', frame)
klawisz = cv.WaitKey(10)

# 'q' = (ASCI) 0x71


if klawisz == 0x71:
print "Wciśnięto 'q', kończę"
break Rysunek 4. Wykrywanie twarzy w obrazie
z kamery

10 05/2010
Przetwarzanie obrazów za pomocą OpenCV

jak obrazy, które przetwarzaliśmy wcze- kolejnej klatki jest niezależne od poprzed- Przykład aplikacji – wykrywanie
śniej. Powoduje to, że przetwarzanie se- niej, ale oczywiście nic nie stoi na przeszko- twarzy w obrazie z kamery
kwencji wideo nie różni się zasadniczo od dzie aby pamiętać część wartości lub cech Ostatnim elementem potrzebnym do zbu-
przetwarzania obrazów statycznych. Se- poprzednich klatek. Wtedy w obliczaniu dowania systemu wykrywającego twarze
kwencja może być pobierana z pliku lub jasności wynikowej danego piksela zosta- jest klasyfikator – funkcja która otrzymaw-
w czasie rzeczywistym z kamery. Listing nie uwzględniony kolejny wymiar – czas. szy obraz znajdzie na nim twarze. Tworze-
5 przedstawia przykład pracy ze strumie- Poprzez porównywanie z historycznymi nie klasyfikatorów rozpoznających obiekty
niami wideo. klatkami można określić na przykład zmia- znajdujące się na obrazie jest bardzo cieka-
Ten ogólny schemat zostanie uzupeł- ny pojawiające się na obrazie, takie jak po- wym problemem, któremu poświęcono wie-
niony w następnym punkcie, tak aby uzy- jawienie się nowych obiektów na obrazie, le prac naukowych; niestety zdecydowanie
skać aplikację, która będzie potrafiła zna- przemieszczenie się już istniejących obiek- wykracza on poza zakres zagadnień prezen-
leźć twarze w obrazie z kamery. W przed- tów, czy zmiana jasności wynikająca na towane w tym artykule. Dlatego zostanie tu-
stawionym powyżej modelu przetwarzanie przykład z nadejścia nocy. taj zostanie wykorzystany istniejący i spraw-
dzony już klasyfikator. Doskonale nadaje się
do tego kaskada Haara, która dodatkowo
OpenCV i Python jest wbudowana w OpenCV (opis działania
Biblioteka OpenCV napisana jest w C, jednak oferuje też API dla innych języków, a w szcze-
gólności dla języka Python. W wersji 1.x biblioteki dostępny był wrapper dla Python stwo- – patrz ramka „W Sieci”). Po wczytaniu pli-
rzony za pomocą narzędzia SWIG (funkcje dostępne były w pakietach opencv.cv oraz ku zawierającego parametry pracy kaskady
opencv.highgui). Jest on tutaj wspomniany, ponieważ można go znaleźć w wielu przykła- (również dołączonego do OpenCV) zwra-
dach dla wersji 1.1 opublikowanych w Internecie. W wersji 2.0 wprowadzono nowe API dla ca ona lokalizację twarzy odnalezionych na
Python (pakiet cv) . W artykule skupiono się właśnie na tym interfejsie, gdyż jest on bardziej
obrazie. Kod programu przedstawiono na
zgodny z „zen” języka Python, a programowanie z jego pomocą jest łatwiejsze przy tej samej
oferowanej funkcjonalności. Warto zwrócić uwagę, że poprzednia wersja jest nadal dostęp- Listingu 6.
na, jeśli ktoś pragnie uruchomić kod napisany dla wersji 1.x. Opis starego wrappera można Efekt działania programu można zoba-
zaleźć pod adresem http://opencv.willowgarage.com/wiki/SwigPythonInterface, a krótki opis czyć na Rysunku 4.
różnic: http://opencv.willowgarage.com/wiki/PythonInterface.
Podsumowanie
Konieczność przetwarzania obrazów, czy
to statycznych, czy sekwencji wideo wy-
Zaawansowane możliwości OpenCV stępuje w wielu dziedzinach życia. Prawdo-
W artykule przedstawiono tylko niektóre z możliwości biblioteki OpenCV. Biblioteka znajdu-
je zastosowanie w wielu obszarach znanych z Computer Vision (polski termin „przetwarzanie podobnie każdy z czytelników zetknął się
obrazów” jest trochę węższy, dlatego autor pozostanie tutaj przy odpowiedniku angielskim) z jednym z wielu zastosowań tej dyscypli-
oraz uczeniem maszynowym, takich jak: ny. W artykule pokazano, że do wykonania
wielu operacji nie potrzeba dedykowanych
• Przetwarzanie obrazów 2D i 3D;
rozwiązań sprzętowych ani specjalistycz-
• Detekcja obiektów;
• Rozpoznawanie twarzy; nego oprogramowania. Przedstawiono bi-
• Rozpoznawanie ruchu; bliotekę OpenCV, która doskonale spraw-
• Rozpoznawanie gestów; dza się w tej kategorii zastosowań. Pokaza-
• Przetwarzanie obrazów w czasie rzeczywistym; no kilka częstych przypadków użycia, a tak-
• Stereowizja; że wskazano, gdzie można szukać dalszych
• Robotyka.
informacji. Przetwarzanie obrazów jest za-
Biblioteka zawiera także implementację wielu algorytmów uczenia maszynowego (głównie gadnieniem trudnym – to co człowiekowi
klasyfikatorów), co umożliwia na przykład nie tylko rozpoznawanie twarzy, ale także przypisa- wydaje się oczywiste i naturalne jest często
nie jej do konkretnej osoby z bazy danych. niemożliwe do opisania za pomocą kompu-
OpenCV oferuje interfejs programistyczny w językach C, C++ oraz C# i Python. terowych algorytmów. Model przechowy-
wania oraz przetwarzania obrazów wyko-
rzystywany w systemach komputerowych
zdecydowanie różni się od postrzegania
W Sieci środowiska przez człowieka. Autor ma na-
• http://python.org/ - strona domowa interpretera python; dzieję, że biblioteka OpenCV oraz ten ar-
• http://sourceforge.net/projects/opencvlibrary/ - strona projektu OpenCV na sourcefor- tykuł choć trochę ułatwią rozwiązywanie
ge.net; problemów z tego ciekawego, choć skom-
• http://opencv.willowgarage.com/wiki/Welcome - dokumentacja OpenCV; plikowanego zagadnienia, a także, że zachę-
• http://opencv.willowgarage.com/documentation/python/index.html - dokumentacja inter-
cił czytelników do własnych eksperymen-
fejsu OpenCV dla języka Python;
• http://tech.groups.yahoo.com/group/OpenCV/messages - archiwum listy mailingowej tów z przetwarzaniem obrazów.
użytkowników OpenCV, można tam znaleźć rozwiązanie wielu problemów, jak i przykła-
dy ciekawych zastosowań OpenCV;
• http://myopencv.wordpress.com/ - zbiór poradników przedstawiający ciekawe zastosowa- IGOR KUPCZYŃSKI
nia OpenCV (autor korzysta z interfejsu dla języka C, nie Python; jednak stworzenie ana- Igor Kupczyński jest pracownikiem STX Next sp.
logicznych programów w języku Python nie powinno nastręczyć większych problemów
zainteresowanemu czytelnikowi); z o.o. gdzie zajmuje się głównie oprogramowa-
• http://opencv.willowgarage.com/documentation/python/object_detection.html?highli- niem tworzonym w języku Python. Do jego za-
ght=haardetectobjects#haar-feature-based-cascade-classi�er-for-object-detection – opis interesowań należą statystyka, analiza danych
działania klasyfikatora Haara. oraz systemy wspomagania decyzji.
Kontakt z autorem: igor@kupczynski.cc

www.sdjournal.org 11
Klub techniczny

Pydev
Python w Eclipse

Dla języka Python istnieje wiele edytorów. Poczynając od konsolowych,


takich jak vim, przez dedykowane, jak IDLE, kończąc na wielo-
językowych platformach programistycznych, jak Netbeans lub Eclipse.
Niniejszy artykuł prezentuje wykorzystanie popularnego Eclipse do
rozwoju aplikacji w Pythonie.

otworzyć okno preferencji (Window –> Prefe-


Dowiesz się: Powinieneś wiedzieć: rences) i przejść do sekcji Pydev.
• Jak skonfigurować Eclipse do pracy z Pytho- • Znajomość środowiska Eclipse; Pydev obsługuje interpretery CPythona,
nem; • Znajomość narzędzia buildout. Jythona i IronPythona. Należy otworzyć pre-
• Jak podłączyć projekt buildout do Eclipse; ferencje wybranego interpretera (np. Inter-
• Jakie udogodnienia oferuje Eclipse progra- preter – Python). Konfiguracji interpretera
mistom Pythona. dokonuje się przez wskazanie jego pliku wy-
konywalnego (lub pliku jar w przypadku Jy-
thona). Pydev może także spróbować auto-
leży zatwierdzić wszystkie dalsze okna dialo- matycznie znaleźć interpreter zainstalowany
gowe i pozwolić na ponowne uruchomienie w systemie (przycisk Auto Config).
Poziom Eclipse. Po ponownym uruchomieniu, Pydev Pydev automatycznie wykrywa zainsta-
trudności powinien być zainstalowany. lowane dla danego interpretera biblioteki.
Alternatywnym sposobem instalacji jest W oknie konfiguracji interpretera można
użycie usługi Yoxos OnDemand, która pozwa- ręcznie dodać dodatkowe biblioteki do PY-
la w łatwy sposób przygotować własną dystry- THONPATH.
Możliwości bucję środowiska Eclipse. Na stronie [3] moż- Pydev analizuje wykryte biblioteki i zapa-
na wybrać, jakie funkcjonalności Eclipse nas miętuje znalezione w nich symbole, których
• Kreatory; interesują, usługa dobierze ich zależności i po- używa potem m.in. w dopełnianiu składni.
• Podświetlanie składni; zwoli na pobranie IDE wraz z dodatkami w po- Oznacza to, że po instalacji nowych bibliotek
• Formatowanie kodu; staci jednego archiwum. Użycie Yoxos OnDe- należy odświeżyć bazę symboli Pydev. Można
• Szablony; mand jest przyjemniejsze niż ręczna instalacja tego dokonać, wybierając akcję Apply na ekra-
• Dopełnianie kodu; pakietów z domyślnej instalacji Eclipse, szcze- nie konfiguracji interpretera. Zmusza to Py-
• Automatyczne importy; gólnie jeśli potrzebujemy wielu wtyczek (typo- dev to ponownego przeskanowania bibliotek.
• Wyświetlanie dokumentacji; wy Pythonowiec zainstaluje zapewne Pydev, Konfiguracja interpretera wystarcza, aby
• Zwijanie bloków kodu; edytory HTML, CSS oraz JavaScript, wtycz- rozpocząć korzystanie z Pydev.
• Zamiana tabulacji na spacje i na odwrót; ki do systemów wersjonowania). Wadą usługi
• Usuwanie plików .pyc z projektu; mogą być starsze wersje niektórych pakietów. Projekt
• Statyczna analiza kodu; Usługa posiada wyszukiwarkę pakietów. Aby Aby rozpocząć pracę z Pydev, należy utwo-
• Refactoring; przygotować podstawową wersję Eclipse dla rzyć nowy projekt. W tym celu wybieramy
• Interaktywna konsola; Pythona, należy wybrać z grupy Programming z menu File –> New –> Project..., następnie
• Wsparcie dla testów jednostkowych; languages komponent Pydev for Eclipse (opcjo- wybieramy z grupy Pydev opcję Pydev project.
• Debugger; nalnie także Pydev Extensions), wybrać Add the Kolejny ekran pozwala na wybór typu (CPy-
• Zdalny debugger. selected components to the Plan i zaakceptować thon, Jython, IronPython) i instancji inter-
zależności. Po kliknięciu przycisku Start Do- pretera oraz wersji gramatyki języka. Wer-
Instalacja wnload rozpocznie się pobieranie. Yoxos On- sja gramatyki nie musi być koniecznie zgod-
Obsługę Pythona można w prosty sposób do- Demand oferuje także funkcjonalność szablo- na z wersją interpretera, przykładowo moż-
instalować do istniejącej instalacji Eclipsa. nów, dzięki czemu można łatwo współdzielić na tworzyć projekt z gramatyką Python 2.4
W tym celu należy przejść do ekranu insta- w organizacji przygotowaną wersję IDE. za pomocą interpretera Python 2.6.
lacji oprogramowania (Help –> Install new so- Wybór opcji Create default 'src' folder and
ftware). Następnie należy dodać (Add) nową Konfiguracja add it to the pythonpath? zależy od preferencji
witrynę z repozytorium Pydev [2]. Ze spisu Przed pierwszym użyciem dodatku Pydev programisty. Zaznaczenie tej opcji spowoduje
pakietów należy wybrać Pydev for Eclipse. Na- należy go skonfigurować. W tym celu należy utworzenie w projekcie osobnego podkatalo-

12 05/2010
Eclipse IDE

gu na źródła. Dodać katalog ze źródłami moż- łać ręcznie przez domyślną kombinację kla- Pydev wyświetla dokumentację używa-
na w dowolnym momencie, otwierając okno wiszy CTRL+spacja. Dopełnianie jest kon- nych symboli. W domyślnej konfiguracji
właściwości projektu. W nim należy przejść tekstowe, przykładowo przy dopełnianiu wy- (można zmienić w opcjach) po najechaniu
do sekcji Pydev – PYTHONPATH. Na za- rażenia self. Pydev podpowiada składowe kla- kursorem na symbol w okienku popup jest
kładce Source folders można dodać katalogi sy oraz jej nadklas. wyświetlana dokumentacja symbolu.
projektu do ścieżki za pomocą akcji Add so- Pydev posiada mechanizm automatycz- Pydev pozwala na definiowanie szablonów,
urce folder. Programiści, którzy preferują trzy- nych importów. Użycie w dopełnianiu sym- umożliwiających przyspieszenie wpisywa-
mać moduły Pythona bezpośrednio w katalo- bolu z niezaimportowanego modułu spowo- nia powtarzających się kawałków kodu. Sza-
gu głównym projektu, powinni dodać cały ka- duje automatyczne dodanie wyrażenia im- blony wykorzystuje się, używając ich nazwy
talog projektu jako Source folder. port do edytowanego pliku. w dopełnianiu kodu. Często używanym sza-
W konfiguracji PYTHONPATH projektu,
na zakładce External libraries można zdefi- Listing 1. Przykładowa kon�guracja Pydev w buildout.cfg
niować dodatkowe biblioteki używane w pro-
jekcie. [buildout]
parts = app pydev
Integracja z buildout develop = .
Konfiguracji zewnętrznych bibliotek można [app]
dokonać automatycznie, jeśli projekt korzy- recipe = zc.recipe.egg:scripts
sta z narzędzia buildout. Dla buildouta istnie- eggs = my.project
je recepta pb.recipes.pydev, która uaktualnia
plik konfiguracyjny projektu (.pydevproject) [pydev]
na podstawie zmiennych buildouta. Recep- recipe = pb.recipes.pydev
ta potrafi tylko uaktualnić istniejącą konfi- eggs = ${app:eggs}
gurację, nie potrafi utworzyć jej od zera, stąd pydevproject_path = ${buildout:directory}/.pydevproject
przed jej wykorzystaniem projekt Eclipsowy
musi już istnieć. Aby użyć recepty w swoim
Listing 2. Dodatkowa kon�guracja Pydev dla instancji Zope w buildout-dev.cfg
projekcie, należy dodać nową sekcję do pli-
ku buildout.cfg. Przykładowy zmodyfikowa-
ny plik przedstawia Listing 1. [buildout]
Parametr eggs w sekcji pydev wskazu- extends = buildout.cfg
je, które biblioteki należy podłączyć do Py- parts +=
dev. Parametr pydevproject_path pozwala make_pydev_init_files
określić położenie pliku konfiguracyjnego. pydev
Dodatkowo można użyć parametru extra_
paths, aby wyspecyfikować wiele dodatko- [make_pydev_init_files]
wych ścieżek. recipe = iw.recipe.cmd:py
Konfiguracja dodatkowych ścieżek jest on_install=true
szczególnie użyteczna w przypadku bardziej cmds =
skomplikowanych projektów, w których kod >>> dirs = """${instance:products}""".split("\n")
jest rozrzucony w wielu miejscach. Dobrym >>> prodlinks = os.path.join("""${buildout:directory}""".strip() ,
przykładem jest tu instancja Zope/Plone, 'prodlinks')
która posiada w osobnych miejscach eggi, bi- >>> Products = os.path.join(prodlinks,'Products')
blioteki Zope oraz wiele produktów współ- >>> import os
egzystujących w przestrzeni nazw Products. >>> if not os.path.isdir(prodlinks): os.mkdir(prodlinks)
Przydatna jest tu recepta przedstawiona >>> if not os.path.isdir(Products): os.mkdir(Products)
w Listingu 2, która oprócz podłączania do >>> open(os.path.join(Products , '__init__.py'),'w').write('#')
Pydev bibliotek Zope, tworzy linki symbo- >>> for dir in dirs:
liczne do wszystkich produktów w jednym >>> if dir:
katalogu, który można podczepić do Pydev >>> for product in [os.path.join(dir,a) for a in os.listdir(dir)
(należy zwrócić uwagę, że recepta wyma- if os.path.isdir(os.path.join(dir,a))]:
ga, aby katalog prodlinks został utworzony >>> linkname = os.path.join(Products, os.path.basename(produc
wcześniej). t))
Po zamknięciu i ponownym otwarciu pro- >>> if not os.path.islink(linkname): os.symlink(product,linkn
jektu w Eclipse ścieżki do bibliotek powinny ame)
być ustawione, co można sprawdzić w sek-
cji Pydev – PYTHONPATH okna właściwo- [pydev]
ści projektu. recipe = pb.recipes.pydev
pydevproject_path = ${buildout:directory}/src/my.product/.pydevproject
Dopełnianie kodu eggs =
Pydev potrafi dopełniać kod Pythona. Dopeł- ${instance:eggs}
nianie odbywa się automatycznie (m.in. po extra_paths =
wpisaniu kropki za wyrażeniem, konfiguro- ${zope2:location}/lib/python
walne w opcjach Pydev) lub można je wywo-

www.sdjournal.org 13
Klub techniczny

blonem jest pd, który wstawia w miejscu kur- ny skrót klawiszowy CTRL+/), tworzyć ko- zawierający już szablon opisu parametrów (li-
sora zatrzymanie PDB: import pdb;pdb.set_ mentarze blokowe (domyślna kombinacja nie @param name: dla każdego parametru).
trace(). Własne szablony można dodawać w CTRL+4). Edytując docstring i wywołując dopełnianie
preferencjach Window –> Preferences –> Pydev Pydev obsługuje wstawianie komentarzy składni, Pydev podpowiada też inne elemen-
–> Editor –> Templates. typu docstring. Ustawiając kursor na nazwie ty docstringów, np. @author lub @rtype.
funkcji lub klasy w ich definicji, można z me-
Komentarze nu Quick fix, dostępnego pod skrótem kla- Przeglądanie
Pydev pomaga przy tworzeniu komentarzy. wiszowym CTRL+1, wybrać opcję Make do- Z pomocą dodatku Pydev można w łatwy
Potrafi zakomentować linie kodu (domyśl- cstring. Dla funkcji Pydev wstawi komentarz sposób przeglądać kod. Edytor Pydev'a umoż-
liwia zwijanie kodu importów, funkcji lub
klas. Na symbolach można wykonać akcję Go
to definition (domyślny klawisz F3), która
przenosi do definicji symbolu. Na atrybucie,
funkcji lub klasie przeniesie do jej definicji,
Pydev automatycznie otwiera plik źródłowy.
Działa to także dla klas bibliotecznych.
Kolejną funkcją Pydev'a jest zaznacza-
nie wystąpień danego tokenu w całym pli-
ku. Jest to przydatne, jeśli chcemy się do-
wiedzieć, gdzie używana jest dana zmienna,
funkcja lub import. Aby podświetlić wszyst-
kie wystąpienia tokenu, wystarczy naprowa-
dzić kursor na token. Wystąpienia zostaną za-
znaczone w kodzie żółtym podświetleniem,
dodatkowo na prawej krawędzi okna edyto-
ra (obok paska przewijania) zostaną wyświe-
tlone znaczniki pozwalające łatwo przejść do
wystąpień tokenu.
Pydev posiada wbudowaną przeglądarkę
symboli pozwalającą szybko znaleźć klasy,
metody, pola lub zmienne globalne na pod-
stawie (części) ich nazwy. Przeglądarkę moż-
na uruchomić z menu Pydev –> Globals brow-
ser lub za pomocą kombinacji CTRL+Shift+T

Refactoring
Rysunek 1. Instalacja Pydev Pydev obsługuje skromny zasób przekształ-
ceń kodu. Możliwe przekształcenia:

• Rename
• Extract method
• Inline local variable
• Extract local variable

Dodatkowo Pydev wyposażony jest w opcje


automatycznej generacji kodu:

• Override/Implement methods
• Generate propeties (tworzenie
getterów/setterów z wykorzystaniem
property)
• Generate Constructor using Fields

Przekształcenia dostępne są w menu Refac-


toring.

Interaktywna konsola
Interaktywną konsolę można otworzyć za po-
mocą kombinacji CTRL+ALT+Enter. Jeśli do-
stajemy w konsoli błędy o niemożności połą-
czenia z konsolą, należy przestawić w opcjach
Window –> Preferences –> Pydev –> Interac-
Rysunek 2. Kon�guracja interpretera tive Console parametr Maximum connection

14 05/2010
Eclipse IDE

attempts for initial communication na • Expressions - wyświetla zdefiniowane zmiennej, której wartość chcemy zmienić,
większą wartość. śledzone wyrażenia i ich wartości. wybrać Change value i wpisać nową wartość
Interaktywna konsola oferuje funkcje po- w polu tekstowym.
dobne jak edytor, m.in. dopełnianie kodu, Aby dodać wyrażenie do śledzonych wy- Klikając na elementach stosu wywołań w pa-
wyświetlanie dokumentacji, automatyczne rażeń, wystarczy zaznaczyć je w edyto- nelu Debug, można poruszać się w górę i w dół
importy, szablony. Interaktywna konsola, gdy rze i z menu kontekstowego wybrać opcję stosu, dzięki czemu można zobaczyć, skąd zo-
uruchomiona w kontekście edytora, ma po- Watch. Wyrażenie będzie wyświetlane w pa- stała wywołana funkcja, w której zatrzymał się
prawnie skonfigurowane zewnętrzne biblio- nelu Expressions. debugger. Edytor automatycznie przełączy się
teki projektu, więc ma dostęp do tych samych Wartości zmiennych oprócz panelu Va- na odpowiednią pozycję w pliku ze źródłem.
symboli co kod w edytorze. Konsola posiada riables można podejrzeć także, najeżdżając
możliwość zapisania treści sesji do pliku tek- kursorem na zmienną w edytorze. Wartości Zdalne debuggowanie
stowego, który może być natychmiast wyko- zmiennych można edytować w czasie działa- Pydev umożliwia zdalne debuggowanie progra-
rzystany jako doctest. nia programu. W tym celu w panelu Varia- mów. Dzięki temu można używać debuggera
Linki do plików pojawiające się w konsoli bles należy wywołać menu kontekstowe na z Eclipse w skryptach uruchamianych nie z we-
są klikalne i przenoszą do pliku źródłowego.
Można dzięki temu błyskawicznie zobaczyć,
w którym miejscu kodu wystąpił wyjątek.

Testy jednostkowe
Pydev w ograniczonym zakresie wspiera testy
jednostkowe. Aby szybko utworzyć przypadek
testowy, należy w kreatorze nowego modułu
Pythona wybrać szablon Module: Unittest lub
Module: Unittest with setUp and tearDown.
Uruchomienie testu jednostkowego jest
możliwe przez opcję Run as –> Python unit-
test. Komunikaty testowania są wypisywa-
ne na konsolę. Traceback błędu jest klikalny,
można przejść od razu do pliku źródłowego,
w którym wystąpił błąd.

Debugger
Pydev pozwala na używanie Eclipsowego
debuggera do pracy ze skryptami Pythona.
Można definiować punkty wstrzymania (bre-
akpoint) przez dwukrotne kliknięcie na le-
wej linijce edytora. Dodatkowo można zde-
finiować warunek, który musi być spełniony,
Rysunek 3. Dopełnianie kodu
aby wykonanie zostało wstrzymane w danym
punkcie. Warunki można dodać, wywołując
menu kontekstowe na ikonie punktu wstrzy-
mania i wybierając Breakpoint properties. Na-
stępnie należy zaznaczyć opcję Enable Con-
dition i wpisać warunek (np. a != 0) w po-
lu tekstowym.
Aby uruchomić skrypt w trybie debug, na-
leży wybrać opcję Debug As –> Python Run.
Eclipse przełączy się na perspektywę Debug.
Perspektywa ta oprócz paneli edytora, konso-
li i Outline posiada dodatkowo panele:

• Debug - wyświetla wątki i ich stos wy-


wołań, pozwala manipulować przebie-
giem programu (przejście do następnej
linii, przejście wgłąb, skok do wyjścia
z aktualnej funkcji, wznowienie działa-
nia skryptu).
• Variables - wyświetla zmienne i ich war-
tości; dla zmiennych złożonych ich war-
tość wyświetlana jest w postaci rozwijal-
nego drzewa.
• Breakpoints - wyświetla znajdujące się
w projekcie punkty wstrzymania. Rysunek 4. Pydev w akcji

www.sdjournal.org 15
Klub techniczny

wnątrz Eclipse lub w skryptach działających na Punkty wstrzymania wstawia się w spo- Opcjonalnym argumentem do settrace jest
innych maszynach. Pydev zawiera w sobie ser- sób podobny jak dla pdb. Należy w kodzie, adres IP maszyny, na której uruchomiony
wer debuggera, który należy ręcznie urucho- w miejscu, gdzie chcemy, aby wykonanie zo- jest serwer debuggera. Jeśli Eclipse i debug-
mić. Można zrobić to przez akcję Pydev: start the stało przerwane, wstawić gowany skrypt działają na tej samej maszy-
pydev server na perspektywie Debug. Serwer bę- nie, argument można pominąć.
dzie uruchomiony w tle i czekał na połączenia. import pydevd;pydevd.settrace('172.16.97.1') Do poprawnego działania debuggera
w zdalnym skrypcie, musi on mieć dostęp
do skryptu pydevd. Skrypt ten należy wydo-
być z katalogu wtyczek Eclipse. Przykładowa
ścieżka do katalogu ze źródłami to

eclipse/plugins/org.python.pydev.debug_
1.5.4.2010011921/pysrc

Katalog ten musi znaleźć się w PYTHON-


PATH skryptu, który chcemy debuggować.
Przykładowa komenda do uruchomienia
skryptu wygląda więc następująco:

PYTHONPATH=.:~/eclipse/plugins/
org.python.pydev.debug_
1.5.4.2010011921/pysrc python -m
my.project.test

Uruchomiony skrypt zostanie wstrzy-


many, gdy dojdzie do instrukcji
pydevd.settrace(). Skrypt połączy się z ser-
werem debuggera, Eclipse pokaże przyłączo-
ny proces, dalej z debuggera można korzy-
Rysunek 5. Interaktywna konsola stać w normalny sposób.

Podsumowanie
W niniejszym artykule starałem się pokazać
możliwości Eclipse jako platformy do pro-
gramowania w Pythonie. Pydev jako edytor
jest w stanie bardzo ułatwić pracę progra-
misty przez dopełnianie składni i wykrywa-
nie błędów, jako debugger pozwala na uży-
cie zachwalanego debuggera z Eclipse do
pracy ze skryptami Python, łatwo integruje
się z bardzo popularnym systemem buildo-
ut. Wszystko to sprawia, że Eclipse jest kom-
pleksowym i wygodnym narzędziem pracy
dla programistów Pythona. Prawdą jest, że
możliwości narzędzi pythonowych odbiega-
ją funkcjonalnością od narzędzi dla Javy, ale
wynika to po części ze specyfiki samego ję-
zyka. Mam nadzieję, że udało mi się zachę-
cić do wypróbowania Pydev na własnej skó-
rze tym, którzy jeszcze z niego nie korzysta-
li, a starzy wyjadacze być może znaleźli opis
nowych funkcji, z których do tej pory nie ko-
rzystali.

Rysunek 6. Pydev debugger


TOMASZ MAĆKOWIAK
W Sieci Pracuje jako Developer w �rmie STX Next. To-
mek specjalizuje się w technologiach webowych
• [0] Strona pobierania środowiska Eclipse http://www.eclipse.org/downloads/
wykorzystujących Pythona i JavaScript. W swo-
• [1] Strona domowa projektu Pydev http://Pydev.org/
• [2] Eclipsowa witryna pobierania Pydev http://Pydev.org/updates jej dotychczasowej pracy zajmował się również
• [3] Yoxos OnDemand – tworzenie spersonalizowanych wersji Eclipse tworzeniem aplikacji w GWT/GXT. Posiada dobrą
http://ondemand.yoxos.com/geteclipse/start znajomość Javy, w tym J2ME.
Kontakt z autorem:kurazu@kurazu.net

16 05/2010
Opis DVD

Programowanie w języku Java Podstawową formą konfiguracji w Struts2 jest plik XML.
O ile istnieje wielu zwolenników tej formy pracy z aplikacjami
Od Witaj świecie do aplikacji korporacyjnych. internetowymi, to utrzymanie złożonych aplikacji staje się kło-
Szkieletu aplikacji Struts2 potliwe. Alternatywną formą konfiguracji mogą być adnotacje
stosowane na poziomie kodu źródłowego, czyli w tym przypad-
Ósmy odcinek wideo kursu ma charakter warsztatowy. Je- ku – akcji, umożliwiające zdefiniowanie informacji, które znaj-
go celem jest rozwój aplikacji do zarządzania konferencjami dują się plikach struts.xml.
wprowadzając mechanizmy Struts2. Ponadto zostanie omówiona wtyczka o nazwie Convention,
W poprzednim odcinku został nakreślone podstawowe dzięki której programista otrzymuje narzędzie, umożliwiające
zasady posługiwania się akcjami, znacznikami na stronach zminimalizowanie niezbędnej konfiguracji poprzez wprowa-
JSP oraz plikiem konfiguracyjnym. W tym odcinku zdoby- dzenie konwencji. Dzięki temu rozwiązaniu, nie musimy pre-
te wcześniej umiejętności zostaną poszerzone i pogłębione cyzować wielu szczegółów, które wynikają z kontekstu tworzo-
w trakcie budowy funkcjonalności dodawania nowych konfe- nego rozwiązania.
rencji oraz wyświetlania ich listy. W oparciu o Struts2 zosta-
nie zbudowany przykładowy przepływ akcji i widoków JSP, Python Eclipse IDE
przedstawiona zostanie szczegółowo komunikacja między
akcjami a widokami JSP. Materiały do artykułów

Jeśli nie możesz


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

17
Narzędzia

Buildout
Narzędzie automatyzujące budowę i zarządzanie
aplikacjami w języku Python
W trakcie rozwoju aplikacji ilość zależnych bibliotek stopniowo się
zwiększa. Ręczne zarządzanie projektem staje się mało wygodne,
a instalacja oprogramowania na nowej maszynie wydłuża się. Użycie
narzędzia Buildout pozwoli zautomatyzować większość tych czynności
i ułatwi pracę programistom i administratorom.
Inne często używane foldery, lecz nie będą-
Dowiesz się: Powinieneś wiedzieć: ce tworzone podczas pierwszego urucho-
• Jak tworzyć pliki konfiguracyjne buildout; • Podstawy obsługi linii komend Unix; mienia, to:
• Jak instalować aplikacje używając buildout; • distutils – mechanizm dystrybucji pakietów.
• Poznasz najciekawsze dodatki do buildout. • etc – pliki konfiguracyjne;
• src – kod źródłowy;
• var – miejsce na dane, np. baza danych,
otstrap.py) oraz plik konfiguracyjny (buildo- pliki logów itp.
ut.cfg). Zadaniem skryptu rozruchowego jest
Poziom stworzenie podstawowego środowiska, dzięki Generowany jest także skrypt ./bin/buildout
trudności któremu buildout będzie mógł wykonać swo- – wykonujący cały proces budowy aplikacji.
je zadania. W przypadku gdy na komputerze,
na którym jest on uruchamiany, brak jest od- Pliki konfiguracyjne
powiednich bibliotek, zostaną one ściągnięte Konfigurację projektu definiuje się w plikach
z Internetu. w formacie ConfigParser (potocznie zwanym
INI). Plik taki składa się z sekcji, a każda sek-

S
ystem Buildout jest podstawowym $ cd simple-site cja zawiera pary klucz – wartość. Za działanie
sposobem na budowanie i dystrybu- $ touch buildout.cfg każdej z sekcji odpowiedzialna jest tak zwana
cję takich projektów składających się $ wget http://tinyurl.com/bootstrap-py recepta (ang. recipe). Uruchomienie systemu
z setek czy dziesiątek bibliotek – Plone, Zo- $ python bootstrap.py buildout jest zatem w rzeczywistości wykona-
pe, Grok. Ułatwia także instalację innych pro- niem serii plug-in'ów budujących poszczegól-
jektów – np.: Django, Pylons, repoze.bfg. Zo- Po uruchomieniu skryptu następuje ścią- ne części składowe projektu. Taki mechanizm
stał napisany w języku Python z myślą o bu- gnięcie i zainstalowanie pakietu zc.buildout, wtyczek pozwala w łatwy sposób rozszerzyć
dowaniu aplikacji w tym samym języku, ale a więc rdzenia systemu. Tworzona jest także podstawową funkcjonalność systemu.
nie tylko. struktura folderów: Zmienne między sekcjami można pobierać
Do zademonstrowania możliwości ofero- poprzez strukturę ${nazwa-sekcji:klucz}.
wanych przez Buildout posłużę się aplikacją • bin – zawiera wygenerowane skrypty; Podstawowe parametry działania skryptu de-
SimpleSite – będącą przykładem strony zbu- • downloads – miejsce, do którego są ścią- finiuje się w sekcji [buildout]. W parame-
dowanej przy użyciu framework-u Pylons. gane paczki; trze parts określona jest lista sekcji, które po-
Jej szerszy opis można znaleźć w „Definitive • eggs – miejsce instalacji pakietów i bi- winny zostać zbudowane.
Guide to Pylons” (http://pylonsbook.com). bliotek Pythona; Przykładowy projekt składać ma się z pa-
• parts – inne biblioteki lub oprogramo- kietu SimpleSite. Pakiet ten dostępny jest
Instalacja wanie. w repozytorium pakietów Python (PyPI
Do instalacji Buildout wymagany jest jedy-
nie interpreter języka Python oraz dostęp do Listing 1. Wynik wykonania skryptu rozruchowego
Internetu. W przypadku instalowania pakie-
tów binarnych potrzebne jest zainstalowanie $ python bootstrap.py
Pythona w wersji deweloperskiej. Nie są wy- Creating directory ‘/tmp/simple-site/bin’.
magane prawa administratora, gdyż wszyst- Creating directory ‘/tmp/simple-site/parts’.
kie operacje wykonywane są w lokalnym Creating directory ‘/tmp/simple-site/eggs’.
folderze i nie wpływają na pozostałe zain- Creating directory ‘/tmp/simple-site/develop-eggs’.
stalowane programy. Na początek potrzeb- Generated script ‘/tmp/simple-site/bin/buildout’.
ne są dwie rzeczy – skrypt rozruchowy (bo-

18 05/2010
Buildout

– ang. Python Package Index) pod adresem Aby zbudować projekt, należy teraz uru- zainstalowana żadna biblioteka do komu-
http://pypi.python.org/pypi/SimpleSite. Do uru- chomić wygenerowany podczas instalacji nikacji z bazą SQL. Do czasu wdrożenia
chomienia tej aplikacji potrzebny będzie ser- skrypt ./bin/buildout. Ściągnie on i zainsta- aplikacji na serwer produkcyjny wystarczy
wer HTTP wspierający standard WSGI. Naj- luje wszystkie zależne pakiety. Zależności te, prosta implementacja – SQLite. Koniecz-
prostszym rozwiązaniem jest użycie zaimple- zgodnie ze standardem przyjętym dla biblio- ne jest zatem dodanie pakietu pysqlite
mentowanego w Pythonie serwera Paste. By tek języka Python, a więc distutils, określa- do projektu. Jest to pakiet binarny, a więc
móc go łatwo uruchomić wprost z listy pole- ne są w pliku setup.py każdej z paczek. W oma- do instalacji konieczny jest kompilator
ceń, potrzebny jest PasteScript instalowany wianym przypadku głównymi składnikami, GCC, a także pliki nagłówkowe Pytho-
przez receptę zc.recipe.egg:scripts. bez których projekt nie może działać, jest Py- na. Te elementy muszą być zainstalowane
lons (framework, na bazie którego zbudowana w systemie. Wymagana jest także bibliote-
Listing 2. Zawartość pliku buildout.cfg jest aplikacja) oraz Mako (system szablonów). ka SQLite. Ponieważ w systemie mogą wy-
Teraz można przystąpić do pierwsze- stępować inne programy używające SQLi-
[buildout] go uruchomienia aplikacji. W tym celu ko- te w innych wersjach, wolimy, aby biblio-
parts = paster nieczne jest wygenerowanie konfiguracji oraz teka była zainstalowana w lokalnym fol-
eggs = SimpleSite utworzenie bazy danych. derze. W tym celu użyta zostanie recep-
ta zc.recipe.cmmi (skrót od configure-
[paster] $ ./bin/paster make-config SimpleSite make-make-install).
recipe = zc.recipe.egg:scripts simplesite.ini Po ponownym przebudowaniu (./bin/
eggs = $ ./bin/paster setup-app simplesite.ini buildout) możliwe jest już uruchomienie
PasteScript serwera:
${buildout:eggs} Niestety ostatnia komenda zakończy się
niepowodzeniem, ponieważ nie została $ ./bin/paster serve simplesite.ini

Listing 3. Wynik wykonania skryptu budującego

Getting distribution for ‘zc.recipe.egg’. Got SQLAlchemy 0.5.8.


Got zc.recipe.egg 1.2.2. Getting distribution for ‘Pylons>=0.9.7,<=0.9.7.99’.
Installing paster. Got Pylons 0.9.7.
Getting distribution for ‘PasteScript’. Getting distribution for ‘PasteDeploy’.
Searching for Paste>=1.3 Got PasteDeploy 1.3.3.
Reading http://pypi.python.org/simple/Paste/ Getting distribution for ‘Paste>=1.3’.
Reading http://pythonpaste.org Got Paste 1.7.2.
Best match: Paste 1.7.2 Getting distribution for ‘WebOb>=0.9.3’.
Downloading http://pypi.python.org/packages/source/P/Paste/ Got WebOb 0.9.8.
Paste-1.7.2.tar.gz#md5=a6a58d08dc4bff Getting distribution for ‘decorator>=2.1.0’.
91d5d1c519d2277f8a Got decorator 3.1.2.
Processing Paste-1.7.2.tar.gz Getting distribution for ‘elementtree>=1.2,<=1.3’.
Got PasteScript 1.7.3. Got elementtree 1.2.7-20070827-preview.
Getting distribution for ‘SimpleSite’. Getting distribution for ‘python-openid>=2.1.1’.
Searching for PasteDeploy Got python-openid 2.2.4.
Reading http://pypi.python.org/simple/PasteDeploy/ Getting distribution for ‘Beaker>=1.1’.
Reading http://pythonpaste.org/deploy/ Got Beaker 1.5.1.
Reading http://pythonpaste.org/deploy/paste-deploy.html Getting distribution for ‘nose>=0.9.2’.
Best match: PasteDeploy 1.3.3 Got nose 0.11.1.
Downloading http://pylons.cachefly.net/download/0.9.7/ Getting distribution for ‘WebHelpers>=0.6.1,<0.6.99’.
PasteDeploy-1.3.3.tar.gz Got WebHelpers 0.6.4.
Processing PasteDeploy-1.3.3.tar.gz Getting distribution for ‘Tempita>=0.2’.
Searching for Paste>=1.3 Got Tempita 0.4.
Reading http://pypi.python.org/simple/Paste/ Getting distribution for ‘WebTest>=1.1’.
Reading http://pythonpaste.org Got WebTest 1.2.
Best match: Paste 1.7.2 Getting distribution for ‘WebError>=0.10.1’.
Downloading http://pylons.cachefly.net/download/0.9.7/Paste- Got WebError 0.10.2.
1.7.2.tar.gz Getting distribution for ‘simplejson>=2.0.8’.
Processing Paste-1.7.2.tar.gz Got simplejson 2.0.9.
Got SimpleSite 0.3.0. Getting distribution for ‘FormEncode>=1.2.1’.
Getting distribution for ‘AuthKit>=0.4.3,<=0.4.99’. Got FormEncode 1.2.2.
Got AuthKit 0.4.5. Getting distribution for ‘Routes>=1.10.3’.
Getting distribution for ‘FormBuild>=2.0.1,<=2.0.99’. Got Routes 1.11.
Got FormBuild 2.0.1. Getting distribution for ‘Pygments’.
Getting distribution for ‘Mako>=0.2.2,<=0.2.99’. Got Pygments 1.2.2.
Got Mako 0.2.5. Generated script ‘/tmp/simple-site/bin/paster’.
Getting distribution for ‘SQLAlchemy>=0.5,<=0.5.99’.

www.sdjournal.org 19
Narzędzia

i obejrzenie rezultatu pod adresem: http:// z systemu kontroli wersji. Wspierane proto- rametr extends sekcji buildout. W plikach,
localhost:5000. koły to: Subversion, Mercurial, Git i CVS. które rozszerzają w ten sposób bazowe pliki,
Deweloperska konfiguracja może instalo- możliwe jest użycie operatora +=, dzięki któ-
Konfiguracja deweloperska wać także inne przydatne narzędzia. Przykła- remu odziedziczona wartość parametru zo-
Obecna konfiguracja pozwala na budowanie dem może być nosetests – skrypt automa- stanie rozszerzona, a nie nadpisana.
aplikacji na podstawie najnowszych pakietów tycznie znajdujący i uruchamiający testy jed- Wtyczki, które ingerują w znaczny spo-
pochodzących z repozytorium Pythona – Py- nostkowe i funkcjonalne. sób w proces budowania aplikacji, dołączane
PI. Podczas rozwijania aplikacji programista Konfiguracja dla osób rozwijających apli- są poprzez parametr extensions. W omawia-
powinien mieć możliwości pracowania na ko- kację powinna zostać umieszczona w od- nym przykładzie mr.developer zmienia dzia-
dzie jeszcze nie opublikowanym. Najczęściej dzielnym pliku, ponieważ zawiera elementy, łanie systemu buildout w ten sposób, że pacz-
pochodzącym wprost z systemu kontroli wer- które nie powinny znaleźć się w wersji osta- ki określone w parametrze auto-checkout
sji. W tej sytuacji bardzo użyteczne jest roz- tecznej. Buildout ułatwia taki podział dzię- zamiast być ściągnięte z repozytorium pakie-
szerzenie mr.developer, które ułatwia pobra- ki możliwości rozszerzania plików konfigu- tów zostaną zbudowane ze źródeł. W sekcji
nie i dołączenie do projektu pakietu wprost racyjnych. W tym celu wykorzystany jest pa- sources określa się adresy, pod którymi znaj-
duje się kod źródłowy.
Należy przebudować aplikację, urucha-
PasteScript miając skrypt buildout z opcją -c wskazują-
Dzięki tej bibliotece możliwe jest łatwe uruchomienie skryptów Pythona wprost z linii ko-
mend. Pakiety podczas instalacji określają w pliku setup.py nazwy funkcji, wykonanie których cą na nowy plik:
uruchomi skrypt, program lub zainicjalizuje komponent – jest to tak zwany entrypoint. Paste-
Script wyszukuje wszystkie dostępne skrypty i pozwala je uruchomić bez znajomości pełnej $ ./bin/buildout -c buildout-devel.cfg
ścieżki do pliku, w którym znajduje się kod źródłowy.
Po zakończeniu działania możliwe jest uru-
chomienie testów dołączonych do SimpleSi-
WSGI te. Służy do tego wygenerowany skrypt:
Skrót od Python Web Server Gateway Interface. Specyfikacja ta określa interfejs na styku apli-
kacji internetowych napisanych w języku Python i serwerów mającymi za zadanie obsługi- $ ./bin/nose SimpleSite
wać przychodzące żądanie HTTP. Określa także sposób współdzielenia i wymiany danych
pomiędzy elementami wchodzącymi w skład aplikacji webowej. Jako serwery dla aplikacji
Dodatkowym ułatwieniem oferowanym
WSGI najczęściej stosuje się Paster oraz Apache wraz z mod _ wsgi. Standard WSGI wspiera
zdecydowana większość aplikacji webowych napisanych w języku Python (m.in: django, Py- przez mr.developer jest skrypt pozwalający na
lons, repoze.bfg, CherryPy, zope). aktualizację wszystkich pakietów źródłowych
w jednym momencie. Nie ma tu znaczenia ro-
dzaj systemu kontroli wersji odpowiedzialny
Listing 4. Plik buildout.cfg po dodaniu SQLite za przechowywanie zmian. Po prostu w celu
aktualizacji wszystkich pakietów źródłowych
[buildout] wystarczy uruchomić skrypt:
parts =
sqlite ./bin/develop update
pysqlite
paster Inne często wykorzystywane recepty w kon-
eggs = figuracji dla programistów to:
SimpleSite
pysqlite • buildout.dumppickedversions – wy-
świetla wersje zainstalowanych pakie-
[paster] tów, przydatne przy tworzeniu konfigu-
recipe = zc.recipe.egg:scripts racji produkcyjnej;
eggs = • pb.recipes.pydev – generuje konfigu-
PasteScript rację dla środowiska Eclipse z rozszerze-
${buildout:eggs} niem PyDev;
• collective.recipe.omelette – połą-
[sqlite] czenie wielu pakietów w jednym drze-
# kompilacja bibliotek binarnych SQLite (lekka baza danych SQL) wie folderów,
recipe = zc.recipe.cmmi • hexagonit.recipe.download – pobiera
url = http://www.sqlite.org/sqlite-amalgamation-3.6.22.tar.gz i rozpakowuje pliki (np.: przykładową
bazę danych);
[pysqlite] • collective.recipe.seleniumrc – in-
# kompilacja biblioteki pozwalającej na używanie stalacja Selenium RC (testy funkcjonal-
# bazy SQLite przez programy napisane w Pythonie ne w przeglądarce internetowej);
recipe = zc.recipe.egg:custom • collective.recipe.funkload – instala-
egg = pysqlite cja FunkLoad (testy obciążeniowe apli-
include-dirs = ${sqlite:location}/include kacji WWW);
library-dirs = ${sqlite:location}/lib • plone.recipe.command – uruchomienie
rpath = ${sqlite:location}/lib dowolnego zestawu komend linii pole-
ceń lub kodu Pythona.

20 05/2010
Buildout

Konfiguracja produkcyjna nego oprogramowania – wystarczy dowolny • plone.recipe.apache – instalacja i kon-


Projekt przystosowany do instalacji na serwe- serwer HTTP z włączoną opcją wyświetla- figuracja serwer Apache;
rze produkcyjnym także posiada inne skład- nia zawartości folderów. Link do tak przygo- • plone.recipe.varnish – instalacja ser-
niki. I w tym przypadku różnicę konfiguruje towanego zasobu należy podać w parametrze wera cache dla aplikacji internetowych;
się w osobnym pliku. find-links. • zest.recipe.mysql – instalacja MySQL
W celu zabezpieczenia przed niespodzie- Aplikacje webowe zgodne ze standardem wraz z MySQL-python;
wanymi błędami wynikającymi z różnic mię- WSGI można uruchamiać przy użyciu dowol- • zc.recipe.cmmi – instalacja dodatkowe-
dzy kolejnymi wersjami zależnych bibliotek nego serwera przystosowanego do tego. W wer- go oprogramowania (np.: PostgreSQL,
często po przeprowadzeniu wszystkich te- sji podstawowej użyty był Paster. W wersji pro- memcached);
stów na instancji testowej zapisuje się w pliku dukcyjnej natomiast najczęściej spotykane jest • collective.recipe.supervisor – kon-
versions.cfg wersje wszystkich użytych bi- użycie rozszerzenia mod_wsgi do serwera Apa- trola wielu procesów;
bliotek. Proces ten automatyzowany jest przez che. W tym celu aplikacja musi udostępnić • z3c.recipe.usercrontab – ułatwia
rozszerzenie buildout.dumppickedversions. plik rozpoczynający (ang. entry point). Plik ta- konfigurację operacji cyklicznych (cron-
Wydanie wersji stabilnej – nadającej się do ki generowany jest przez receptę tab);
instalacji na serwerach produkcyjnych wiąże Podczas budowania aplikacji wygenerowa- • iw.recipe.backup – kopie zapasowe wy-
się z opublikowaniem nowych wersji wszyst- ny zostanie plik wsgi w folderze parts/wsgiapp. branych plików.
kich pakietów, w których były zmiany. Jeże- Pełną ścieżkę do tego pliku należy ustawić
li są to biblioteki OpenSource, nowe wydania w parametrze WSGIScriptAlias konfigura- Wady i zalety
znajdą się w ogólnym repozytorium – PyPI. cji Apache. Buildout nie jest systemem pozbawionym
Pozostałą część należy umieścić na prywat- Konfiguracja produkcyjna często zawiera wad. Najbardziej irytującym z nich jest po-
nym serwerze z ograniczonym dostępem. także dodatkowe elementy. Najbardziej przy- wolne działanie w przypadku problemów
Nie jest konieczne instalowanie specjalistycz- datne z nich to: z siecią. Pomaga wtedy opcja -t do skryptu
buildout, pozwalająca na ustawienie limi-
Listing 5. Plik buildout-devel.cfg tu czasu odpowiedzi. W przypadku gdy nie-
osiągalne jest repozytorium PyPI, nawet pro-
[buildout] ste przebudowanie aplikacji nie jest w ogóle
extensions = możliwe. W takim przypadku można użyć
mr.developer opcji -N blokującej sprawdzanie, czy dostęp-
extends = na jest nowsza wersja pakietu lub opcji -o
buildout.cfg włączająca tryb offline.
parts += Utrudnione jest także szukanie przyczyn
nose błędów budowania. Buildout niestety poka-
auto-checkout = zuje mało przydatne informacje. Uruchomie-
SimpleSite nie wraz z opcją -v lub -vv zwiększa ilość ko-
munikatów pomocniczych, ale w większości
[sources] przypadków są one mało użyteczne.
SimpleSite = hg http://bitbucket.org/meatballhat/simplesite/ Według mnie podstawową zaletą jest to, że
przy użyciu paru komend można zbudować
[nose] lub zaktualizować całą aplikację. Jest to tym
recipe = pbp.recipe.noserunner bardziej pomocne, gdy nad projektem pra-
eggs = cuje kilka osób i co pewien czas każda z nich
${paster:eggs} musi dostosować się do najnowszych zmian.
working-directory = ${buildout:directory}/src Buildout pozwala na szybkie zbudowanie
defaults = -v --nocapture --with-doctest --doctest-tests aplikacji w identycznej konfiguracji na czy-
--with-pylons=${buildout:directory}/src/SimpleSite/test.ini stym serwerze. Jest to przydatne szczególnie
w sytuacjach awaryjnych.
Sądzę, że nakład pracy potrzebny na stwo-
Listing 6. Plik buildout-production.cfg
rzenie konfiguracji Buildout zwraca się dość
[buildout] szybko, a dodatkowo oszczędza się sporo stre-
extends = su podczas uaktualnień, migracji i sytuacji
buildout.cfg nieoczekiwanych.
versions.cfg
parts +=
wsgiapp WOJCIECH LICHOTA
versions = versions Absolwent Uniwersytetu im. A. Mickiewicza w Po-
find-links = znaniu, kierunek Informatyka Stosowana. Obec-
http://login:passwd@dist.example.com nie pracuje jako analityk i programista w �rmie
STX Next (http://stxnext.pl). Zawodowo zajmu-
[wsgiapp] je się aplikacjami internetowymi, począwszy od
recipe = collective.recipe.modwsgi małych portali społecznościowych, po duże roz-
eggs = ${buildout:eggs} wiązania dla sektora bankowego. Języka Python
config-file = ${buildout:directory}/production.ini oraz systemu Linux używa od 8 lat.
Kontakt z autorem: wojciech@lichota.pl

www.sdjournal.org 21
Programowanie

Django
Szybkie tworzenie serwisów Web 2.0

Jeśli cenisz sobie prostotę, elegancką architekturę i zwięzły kod,


a jednocześnie potrzebujesz zaawansowanych funkcjonalności i do
tego gonią Cię terminy – framework Django jest dla Ciebie. Powstał na
potrzeby redakcji on-line, gdzie szybkość reakcji na ciągłe zmiany jest
kluczowa.
W katalogu, w którym chcemy mieć źró-
Dowiesz się: Powinieneś wiedzieć: dła najnowszego Django, wykonujemy po-
• jak zainstalować i zacząć pracę z najnowszą • powinieneś znać podstawy programowania lecenie:
wersją frameworka Django w języku Python
• jak uwierzytelniać i autoryzować użytkow- • powinieneś znać (X)HTML / CSS i podsta- $ svn co http://code.djangoproject.com/
ników aplikacji internetowej przy pomocy wowe zagadnienia związane z tworzeniem svn/django/trunk/ django-trunk
standardowych mechanizmów Django stron internetowych
Zostanie utworzony katalog django-trunk,
w którym znajdzie się najnowszy kod z re-
Krok 1. Instalacja Django oraz pozytorium SVN.
utworzenie nowego projektu Jeśli w systemie nie posiadamy klienta
Poziom Najnowsze Django 1.2 wymaga zainstalo- Subversion, ze strony projektu możemy po-
trudności wanego w systemie języka Python w wersji brać paczkę zip ze źródłami i rozpakować ją
co najmniej 2.4. Z powodu braku wstecznej tak, aby źródła znalazły się w katalogu djan-
zgodności, uruchomienie z wersją 3.0 nie jest go-trunk.
obecnie możliwe. Powinniśmy dysponować Stwórzmy dowiązanie do tego katalogu

D
jango pozwala Ci tworzyć apli- też jakimś silnikiem relacyjnej bazy danych w katalogu z bibliotekami.
kacje webowe o wysokiej wydaj- (framework oficjalnie wspiera MySQL, Post-
ności szybko, a co najważniej- greSQL oraz Oracle), choć na czas fazy two- $ ln -s `pwd`/django-trunk/django SITE-
sze, struktura Twojego projektu nie bę- rzenia aplikacji wystarczy prosty SQLite. PACKAGES-DIR/django
dzie przypominała pozlepianych ze sobą Użyjemy najnowszej, deweloperskiej
brył ciągle powtarzającego się kodu. Dzięki wersji Django (w chwili powstania artyku- Oczywiście zamiast SITE-PACKAGES-DIR
temu, jego dalszy rozwój i utrzymanie nie łu oznaczona jako 1.2 beta). Jak zapewnia- wpisujemy katalog, gdzie znajdują się bi-
będzie już udręką. Tak przynajmniej twier- ją twórcy, jest stabilna, oferuje więcej funk- blioteki Pythona.
dzą twórcy Django. cjonalności oraz mniej błędów niż wydanie Utwórzmy jeszcze dowiązanie do skryp-
My spróbujemy stworzyć szybko społecz- „oficjalne”. tu administracyjnego w katalogu, gdzie
nościowy serwis mikroblogowy, korzysta- Sprawdzamy, gdzie w systemie mamy za- system składuje lokalne pliki wykonywal-
jąc ze standardowych funkcjonalności do- instalowane biblioteki dla Pythona: ne, abyśmy mieli do niego dostęp z każde-
starczanych przez framework. Idea mikro- go miejsca:
blogów jest prosta, o czym świadczy olbrzy- $ python -c "from distutils.sysconfig
mia na świecie popularność Twittera czy, import get_python_ $ ln -s `pwd`/django-trunk/django/bin/
wśród polskich użytkowników, naszego ro- lib; print get_ django-admin.py
dzimego Blipa. python_lib()" /usr/local/bin
Nasz projekt będzie oferował podstawo-
wą funkcjonalność tego typu serwisów:
umieszczamy swoje krótkie wiadomości
Django
Nazwa frameworka pochodzi od pseudonimu genialnego gitarzysty jazzowego Jean'a „Djan-
(statusy), które widzą śledzący nas znajo- go” Reinhardt'a. Django był Belgiem cygańskiego pochodzenia. W wyniku wypadku doznał
mi (followers), jak również na nasz 'pulpit' rozległych oparzeń, przez co miał sparaliżowane dwa palce. Opracował jednak własną, uni-
trafiają statusy obserwowanych przez nas kalną technikę tak, aby mógł grać swoje solówki gitarowe pozostałymi zdrowymi palcami.
przyjaciół. Jego muzykę możemy usłyszeć m.in. w ścieżce dźwiękowej do gry Bioshock.
Prawidłowa polska wymowa nazwy frameworka brzmi po prostu „dżango”. Angielską może-
Zobaczymy jak Django nam to ułatwi,
my usłyszeć w pliku MP3 na stronie: http://docs.djangoproject.com/en/dev/faq/general/#what-
dostarczając przy okazji sporo zadowolenia does-django-mean-and-how-do-you-pronounce-it
z tworzonego kodu.

22 05/2010
Django – szybkie tworzenie serwisów Web 2.0

Spróbujmy teraz utworzyć nowy projekt: CREATE DATABASE ublog CHARACTER SET uft8; GRANT ALL PRIVILEGES ON *.* TO
CREATE USER 'ublog'@'localhost' 'ublog'@'localhost'
$ django-admin startproject ublog IDENTIFIED BY 'mypassword'; WITH GRANT OPTION;

Zostanie utworzony katalog ublog zawiera- Listing 1. Fragmenty pliku settings.py


jący następujące pliki:
# Konfiguracja bazy danych
• __init.py__ - pusty plik mówiący Py- DATABASES = {
thonowi że katalog jest package'em 'default': {
• manage.py - skrypt do wykonywania 'ENGINE': 'django.db.backends.mysql',
różnych zadań administracyjnych 'NAME': 'ublog',
• settings.py - ustawienia / konfiguracja 'USER': 'ublog',
projektu 'PASSWORD': 'mypassword',
• urls.py - deklaracje URLi dla projektu 'HOST': '' // standardowo localhost
'PORT': '' // standardowy port
W ramach projektu, Django pozwala na }
tworzenie wielu aplikacji. Aplikacje takie }
są swego rodzaju modułami, które można
włączać lub wyłączać w razie potrzeby lub # Bezwzględna ścieżka do katalogu przechowującego media:
wykorzystywać w innych projektach. Apli- MEDIA_ROOT = '/home/pmandes/Devel/ublog/static/'
kacja jest po prostu swego rodzaju opako-
waniem niezależnej funkcjonalności. # URL do plikół przechowywanych w MEDIA_ROOT.
Tworzymy więc aplikację do tworzenia MEDIA_URL = '/static/'
i wyświetlania postów.
# Plik ze zworcami URLi dla projektu
$ cd ublog ROOT_URLCONF = 'ublog.urls'
$ python manage.py startapp posts
# Bezwzględna ścieżka do katalogu z szablonami
W katalogu z projektem zostanie utworzony TEMPLATE_DIRS = (
podkatalog posts, a w nim następujące pliki: "/home/pmandes/Devel/ublog/templates"
)
• __init.py__
• models.py - klasy modeli # Aplikacje użyte w projekcie
• tests.py - testy INSTALLED_APPS = (
• views.py - definicje widoków 'django.contrib.admin',
'django.contrib.auth',
Teraz do pliku settings.py należy dopi- 'django.contrib.contenttypes',
sać aplikację posts do INSTALLED _ APS 'django.contrib.sessions',
(patrz listing 1). Modelami i widokami zaj- 'django.contrib.sites',
miemy się później. 'django.contrib.messages',
Pozostałe używane aplikacje przydadzą się 'ublog.posts'
w naszym projekcie m.in. do wygenerowania )
panelu administracyjnego, autoryzacji i uwie-
rzytelniania czy obsługi sesji. Wszystkie te
funkcjonalności mamy w Django gotowe. Jeśli
którejś z nich nie potrzebujemy, usuwamy jej
wpis. Uruchamiamy wbudowany serwer:

$ python manage.py runserver

Krok 2. Baza danych i modele


Zakładam, że MySQL jest już zainstalowany
i skonfigurowany w naszym systemie. Aby
Python mógł używać MySQL'a, należy zain-
stalować moduł MySQLdb. Pozostaje utwo-
rzyć bazę danych dla naszej aplikacji oraz
użytkownika, dla którego Django będzie łą-
czyć się z tą bazą.

$ mysql --user=root mysql --password

W konsoli mysql'a wydajemy następujące


komendy SQL: Rysunek 1. Ekran powitalny Django

www.sdjournal.org 23
Programowanie

CREATE USER 'ublog'@'%' IDENTIFIED BY


Listing 2. Plik posts/models.py – klasy modeli 'mypassword';
from django.db import models GRANT ALL PRIVILEGES ON *.* TO
'ublog'@'%' WITH
GENDER_CHOICES = ( GRANT OPTION;
('M', 'Male'),
('F', 'Female'), Należy pamiętać, aby w docelowym środo-
) wisku produkcyjnym użytkownik root był
zabezpieczony hasłem oraz aby dostęp do
class Profile(models.Model): bazy dostępny był tylko z konkretnej ma-
nick = models.CharField(max_length=20, unique=True) szyny produkcyjnej.
full_name = models.CharField(max_length=100) W pliku settings.py definiujemy połącze-
gender = models.CharField(max_length=1, choices=GENDER_CHOICES) nie z utworzoną bazą danych wypełniając
location = models.CharField(max_length=255) pola tablicy DATABASES jak na Listingu 1.
url = models.URLField(max_length=255) W przypadku używania do celów dewelo-
avatar = models.CharField(max_length=255) perskich bazy SQLite wystarczy wpis:
info = models.CharField(max_length=255)
DATABASES = {
def __unicode__(self): 'default': {
return self.full_name 'ENGINE': 'django.db.backends.sq
lite3',
'NAME': 'ublog.db' // nazwa pliku
class Post(models.Model): do którego sqlite
content = models.CharField(max_length=160) zapisuje dane
author = models.ForeignKey(Profile) }
pub_date = models.DateTimeField('date published') }

def __unicode__(self): Mamy połączenie z bazą danych. Teraz na-


return self.content leży zdefiniować modele, czyli klasy repre-
zentujące zapisywane dane. Wbudowany
w Django ORM zajmie się resztą.
Listing 3. Plik posts/admin.py
W pliku posts/models.py zdefiniujemy
dwie klasy dziedziczące po klasie Model:
from ublog.posts.models import Profile
from ublog.posts.models import Post • – klasa reprezentująca dane
Profile
from django.contrib import admin użytkownika, czyli autora postów;
• Post – klasa reprezentująca pojedyn-
admin.site.register(Profile) czy post w naszym serwisie mikroblo-
admin.site.register(Post) gowym.

Plik ten powinien wyglądać jak na Listin-


gu 2.
Zauważmy, że w klasie Profile pole
nick (czyli pseudonim użytkownika) ma
ustawioną flagę uniqe. Znaczy to, że w sys-
temie może istnieć tylko jeden użytkow-
nik o danym pseudonimie. Póki co profil
nie ma nic wspólnego z reprezentacją za-
logowanego w systemie użytkownika, zaj-
miemy się tym później. Pozostałe pola de-
finiują takie właściwości profilu użytkow-
nika jak: jego pełna nazwa, płeć, położenie,
URL do strony domowej, ścieżka do pliku
z awatarem oraz krótka notka informacyj-
na o sobie.
Klasa Post posiada pole author zdefinio-
wany jako klucz obcy. Jeden autor może
umieścić wiele postów, a dany post ma tyl-
ko jednego autora. Mamy więc tu związek je-
den-do-wielu. ORM wygeneruje odpowied-
nie relacje.
Warto zauważyć jeszcze zdefiniowane
Rysunek 2. Panel administracyjny po zalogowaniu opcje wyboru dla płci użytkownika w krot-

24 05/2010
Django – szybkie tworzenie serwisów Web 2.0

ce (ang. tuple) GENDER_CHOICES przekazanej urlpatterns = patterns('ublog.posts.vi my w nim klasy Profile i Post aby aplikacja
jako parametr dla pola gender. ews', admin mogła z nich korzystać.
Dodatkowo każda klasa ma zdefiniowa- (r'^admin/', include(admin.site.ur Zalogujmy się do panelu administracyjne-
ną metodę __unicode__ zwracającą repre- ls)), go utworzonymi wcześniej danymi superu-
zentację obiektu w postaci łańcucha zna- ) żytkownika – powinniśmy zobaczyć nasze
ków. zarejestrowane klasy jak na rysunku 2.
Sprawdźmy teraz, jakie tabele zostaną Teraz w katalogu z aplikacją posts two- Dodajmy jakiś przykładowy profil użyt-
utworzone dla aplikacji posts: rzymy plik admin.py którego cała zawar- kownika oraz kilka postów. Widzimy, że ma-
tość znajduje się na listingu 3. Rejestruje- my wszystko, czego potrzeba: walidację pól
$ python manage.py sqlall posts

Listing 4. Plik urls.py – mapowanie wzorców URL na metody widoków


Jeśli nie popełniliśmy nigdzie jakiegoś błędu,
dostaniemy w wyniku ciąg komend SQL ge- from django.conf.urls.defaults import *
nerujących odpowiednie tabele. from django.conf import settings
Widzimy więc, że zostanie utworzony from django.contrib import admin
klucz obcy oraz indeks na odpowiednich
polach. Poleceniem syncdb zatwierdzamy admin.autodiscover()
wszelkie zmiany do bazy danych. urlpatterns = patterns('ublog.posts.views',
(r'^$', 'index'),
$ python manage.py syncdb (r'^dashboard/$', 'dashboard'),
(r'^profile/$', 'profile'),
Oprócz naszych tabel zostaną też utworzo- (r'^post/$', 'add_post'),
ne tabele dla pozostałych dołączonych do (r'^post/(?P<post_id>\d+)/$', 'get_post'),
projektu aplikacji. Przy okazji skrypt zapy- (r'^login/$', 'login'),
ta nas, czy utworzyć dla aplikacji auth su- (r'^logout/$', 'logout'),
perużytkownika oraz poprosi o zdefinio- (r'^admin/', include(admin.site.urls)),
wanie jego nazwy i hasła: )
if settings.DEBUG:
You just installed Django's auth system, urlpatterns += patterns("django.views",
which means you don't have any superusers url(r"^static/(?P<path>.*)", "static.serve", {
defined. "document_root": '/home/pmandes/Devel/ublog/static/',
Would you like to create one now? (yes/no): })
yes )
Username (Leave blank to use 'jasio'):
admin
Listing 5. Plik ublog/views.py – de�nicje funkcji widoków
E-mail address: admin@ublog.pl
Password:
Password (again): from django.http import HttpResponseRedirect, HttpResponse
Superuser created successfully. from django.core.urlresolvers import reverse
from django.http import HttpResponse
W tym momencie mamy już gotową bazę
danych dla naszego projektu oraz zdefinio- def index(request):
wane podstawowe modele. return HttpResponse("To jest widok główny")

Krok 3. Panel administracyjny def dashboard(request)


Przyszła pora na to, aby wprowadzić jakieś return HttpResponse("To jest widok pulpitu użytkownika")
przykładowe dane oraz mieć możliwość za-
rządzania nimi z panelu administracyjne- def get_post(request, post_id):
go. Z pomocą przyjdzie nam aplikacja ad- return HttpResponse("Widok dla pojedynczego statusu: %s" % post_id)
min, która odciąży nas od żmudnego two-
rzenia formularzy edycyjnych dla każdej def add_post(request):
tabeli z bazy danych. Automatyczne pane- return HttpResponseRedirect(reverse('ublog.posts.views.dashboard'))
le administracyjne to jedna z najprzyjem-
niejszych funkcjonalności, jakie oferuje nam
Django. Jedyne, co my musimy zrobić, to
odkomentować odpowiednie linijki w pli-
ku urls.py oraz określić, którymi modelami
MVC czy MTV?
W klasycznym podejściu do wzorca MVC (Model-View-Controller) za prezentację danych
chcemy zarządzać. z modelu dostarczonych przez którąś z metod - akcji kontrolera (Controller) odpowiada wi-
W pliku ulrs.py powinna znajdować się dok (View). Jednakże wg twórców Django naturalne jest rozdzielenie tego „co chcę wyświe-
następujący kod: tlić” od tego „jak chcę to wyświetlić”. Dlatego też to w widokach (będącymi zwykłymi funk-
cjami) pobieramy z modeli potrzebne dla danej prezentacji dane („co”) i renderujemy je przy
pomocy szablonów („jak”). Stąd też akronim MTV (Model-Template-View).
from django.contrib import admin
admin.autodiscover()

www.sdjournal.org 25
Programowanie

formularza, komponenty takie jak wybór Krok 4. Widoki i szablony własne posty, oczywiście z formularzem do
daty czy listy rozwijane oraz komunikaty Sama baza danych oraz panel administra- ich umieszczania. Zajmiemy się teraz war-
o błędach. Oczywiście panel administracyj- cyjny to jeszcze nie wszystko. Brakuje naj- stwą widoku.
ny można łatwo dostosować do własnych po- ważniejszego, czyli interfejsu użytkownika Zacznijmy od zdefiniowania URLi do po-
trzeb, łącznie ze zmianą całego wyglądu, ale - strony WWW, na której użytkownik bę- szczególnych widoków i zasobów (w sty-
wykracza to poza temat tego artykułu. dzie widział statusy swoich znajomych, oraz lu REST):

Listing 6. Widok główny • GET /- strona główna, czyli wyświetla-


nie najnowszych statusów umieszcza-
from django.template import Context, loader nych przez wszystkich użytkowników;
from ublog.posts.models import Post • GET /dashboard - pulpit zalogowanego
from django.http import HttpResponse użytkownika, tu wyświetlają się posty
tylko jego znajomych;
def index(request): • GET /post/123 - wyświetlenie pojedyn-
czego statusu o podanym identyfikato-
# modelu Post obieramy 20 ostatnich obiektów posortowanych po dacie rze
latest_post_list = Post.objects.all().order_by('-pub_date')[:20] • POST /post - zasób, na który zostaną
wysłane dane z formularza do umiesz-
# ładujemy szablon z pliku czania statusów.
template = loader.get_template('posts/index.html')
Mapowanie URLi na definicje widoków do-
# tworzymy kontekst dla szablonu zawierający dane do wyświetlenia konuje się przy pomocy wyrażeń regular-
context = Context({ nych w zmiennej urlpatterns znajdującej
'latest_post_list': latest_post_list, się w pliku urls.py (Listing 4).
}) Django zaczyna dopasowywać otrzyma-
ny URL z powyższymi wyrażeniami po ko-
# renderujemy szablon i przekazujemy go do obiektu odpowiedzi HttpRespose lei i jeśli to się uda, to wywołuje podaną
return HttpResponse(templete.render(context)) funkcję zwrotną. Jako pierwszy argument
do tej funkcji zostanie przekazany obiekt
HttpRequest. Kolejnymi argumentami bę-
Listing 7. Plik templates/posts/index.html – szablon widoku postów
dą przechwycone z wyrażenia regularne-
{% extends "base.html" %} go wartości (jak w powyższym przykładzie
post_id). Na koniec przekazane zostaną ar-
{% block content %} gumenty wraz z ich wartościami zdefinio-
wane w opcjonalnym słowniku. Pełna skład-
{% if error_message %}<p><strong>{{ error_message }}</strong></p>{% endif %} nia krotek występujących w urlpatterns
wygląda następująco:
Ustaw swój status:
<form action="/post/" method="post"> (regular expression, Python callback
{% csrf_token %} function
<textarea name="content" rows="4" cols="60"></textarea> [, optional
<input type="submit" value="Post" /> dictionary])
</form>
Funkcje zwrotne definiujemy w pliku
<br/><br/> ublog/views.py (Listing 5).
O funkcjach zwrotnych możemy my-
{% if latest_post_list %} śleć jak o akcjach w kontrolerach we wzor-
<div class="ublog_posts"> cu MVC (model-view-controller). Jednakże
{% for post in latest_post_list %} Django stosuje nieco inne podejście do te-
<div class="ublog_post"> go wzorca niż takie frameworki jak np. Ru-
<div class="ublog_post_content">{{ post.content }}</div> by On Rails czy popularny dla środowiska
<div class="ublog_post_date">{{ post.pub_date }}</div> Java – Spring. Nie definiujemy kontrole-
<div class="ublog_post_author">{{ post.author }}</div> rów, gdyż kontrolerem i zawiadowcą (ang.
</div> dispatcher) jest samo Django. Zamiast te-
<hr/> go definiujemy funkcje zwrotne będące lo-
{% endfor %} giką widoków w ramach aplikacji. Pobiera-
</div> ją one dane z modeli, renderują je przy po-
{% else %} mocy szablonów i zwracają w postaci obiek-
<p>No posts are available.</p> tu HttpResponse. Podejście takie nazywa
{% endif %} się MTV.
Oczywiście funkcje te nie muszą zwra-
{% endblock%} cać wyrenderowanego widoku. Jak widzimy
w definicji add_post, zwracany jest obiekt

26 05/2010
Django – szybkie tworzenie serwisów Web 2.0

HttpResponseRedirect powodujący prze-


Listing 8. Poprawina funkcja index korzystająca ze skrótu
kierowanie na inny URL. Zamianę nazwy
funkcji na odpowiadający jej URL dokonu- from django.shortcuts import render_to_response
je funkcja reverse.
Pobierzmy teraz dane dla widoków i wy- def index(request):
renderujmy je przy pomocy szablonów.Przy-
kładowo definicja funkcji index mogłaby latest_post_list = Post.objects.all().order_by('-pub_date')[:10]
wyglądać jak na Listingu 6.
Kod ten pobiera 20 ostatnich postów, ła- return render_to_response('posts/index.html', {'latest_post_list': latest_
duje szablon zdefiniowany w pliku posts/ post_list}, context_instance=RequestContext(request))
index.html , a następnie umieszcza pobrane
dane w kontekście. Kontekst jest obiektem
Listing 9. Funkcja get_post z obsługą wyjątku 404
mapującym nazwy zmiennych występujące
w szablonie na konkretne obiekty Pythona. from django.http import Http404
Oczywiście wywołanie teraz strony zakoń-
czy się komunikatem TemplateDoesNotE- def get_post(request, post_id):
xist. Musimy wskazać Django w konfigura-
cji, gdzie ma szukać szablonów oraz utwo- try:
rzyć w tej lokalizacji sam szablon. post = Post.objects.get(id=post_id)
W pliku settings.py definiujemy pełną except Post.DoesNotExist:
ścieżkę do szablonów naszego projektu, np. raise Http404

TEMPLATE_DIRS = ( return render_to_response('posts/post.html', {'post': post})


"/home/jasio/projects/ublog/
templates"
)
Język szablonów Django
Najczęściej używane tagi w szablonach:
W katalogu z naszym projektem tworzy-
my katalog templates, a w nim posts. Tu dziedziczenie po szablonie nadrzędnym:
umieścimy wszystkie szablony dla aplikacji {% extends „base.html” %}
posts. Plik templates/posts/index.html po-
wczytanie innego szablonu i wyrenderowanie go w miejscu:
winien wyglądać ja na Listingu 7.
{% include „szablon.html” %}
Widzimy, że w szablonie możemy uży-
wać takich konstrukcji sterujących, jak definicja bloku:
if-else czy iterować po liście z obiekta- {% block nazwa_bloku %}{% endblock %}
mi pętla for. Pusta lista daje wartość lo- iterowanie po liście:
{% for artykul in lista_artykulow %}
giczną false.
{{ artykul.tytul}}
W tym momencie, odświeżając stronę,
{% endfor %}
powinniśmy zobaczyć nasze posty, które
wcześniej dodaliśmy testowo do panelu ad- iterowanie po liście z obsługą listy pustej:
ministracyjnego. {% for artykul in lista_artykulow %}
Django oferuje nam jeszcze tzw. skróty {{ artykul.tytul }}
dla najczęściej tworzonego w widokach ko- {% empty %}

du. Wszystko po to, żeby zgodnie z zasadą brak artykulow


DRY (don't repeat yourself) było jak najmniej {% endfor %}
powtarzających się fragmentów kodu. Tym-
czasem niemalże we wszystkich widokach konstrukcja warunkowa if:
będziemy robić to samo. {% if lista_arykulow %}
Zmieńmy teraz funkcje index, tak aby ko-
liczba artykulow: {{ lista_artykulow|lenght }}
rzystała ze skrótu (Listing 8). {% else %}
Skrót render_to_response pobiera ścież-
kę do plik szablonu, kontekst z obiektami brak artykulow
z danymi do wyrenderowania oraz dodatko- {% endif %}
wo kontekst żądania, który przyda nam się
porównanie, czy wartości są równe:
nieco później. {% ifequal artykul.tytul artykul_glowny.tytul %}
Pozostaje jeszcze obsługa sytuacji, kiedy {% endifequal %}
post o podanym id nie istnieje i w takim
wypadku należałoby zgłosić stronę błędu porównanie, czy wartości są różne:
Http 404, zamiast komunikatu o błędzie {% ifnotequal uzytkownik.nazwa „józek” %}
{% endifnotequal %}
aplikacji.
Można to zrobić na kilka sposobów. więcej o języku szablonów i wbudowanych tagach na stronie:
Pierwszym z nich jest rzucenie wyjątku http://docs.djangoproject.com/en/dev/ref/templates/builtins/
Http404.

www.sdjournal.org 27
Programowanie

Kod funkcji get_post wyglądałby jak na Częstym problemem dla początkujących na ścieżka do plików na dysku oraz ścieżka
Listingu 9. programistów Django jest serwowanie statycz- z URL'a):
Drugim sposobem jest oczywiście skorzy- nych plików, takich jak np. grafiki czy szablo-
stanie ze skrótu get_object_or_404, który ny css. Wynika to z tego, że w produkcyjnym MEDIA_ROOT = '/home/jasio/project/ublog/
robi dokładnie to samo (Listing 10). środowisku pliki takie najczęściej serwowane static'
W przypadku kiedy post nie zostanie zna- są z osobnego miejsca, będące wewnątrz kata- MEDIA_URL = '/static/'
leziony, Django wygeneruje standardowy logu DOCUMENT_ROOT serwera WWW.
widok django.views.defaults.page_not_ Natomiast projekt Django znajduje się poza Teraz w pliku urls.py definiujemy odpowied-
found() . Możemy też zdefiniować własny nim, tak aby nie było dostępu do jego plików ni wzorzec dla statycznych plików. Wzorce te
szablon dla błędu 404. Wystarczy, że utwo- z sieci. W środowisku deweloperskim, kiedy powinny działać tylko wtedy, kiedy będzie-
rzymy plik 404.html w katalogu templates. używamy wbudowanego serwera, można po- my w trybie DEBUG. Definicja tego wzorca
Django skorzysta z niego, ale tylko wtedy, radzić sobie z tym w następujący sposób: została umieszczona na Listingu 4.
gdy w ustawieniach tryb DEBUG przełączy- W pliku settings.py definiujemy katalogi, Należy jednak pamiętać, że rozwiązanie
my na false. w których znajdują się statyczne media (peł- tego typu w środowisku produkcyjnym by-
łoby niezbyt bezpieczne i niewydajne.
Listing 10. Funkcja get_post używająca skrótu W warstwie widoku naszej aplikacji bra-
kuje jeszcze dwóch rzeczy: głównego sza-
from django.shortcuts import render_to_response, get_object_or_404 blonu dla strony WWW oraz formularza
do umieszczania na mikroblogu swoich
def get_post(request, post_id): statusów.
post = get_object_or_404(Post, id=post_id) W katalogu templates tworzymy plik ba-
return render_to_response('posts/post.html', {'post': post}) se.html. Powinien on zawierać definicję DO-
CTYPE oraz wszystkie niezbędne nagłówki
HTML, a także miejsce, w które będą ren-
Listing 11. Plik post/views.py.
derowane bloki z szablonów dziedziczących
po nim. np.:
import datetime
<div id="content">
from ublog.posts.models import Post, Profile {% block content %}{% endblock %}
</div>
from django.template import RequestContext
from django.http import HttpResponseRedirect, HttpResponse Ze względu na wielkość, pełen kod tego
from django.shortcuts import render_to_response, get_object_or_404 szablonu został umieszczony na naszej pły-
from django.core.urlresolvers import reverse cie CD.
W szablonie tym widzimy użycie stałej
def index(request): MEDIA_URL, która prowadzi do pliku ze sty-
latest_post_list = Post.objects.all().order_by('-pub_date')[:20] lami css, oraz znaczniki bloków, w które ren-
derowane będą szablony stworzone dla po-
return render_to_response('posts/index.html', {'latest_post_list': latest_post_ szczególnych funkcji zwrotnych w views.py.
list}, context_instance=RequestContext(request)) Utwórzmy katalog static w głównym kata-
logu projektu – umieścimy w nim nasze de-
def dashboard(request): finicje stylów css - plik ublog.css, obrazki oraz
latest_post_list = Post.objects.all().order_by('-pub_date')[:20] skrypty js.
Przeróbmy teraz szablon templates/posts/
return render_to_response('posts/index.html', {'latest_post_list': latest_post_ index.html tak, aby dziedziczył po głównym
list}, context_instance=RequestContext(request)) szablonie base.html oraz wypełnił odpowied-
nie bloki wyrenderowanymi danymi. Przy oka-
zji dodajmy do niego formularz (Listing 7).
def get_post(request, poll_id): Teraz uzupełnijmy plik views.py uzupełnio-
post = get_object_or_404(Post, id=post_id) ny o obsługę formularza w funkcji add_post.
Pełny kod tego pliku widzimy na listingu 11.
return render_to_response('posts/post.html', {'post': post}, context_instance= W tym momencie mamy już działający
RequestContext(request)) zrąb aplikacji. Można wysyłać formularzem
statusy, które dodają się do bazy danych i wy-
def add_post(request): świetlają na stronie.
content = request.POST['content'] Oczywiście pozostało jeszcze wiele do
author = Profile.objects.get(id=1) zrobienia, jak np. edycja profilu użytkowni-
post = Post(author=author, content=content, pub_date=datetime.datetime.now()) ka, upload i wyświetlanie awatarów czy wy-
post.save() świetlanie obserwowanych przyjaciół, nie
mówiąc już o stworzeniu nieco mniej asce-
return HttpResponseRedirect(reverse('ublog.posts.views.index')) tycznego wyglądu. Mamy już jednak zrąb
aplikacji. Na koniec zajmijmy się jeszcze jed-
nym bardzo ważnym aspektem.

28 05/2010
Django – szybkie tworzenie serwisów Web 2.0

Krok 5. Uwierzytelnianie Dodajmy teraz do posts/views.py funkcję nie próbuje go uwierzytelnić metodą
i autoryzacja login. auth.authenticate. Jeśli podane dane się
Django dostarcza standardowo mechanizmy Pobiera ona z formularza logowania na- zgadzają oraz użytkownik jest oznaczony
do uwierzytelnienia i autoryzacji użytkow- zwę użytkownika oraz hasło, a następ- w systemie jako aktywny, następuje jego za-
nika. Należy rozróżnić dwa te dwa etapy:

• Uwierzytelnianie (ang. authentication) -


sprawdzenie, czy użytkownik jest fak-
tycznie tym, za kogo się podaje. Zazwy-
czaj polega to na sprawdzeniu, czy po-
dana przez niego nazwa użytkownika
i hasło zgadza się z tym, co mamy w ba-
zie danych użytkowników.
• Autoryzacja (ang. authorization) –
sprawdzenie, czy użytkownik jest
uprawniony do wykonania określo-
nych operacji w systemie. Zwykle pole-
ga to na sprawdzeniu, czy operacja jest
dla niego zdefiniowana jako dozwolona
w tabeli uprawnień.

Procesem tym (zwanym w skrócie A&A)


zajmuje się aplikacja auth. System A&A
w Django składa się z następujących części:

• Users – użytkownicy zarejestrowani


w naszym serwisie;
• Permissions – uprawnienia, czyli flagi Rysunek 3. Pulpit użytkownika z formularzem
binarne (tak/nie) określające, czy dany
użytkownik może wykonać pewną ope-
rację;
• Groups – użytkownicy mający przy-
znane w ramach danej grupy te same
uprawnienia;
• Messages – komunikaty, prosty sposób
na kolejkowanie i wyświetlanie komu-
nikatów systemowych użytkownikom.

Na początku projektu dołączyliśmy od-


powiednie składniki (Authentication-
Middleware oraz django.contrib.auth),
a odpowiednie tabele zostały potworzo-
ne w bazie danych. Dopóki nie mamy me-
chanizmu pozwalającego na rejestrowa-
nie się użytkowników w systemie, stwórz-
my jednego testowego w panelu admi-
nistracyjnym. Przyznajmy mu prawa do
dodawania/usuwania posta oraz tworzenia
i edycji profilu.
To, czy użytkownik został uwierzytelnio-
ny, możemy sprawdzić w funkcjach wido-
ków następującym kodem:

if request.user.is_authenticated():
# zrób coś dla uwierzytelnionego
użytkownika
else:
# zrób coś dla użytkownika
anonimowego

Jeśli użytkownik jest niezalogowany,


obiektem request.user będzie instancja
AnonymousUser. Rysunek 4. Przyznawanie praw użytkownikowi w panelu administracjnym

www.sdjournal.org 29
Programowanie

logowanie w systemie metodą auth.login, def logout(request): stworzyć formularz do logowania oraz pod-
po czym następuje przekierowanie na stronę auth.logout(request) łączyć funkcje login/logout w urls.py:
/posts/dashboard. W przypadku niepowodze- return HttpResponseRedirect
nia zostaniemy przekierowani z powrotem ("/posts/index/") (r'^login/$', 'login'),
na stronę główną. (r'^logout/$', 'logout'),
Aby użytkownik mógł się wylogować, po- Wylogowanego użytkownika przekierowu-
trzebuje oczywiście też funkcji logout: jemy na stronę główną. Pozostaje jeszcze Dla formularza stworzymy szablon lo-
gin.html (Listing 13).
Listing 12. Funkcja login Teraz dla przykładu zabezpieczmy for-
mularz do umieszczania statusów tak, aby
from django.contrib import auth nie wyświetlał się niezalogowanemu użyt-
kownikowi.
def login(request):
def dashboard(request):
username = request.POST.get('username', '') if not request.user.is_
password = request.POST.get('password', '') authenticated():
return HttpResponseRedirect('/
user = auth.authenticate(username=username, password=password) posts/index')
# ...
if user is not None and user.is_active:
W szablonach również możemy korzy-
# Hasło prawidłowe oraz użytkonik jest oznaczony jako "active" stać z obiektu User, jeśli przekażemy
auth.login(request, user) RequestContext:

# Przekierowanie na pulpit użytkownika {% if user.is_authenticated %}


return HttpResponseRedirect("/posts/dashboard/") <p>Witaj, {{ user.username }}. Jessteś
zalogowany.</p>
else: {% else %}
<p>Witaj. Proszę się zalogować.</p>
# Przekierowanie na stronę główna {% endif %}
return HttpResponseRedirect("/posts/index/")
I to by było na tyle. Zostało jeszcze do za-
implementowania jeszcze kilka funkcjonal-
Listing 13. Formularz logowania.
ności, jak chociażby rejestracja użytkowni-
{% block content %} ka z wysłaniem wiadomości email z prośbą
o potwierdzenie, czy edycja własnego profi-
{% if form.errors %} lu. Temat jest na tyle obszerny, że można by
<p class="error">Nieprawidłowy login lub hasło.</p> mu poświęcić cały osobny artykuł.
{% endif %}
Podsumowanie
<form action="" method="post"> Django oferuje nam olbrzymie możliwości
{% csrf_token %} przy tworzeniu aplikacji webowych. Auto-
matyczne generowanie kodu, paneli admi-
<label for="username">Nazwa użytkownika:</label> nistracyjnych oraz wiele gotowych do uży-
<input type="text" name="username" value="" id="username"> cia aplikacji powoduje, że projekt powstaje
<label for="password">Hasło:</label> szybko, a standardowe problemy rozwiązuje
<input type="password" name="password" value="" id="password"> sam framework. W końcu, nasz serwis posia-
da zwięzły, łatwy do utrzymania kod, a dal-
<input type="submit" value="login" /> szy rozwój nie oznacza konieczności przepi-
</form> sywania wszystkiego od zera.
Cały kod źródłowy niniejszego projektu
{% endblock %} dostępny jest w repozytorium GIT pod ad-
resem: http://github.com/pmandes/ublog.

PAWEŁ MANDES
W Sieci Autor jest współpracownikiem GG Network S.A.,
• http://www.djangoproject.com – oficjalna strona projektu Django; gdzie m.in. współtworzy i rozwija Pocztę Ga-
• http://code.djangoproject.com/wiki – wiki projektu, prawdziwa kopalnia wiedzy; du-Gadu. Jako programista interesuje się wie-
• http://www.django.pl – polska strona społeczności Django; loma technologiami i językami (jak np. Python/
• http://www.djangobook.com – online'owa wersja książki „The Django Book”; Django, czy Ruby on Rails). Pasjonują go również
• http://djangoadvent.com – blog z artykułami o nadchodzącej wersji 1.2 frameworka.
algorytmy genetyczne oraz programowanie gier.
Kontakt z autorem: pawel.mandes@gmail.com

30 05/2010
Programowanie

Plone
Zbuduj firmowy intranet
Wybierając narzędzie mające zapewnić bezpieczną i sprawną
komunikację wewnątrz-firmową, warto zwrócić uwagę na Plone –
otwarty system CMS oferujący szeroki zakres możliwości dysponujący
wieloma dodatkowymi produktami, które pozwalają dopasować go
do własnych potrzeb. W poniższym artykule przedstawione zostało
zastosowanie Plona w roli firmowego intranetu.
ni lat 2008 – 2009 niosły ze sobą dalsze roz-
Dowiesz się: Powinieneś wiedzieć: szerzenia w funkcjonalności oraz przejście na
• Jak stworzyć serwis intranetowy przy wyko- • Znać podstawowe zagadnienia dotyczące dystrybucje w postaci pakietów (python eggs).
rzystaniu systemu CMS Plone; języka Python. W chwili wydawania niniejszego artykułu
• W jaki sposób dokonać instalacji i podsta- najnowszą wydaną stabilną wersją Plona jest
wowej konfiguracji Plona; wersja 3.3.4. Działa ona na pythonie 2.4.3+,
• Jak dostosować możliwości Plona do własnych w oparciu o zope 2.10.4+.
potrzeb za pomocą dodatkowych produktów. W najbliższej przyszłości zostanie wyda-
na wersja 4.0 (obecnie istniejąca jako beta),
działająca na zope 2.12 (w pełni dystrybu-
chetypes. Od momentu wydania Plona w wer- owanym w postaci pakietów) i pythonie 2.6
sji 2.1 (działającej z pythonem 2.3) w 2005 – szybszym i cechującym się lepszym zarzą-
Poziom roku, systematycznie postępował rozwój sys- dzaniem pamięcią. W Plonie 4 dane w posta-
trudności temu. W 2006 roku została wydana wersja ci plików binarnych są domyślnie przechowy-
2.5, która niosła ze sobą przejście na pythona wane w systemie plików. Jednak najważniej-
2.4. Wprowadziła również, dzięki produkto- sze zmiany tego wydania dotyczą wzrostu wy-
wi Five, możliwość wykorzystania technologii dajności działania systemu. Na Rysunku 1 [2]
Podstawowe informacje z zope 3 – komponentowej architektury (Zo- przedstawione zostało porównanie wydajno-
Plone jest systemem CMS, który pozwala na pe Component Architecture). Kolejnym du- ści mierzonej w liczbie obsługiwanych żądań
zarządzanie treścią w formie elektronicznej żym krokiem była wersja 3.0, której premie- w czasie 1 sekundy, uwzględniając różne sytu-
(dokumentami, plikami czy obrazami) za po- ra nastąpiła w 2007 roku. Wydanie to miało acje – wyświetlanie strony dla niezalogowane-
mocą przeglądarki internetowej, umożliwia- na celu uczynienie pracy z Plone bardziej wy- go i zalogowanego użytkownika, widoku listin-
jąc publikowanie wybranych fragmentów tre- dajnej oraz wniosło wiele istotnych funkcjonal- gu newsów i widoku edycji obiektu. Porówna-
ści w Internecie lub lokalnym intranecie. Plo- ności, takich jak wersjonowanie treści, mecha- niu zostały poddane wersje 3.3.3, 4.0b, oraz
ne jest zbudowany w oparciu o serwer aplika- nizm blokowania treści poddawanej edycji czy 4.0b z wykorzystaniem systemu Chameleon,
cji Zope napisany w języku Python. Projekt nowy mechanizm portletów, umożliwiający który dokonuje kompilacji szablonów zpt do
został zapoczątkowany pod koniec 1999 ro- kontekstowe zarządzanie nimi. Kolejne wersje postaci byte-codu, przynosząc poprawę szyb-
ku, a jego pierwsze wydanie nastąpiło w roku – 3.1, 3.2 oraz 3.3 – wydawane na przestrze- kości ich renderowania do kilkudziesięciu pro-
2001, szybko zyskując sobie zwolenników na
całym świecie. Z racji tego, że Plone jest pro-
jektem otwartym – jego fundamentem jest
Produkt
Produkt – w nomenklaturze zope'owej określa się w ten sposób zewnętrzny moduł, zazwy-
duża i aktywna społeczność, która zapewnia czaj w postaci pakietu pythona, pozwalający na rozszerzenie standardowej funkcjonalności
ciągły rozwój i stabilność projektu. Wśród w dowolny sposób. Spis wszystkich wydanych produktów Plona można znaleźć na stronie [1]
użytkowników Plona znajdują się takie organi- – w chwili obecnej jest ich tam ponad 1200. Przykład instalacji dodatkowego produktu został
zacje jak: NASA, Oxfam, Amnesty Internatio- opisany w czwartym rozdziale niniejszego artykułu.
nal, eBay czy Novell.
Pierwsze wydanie systemu CMS Plone
miało miejsce w 2001 roku i doczekało się po-
nad 15 000 pobrań, zanim w roku 2002 wy-
ZopeSkel
Moduł ZopeSkel jest kolekcją szablonów dla narzędzia PasteScript pozwalających na bły-
dana została wersja 1.0. Wersja 2.0 wydana skawiczne tworzenie szkieletów projektów dla Zopa i Plona. Można za jego pomocą w pro-
w 2004 roku wniosła wiele zmian, wprowa- sty sposób przy użyciu tekstowego kreatora stworzyć inicjalną strukturę produktu Plona lub
dzając m.in. framework do budowania wła- czystą konfigurację buildouta dla wybranej wersji Plona.
snych typów treści w postaci produktu Ar-

32 05/2010
Plone – zbuduj firmowy intranet

cent. Chameleon będzie możliwy do wykorzy- Lisitng 1. buildout.cfg


stania w Plonie 4, jednak zostanie uwzględnio-
ny w domyślnej konfiguracji w wersji 5.0, nad [buildout]
którą również postępują prace. Głównym ce- parts =
lem wersji 5.0 jest dalsza poprawa wydajno- zope2
ści oraz wprowadzenie rewolucyjnych zmian productdistros
w interfejsie użytkownika dzięki zastosowa- instance
niu Deco – rozwiązaniu pozwalającemu użyt-
kownikowi na zarządzanie layoutem strony # Rozszeezenie konfiguracji o plik versions.cfg zawierający numery wersji
przy pomocy akcji 'drag and drop'. # modułów wchodzących w skład danej wersji Plona
Ważną cechą odróżniającą Plone od więk- extends =
szości CMS-ów jest wykorzystywanie obiekto- http://dist.plone.org/release/3.3.4/versions.cfg
wej bazy danych – ZODB. Świetnie sprawdza versions = versions
się ona tam, gdzie mamy do czynienia z hie- # Adresy url pod którymi wyszukiwane są pakiety
rarchiczną strukturą i wieloma typami treści, find-links =
a więc w zastosowaniach webowych. Jest ła- http://dist.plone.org/release/3.3.4
twa w utrzymaniu, stabilna i niezawodna. Do http://dist.plone.org/thirdparty
jej zalet należy również elastyczność w tworze- # Dodatkowe produkty
niu modeli danych. eggs =
Zastosowanie technologii ZEO [3] umożli- Products.LinguaPlone
wia korzystanie z wielu procesów klienckich stxnext.pdb
z pojedynczego serwera bazy ZODB (Zope Sto- # Moduły deweloperskie
rage Server). Z kolei komercyjne rozwiązanie develop =
ZRS [4] umożliwia dokonywanie replikacji ba-
zy, dzięki czemu eliminowany jest pojedynczy [versions]
punkt awarii. Może być to również osiągnięte # Możliwość ustawienia specyficznego numeru wersji pakietu
za pomocą rozszerzenia 'RelStorage' [5], które Products.LinguaPlone = 3.0
pozwala na przechowywanie danych w postaci plone.recipe.zope2instance = 3.6
zserializowanych obiektów w bazie relacyjnej
i wykorzystanie jej możliwości replikacji. [zope2]
# Recepta instalacji zope2
Interfejs użytkownika recipe = plone.recipe.zope2install
Od samego początku swojego istnienia Plone fake-zope-eggs = true
cechuje się przejrzystym i intuicyjnym inter- url = ${versions:zope2-url}
fejsem użytkownika. Na Rysunku 2 pokaza-
ny jest zrzut ekranu przedstawiający widok [productdistros]
dla zalogowanego użytkownika. Struktura # Recepta pozwalająca na zdefiniowanie dodatkowych produktów,
danych jest łatwa do odczytania – pasek gór- # które nie występują w postaci pakietów
nych zakładek przedstawia obiekty stworzo- recipe = plone.recipe.distros
ne na najwyższym poziomie, a poniżej wy- urls =
świetlana jest ścieżka (breadcrumbs) umożli- nested-packages =
wiająca śledzenie aktualnej lokalizacji. Sekcja version-suffix-packages =
treści podzielona jest na 3 kolumny. W lewej
i prawej kolumnie wyświetlane są zarządza- [instance]
ne kontekstowo portlety. Plone oferuje stan- # Recepta pozwalająca na dokonanie inicjalnej konfiguracji środowiska zope2
dardowo kilka typów portletów, np. kontek- recipe = plone.recipe.zope2instance
stowe menu nawigacji, listę ostatnio mody- zope2-location = ${zope2:location}
fikowanych obiektów, listę najnowszych wy- user = admin:pass
darzeń czy aktualności. Ponadto istnieje wie- http-address = 8080
le rodzajów portletów, które można zainsta- #debug-mode = on
lować w postaci dodatkowych produktów. #verbose-security = on
W środkowej kolumnie wyświetlany jest wi- eggs =
dok aktualnego obiektu. Zalogowany użyt- Plone
kownik, posiadający uprawnienia do modyfi- ${buildout:eggs}
kacji danego obiektu, widzi zielone obramo-
wanie zawierające linki do akcji, które może # Rejestracja dodatkowych produktów nie należących do przestrzeni nazw 'Products'
na nim wykonać, np. przejść do widoku edy- zcml =
cji, usunąć dany obiekt czy zmienić jego stan stxnext.pdb
w obiegu informacji. Oprócz tego, użytkow-
nik z uprawnieniami do zarządzania porta- products =
lem ma możliwość przejścia do widoku usta- ${buildout:directory}/products
wień witryny, gdzie może dokonywać zmian ${productdistros:location}
w globalnych ustawieniach portalu, zarzą-

www.sdjournal.org 33
Programowanie

dzać użytkownikami i grupami czy konfigu- z nich ogranicza się do zastąpienia lub zmia- więc dokonać instalacji Plona niezależnie od
rować dodatkowe produkty. ny standardowych szablonów stylów własny- systemu operacyjnego, którym dysponujemy.
Plone został pierwszym systemem CMS, mi. Innym stosowanym sposobem jest po- Na stronie projektu dostępne są przygotowa-
który spełnił wymagania wytycznych doty- dział na warstwę zarządzania, w której zalogo- ne zautomatyzowane instalatory dla każdego
czących dostępności treści internetowych wani użytkownicy mogą swobodnie pracować z systemów, które pozwalają na dokonanie pro-
(WCAG) w wersji 2.0 na poziomie AA. Jest w przejrzystej klasycznej skórce Plona oraz na stej instalacji za pomocą jednego kliknięcia.
również zgodny z Sekcją 508 – aktem praw- warstwę prezentacji, gdzie opublikowana treść Innym sposobem przeprowadzenia insta-
nym Kongresu Stanów Zjednoczonych regu- wyświetlana jest w widokach przygotowanych lacji jest wykorzystanie systemu zc.buildo-
lującym i gwarantującym prawa osób niepeł- na podstawie szablonów danego projektu gra- ut, który umożliwia dokonanie bardziej za-
nosprawnych w dostępie do treści elektro- ficznego. Najnowsze podejście polega na auto- awansowanej konfiguracji. Przykładowy plik
nicznych. Jako ciekawostkę można przytoczyć matycznym osadzaniu elementów z generowa- konfiguracyjny buildout.cfg został przedsta-
fakt, że arkusze stylów stworzone dla Plona nego przez Plone htmla w przygotowanym sta- wiony w Listingu 1, można go wygenerować
2.0 zostały luźno wykorzystane podczas two- tycznym projekcie html za pomocą reguł napi- dzięki modułowi 'ZopeSkel', który zawiera
rzenia layoutu Wikipedii. sanych w plikach xml. zestaw szablonów do generowania szkiele-
Istnieje możliwość łatwej zmiany domyślnej tów projektów Zope/Plone za pomocą narzę-
skórki na jedną z wielu dostępnych w postaci Instalacja dzia PasteScript.
dodatkowych produktów lub stworzenie wła- i podstawowa konfiguracja
snej. Jest kilka podejść pozwalających na doko- Zope – serwer aplikacji, na którym działa Plo- # instalacja pakietu ZopeSkel
nanie zmian w wyglądzie systemu. Pierwsze ne, jest aplikacją wieloplatformową. Można $ easy_install-2.4 ZopeSkel
# wygenerowanie skryptu instalacyjnego
i pliku konfiguracji
dla Plone 3
$ paster create -t plone3_buildout

Edytując wygenerowany plik buildout.cfg,


można wskazać dodatkowe produkty, które
mają zostać zainstalowane, wpisując ich na-
zwy w sekcji 'eggs' (oraz w sekcji 'zcml', jeżeli
dany produkt nie należy do przestrzeni nazw
'Products'), zdefiniować port, na którym bę-
dzie działać aplikacja oraz dokonać bardziej
zaawansowanych ustawień związanych z eks-
ploatacją aplikacji. Po dokonaniu konfigura-
cji można uruchomić proces instalacji, wy-
konując najpierw skrypt bootstrap.py (za po-
mocą instancji interpretera python w wer-
sji 2.4.3+):

$ python2.4 ./bootstrap.py
# uruchomienie procesu instalacji:
$ ./bin/buildout -v

Rysunek 1. Porównanie wydajności mierzonej w liczbie obsługiwanych żądań na sekundę, Po uruchomieniu procesu instalacji wszyst-
uwzględniając wyświetlanie różnych widoków kie niezbędne pakiety zostaną pobrane z in-
ternetowych repozytoriów. Po pomyślnym
zakończeniu instalacji można utworzyć ini-
cjalnego użytkownika, za pomocą którego bę-
dzie można zalogować się i zarządzać aplika-
cją z poziomu przeglądarki:

$ ./bin/instance adduser admin password

Następnie można uruchomić aplikację za po-


mocą skryptu ./bin/instance służącego do
kontrolowania aplikacji:

# uruchomienie aplikacji:
$ ./bin/instance start
# zatrzymanie aplikacji:
$ ./bin/instance start
# uruchomienie aplikacji w trybie
"foreground":
Rysunek 2. Przykładowy widok dla zalogowanego użytkownika $ ./bin/instance fg

34 05/2010
Plone – zbuduj firmowy intranet

Po zainstalowaniu dodatkowego produktu tów lub obszarów serwisu. Na przykład moż- kowników. Grupom mogą być również przy-
zazwyczaj należy jeszcze dokonać wczytania na przydzielić danemu użytkownikowi moż- pisywane role, zarówno globalne, jak i lokal-
jego ustawień inicjalnych. Może tego dokonać liwość edytowania lub publikowania treści ne. Uprawnienia posiadane przez grupy są
użytkownik posiadający prawa Zarządzające- w katalogu zawierającym dokumenty związa- przypisywane użytkownikom do nich przy-
go za pomocą panelu 'Dodaj/Usuń produkty' ne z obszarem jego działalności w firmie, nie należącym. Pozwala to na przykład na stwo-
znajdującego się w ustawieniach witryny. dając jednocześnie tych uprawnień w innych rzenie grupy 'Marketing', której zostaną nada-
katalogach, które nie są związane pełnioną ne uprawnienia do zarządzania treścią w czę-
Plone jako intranet przez niego funkcją. Role lokalne są domyśl- ści serwisu związanej z dokumentami prze-
Jak już wcześniej zostało wspomniane, głów- nie dziedziczone przez elementy znajdujące znaczonymi do realizacji działań marketingo-
ną zaletą Plona jest szeroki zakres oferowanych się w danym kontenerze. wych firmy, a każdego nowego użytkownika,
możliwości. Poniżej zostały opisane jego cechy, Kolejnym mechanizmem ułatwiającym za- który powinien posiadać takie uprawnienia,
dzięki czemu świetnie nadaje się do wykorzy- rządzanie użytkownikami i ich uprawnienia- wystarczy przypisać do tej grupy.
stywania go w roli firmowego intranetu. mi jest możliwość tworzenia i zarządzania gru- Rysunek 4 przedstawia ekran zarządzania
pami, do których można przypisywać użyt- rolami lokalnymi dla katalogu 'Aktualności'.
Zarządzanie użytkownikami i grupami
Jednym z podstawowych wymagań stawia-
nych przed systemem intranetowym jest moż-
liwość sprawnego zarządzania użytkownika-
mi. Plone charakteryzuje się rozbudowanym
systemem uprawnień, pozwalającym na spro-
stanie nawet bardzo zaawansowanym wyma-
ganiom, które mogą być wymagane podczas
tworzenia intranetu. Po pierwsze, użytkowni-
kom można przypisywać role globalne wiążące
się z przypisaniem danych uprawnień. Na Ry-
sunku 3 przedstawiony jest panel zarządzania
użytkownikami. Standardowo istnieje 6 ról:

• 'Użytkownik' – rola przypisywana do-


myślnie każdemu użytkownikowi, po- Rysunek 3. Panel zarządzania użytkownikami
zwalająca na zalogowanie się w systemie
i tworzenie treści we własnym katalo-
gu domowym, ale bez możliwości publi-
kowania treści. Umożliwia przeglądanie
opublikowanych obiektów.
• 'Czytelnik' – rola pozwalająca na przeglą-
danie treści, która nie została opubliko-
wana
• 'Wspierający' – użytkownik posiadający
tę rolę może tworzyć nową treść w porta-
lu, ale nie może edytować obiektów utwo-
rzonych przez innych użytkowników.
• 'Edytor' – daje możliwość edytowania ist-
niejącej treści.
• 'Recenzent' – rola umożliwiająca publi-
kowanie i wycofywanie z publikacji treści
w portalu.
• 'Zarządzający' – rola pozwalająca na glo-
balne administrowanie portalem – posia-
da wszystkie uprawnienia do zarządzania
treścią i użytkownikami oraz ustawienia- Rysunek 4. Ekran zarządzania rolami
mi portalu.

Oprócz wyżej wymienionych ról, które mo-


gą być przypisane danym użytkownikom,
istnieje również rola 'Właściciela', która jest
przypisywana automatycznie użytkowniko-
wi w kontekście utworzonych przez niego
obiektów i wiąże się z możliwością dokony-
wania ich modyfikacji.
Oprócz przypisywania ról globalnych, Plo-
ne daje również możliwość nadawania upraw-
nień lokalnych – dla poszczególnych obiek- Rysunek 5. Schemat 'Intranetowego/Extranetowego obiegu informacji'

www.sdjournal.org 35
Programowanie

Jak widać, pozwala on na nadanie uprawnień


dla danego użytkownika lub grupy, ale także
wyświetla uprawnienia przez nie posiadane
z racji dziedziczenia z katalogów nadrzędnych
lub posiadania przypisanej roli globalnej.

Obieg informacji
Kolejnym z zadań stawianych przed syste-
mem intranetowym jest możliwość ustalenia
obiegu informacji, pozwalającego na utrzy-
manie kontroli nad treścią. Plone pozwala na
wybór jednego z ośmiu standardowych obie-
gów, wśród których znajdują się 'Intranetowy/
Extranetowy obieg infomracji' oraz 'Intrane-
towy obieg informacji dla folderów'. Schemat
pierwszego z nich został przedstawiony na
Rysunku 5. Każdy ze stanów, w którym znaj-
duje się dany obiekt, cechuje się odpowiedni-
mi wymaganymi uprawnieniami do dokony-
wania danych akcji. Na przykład jeżeli doku-
ment znajduje się w stanie 'Prywatny' – tylko
jego właściciel lub użytkownik o roli 'Zarzą-
dzającego' lub 'Edytora' może dokonywać na
nim modyfikacji. Obiekt taki nie jest widocz-
ny dla wszystkich zalogowanych użytkowni-
ków. Obieg ten rozróżnia stany 'Opubliko-
wany wewnętrznie', kiedy dany dokument
jest widoczny dla wszystkich zalogowanych
użytkowników, ale nie widzą go użytkowni-
cy niezalogowani, oraz 'Zewnętrznie widocz-
ne', kiedy również niezalogowani użytkow-
nicy mają uprawnienia do wyświetlania tre-
ści dokumentu. Dla każdego z typów treści
Rysunek 6 Przykładowy ekran de�nicji kryteriów zbioru użytkownik o globalnej roli 'Zarządzającego'
może ustawić dany rodzaj obiegu informacji
w panelu 'Ustawienia typów treści'. Oprócz
standardowych obiegów oferowanych przez
Plona, można również wykorzystać któryś
z istniejących jako produkty zewnętrzne.
Można także stworzyć własny obieg, definiu-
jąc odpowiednie stany, przejścia, wymagane
uprawnienia oraz akcje wykonywane podczas
zmiany stanu, np. wysyłanie powiadomień
mailowych do osób, których może dotyczyć
dana zmiana stanu.

Podstawowe typy treści


Plone domyślnie oferuje kilka podstawowych
typów treści takich jak 'Folder', 'Strona', 'Ak-
tualność' czy 'Wydarzenie'. Charakteryzują
się one zestawem pól do wpisywania odpo-
wiednich informacji oraz funkcją pełnioną
w serwisie. Na przykład 'Strona' posiada pole
do wpisania tytułu, krótkiego opisu wyświe-
tlanego w listingach oraz pola zawierającego
edytor wysiwyg do wstawienia treści. Ponad-
to można zdefiniować słowa kluczowe bra-
ne pod uwagę przy zwracaniu wyników wy-
szukiwania, datę publikacji oraz datę ważno-
ści – pozwalające ustawić okres, w którym
obiekt będzie wyświetlany, autorów doku-
mentu oraz dokonać ustawień decydujących
Rysunek 7. Przykładowa lista historii zmian o tym, czy strona ma być wyświetlana w na-

36 05/2010
Plone – zbuduj firmowy intranet

wigacji, czy będzie możliwe dodawanie ko- nuje wewnętrzną wyszukiwarką, która pozwa- mentu, autor, stan w obiegu informacji czy da-
mentarzy do strony itp. Kolejnymi domyślny- la na przeszukiwanie treści portalu na podsta- tę utworzenia. Istnieje możliwość integracji
mi typami Plona są 'Plik' i 'Obraz', które po- wie zawartośći pól podlegających indeksowa- z zewnętrznym systemem wyszukiwania jak
zwalają na przechowywanie uploadowanych niu, takich jak 'Tytuł', 'Opis' czy 'Treść'. Po- na przykład Xapian czy Solr, w przypadku któ-
plików binarnych. Jednym z ciekawszych ty- nadto do obiektu można przypisać słowa klu- rego można skorzystać z gotowego produktu
pów jest 'Zbiór', który pozwala na grupowa- czowe, które również będą brane pod uwa- – collective.solr.
nie obiektów spełniających podane kryteria. gę przy zwracaniu wyników wyszukiwania.
Można na przykład stworzyć za jego pomocą Ważną cechą Plona jest możliwość indekso- Blokowanie aktualnie
zbiór obiektów typu 'Strona', które znajdują wania tekstu załączanych plików np. w posta- edytowanych dokumentów
się w stanie 'Wysłany do akceptacji', przykła- ci dokumentów MSWord lub PDF. Plone ofe- Plone domyślnie posiada mechanizm bloko-
dowy ekran definicji kryteriów zbioru został ruje również możliwość zaawansowanego wy- wania możliwości edycji treści, która aktualnie
przedstawiony na Rysunku 6. Obiekty speł- szukiwania, gdzie oprócz tekstu można podać podlega edytowaniu przez innego użytkowni-
niające podane kryteria będą wyświetlone inne kryteria, takie jak typ wyszukiwanego ele- ka. Zapobiega to sytuacjom, w których użyt-
w listingu zbioru, który może wyglądać jak
listing standardowego folderu. Jeżeli standar-
dowo istniejące typy treści okażą się niewy-
starczające – istnieje możliwość wykorzysta-
nia innych typów charakteryzujących się po-
żądanymi właściwościami, które można zain-
stalować w postaci dodatkowych produktów
lub stworzyć własny produkt definiujący nie-
zbędny typ treści.

Historia zmian
Plone umożliwia zapisywanie historii zmian
obiektów, co może okazać się bardzo przy-
datne podczas nanoszenia zmian przez róż-
nych użytkowników na danym dokumencie.
Po dokonaniu edycji użytkownik może dodać
w komentarzu czego dotyczyły jego zmiany.
Komentarz ten będzie wyświetlony w liście
historii zmian przeprowadzonych na danym Rysunek 8. Przykładowe porównanie zmian w dokumencie
obiekcie. Przykładowa lista zawierająca histo-
rię zmian przedstawiona jest na Rysunku 7.
Oprócz komentarza wyświetlany jest link po-
zwalający porównać zmiany pomiędzy kolej-
nymi wersjami, zmiany pomiędzy daną wer-
sją a wersją aktualną, oraz przycisk pozwalają-
cy przywrócić daną wersję dokumentu. Przy-
kładowe porównanie zmian w dokumencie
przedstawione zostało na Rysunku 8.

Wersje robocze
Kolejnym mechanizmem przydatnym w ser-
wisie intranetowym, gdzie nad danym doku-
mentem może pracować wiele osób, jest me-
chanizm wersji roboczych. Użytkownik może
stworzyć wersję roboczą dokumentu, na któ-
rym zamierza dokonywać zmian we własnym
katalogu domowym. Aż do momentu umiesz-
czenia swoich zmian w głównej wersji doku-
mentu lub ich anulowania – możliwość edy-
cji wersji głównej dokumentu staje się zabloko-
wana dla pozostałych użytkowników i jest opa-
trzona informacją o dokonywaniu zmian wraz
z linkiem do wersji roboczej oraz do widoku
porównania wersji roboczej do wersji głównej
(wyświetlanym w podobny sposób jak na Ry-
sunku 8).

Wewnętrzna wyszukiwarka
Wyszukiwanie treści jest istotnym elemen-
tem w systemie intranetowym. Plone dyspo- Rysunek 9. Interfejs kon�guracji produktu PloneLDAP

www.sdjournal.org 37
Programowanie

kownicy mogliby nieświadomie dokonywać Dodatkowe produkty wiązania pozwalające sprostać indywidual-
zmian w tym samym czasie na jednym obiek- Plone, oprócz tego, że jest gotowym do wyko- nym potrzebom jego odbiorców. W ten sposób
cie. Użytkownik ma możliwość świadomego rzystania produktem, stanowi również plat- powstało wiele dodatkowych produktów roz-
odblokowania danego obiektu. formę, na podstawie której tworzone są roz- szerzających podstawowe możliwości Plona
np. o integrację z serwerem LDAP, narzędzia
do zarządzania projektem (ticket tracking) czy
tworzenie treści w wielu wersjach językowych.
Praktycznie wszystkie z nich są dostępne jako
rozwiązania otwarte, więc można z nich korzy-
stać czy nawet dostosowywać je do własnych,
bardziej specyficznych potrzeb. Poniżej zosta-
ły krótko przedstawione dodatkowe produkty,
które mogą być przydatne w zastosowaniu Plo-
na jako systemu intranetowego.

PloneLDAP
Produkt pozwalający na dokonanie integra-
cji z LDAP-em – zarówno standardowym ser-
werem LDAP, jak i Microsoft Active Directory
Server. Dzięki niemu dane użytkowników zde-
finiowanych w wewnątrz-firmowym LDAP-ie
mogą być wykorzystywane w Plonie – użyt-
kowników można tworzyć, usuwać, wyszuki-
wać i przypisywać im role. Można również wy-
korzystywać grupy użytkowników zdefinio-
wane w LDAP-ie – można tworzyć nowe gru-
py i je usuwać oraz zarządzać przypisywaniem
im użytkowników.
Zainstalowanie innego produktu – sim-
plon.plone.ldap umożliwia dokonanie konfi-
guracji połączenia z serwerem LDAP, mapo-
wania właściwości zdefiniowanych w LDAP-ie
na właściwości w Plonie oraz innych ustawień
Rysunek 10. Współdzielony kalendarz – wydarzenia w kontekście miesiąca globalnych w interfejsie Plona. Na Rysunku
9 przedstawiony został interfejs konfiguracji
produktu PloneLDAP.

Singing & Dancing


Jest to produkt umożliwiający kompono-
wanie, kolejkowanie i wysyłanie wiadomo-
ści newsletter do subskrybentów. Może być
wykorzystywany w intranecie do cykliczne-
go informowania użytkowników o nowej tre-
ści w serwisie drogą mailową. Funkcjonal-
ność oferowana przez ten produkt umożli-
wia dokonanie konfiguracji za pomocą inter-
fejsu Plona – kiedy newsletter ma być wysyła-
ny (periodycznie lub manualnie), jaka treść ma
wchodzić w skład wysyłanej wiadomości (lista
utworzona za pomocą zbioru z ustawiony-
mi odpowiednimi kryteriami lub ręcznie wy-
brana treść) oraz do kogo ma zostać wysłana
wiadomość. Podczas dokonywania subskryp-
cji, użytkownik musi dokonać jej potwierdze-
nia za pomocą linku wysyłanego w wiadomo-
ści potwierdzającej subskrypcję.

Products.CalendarX
Produkt, który oferuje szeroko konfiguro-
walny kalendarz ułatwiający użytkownikom
współdzielenie informacji o wydarzeniach.
W intranecie może pełnić rolę informacyjną
Rysunek 11. Współdzielony kalendarz – wydarzenia w kontekście tygodnia oraz ułatwić kooperację użytkownikom serwi-

38 05/2010
Plone – zbuduj firmowy intranet

su. Na Rysunku 10 przedstawiony został wi- tekście tygodnia z podziałem na godziny. Kon- budowana. Do zalet tego produktu należy ła-
dok kalendarza wyświetlającego wydarzenia figuracja kalendarza umożliwia dostosowanie twość w używaniu.
odbywające się w danym miesiącu. Po najecha- go do własnych potrzeb.
niu kursorem na wydarzenie – na kalendarzu Products.Quills
podświetlone zostają dni, w których wydarze- Products.Ploneboard Produkt umożliwiający użytkownikom in-
nie ma miejsce, oraz wyświetlane są dodatko- W serwisie pełniącym rolę firmowego intra- tranetu prowadzenie bloga związanego np.
we informacje o tym wydarzeniu. CalendarX netu przydatną funkcjonalnością może być z ich aktualną działalnością wewnątrz firmy.
oferuje kilka widoków wyświetlających wyda- forum internetowe. Produkt Ploneboard da- Umożliwia on stworzenie przez użytkownika
rzenia w różnych kontekstach, na przykład na je możliwość prowadzenia w Plonie forum in- struktury bloga oraz daje możliwość tworze-
Rysunku 11 przedstawiony został widok ka- ternetowego z możliwością moderacji komen- nia wpisów. Ponadto daje możliwość wyświe-
lendarza wyświetlającego wydarzenia w kon- tarzy. Jego funkcjonalność nie jest mocno roz- tlenia portletów zawierających np. archiwum
wpisów na blogu z podziałem na miesiące czy
chmurę tagów.

Products.PlonePopoll
Jest to produkt umożliwiający zarządzanie
sondami internetowymi. Dzięki niemu użyt-
kownicy firmowego intranetu będą mieli moż-
liwość oddania swojego głosu na pytanie posta-
wione przez twórcę sondy. Podobnie jak Plone-
board, produkt ten cechuje się prostotą w ob-
słudze. Twórca sondy może zdefiniować pyta-
nie, możliwe odpowiedzi oraz liczbę jednocze-
snych możliwości wyboru. Użytkownikowi po
oddaniu głosu mogą zostać przedstawione wy-
niki sondy w postaci diagramu słupkowego.
Przykładowy ekran z wynikami sondy został
przedstawiony na Rysunku 12.

Collective.plonetruegallery
Produkt dający możliwość wyświetlania ob-
Rysunek 12. Produkt PlonePopoll – widok z wynikami sondy razków uploadowanych przez użytkowników
intranetu w postaci atrakcyjnej galerii. Po wy-
braniu widoku galerii dla folderu zawierające-
go uploadowane obrazki, wyświetlane są one
w postaci galerii zgodnie z wybranymi usta-
wieniami, pozwalającymi na wybranie roz-
miaru wyświetlanych obrazków, opcji automa-
tycznego przewijania po ustalonym czasie czy
wyświetlania listy zawierającej miniaturki wy-
świetlanych obrazków. Przykładowy widok ga-
lerii został przedstawiony na Rysunku 13.

Podsumowanie
Przedstawione w artykule informacje doty-
czące systemu CMS Plone prezentują jedynie
podstawowe jego cechy, dzięki którym moż-
na rozważać wykorzystanie go w charakterze
serwisu intranetowego. O bardziej szczegó-
łowych zagadnieniach można dowiedzieć się
dzięki szerokiej dokumentacji i wielu tutoria-
lom, które można znaleźć na stronie projektu
[6]. Ponadto, dzięki temu, że wokół Plona wy-
Rysunek 13. Produkt plonetruegallery – widok galerii obrazków tworzyła się duża i otwarta społeczność – in-
formacje można czerpać również z forów in-
Referencje ternetowych oraz list dyskusyjnych.

• (1) http://plone.org/products; RADOSŁAW JANKIEWICZ


• (2) http://blog.hannosch.eu/2010/01/plone-4-how-much-faster-is-it.html; Autor bierze udział w projektach związanych
• (3) http://zodb.org/documentation/guide/zeo.html; z wdrożeniami systemu CMS Plone. Jest entuzja-
• (4) http://www.zope.com/products/zope_replication_services.html;
• (5) http://pypi.python.org/pypi/RelStorage/1.4.0b3; stą ruchu open source i stara się aktywnie udzielać
• (6) http://plone.org/. w społeczności skupionej wokół Plona.
Kontakt z autorem: radoslaw.jankiewicz@stxnext.pl

www.sdjournal.org 39
Programowanie

Python 3
...czyli co nowego w trzeciej edycji języka

Łukasz przeprowadzi Cię przez nowości w najświeższej edycji języka


programowania Python i pokaże, w jaki sposób wpływają na sposób
tworzenia programów.

mego problemu jest w sprzeczności z pod-


Dowiesz się: Powinieneś wiedzieć: stawową filozofią Pythona. Co więcej, taka
• Dlaczego nowa wersja języka programowa- • Czym jest język Python i znać przynajmniej sytuacja może być groźna, ponieważ niejed-
nia Python odważnie zrywa z przeszłością, podstawy programowania w wersji drugiej. nokrotnie zupełnie nowy kod pisany przez
jakie nowe rozwiązania proponuje i co to Przyda się znajomość sposobu interakcji z początkujących programistów, bezwiednie
oznacza dla zwykłego programisty. interpreterem w celu zrozumienia przykła- powiela złe szablony programistyczne, któ-
dów kodu. re od dawna są niewspierane.

T-1000, Blues Brothers 2000,


strukcji językowych (m.in. wyjątki i modu- Python 3000
ły). Musiało jednak minąć wiele czasu, za- W społeczności programistów Pythona krą-
Poziom nim Python zaczął wspierać programowa- żył żart, że zmiany konieczne do uporząd-
trudności nie funkcyjne, unikod, obsługę pakietów, kowania języka zostaną w końcu zaimple-
zbieranie nieużytków (ang. garbage collec- mentowane w przyszłej wersji 3000. Po-
tion) czy wiele innych dzisiaj przyjmowa- dobny do Terminatora T-1000 z płynnego
nych za oczywiste cech języka. Przykłado- metalu, mityczny, idealny Python 3000 po-

D
ostępna od jakiegoś czasu wer- wo, metody na typie string pojawiły się jawiał się na listach dyskusyjnych tak czę-
sja trzecia języka Python jest dopiero w wersji 2.0, iteratory i generatory sto, że przyjęła się nawet skrócona wersja
przedmiotem wielu kontrower- w wersji 2.2. Do tej wersji zresztą istniało nazwy: Py3K. Ostatecznie w roku 2006
sji. W społeczności programistów wytwo- rozróżnienie na typy danych implemento- Guido van Rossum zaskoczył społeczność
rzyło się sporo mitów i obaw związanych wane na poziomie języka C oraz typy dane stwierdzeniem, że planuje realną imple-
z niekompatybilnością wstecz tej wer- komponowane w języku Python. Jedne ty- mentację Pythona 3000 i wydanie go jako
sji z linią 2.x. W tym artykule pokażemy, py miały bardzo ograniczoną możliwość in- wersji 3.0. Z olbrzymiego worka z życzenia-
że nie taki diabeł straszny, jak go malują, terakcji z drugimi poprzez typowo obiekto- mi dla Pythona 3000 wybrano spójny ze-
a stopniowe otwieranie się na wersję trze- we konstrukcje takie jak dziedziczenie czy staw zmian i zaczął się żmudny proces im-
cią niesie za sobą sporo wymiernych korzy- polimorfizm. plementacji. Ostatecznie, 3 grudnia 2008
ści. Nawet jeżeli nie planujesz w najbliż- Wraz z ewolucją języka i biblioteki stan- roku wersja 3.0 ujrzała światło dzienne.
szej przeszłości przesiadać się na nową edy- dardowej, niektóre z rozwiązań stosowa- Zmiany w Pythonie 3.0 są z jednej strony
cję Pythona, znajomość nowinek jest przy- nych w starszych programach uznawano fundamentalne, z drugiej jednak to nadal
datna, bo spora część z nich trafia również z czasem za chybione, czy to z powodu czy- w gruncie rzeczy ten sam doskonały język
do edycji 2.x. telności, wydajności, ograniczonej elastycz- programowania. Różnice dotyczą głównie
ności czy wręcz po prostu błędnego działa- pozbycia się zaszłości historycznych, naj-
Trudna droga do zen nia. W tym samym czasie, z roku na rok, częściej takich, gdzie domyślne zachowa-
Historia rozwoju języka Python sięga póź- Python stawał się coraz bardziej popular- nie języka nie było intuicyjne i jego nowi
nych lat osiemdziesiątych, kiedy Guido ną platformą, na której budowane były sys- użytkownicy produkowali w konsekwencji
van Rossum rozpoczął implementację na- temy wielkiej skali. Ta popularność stała się suboptymalny kod. Przyjrzyjmy się po ko-
stępcy języka ABC działającą pod rozpro- dla języka przekleństwem, ponieważ w ce- lei najważniejszym zmianom wprowadzo-
szonym systemem operacyjnym Amoeba. lu zachowania zgodności wstecz z istnieją- nym w wersji trzeciej.
Od tego czasu funkcjonalność po funk- cymi programami, język musiał nadal ob-
cjonalności, możliwości języka rosły. Już sługiwać nawet najbardziej przestarzałe Bajty lub znaki
pierwsza opublikowana wersja 0.9 posiada- rozwiązania. Taka sytuacja jest o tyle nie- Python 3.0 wprowadza rozróżnienie da-
ła wiele rozpoznawalnych do dzisiaj struk- ciekawa, iż dostępność wielu równorzęd- nych, na których operuje program, na dwa
tur danych (m.in. listy i słowniki) oraz kon- nych możliwości oprogramowania tego sa- rodzaje: dane binarne i dane znakowe. Te

40 05/2010
Python 3

pierwsze to tablice bajtów (typ bytes), któ-


rych treść może być dowolna, dlatego in- Listing 1. Obsługa tekstu międzynarodowego
terpreter nie pozwala na traktowanie da- >>> names = []
nych w nich zawartych jako tekst. Takie da- >>> first_name = "łukasz"
ne mogą być odczytywane z plików, trans- >>> names.append(first_name[0].upper() + first_name[1:])
mitowane przez sieć itd. Drugi rodzaj da- >>> names
nych natomiast to abstrakcyjny tekst (typ ['Łukasz']
str) przechowujący znaki: interpreter nie >>> names.append("René")
pozwala na transmisję takiego tekstu przez >>> names.append("Krüger")
sieć lub do pliku bez uprzedniego okre- >>> text = " ".join(names)
ślenia, z jakiego kodowania znaków nale- >>> text
ży przy tej operacji skorzystać. Jawna kon- 'Łukasz René Krüger'
wersja między ciągami bajtów a łańcucha-
mi tekstowymi jest doskonałym pomysłem,
Listing 2. Kodowanie tekstu w celu transmisji danych
ponieważ pozwala wydzielić zadania zwią-
zane z przetwarzaniem tekstu od zadań
związanych z transmisją lub przechowa- names_file = open("/tmp/names", "wb")
niem danych. >>> names_file.write(text)
Przy okazji przedstawiania różnicy Traceback (most recent call last):
w traktowaniu tekstu i danych między wer- File "<stdin>", line 1, in <module>
sjami 2 i 3 często zwraca się dużą uwagę na TypeError: must be bytes or buffer, not str
fakt, że wszystkie łańcuchy znaków w wer- >>> encoded_text = text.encode("utf-8")
sji trzeciej to Unicode. W praktyce podczas >>> encoded_text
korzystania z tekstu w Pythonie 3 bardzo b'\xc5\x81ukasz Ren\xc3\xa9 Kr\xc3\xbcger'
rzadko trzeba myśleć o Unikodzie. Moż- >>> names_file.write(encoded_text)
na po prostu założyć, że Python 3 operu- 21
je na abstrakcyjnym tekście, który może >>> names_file.close()
przechować praktycznie nieograniczony
zestaw znaków [1]. Dopóki operujemy na
Listing 3. Wczytanie tekstu z postaci binarnej
takim tekście w ramach programu, nie ma
dla nas znaczenia jego reprezentacja binar- >>> names_file = open("/tmp/names", "rb")
na (Listing 1). >>> byte_content = names_file.read()
Dopiero w momencie, kiedy zapisujemy >>> byte_content
taki tekst na dysku lub przesyłamy przez b'\xc5\x81ukasz Ren\xc3\xa9 Kr\xc3\xbcger'
sieć, należy nadać mu odpowiednie kodo- >>> byte_content.decode("utf-8")
wanie znaków (Listing 2). 'Łukasz René Krüger'
Podobnie, przy odczycie nowego tekstu
z dysku Python musi wiedzieć, w jakim ko-
Listing 4. Odczyt pliku w trybie binarnym i tekstowym
dowaniu znaków ten tekst jest przechowy-
wany (Listing 3). >>> byte_file = open("/tmp/names", "rb")
W celu ułatwienia pracy programisty do- >>> byte1 = byte_file.read(1)
dano nowy tryb dostępu do plików: tryb >>> byte1
tekstowy. W trybie tym konwersja z typu b'\xc5'
bytes na pythonowy str odbywa się w mo- >>> byte1.decode("utf-8")
mencie odczytu z dysku, odczytywanie Traceback (most recent call last):
więc odbywa się znak po znaku (a nie bajt File "<stdin>", line 1, in <module>
po bajcie) (Listing 4). UnicodeDecodeError: 'utf8' codec can't decode byte 0xc5 in position 0: unexpected
Jak widać na powyższym przykładzie, end of data
odczytując plik w trybie tekstowym Py- >>> text_file = open("/tmp/names", "rt", encoding="utf-8")
thon 3 za naszymi plecami buforuje zawsze >>> char1 = text_file.read(1)
odpowiednią ilość bajtów, aby odczytać peł- >>> char1
ne znaki. Twórcy Pythona 3 poszli jednak 'Ł'
jeszcze o krok dalej i zauważyli, że odczyt >>> char1.encode("utf-8")
plików w programach pythonowych naj- b'\xc5\x81'
częściej odbywa się właśnie w trybie teksto-
wym, a najpopularniejszym kodowaniem
Listing 5. Dostęp do indeksów sekwencji i atrybutów obiektów w formatowaniu
znaków jest UTF-8. Stąd domyślne otwar-
cie pliku w trybie "r" bez jawnego poda- >>> 'Pierwszy element: {keys[0]:>10s}'.format(keys=sorted(sys.modules.keys()))
nia typu danych ("rb" lub "rt") spowoduje 'Pierwszy element: __main__'
otwarcie w trybie tekstowym. Jeżeli progra- >>> f = open('/tmp/names', 'r')
mista pominie deklarację kodowania zna- >>> 'Kodowanie pliku {f.name}: {f.encoding}'.format(f=f)
ków w tak otwieranym pliku, Python 3 za- 'Kodowanie pliku /tmp/names: UTF-8'
kłada UTF-8:

www.sdjournal.org 41
Programowanie

>>> text_file = open("/tmp/names", "r") Jak widać, każda z implementacji wbu- Kolejną dużą zmianą w przetwarza-
>>> text_file.encoding dowanych funkcji w danym typie służy niu tekstu jest przekształcenie wyrażenia
'UTF-8' do czegoś innego. Ta ostatnia, ze względu print w funkcję. Pozwala to z jednej stro-
>>> text_file.readline() na swoją konfigurowalność poprzez argu- ny na bardziej spójny kod, gdzie składnia
'Łukasz René Krüger' ment, jest szczególnie przydatna w prze- print nie jest wyjątkiem. Z drugiej stro-
twarzaniu tekstu. Do tego celu można ny pozwala na podmianę implementacji
Przetwarzanie tekstu używać zarówno wbudowanej funkcji funkcji print() inną w trakcie wykona-
Rozumiejąc już różnicę między tekstem format(), jak i nowej metody format() na nia programu, dzięki czemu można w bar-
a danymi binarnymi w wersji trzeciej Pytho- łańcuchach znaków: dziej elegancki sposób obsługiwać ko-
na, skupmy się chwilowo na samym tekście i munikaty diagnostyczne. Kilka przykła-
nowych cechach w jego przetwarzaniu. Du- >>> format(x, "6.1f") dów możliwości nowej funkcji print (Li-
żą rolę w trakcie operacji na tekście ma moż- ' 0.1' sting 6).
liwość wstrzykiwania w łańcuchy teksto- >>> format(x, "<6.1f")
we danych zewnętrznych, po odpowiednim '0.1 ' Najlepsza rzecz od odkrycia
sformatowaniu. Funkcjonalność tę zapo- >>> '{0:6.1f}, {0:<6.1f}'.format(x) krojonego chleba: iteracja
czątkowała funkcja printf w języku C i do ' 0.1, 0.1 ' Od czasu wprowadzenia do języka genera-
czasu Pythona 3 niewiele się w tej kwestii torów i iteracji, podejście do rozwiązywa-
zmieniło. Klasyczna notacja jest nadal do- Metoda format() z ostatniego przykła- nia wielu problemów obliczeniowych dia-
stępna, ale w przyszłości zostanie ostatecz- du korzysta z nowej notacji {indeks _ metralnie się zmieniło. Możliwość opisy-
nie usunięta z języka. W jej miejsce wprowa- a r g u m e n t u : s p o s ó b _ fo r m at o w a n i a} . wania problemu, jak gdyby był wykonywa-
dzono nowy mechanizm, o znacznie zwięk- W powyższym przykładzie dwukrotnie ny sekwencyjnie, powoduje z jednej stro-
szonej elastyczności: format(). Podstawo- wykorzystano argument o indeksie ze- ny dużą czytelność, a z drugiej brak na-
wą różnicą w stosunku do tradycyjnego jest rowym podany do metody format(), za rzutu pamięciowego i wydajnościowego na
fakt, że obiekt formatowany sam definiuje, każdym razem formatując go inaczej. In- uprzednie przygotowanie struktur danych.
w jaki sposób jego formatowanie przebiega: deksowanie jest jednak bardzo elastycz- To, co w wersji drugiej Pythona wymagało
ne i nie ogranicza się do prostego podawa- stosowania metod z przedrostkiem iter lub
>>> x = 0.3/3 nia numeru argumentu funkcji format(). x, w Pythonie 3 jest zachowaniem domyśl-
>>> x.__str__() Możliwe jest również odwoływanie się do nym (Listing 7).
'0.1' konkretnych indeksów w kolekcjach lub Zmiana ta jest o tyle istotna, że teraz za-
>>> x.__repr__() wręcz atrybutów obiektów (Listing 5). chowanie naturalne - domyślne, jest zacho-
'0.09999999999999999' Sposób formatowania jest opisywany waniem generującym algorytmy o znacznie
>>> x.__format__("0.2f") w sposób bardzo zbliżony do tradycyjnego, lepszej charakterystyce pamięciowej i wy-
'0.10' możliwe wartości opisuje Tabela 1. dajnościowej. Jeżeli jednak nasz konkretny
algorytm będzie wymagał klasycznej listy,
Tabela 1. Zapis łańcuchów formatujących w Python 3 możemy ją nadal uzyskać za pomocą jaw-
Rodzaj Wartość Znaczenie nej konwersji:
Wyrównanie < wyrównanie do lewej
>>> modules_keys = list(sys.modules.keys())
^ wyrównanie do środka >>> modules_keys.sort()
> wyrównanie do prawej >>> modules_keys[:3]
Szerokość liczba ilość znaków, które zajmie całe pole ['__main__', '_abcoll', '_bisect']

Dokładność liczba dla zmiennych typu int i float, ilość miejsc po przecinku
Cukierki składniowe
Kod d formatowanie dziesiętnej liczby całkowitej Tzw. syntactic sugar to cechy języka bez
f formatowanie dziesiętnej liczby zmiennoprzecinkowej istotnego wkładu funkcjonalnego, które
s formatowanie łańcucha znaków jednak pozwalają w lepszy sposób wyrażać
e formatowanie liczby w notacji naukowej
zamiary programisty. Najczęściej cukierki
takie cechuje zwięzłość i czytelność. W kul-
x formatowanie liczby szesnastkowej
turze programistów Pythona cechy te są
o formatowanie liczby ósemkowej szczególnie pożądane, nic więc dziwnego,
b formatowanie liczby binarnej że wersja trzecia przyniosła kilka nowych.
% formatowanie liczby w procentach (1.0 == 100%) Najciekawsze wydaje się składanie słowni-
ków i zbiorów (ang. odpowiednio dictiona-
Tabela 2. Reorganizacja bibliotek HTTP ry comprehensions, set comprehensions),
przykładowo (Listing 8).
Python 2.x Python 3
Ciekawa wydaje się też możliwość ano-
httplib http.client towania funkcji i metod. Język sam w so-
BaseHTTPServer http.server bie nie interpretuje tych anotacji, ale są
CGIHTTPServer http.server dostępne w czasie uruchomienia do intro-
SimpleHTTPServer http.server
spekcji. Taka konstrukcja może posłużyć do
eleganckiego implementowania różnego ro-
Cookie http.cookies
dzaju kontroli typów, interfejsów lub doku-
cookielib http.cookiejar mentowania kodu (Listing 9).

42 05/2010
Python 3

Biblioteka standardowa krotek w listach argumentów def fun(a, Zmiany dotknęły też samą definicję klas,
Python 3.0 posiada w pełni zrewidowaną (b, c)), usunięto notację `var` na rzecz która teraz wspiera dynamiczne podawa-
bibliotekę standardową. Usunięto z niej repr(var)). Ponadto wynikiem dzielenia nie klas bazowych, zmienia określanie me-
wiele nieutrzymywanych bibliotek, zlikwi- jest teraz zawsze liczba zmiennoprzecin- taklas oraz pozwala dołączać dowolne ar-
dowano też biblioteki o powtarzającej się kowa, a niejawne importy zależne są nie- gumenty kluczowe do definicji klas (Li-
funkcjonalności lub rzadko wykorzystywa- dozwolone. sting 10).
ne. Pełną listę można znaleźć pod adresem
[2]. Struktura pozostałych bibliotek zosta- Listing 6. Nowa funkcja print w działaniu
ła przeorganizowana tak, aby lepiej odpo-
wiadała logicznie funkcjonalności zawar- >>> print('Hello', 'World')
tej w danej bibliotece. Ponadto, nazewnic- Hello World
two bibliotek zostało dostosowane do ofi- >>> print('Hello', 'World', end='!\n\n')
cjalnych reguł stylu [3]. Przykład zmian dla Hello World!
pakietów odpowiedzialnych za komunika-
cję HTTP przedstawia Tabela 2. >>> print(1, 2, 3, sep='; ')
1; 2; 3
Zmiany występujące >>> print('Error message!', file=sys.stderr)
również w Pythonie 2.6 Error message!
Szereg oryginalnych zmian z Pythona 3.0
pojawiło się również w wersji 2.6. W po-
Listing 7. Domyślne wykorzystanie iteratorów w Pythonie 3
dobny sposób wersja 2.7 będzie poszerzo-
na o część nowych cech wersji 3.1 i nad- >>> for i in range(10):
chodzącej 3.2. Takie przenoszenie wstecz ... print(i, end=' ')
nowych funkcjonalności ma na celu uła- ... if i == 9: print()
twienie późniejszej aktualizacji progra- ...
mów do wersji trzeciej języka. Użytkow- 0 1 2 3 4 5 6 7 8 9
ników Pythona, którzy nie śledzą na bieżą-
co zmian w kolejnych jego odsłonach, mo- >>> type(range(10))
że zaskoczyć, że następujące funkcjonalno- <class 'range'>
ści są dostępne zarówno w wersji 3.0, jak >>> isinstance(range(10), list)
i w 2.6: False
>>> import sys
• wyrażenie with, uogólniające zarzą- >>> type(sys.modules)
dzanie kontekstowe zasobami (np. pli- <class 'dict'>
kami) [5] >>> type(sys.modules.keys())
• pakiet multiprocessing, pozwalają- <class 'dict_keys'>
cy implementować aplikacje równole- >>> for i in sys.modules.keys():
głe wykorzystujące osobne procesy za- ... if i[0] == '_':
miast wątków [6] ... print(i, end=' ')
• dekoratory klas [7] ...
• nowa składnia obsługi wyjątków: _collections _sre __main__ _heapq _weakref _codecs _bisect _functools _locale _io
except Error as varError2 as var2 _weakrefset _abcoll
• usunięte zostało rzucanie łańcuchów
znaków jako wyjątków (zaszłość z wer-
Listing 8. Składanie słowników i zbiorów
sji 0.9!)
>>> some_dict = {'a':1, 'b':2, 'c':3, 'd':3, 'e':3}
Oprócz wymienionych wyżej i kilku >>> inverted = {v: k for k, v in some_dict.items()}
mniej istotnych, Python 2.6 zawiera rów- >>> inverted
nież opisane w poprzednich sekcjach no- {1: 'a', 2: 'b', 3: 'd'}
we formatowanie łańcuchów, nową funk- >>> some_set = {value/2 for value in some_dict.values()}
cję print czy też nową bibliotekę io. >>> some_set
{0.5, 1.5, 1.0}
Zmiany usuwające >>> other_set = {1,3,5}
przestarzałe cechy języka
W wersji 3.0 na dobre usunięto wiele roz-
Listing 9. Anotacje
wiązań, które od dawna były uznawane
przez całe środowisko za przestarzałe i pro- >>> def fun(a: "non-empty", b: "positive integer") -> "string":
blematyczne. Na pierwszy ogień poszły kla- ... pass
sy starego typu, czyli rodzaj klas stworzony ...
przed zunifikowaniem typów C i typów py- >>> fun.__annotations__
thonowych. Wraz z nimi dokonano porząd- {'a': 'non-empty', 'b': 'positive integer', 'return': 'string'}
ków w składni języka (m.in. zrezygnowano
ze znaku nierówności <>, rozpakowywania

www.sdjournal.org 43
Programowanie

3000 niezgodności kompatybilnych pakietów rośnie, nadal jed- Co więc robić? Czekać dalej, aż masa kry-
Ze względu na rozmach zmian w inter- nak bardzo łatwo trafić na bibliotekę, bez tyczna zostanie przekroczona? Właśnie ta-
preterze i bibliotece standardowej, progra- której nie wyobrażamy sobie życia, a która kie oczekiwanie powoduje, że przejście
my tworzone z myślą o Pythonie 2.x nie nie działa pod "trójką". Wspomnieć można z wersji 2.x do 3.x zajmuje tak długo. Każ-
są zgodne z nową wersją. Takie założenie choćby o takich gigantach jak Python Ima- dy większy projekt pisany w oparciu o Py-
twórców stanowi jednak nie lada wyzwa- ging Library, virtualenv, easy_install [8] czy thona ma z pewnością wydzielone bibliote-
nie dla programistów, ponieważ w prakty- WSGI. Z czasem jednak przybywa uaktual- ki, które da się przeportować, bo nie są bez-
ce nawet najprostszy program pisany z my- nionych pakietów, ostatnio przeportowane pośrednio zależne od nieistniejących kom-
ślą o wersji 2.x nie uruchomi się pod wersją zostały biblioteki Jinja2 i lxml. Część biblio- ponentów. Utrzymywanie dla nich wersji
3.x bez zmian w kodzie. W konsekwencji tek zawiera wersje kompatybilne w repozy- zgodnej z Pythonem 3 jest o tyle mądre, iż
większość istniejących bibliotek zewnętrz- toriach kodu źródłowego i można liczyć na w momencie, kiedy giganci środowiska py-
nych na dzień dzisiejszy nie wspiera jesz- to, że w niedalekiej przyszłości ujrzą światło thonowego wydadzą wersje zgodne z Py-
cze nowej edycji Pythona. Na szczęście ilość dzienne na PyPI [9]. thonem 3, nasze projekty będą gotowe na
migrację. PyQt już działa, portowane są fra-
Listing 10. Argumenty kluczowe w de�nicji klas meworki Django i Pylons. W dalszej per-
spektywie ujrzymy też ZOPE i Twisted.
>>> class A: pass Jak portować? Nie jest to na szczęście
>>> class B: pass takie trudne, jakby się mogło wydawać.
>>> bases = A, B W dystrybucji Pythona 3 zawarte jest na-
>>> class C(*bases): pass rzędzie 2to3 [10], które dużą część pracy
>>> C.__bases__ wykonuje automatycznie za programistę.
(<class '__main__.A'>, <class '__main__.B'>) Kiedy narzędzie to trafia na odpowiednio
dostosowany kod 2.x, potrafi wyproduko-
>>> class Meta(type): wać w pełni działającą wersję dla Pythona
... def __new__(cls, name, bases, cls_dict, message): 3. Nie zawsze jest tak łatwo, niemniej jed-
... print('new', message) nak warto spróbować. Portowanie za pomo-
... return type.__new__(cls, name, bases, cls_dict) cą 2to3 działa szczególnie dobrze dla bi-
... def __init__(cls, name, bases, cls_dict, message): bliotek operujących na tekście, w odróżnie-
... print('init', message) niu od takich, które operują na danych bi-
... super().__init__(name, bases, cls_dict) narnych. Dodatkowo, możliwe jest dystry-
... buowanie pakietów źródłowych opartych
>>> class D(metaclass=Meta, message="This is D"): pass o distribute, które w przypadku wykrycia
new This is D wersji trzeciej Pythona automatycznie wy-
init This is D konają konwersję przy użyciu 2to3. Ozna-
>>> D() cza to, że możemy przygotować pakiety
<__main__.D object at 0x100667f10> w PyPI, które będą poprawne zarówno dla
>>> class E(metaclass=Meta, message="This is E"): pass wersji drugiej jak i trzeciej. Jedyną wadą ta-
new This is E kiego rozwiązania jest fakt, że kod źródło-
init This is E wy pozwalający na bezbłędną pracę zarów-
no w interpreterze w wersji 2 jak i w wersji
najnowszej, nie jest tak ładny jak może być
kod pisany z myślą o tylko jednej gałęzi.
Przypisy Podsumowanie
• [1] Jest to pewne uproszczenie, Unicode posiada kilka możliwych reprezentacji binar- W ostatecznym rozrachunku wersja 3 Py-
nych, spośród których Python może wewnętrznie wykorzystywać dwie: UCS-2 i UCS-4. thona jest dużym krokiem naprzód. Wpro-
Ta pierwsza posiada alfabet ograniczony do 65536 podstawowych symboli, ta druga po- wadzenie szeregu niezgodnych wstecz mo-
zwala na reprezentację pełnego alfabetu Unicode, wymaga natomiast dwukrotnie więk- dyfikacji do języka i biblioteki standardo-
szej ilości bitów na przechowanie takiego samego ciągu znaków. Zmiana sposobu kodo-
wej było dla twórców posunięciem ryzy-
wania znaków Unicode jest możliwa na etapie kompilacji interpretera, domyślnie używa-
ny jest bardziej popularny zestaw UCS-2. kownym, ponieważ biorąc pod uwagę popu-
• [2] http://www.python.org/dev/peps/pep-3108/ larność języka i mnogość bibliotek zewnę-
• [3] http://www.python.org/dev/peps/pep-0008/ trnzych, niebagatelnie utrudnia migrację
• [4] Oczywiście bardziej złożone aplikacje zdecydowanie zyskają, korzystając z biblioteki na wersję najnowszą. Jednocześnie jednak
logging, która daje znacznie większą konfigurowalność. zmiany te porządkują język i umożliwiają je-
• [5] http://www.python.org/dev/peps/pep-0343/
• [6] http://www.python.org/dev/peps/pep-0371/ go dalszy rozwój.
• [7] http://www.python.org/dev/peps/pep-3129/
• [8] Istnieje ambitny projekt porządkujący kwestię paczkowania oprogramowania pytho-
nowego: distribute (http://python-distribute.org/). Ze względu na to, że odchodzi on od
koncepcji paczek egg, nie implementuje on funkcjonalności easy_install. Zostanie ona ŁUKASZ LANGA
zastąpiona przez PIP (http://pip.openplans.org/), który posiada wersję zgodną z Pytho-
Autor interesuje się muzyką, reżyserią dźwię-
nem 3 w repozytorium.
• [9] Python Package Index: http://pypi.python.org/pypi ku i fotogra�ą, sprawdza się jako młody tata,
• [10] http://docs.python.org/library/2to3.html a w wolnym czasie prowadzi własną �rmę progra-
mistyczną. Kontakt z autorem: lukasz@langa.pl

44 05/2010
Programowanie

Testy wydajnościowe
z Funkloadem
Masz problemy z wydajnością swojej aplikacji? Nie wiesz gdzie leży
problem? A może po prostu chcesz wiedzieć czy twoja konfiguracja
wytrzyma prawdziwe obciążenie? W dodatku szukasz rozwiązania
OpenSource? Przeczytaj koniecznie ten artykuł...

Ponieważ scenariusze to czysty Python,


Dowiesz się: Powinieneś wiedzieć: możemy skorzystać z całego bogactwa te-
• Jak zainstalować Funkloada; • Co to są testy wydajnościowe. go języka (np. w celu wygenerowania loso-
• Jak nagrać scenariusz testu wydajnościo- wych danych, skorzystania z wyrażeń regu-
wego; larnych etc).
• Jak wygenerować raport i jak go zinterpre-
tować. Instalacja dla systemów Ubuntu
Funkloada można zainstalować na kilka spo-
sobów. Jeżeli jesteś szczęśliwym użytkowni-
Specyfika Funkloada kiem Ubuntu, możesz skorzystać z repozy-
Funkload to bardzo ciekawa alternatywa, toriów systemu operacyjnego – wystarczy
Poziom która łączy testy wydajnościowe z jednost- więc wykonać:
trudności kowymi. Poszczególne scenariusze zapisy-
wane są w formacie pythonowych unitte- $ sudo apt-get install funkload
stów, a API obsługujące interakcję HTTP
z testowanym serwerem oparte jest o webu- W ten sposób zostanie zainstalowany

I
stnieje wiele różnych sposobów testo- nity. Umożliwia to automatyczne pobiera- Funkload wraz ze wszystkimi wymaga-
wania wydajności aplikacji interneto- nie wszystkich zasobów strony (tj arkuszy nymi bibliotekami. Jeżeli posiadasz przy-
wych. Większość programistów zetknę- styli, obrazków, skryptów JavaScript), ob- najmniej wersję Ubuntu Karmic Koala,
ła się z tym problemem i to zapewne nie je- sługę cookies, HTTP, HTTPS, GET, POST, zostanie zainstalowana wersja Funklo-
den raz. Wśród rozwiązań niekomercyjncyh BasicAuthentication, ResponseRedirects ada 1.10.0-3 (najnowsza to 1.11.0). Nie-
jednym z najbardziej popularnych (a zara- etc. Większość parametrów można oczywi- stety w przypadku starszych dystrybucji
zem jednym z najstarszych – wersja 1.0 zo- ście konfigurować. Scenariusze mogą być dostępna wersja ma ponad 3 lata. W ta-
stał wydana w 1998 roku) jest JMeter. Jest uruchamiane masowo (tzw. bench) – mo- kim przypadku zawsze możesz skorzystać
to projekt Jakarty, w 100% napisany w Javie żemy wtedy testować obciążenie naszej z ręcznej instalacji.
opublikowany na licencji Apache 2.0. Posia- aplikacji. Istnieje także możliwość odpale-
da dość liczną grupę wiernych użytkowni- nia testów jednostkowych (tzw. test), które Instalacja
ków, sam jednak nigdy nie mogłem się do w dość ciekawy sposób mogą weryfikować za pomocą easy_install
niego przekonać. poprawność działania serwisu (np. jako te- Drugim sposobem, polecanym wszystkim
Nie podoba mi się jego drzewiasta struk- sty akceptacyjne). użytkownikom, jest ręczna instalacja za po-
tura, która wymaga przeklikania się przez Sam funkload zawiera kilka ciekawych na- mocą skryptu easy_install. Sam Funkload
gąszcz parametrów w celu skonfigurowa- rzędzi pomocniczych: wymaga kilku dodatkowych bibliotek i na-
nia testu. Bardzo ucieszył mnie zatem fakt, rzędzi, tak więc ZANIM zainstalujemy Fun-
że środowisko Pythona ma swoje własne • proxy oparte na TCPWatch, nagrywają- kloada, musimy upewnić się, że je mamy.
narzędzie w wielu miejscach przewyższa- ce scenariusz z operacji realizowanych W przypadku Ubuntu (Listing 1).
jące wspomnianego JMetera. Mowa o pro- w przeglądarce (opisane szczegółowo Na innych systemach trzeba zainstalować
jekcie Funkload, który od prawie 5 lat zdo- poniżej); powyższe biblioteki Pythona ręcznie. Gnu-
bywa coraz większą popularność. Pierwsza • funkcje do tworzenia danych testo- Plot wymagany jest do generowania rapor-
jego wersja została wydana w roku 2005 wych; tów i jest opcjonalny. Podobnie TCPWatch
przez francuską firmę Nuxeo. Został na- • monitor obciążenia serwera; – wymagany jest tylko, jeśli chcemy skorzy-
pisany w Pythonie, w 100% open source, • generator raportów (ReST, HTML, stać z nagrywarki proxy. Będziesz potrzebo-
wydany na licencji GNU General Public PDF, XML); wać także narzędzia easy_install. Jeśli posia-
License v2. • generator raportów różnicowych. dasz Ubuntu:

46 05/2010
Testy wydajnościowe z Funkloadem

$ sudo apt-get install python-setuptools FooBar.conf stały one opisane szczegółowo na stronie
Plik konfiguracyjny naszego testu. Ilość projektu). Postaram się przedstawić tylko te
Możesz zainstalować go też ręcznie: opcji konfiguracyjnych jest dość spora (zo- najważniejsze:

$ cd /tmp
$ wget http://peak.telecommunity.com/
dist/ez_setup.py
$ sudo python ez_setup.py

Nareszcie możemy zainstalować samego


Funkloada:

$ sudo easy-install -U funkload

W efekcie powinny zostać zainstalowane


dodatkowe skrypty:

• fl-run-test – uruchamia testy jednost-


kowe;
• fl-run-bench – uruchamia testy wydaj-
nościowe;
• fl-record – uruchamia nagrywarkę
proxy;
• fl-build-report – generuje raport;
• fl-monitor-ctl – uruchamia narzędzie
monitorujące maszynę;
• fl-credential-ctl – narzędzie do prze-
chowywania haseł;
• f l-install-demo – test poinstalacyj-
ny.

Pierwszy test wydajnościowy


Jednym ze sposobów tworzenia testów jest
skorzystanie z nagrywarki proxy. W ten spo-
sób bardzo szybko stworzymy szkielet na-
szego scenariusza (który nagrywarka proxy
zapisze w postaci gotowego unittestu Py-
thona). Uruchomienie proxy jest dość pro-
ste (Listing 2). Rysunek 1. Kon�guracja Firefoxa
Parametr port definiuje numer por-
tu, na którym proxy będzie nasłuchiwać, Listing 1. Instalacja wymaganych bibliotek
foo_bar to nazwa naszego testu (po skoń-
czonym nagrywaniu zostaną utworzone $ sudo apt-get install python-dev python-xml python-setuptools \
dwa pliki test_FooBar.py oraz FooBar.conf). python-webunit python-docutils gnuplot
Ostatni parametr jest ważny, jeśli go zapo- $ sudo apt-get install tcpwatch-httpproxy --without-recommends
mnimy fl-record nie stworzy żadnych pli-
ków, tylko zrzuci wszystko na standardo-
Listing 2. Nagrywarka proxy Funkloada
we wyjście.
Następnym krokiem jest konfiguracja na- $ fl-record --port=8080 foo_bar
szej przeglądarki, tak aby wszystkie żądania Hit Ctrl-C to stop recording.
przekazywała do nagrywarki. W przypadku HTTP proxy listening on :8080
Firefoxa ustawienia te powinny wyglądać Recording to directory /tmp/tmpehfOBw_funkload.
tak jak na Rysunku 1.
Po skonfigurowaniu proxy, wystarczy
wpisać adres testowanej strony, aby rozpo-
Dodatki do Funkloada dostępne na http://pypi.python.org:
cząć nagrywanie. W moim przypadku bę-
dzie to http://sdjournal.org/. Następnie kli- • collective.funkload – bardzo pomocny wrapper do Funkloada integrujący go z aplikacja-
kam na podstrony serwisu, które zamie- mi Plone/Zope;
rzam poddać testom. Po skończonym te- • collective.funkbot – integracja raportów Funkloada z buildbotem (narzędzie do tzw. cią-
głej integracji);
ście w terminalu naciskamy Ctrl+C, aby za-
• collective.recipe.funkload – integracja Funkloada z buildoutem (system do tworzenia,
kończyć nagrywanie. Funkload powinien konfigurowania i wdrażania aplikacji, popularny w środowisku Plone, Django, Pylons,
utworzyć dwa pliki, przyjrzyjmy się im do- Repoze etc).
kładniej.

www.sdjournal.org 47
Programowanie

• url – adres url testowanego serwe-


Listing 3. Scenariusz testowy Funkloada ra. Zmieniając ten parametr, możemy
w prosty sposób testować różne serwe-
import unittest ry za pomocą tego samego scenariusza;
from funkload.FunkLoadTestCase import FunkLoadTestCase • cycles – lista cykli testów wydajnościo-
from webunit.utility import Upload wych wraz z liczbą równoległych użyt-
from funkload.utils import Data kowników;
• duration – długość trwania jednego cy-
class FooBar(FunkLoadTestCase): klu (w sekundach).
"""XXX
This test use a configuration file FooBar.conf. test_FooBar.py
""" Scenariusz naszego testu w formacie pytho-
nowego unittestu (Listing 3).
def setUp(self): Jak widać na powyższym listingu, Funklo-
"""Setting up test.""" ad utworzył za nas gotowy scenariusz wraz
self.logd("setUp") z wszystkimi żądaniami: zarówno GET, jak
self.server_url = self.conf_get('main', 'url') i POST. Możemy teraz dowolnie zmodyfi-
kować test, dodać dodatkowe kroki etc. Po
def test_foo_bar(self): skończonej edycji przyszedł czas na odpale-
server_url = self.server_url nie testów.
self.get(server_url + "/",
description="Get /") Uruchamianie
Najpierw sprawdźmy, czy test działa po-
self.get(server_url + "/aktualnosci", prawnie:
description="Get /aktualnosci")
self.get(server_url + "/o-nas", $ fl-run-test -v test_FooBar.py
description="Get /o-nas") -------------------------------
self.get(server_url + "/download", Ran 1 test in 29.944s
description="Get /download") OK
self.get(server_url + "/magazine/article",
description="Get /magazine/article") Status OK oznacza, że wszystko jest w po-
self.get(server_url + "/magazine", rządku, możemy przystąpić do testów wy-
description="Get /magazine") dajnościowych:
self.get(server_url + "/newsletter", description="Get /newsletter")
self.get(server_url + "/forum",
description="Get /forum")
self.get(server_url + "/wspolpraca",
description="Get /wspolpraca")
self.get(server_url + "/subscription",
description="Get /subscription")

self.post(server_url + "/user/create", params=[


['user[login]', 'username'],
['user[email]', 'user@domain.com'],
['user[password]', 'password'],
['user[password_confirmation]', 'password'],
['user[newsletter]', '0'],
['user[newsletter]', '1'],
['user[website_url]', ''],
['commit', 'Zarejestruj si\xc4\x99']],
description="Post /user/create")

def tearDown(self):
"""Setting up test."""
self.logd("tearDown.\n")

if __name__ in ('main', '__main__'):


unittest.main()

Rysunek 2. Raport Funkloada w HTML

48 05/2010
Testy wydajnościowe z Funkloadem

$fl-run-bench test_FooBar.py FooBar.test_


Listing 4. Podsumowanie testu wydajnościowego foo_bar

===================================== Pierwszy parametr definiuje plik z testa-


Benching FooBar.test_foo_bar mi, a następnie lista Klas.funkcji do prze-
===================================== testowania.
Configuration W rezultacie powinniśmy otrzymać (Li-
============= sting 4).
* Current time: 2010-02-24T19:09:03.845624 W tym krótkim podsumowaniu, które
* Configuration file: /virtualenv/funkload/FooBar.conf Funkload zwrócił na standardowe wyjście,
* Log xml: /virtualenv/funkload/foo_bar-bench.xml możemy wydzielić trzy części:
* Server: http://sdjournal.org
* Cycles: [1, 2, 3] • konfiguracja – czyli parametry, z który-
* Cycle duration: 30s mi zostały odpalone testy (url, ilość cy-
* Sleeptime between request: from 0.0s to 2.0s kli, parametry czasu etc);
* Sleeptime between test case: 1.0s • benchmarking – czyli dokładny opis
* Startup delay between thread: 0.2s poszczególnych cykli z informacją, jak
długo trwał test, z jakim statusem się
Benching zakończył etc.;
======== • wynik testu – ostateczne podsumowa-
Cycle #0 with 1 virtual users nie z podziałem na testy, które zakoń-
----------------------------- czyły się pozytywnie (success), które za-
* Current time: 2010-02-24T19:09:03.846084 kończyły się błędem serwera testowego
* Starting threads: . done. (failures), lub błędem samego testu (er-
* Logging for 30s (until 2010-02-24T19:09:34.047316): done. rors).
* Waiting end of threads: . done.
* Waiting cycle sleeptime 1s: ... done. Dodatkowo został utworzony plik xml, na
* End of cycle, 33.11s elapsed. bazie którego możemy stworzyć raport:
* Cycle result: **SUCCESSFUL**, 0 success, 0 failure, 0 errors.
$fl-build-report --html foo_bar-bench.xml
Cycle #1 with 2 virtual users --output-
----------------------------- directory=./output
* Current time: 2010-02-24T19:09:36.955814
* Starting threads: .. done. Tak wygląda fragment wygenerowanego ra-
* Logging for 30s (until 2010-02-24T19:10:07.360480): done. portu w HTML (Rysunek 2).
* Waiting end of threads: .. done.
* Waiting cycle sleeptime 1s: ... done. Podsumowanie
* End of cycle, 49.01s elapsed. W artykule przedstawiłem najbardziej
* Cycle result: **SUCCESSFUL**, 0 success, 0 failure, 0 errors. podstawowe wykorzystanie Funkloada.
Ilość opcji i konfiguracji jest naprawdę spo-
Cycle #2 with 3 virtual users ra. Zachęcam do zapoznania się z doku-
----------------------------- mentacją (niestety tylko w języku angiel-
* Current time: 2010-02-24T19:10:25.969717 skim) na stronie projektu. Pomimo wie-
* Starting threads: ... done. lu zalet, które starałem się zaprezentować,
* Logging for 30s (until 2010-02-24T19:10:56.577034): done. Funkload ma też ograniczenia. Jednym
* Waiting end of threads: ... done. z najbardziej irytujących jest brak możli-
* Waiting cycle sleeptime 1s: ... done. wości uruchomienia testu na wielu ma-
* End of cycle, 44.80s elapsed. szynach oraz używanie osobnego wątku
* Cycle result: **SUCCESSFUL**, 0 success, 0 failure, 0 errors. dla każdej symulowanej sesji. Pojedynczą
aplikację w ten sposób przetestujemy, wy-
Result dajność bardziej złożonej farmy serwerów
====== już raczej nie.
* Success: 1 Nadal jednak jest to narzędzie bardzo uży-
* Failures: 0 teczne, które umożliwia pisanie testów przy
* Errors: 0 minimalnym nakładzie pracy, a ich kod jest
Bench status: **SUCCESSFUL** przejrzysty i w 100% w Pythonie.

ANDRZEJ MLECZKO
W Sieci Plone Integrator. Pracuje dla RedTurtle Technolo-
• Strona projektu Jmeter: http://jakarta.apache.org/jmeter/index.html gy – jednej z czołowych �rm Plone w Europie.
• Strona projektu Funkload: http://funkload.nuxeo.org Kontakt z autorem:
andrzej.mleczko@redturtle.net

www.sdjournal.org 49
Programowanie

Django
Doświadczenia z pracy z frameworkiem

Łukasz pokaże Ci kilka mniej oczywistych wskazówek, które pozwolą


uniknąć błędów projektowych przy pierwszych serwisach tworzonych
w oparciu o framework Django.

ZONE itp. Dzięki rozdziałowi ustawień glo-


Dowiesz się: Powinieneś wiedzieć: balnie prawdziwych od tych, które z pew-
• W jaki sposób można zadbać o sukces wdro- • Czym jest framework Django i znać podsta- nością będą się różnić między konkretnymi
żenia systemu, jak najlepiej dzielić funkcjo- wy programowania w oparciu o wersję 1.1 instalacjami systemu, unikamy kilku nie-
nalność w serwisie i o jakich cechach Djan- lub nowszą. Możesz oprzeć się na artyku- bezpiecznych sytuacji. Z jednej strony cho-
go należy pamiętać podczas tworzenia apli- le wprowadzającym do tworzenia aplikacji dzi o nieświadome użycie nieprawidłowych
kacji WWW. WWW w Django w tym numerze. ustawień w obcym środowisku (np. strefa
czasowa lub włączenie trybu DEBUG), z dru-
giej o przypadkowe nadpisanie odpowied-
wisu w warunkach polowych. O czym więc nich dla danego środowiska ustawień przez
warto pamiętać? ustawienia programisty podczas aktualiza-
Poziom Po pierwsze, chcąc nie chcąc, żaden nietry- cji kodu źródłowego w repozytorium (o bez-
trudności wialny projekt nie jest samotną wyspą i korzy- względnej konieczności używania systemu
sta z szeregu bibliotek zewnętrznych. Od po- wersjonowania kodu [3] nie muszę chy-
czątku więc warto zadbać o odpowiednie au- ba przekonywać?). Istnieje kilka podejść do
tomatyczne zarządzanie zależnościami. Mo- stworzenia takiego podziału, z których naj-

O
ile dokumentacja Django i blo- żemy to zrobić zarówno paczkując nasz pro- prostszym jest importowanie ustawień lo-
gosfera obfitują w zachęcające tu- jekt narzędziami distutils lub distribute kalnych na końcu globalnego settings.py.
toriale i przewodniki dla począt- [1], albo też korzystając z buildout [2]. Naj- Wadą takiego podejścia jest jednak to, że nie
kujących, dość rzadko znaleźć można ar- gorszym możliwym pomysłem jest natomiast możemy odnieść się w pliku lokalnym do
tykuły wykraczające poza przysłowiowy ręczne zarządzanie zależnościami. W natło- globalnie zdefiniowanych zmiennych, nie
"pierwszy blog w 15 minut". Tego typu ku bibliotek zewnętrznych łatwo zapomnieć mówiąc już o możliwości modyfikacji ta-
przewodniki dotykają często bardzo płyt- o jednej z nich. Przy odrobinie pecha apli- kich ustawień. W szczególności chcieliby-
kiej warstwy tego, co w rzeczywistym pro- kacja wystartuje i dopiero po pewnym cza- śmy mieć możliwość dodania w pliku lokal-
jekcie składa się na udany system. W tym sie okaże się, że środowisko jest niekomplet- nym dodatkowych middleware'ów lub ap-
krótkim artykule zdrapujemy zewnętrz- ne. Co więcej, nawet gdy będziemy pamięta- p'ów, np. poprzez konstrukcję:
ną warstwę lukru i sprawdzamy, co moż- li o tym, żeby zainstalować wszystkie biblio-
na znaleźć pod spodem. Dzielimy się sze- teki, brak zadeklarowania konkretnych wersji INSTALLED_APPS += (
regiem doświadczeń z produkcji rzeczy- pakietów zewnętrznych może w przyszłości 'debug_toolbar',
wistych aplikacji internetowych opartych spowodować nieoczekiwaną awarię aplikacji, )
o Django. kiedy któraś z wykorzystywanych bibliotek
zmieni się w sposób niezgodny z wcześniej- Zwróćmy uwagę na operator . Rozwiąza-
Od początku przygotuj się szą implementacją. Jest to o tyle niebezpiecz- niem, które umożliwia wszystkie te rze-
na wdrożenie na sytuacja, że pakiety zewnętrzne same za- czy, a dodatkowo daje możliwość przecho-
Łatwość rozpoczęcia pracy nad zupełnie no- wierają zależności i podobne zagrożenie mo- wywania wielu zbiorów ustawień lokalnych
wym projektem w Django wywołuje optymi- że dotyczyć ich samych, jeżeli nie zadeklaro- i przełączania się między nimi z linii pole-
styczne wrażenie, że samo wdrożenie syste- wali konkretnych wersji swoich zależności. ceń, jest [4].
mu na serwerze produkcyjnym nie będzie się Drugim dobrym zwyczajem, którego nie Trzecią istotną sprawą jest zadbanie o to,
wiele różniło i wobec tego nie wymaga spe- wymusza sam framework, jest wydzielenie żeby już początkowa instalacja systemu
cjalnie wielkiej uwagi ze strony programi- z głównego settings.py ustawień specy- w środowisku produkcyjnym posiadała po-
stów. Nic bardziej mylnego, a początkowo ficznych dla konkretnej instancji aplikacji. prawnie wypełnione tabele w bazie danych.
poczynione założenia i uproszczenia mogą Do takich ustawień należą m.in. SECRET_ Możliwość zarządzania takimi danymi po-
w ostateczności utrudnić uruchomienie ser- KEY, DATABASE_*, ADMINS, DEBUG, TIME_ czątkowymi dają fixtures [5], bardzo pro-

50 05/2010
Django

sty w użyciu mechanizm umieszczania da- szy rozwój app'a, a jednak zyskujemy coś bar- Kilka gorzkich słów
nych w bazie. Posiadając odpowiedni zbiór dzo istotnego: pełną dowolność w reorganiza- o buforowaniu
danych początkowych w aktualnej instan- cji źródeł w sposób maksymalnie dostosowa- Domyślny model implementacji cache
cji bazy danych, wystarczy użyć polecenia ny do naszych potrzeb. Ostatecznie nie mo- w Django jest podatny na tzw. efekt gromad-
manage.py dumpdata. Umożliwia ono wyeks- żemy przecież powiedzieć klientowi, że cze- ki psów (ang. dog-pile effect). Polega on na
portowanie istniejących danych do formatu goś "nie da się", tylko dlatego, że korzystamy tym, że w przypadku kiedy wygaśnie waż-
XML, YAML lub JSON i późniejsze załado- z zewnętrznej biblioteki do jakiejś funkcjo- ność cache dla danego klucza więcej niż je-
wanie ich do bazy danych poprzez manage.py nalności. den klient zapyta o jego wartość jednocze-
loaddata nazwa_pliku_z_danymi. Takie pli- śnie, każde zapytanie spowoduje rozpoczę-
ki powinny być przechowywane w katalo- manage.py runserver oszukuje cie procedury odświeżania cache. Efekt ten
gu fixtures w danym app'ie. Przypadkiem Możliwość uruchomienia rozwijanej aplika- jest szczególnie ewidentny przy bardzo wie-
szczególnym jest plik initial_data.xml (lub cji jednym prostym poleceniem jest nieoce- lu klientach lub w przypadku, gdy czas od-
.yml czy .json), którego zawartość jest za- nioną oszczędnością czasu. Ta reklamowa- świeżenia cache znacznie przekracza średni
wsze umieszczana w bazie danych podczas na w każdym tutorialu funkcjonalność ma okres między kolejnymi zapytaniami do sys-
polecenia manage.py syncdb. jednak dwie cechy, które szybko ugryzą każ- temu. W konsekwencji tego problemu spo-
dego programistę Django. Pierwsza z nich ry procent zasobów serwera jest marnowany
Odważnie dziel funkcjonalność związana jest z faktem, że automagicznie na zbędną, bo wielokrotnie powielaną, pra-
serwisu na osobne app'y serwuje nam media wbudowanej aplikacji cę. Istnieje szereg podejść do rozwiązania te-
Serwisy tworzone w oparciu o Django są dzie- admina. To, co na pierwszy rzut oka wyda- go problemu w Django, gotowe rozwiązania
lone na tzw. aplikacje (ang. apps), nazywane je się zaletą, w momencie faktycznej instala- można znaleźć w [4] i [7].
przez społeczność po prostu app'ami. Każ- cji serwisu na serwerze produkcyjnym naj- Pomijając wymienioną wyżej niedosko-
dy app implementuje wydzieloną niewielką częściej dokłada nam bólu głowy, bo jest to nałość Django, problem z buforowaniem
funkcjonalność, a działający system jest zbio- jedna z wielu drobnych rzeczy, o których nie w zasadzie sprowadza się do odpowiedzi
rem wielu takich aplikacji. Kiedy konkretne pomyśleliśmy. na dwa pytania: jak dużo możemy wrzucić
app'y są projektowane tak, żeby ich zakres od- W trakcie samego programowania do cache i jak długo możemy tak wrzuco-
powiedzialności był możliwie wąski, moż- runserver potrafi nas również zmylić co do nych danych nie aktualizować. Django udo-
na łatwo podmienić jeden z nich na inny bez rzeczywistego zachowania budowanego ser- stępnia szereg skrótów dla typowych sche-
konieczności ingerencji w resztę serwisu. Ła- wisu w środowisku produkcyjnym. Jako że matów buforowania, wliczając w to m.in.
twiej też testować jednostkowo implemen- runserver jest jednowątkową aplikacją dzia- dekorator @django.views.decorators.c
tację, kiedy jest ona podzielona na niewiel- łającą w ramach jednego procesu, nie prze- ache.cache_page. W wielu przypadkach
kie kawałki. testujemy w nim żadnych przypadków uży- buforowanie całości danej strony nie bę-
Dobrym zwyczajem jest wobec tego bar- cia związanych z równoległym dostępem do dzie akceptowalne (np. dlatego, że w części
dzo liberalne podejście do dzielenia funkcjo- serwisu przez wielu użytkowników. Z tego strony widoczne są kontekstowe informa-
nalności swojego projektu na szereg niewiel- samego powodu, uruchamiając serwis przez cje danego użytkownika), ale jeżeli więk-
kich aplikacji. nie uzyskujemy pełnej informacji na temat szość wizyt na stronie nie składają użyt-
zachowania zapytań AJAX, pamięci współ- kownicy zalogowani, warto z niego skorzy-
Ostrożnie z wykorzystaniem dzielonej (patrz następna wskazówka) lub stać ze względu na olbrzymie zyski wydaj-
zewnętrznych app'ów sterowania współbieżnością (np. sekcje kry- nościowe. W takim przypadku warto jed-
Bardziej ostrożnie należy jednak podchodzić tyczne). nak pamiętać o ustawieniu w settings.py
do wykorzystania w projekcie zewnętrznych ignorowania cache dla użytkowników za-
app'ów. Największym problemem jest w ta- settings.py to nie pamięć logowanych (poprzez dyrektywę CACHE_
kim przypadku sytuacja, kiedy okazuje się, współdzielona MIDDLEWARE_ANONYMOUS_ONLY.
że zewnętrzny app spełnia 90% naszych po- Początkujący programiści czasem naduży- Jeżeli chodzi o to, jak długo trzymać dane
trzeb, ale musimy go dostosować do nasze- wają wolności, jaką dają ustawienia projek- w cache, kwestia jest znowu indywidualna
go projektu. Co wówczas? Pobieramy kod tu Django, które są klasycznym plikiem źró- i każdy większy serwis ma w tej kwestii wła-
źródłowy i dołączamy do naszej dystrybucji? dłowym Pythona. Najbezpieczniej jednak sną politykę. Z punktu widzenia użytkow-
Trzymamy nadal osobno i łatamy w locie? Je- traktować je jako ni mniej ni więcej tylko nika istotne jest to, żeby obecność mechani-
żeli to pierwsze, to co w przypadku, gdy app plik konfiguracyjny. Ustawienia są bowiem zmów buforujących była dla niego przezro-
zostanie zaktualizowany przez twórców? Na ładowane wielokrotnie podczas cyklu życia czysta. Innymi słowy, jeżeli w serwisie użyt-
ile łatwo będzie można przenieść nasze zmia- serwisu, osobno dla każdego procesu serwe- kownik zauważa, że konkretne dane są nie-
ny między wersjami? ra, osobno dla poleceń wykonywanych z li- spójne, bo część z nich jest ewidentnie nieak-
Nie ma oczywistej odpowiedzi na te pyta- nii poleceń. Nawet w trakcie wykonania po- tualna, wówczas czas buforowania jest dla te-
nia. Wszystko zależy od konkretnego app'a, jedynczego polecenia manage.py plik konfi- go przypadku zbyt długi.
konkretnych zmian, od specyfiki tworzonego guracyjny jest parsowany kilkukrotnie. Wy- Ostatnia uwaga: włączanie buforowania
serwisu i pewnej dozy szczęścia. Doświadcze- korzystanie więc go w formie uproszczo- podczas programowania znacząco utrudnia
nie pokazuje jednak, że często najbezpiecz- nej pamięci współdzielonej może prowa- sensowne usuwanie błędów w logice aplika-
niejszym rozwiązaniem jest mimo wszyst- dzić do trudnych do zdiagnozowania błę- cji. Z drugiej strony konieczne jest dogłębne
ko dołączenie kodu zewnętrznej aplikacji do dów. Zawsze, kiedy wymagamy od serwisu przetestowanie systemu z włączonym cache
źródeł naszego projektu i po naszych lokal- przechowania dowolnych danych między tak, aby wykluczyć wszystkie sytuacje błęd-
nych zmianach traktowanie go jak własnego żądaniami użytkowników, powinno się to nego buforowania. Szczególnie ważne jest za-
kodu [6]. Tracimy możliwość bezbolesnego odbyć przez mechanizm sesji, cache (patrz pewnienie, że poprzez cache nie przeciekają
korzystania z aktualizacji zewnętrznych źró- następna wskazówka) lub oczywiście ba- dane wymagające specyficznych uprawnień
deł, obarczamy się odpowiedzialnością za dal- zę danych. od użytkowników systemu.

www.sdjournal.org 51
Programowanie

Schizofrenia użytkowników, Nie daj się porwać magii modeli nalność soft delete moglibyśmy zaimple-
czyli zarządzanie profilami System mapowania obiektowo-relacyjne- mentować jako klasę abstrakcyjną dla mode-
Konwencją Django jest wydzielenie osobnych go w Django jest wystarczająco magiczny, li i jedynie dziedziczyć po raz zdefiniowanej
modeli na konto użytkownika i profil użyt- że często można zapomnieć o tym, że pod funkcjonalności w przyszłości. W takiej sy-
kownika. Ten pierwszy zawiera tylko podsta- spodem leży rzeczywista relacyjna baza da- tuacji należy jednak pamiętać o dwóch kwe-
wowe informacje takie jak login, e-mail i ha- nych. W dodatku, prostota definiowania mo- stiach: żeby nie zapomnieć o wywoływaniu
sło, w tym drugim natomiast programista deli może być niekiedy myląca. O sztuczkach metod zdefiniowanych w klasach bazowych
może zawrzeć dowolne interesujące go cechy i kruczkach ORM w Django można napisać (poprzez odwołanie do super()). Najczęściej
użytkownika (np. datę urodzenia, awatar czy osobny artykuł, przy tej okazji skupmy się je- implementowanymi metodami w takich kla-
kraj pochodzenia). Takie rozdwojenie zarzą- dynie na dwóch drobnych kwestiach o znacz- sach są właśnie save() i delete().
dzania pojedynczym użytkownikiem umoż- nych konsekwencjach. Zacznijmy od usuwa-
liwia jednocześnie uzyskanie zgrabnej archi- nia obiektów z bazy. Google pamięta
tektury Django, bywa jednak również powo- ORM Django domyślnie umożliwia usu- ...o ile znajdzie. Innymi słowy, struktura lin-
dem problemów. Profil użytkownika łączy się wanie obiektów z bazy w sposób permanent- ków w serwisie jest jedną z najistotniejszych
z modelem User poprzez podanie w konfigu- ny. Dodatkowo, symuluje on działanie ON kwestii, którą warto zaplanować i zaimple-
racji nazwy modelu, który ma zostać użyty DELETE CASCADE z baz SQL, co oznacza, że mentować poprawnie od pierwszego dnia.
jako profil użytkownika (w zmiennej AUTH_ obiekty zależne od usuwanego są także usu- Zmiany w sposobie linkowania treści w sys-
PROFILE_MODULE). Tak skonfigurowany pro- wane z bazy w nieodwracalny sposób. Dla temie już w trakcie jego działania spowodują,
fil jest dostępny w obiektach użytkownika przykładu, jeżeli usuniemy kategorię na fo- że wielu użytkowników będzie odbijało się od
przez metodę get_profile(). Wywołanie tej rum, wszystkie wpisy w tej kategorii są usu- serwisu przez nieaktualne linki zaindeksowa-
metody powoduje wykonanie drugiego zapy- wane wraz z nią. Najczęściej jest to zachowa- ne przez wyszukiwarki lub dodane do kata-
tania do bazy danych [8]. Warto o tym pamię- nie pożądane. Pożądane na tyle często, że w logów stron, agregatorów treści lub zakładek
tać, gdy ilość zapytań do bazy danych stanie tym jednym przypadku, kiedy byśmy go so- w przeglądarce. Na co zwrócić uwagę?
się wąskim gardłem w wydajności systemu. bie nie życzyli, łatwo można o nim zapo- Po pierwsze, wyszukiwarki wysoko ocenia-
Ponadto, kod źródłowy z licznymi wywoła- mnieć. Problem dotyczy bezpośrednich za- ją linki zawierające słowa kluczowe zapytania
niami w stylu user.get_profile().birth_ leżności definiowanych w modelach przez użytkownika. Żeby dołączyć je do naszych
date wygląda po prostu brzydko. ForeignKey. Co możemy zrobić? adresów URL, możemy użyć automatyczne-
Dodatkowo, istniejącą funkcjonalność Najładniejszym rozwiązaniem wydaje się go pola typu SlugField w modelu lub filtra
konta użytkownika zdefiniowaną w modelu implementacja tzw. soft delete, czyli usu- slugify w szablonach HTML. W obu przy-
django.contrib.auth.models.User trud- wanie z widoku w serwisie poprzez usta- padkach trzeba mieć jednak na uwadze, że
no jest zmodyfikować. Przykładowo, zmiana wianie odpowiedniego pola w modelu (np. wbudowana implementacja slug'ów zawiera
sposobu działania serwisu na taki, w którym category.removed = True). Dzięki możli- tylko znaki alfanumeryczne ASCII, przemil-
adres e-mail jest jednocześnie nazwą użyt- wości zdefiniowania dla modelu dedykowa- czając inne znaki podczas konwersji. W kon-
kownika, albo inny sposób decydowania nego menedżera (django.db.models.Ma- sekwencji, tekst "Żółć?" zostanie przekonwer-
o tym, czy konto użytkownika jest aktyw- nager), możemy ograniczyć wyświetlanie towana na pusty łańcuch znaków. Warto wo-
ne w serwisie czy nie, są dość podchwytli- obiektów danego modelu na przestrzeni całe- bec tego mieć własną, trochę pewniejszą im-
we w implementacji. Z wymienionych wy- go serwisu tylko do takich, które spełniają da- plementację.
żej powodów użyteczne okazuje się korzy- ny warunek (np. removed == False). W ten Po drugie, ludzie dzielą się linkami! Z tego
stanie na przestrzeni całego serwisu z obiek- sposób nie musimy dodatkowo przy każdym powodu każda strona serwisu powinna być
tów profilu użytkownika (w razie potrzeby wyświetlaniu modelu z soft delete pamiętać dostępna pod unikalnym, ale również sensow-
z pobieraniem w jednym zapytaniu skoja- o przefiltrowaniu "obiektów usuniętych". nym i zrozumiałym dla człowieka linkiem. Je-
rzonego konta użytkownika przez select_ Drugą kwestią, którą warto poruszyć, jest żeli to możliwe, należy ograniczać dostęp do
related()). Z bazy pobieramy więc profil dziedziczenie w modelach. Django umożli- treści przez zapytania POST lub parametry
użytkownika, a nie dane konta. Taki obrót wia definiowanie modeli z wykorzystaniem GET, odpowiednie identyfikatory przekazu-
sprawy umożliwia skoncentrowanie się nie tego mechanizmu obiektowego, co daje nam jąc bezpośrednio w strukturze linków.
na domyślnej funkcjonalności, ale na mody- możliwość właściwego rozdziału funkcji za-
fikacjach pod konkretny serwis. wartych w modelu. Przykładowo, funkcjo- Podsumowanie
Poza wyżej wymienionymi wskazówkami,
można wymienić jeszcze olbrzymią rzeszę in-
Przypisy nych. Są to wszystko rzeczy, na które każdy
• [1] http://packages.python.org/distribute/ programista rzeczywistej aplikacji interneto-
• [2] http://www.buildout.org/ wej prędzej czy później się natknie. Właśnie
• [3] Przy tej okazji warto polecić któryś ze współczesnych rozproszonych systemów ta- to doświadczenie, zdobywane dzień do dniu
kich jak Git lub Mercurial. Szczególnie ten drugi znajduje duży poklask w społeczności podczas pracy z Django, jest najcenniejszą war-
programistów Pythona. Joel Spolsky przygotował świetne wprowadzanie do tego syste-
tością i odróżnia dopracowane rozwiązania od
mu: http://www.hginit.com/ .
• [4] (1, 2) http://packages.python.org/langacore.kit.django/ kolejnego przepisu na blog w 15 minut.
• [5] http://docs.djangoproject.com/en/dev/howto/initial-data/
• [6] Na tyle, na ile pozwala na to licencja.
• [7] http://www.djangosnippets.org/snippets/155/ ŁUKASZ LANGA
• [8] Wynik tego zapytania jest potem trzymany w obiekcie modelu tak, żeby kolejne wy- Autor interesuje się muzyką, reżyserią dźwięku i fo-
konania nie musiały za każdym razem pytać bezpośrednio bazy danych. Jest to jednak
buforowanie tylko na poziomie pojedynczego żądania HTTP. togra�ą, sprawdza się jako młody tata, a w wol-
nym czasie prowadzi własną �rmę programistycz-
ną. Kontakt z autorem: lukasz@langa.pl

52 05/2010
Bazy danych

Krótki wstęp do ZODB


Pythonowe podejście do obiektowych baz danych
Prawie każda aplikacja, z wyjątkiem najprostszych skryptów, musi
w jakiś sposób gromadzić przetwarzane dane. Może je zapisywać
bezpośrednio w plikach, w relacyjnych bazach danych czy w jednej
z modnych ostatnio baz NoSQL, takich jak CouchDB czy MongoDB.
Wiele z cech tych nowych projektów ma najpopularniejsza pythonowa
obiektowa baza danych – ZODB.
są w większości dostosowywane do dużej ilo-
Dowiesz się: Powinieneś wiedzieć: ści współbieżnych zapisów (charakterystycz-
• Jak otworzyć ZODB; • Jak pracuje się ze słownikami i listami w Py- nych dla środowisk OLTP), ZODB spraw-
• Jak zapisywać i odczytywać obiekty w thonie; dza się przede wszystkim tam, gdzie jedno-
ZODB; czesnych modyfikacji jest stosunkowo mało
(np. w CMSach, bazach konfiguracji, itp.). Ze
względu na przyjęty model optymistycznego
wyklucza możliwość zapamiętywania gniazdek blokowania (nie ma tu znanych z innych baz
sieciowych, otwartych plików itp.). W swej isto- wysokich poziomów izolacji), najlepiej pracu-
Poziom cie bardzo przypomina rozbudowaną wersję ją aplikacje, w których współbieżne procesy
trudności klasy Shelf z modułu shelve w standardowej nie modyfikują tych samych obiektów - gdy
dystrybucji Pythona [PSF.Shelve]. Rożni się od poszczególne wątki aplikacji zaczynają wal-
niej przede wszystkim: czyć o dostęp do tych samych danych, ZODB
znacząco zwalnia. Jest to spowodowane ko-

M
nie najbardziej interesują rozwiąza- • obsługą transakcji; niecznością rozwiązywania konfliktów (jeśli
nia, które pozwalają przy możliwie • wsparciem dla undo; zapisywane obiekty mają zaimplementowa-
najmniejszym wysiłku udostępnić • wieloma typami storage (enginami zapisu ną ich obsługę) lub powtarzaniem transakcji.
mechanizm trwałego przechowywania danych danych) umożliwiających zapis bazy w pli- Duże natężenie zmian może też powodować
moim pythonowym aplikacjom. Wśród nich kach (FileStorage), strukturze katalogów trudny do opanowania rozrost bazy: wszyst-
zdecydowanie najpopularniejsze jest ZODB. (DirStorage), na pośredniczącym serwerze kie znane mi storage ZODB zapisują dane
ZODB, czyli Zope Object Database, to obiek- Zope Enterprise Objects (ClientStorage), w trybie append only. Nie modyfikują w miej-
towa baza danych, pozwalająca na zapisywanie bazie relacyjnej (RelStorage) i pamięci (De- scu wcześniej zapisanych obiektów, ale za-
grafu pythonowych obiektów. To dziecko Ji- moStorage); chowują ich kolejno uaktualnione wersje. Po-
ma Fultona, jednego z twórców Zope [Wikipe- • długoletnim testowaniem w warunkach zwala to w na implementację transakcji i un-
dia.ZODB]. Prace nad nią rozpoczęły się grubo bojowych w setkach tysięcy instancji Zo- do, ale powoduje rośnięcie bazy danych z każ-
ponad 10 lat temu i trwają właściwie nieprze- pe, Plone, Groka na całym świecie. dą modyfikacją zapisanych w niej informacji.
rwanie do dzisiaj. Jako część projektu, Zope Zmusza to administratora ZODB do cyklicz-
jest najczęściej wykorzystywana przy budowie Czym ZODB różni się od baz relacyjnych, nego pakowania bazy, które usuwa wszystkie
CMSów (jest podstawowym mechanizmem takich jak PostgreSQL czy Oracle? Przede nieaktualne wersje obiektów. Jednak jeśli nie
zapisu danych Plone). wszystkim ścisłym powiązaniem z Pytho- stawia się na niej bankowych systemów trans-
Co odróżnia ZODB od innych baz danych? nem. Format zapisu obiektów (pickle) zde- akcyjnych, ZODB potrafi zaskoczyć wydajno-
Przede wszystkim przezroczystość: aplikacje cydowanie utrudnia bezpośrednie opera- ścią i przede wszystkim szybkością pisania
operujące na pythonowych obiektach wyma- cje na tej bazie programom napisanym w in- wykorzystujących ją aplikacji.
gają jedynie minimalnych zmian, by z niej ko- nych językach. Od RDBMSów różni się rów- O tym, że ZODB jest faktycznie bardzo pro-
rzystać. Przy pracy z ZODB nie trzeba uży- nież sposobem optymalizacji: bazy relacyjne sta w obsłudze, najlepiej jest się przekonać sa-
wać mapperów (takich jak np. SQLAlchemy),
bo nie ma potrzeby przekształcania przetwa-
NoSQL [Wikipedia.NoSQL] to termin, jakim określa się bazy danych, które, głównie dla lep-
rzanych danych na inną postać. Nie ma tu ta-
szej skalowalności, odchodzą od ścisłego modelu relacyjnego i gwarancji ACID. Oprócz Co-
bel, kolumn, kluczy obcych, tylko zwykłe kla- uchDB i MongoDB do tego grona zalicza się np. BigTable Google, Cassandra Facebooka czy
sy, słowniki i listy (no, nie jest tak do końca, ale Dynamo Amazona. Zwykle nie obsługują transakcji powodujących zmiany w kilku obiektach,
o tym w dalszej części artykułu). W zasadzie nie strukturyzują ściśle przechowywanych danych, oferując w zamian dużą szybkość i możli-
w ZODB można zapisać każdy obiekt, który da wość prostego skalowania poziomego (na wiele maszyn).
się zserializować za pomocą modułu pickle (co

54 05/2010
Krótki wstęp do ZODB

memu. By oszczędzić Czytelnikowi samo- gine ZODB, ma jednak jedną wadę: pozwa- Wszystkie działania na ZODB odbywają się
dzielnej konfiguracji środowiska testowego, la na pracę z bazą tylko jednemu procesowi w transakcjach, co ułatwia utrzymanie spójno-
przygotowałem prościutką aplikację przetwa- (który może uruchamiać wiele wątków). Jeśli ści bazy, gdy coś pójdzie nie tak. Dodatkowo,
rzającą dane o odcinkach serialu „Dr House” do bazy musi mieć dostęp kilka procesów, na- mechanizm transakcji można dosyć łatwo roz-
[Wikipedia.HouseEpisodes] – jej kod źródło- leży skorzystać z serwera ZEO i powiązanego szerzać tak, że możliwe staje się zsynchronizo-
wy jest na dołączonej do czasopisma płycie. z nim ClientStorage (można też użyć niedaw- wane cofanie zmian np. w bazach relacyjnych
Aplikacja korzysta z zc.buildout (opisanego no uaktualnionego RelStorage). czy w plikach utworzonych na dysku. Oczywi-
szczegółowo w innym artykule), by nie insta- Po utworzeniu wybranego storage engine’u ście nie dzieje się to w jakiś magiczny sposób –
lować niezbędnych pakietów globalnie. Testo- tworzy się instancję bazy danych (3 linia listin- cofnięcie zmian poza ZODB trzeba oprogramo-
wałem ją pod Pythonem w wersji 2.5.4 i 2.6.4 gu 2). Storage i baza danych mogą być w apli- wać samemu, maszyneria ZODB udostępnia je-
pod Ubuntu, powinna też bez większych pro- kacjach wielowątkowych swobodnie współ- dynie punkty styku, które pozwalają wykony-
blemów dać się uruchomić pod Windowsem i dzielone, każdy wątek musi mieć jednak do- wać odpowiednie akcje przy rozpoczynaniu,
OSXem. Po rozpakowaniu jej źródeł na dysku, stęp do osobnej instancji połączenia (two- potwierdzaniu i anulowaniu transakcji. Z tych
wystarczy w katalogu głównym aplikacji wy- rzonego w 4 linii listingu 2) – podobnie, jak mechanizmów intensywnie korzysta Zope i je-
konać polecenia (Listing 1). w większości modułów zapewniających do- go pochodne: umożliwiają ciągłe utrzymywanie
To spowoduje ściągnięcie niezbędnych pakie- stęp do baz relacyjnych. Nasze świeżo utwo- aplikacji w spójnym stanie, nawet przy występo-
tów i utworzenie skryptu bin/demo, który uru- rzone połączenie ma metodę root, która daję waniu nieprzewidzianych błędów.
chamia wszystkie przykłady z artykułu. Każ- dostęp do „katalogu głównego” bazy, z którego Przy tworzeniu połączenia (metodą open()
dy, kto chciałby krok po kroku wypróbowywać można korzystać, jak z każdego innego słowni- obiektu bazy danych), domyślnie tworzo-
kod z listingów, powinien skorzystać ze skryptu ka (co widać na Listingu 3). na jest również nowa transakcja: aby utrwalić
bin/przyklady – skrypt uruchamia interpreter
IPythona ze wszystkimi potrzebnymi pakieta- Listing 2. Otwieranie bazy danych i uzyskiwanie dostępu do roota
mi na ścieżce.
Tyle tytułem nieco przydługiego wstępu >>> from ZODB import FileStorage, DB
– po przygotowaniu środowiska do ekspery- >>> storage = FileStorage.FileStorage(‘Data.fs’) # Tworzenie storage
mentów można przejść do konkretów. Zacznę >>> db = DB(storage) # Tworzenie obiektu bazy
od uzyskania dostęp do obiektu root (Listing >>> conn = db.open() # Otwieranie połączenia
2.) – specjalnego słownika, który jest tworzony >>> root = conn.root() # Uzyskiwanie dostępu do roota
przy pierwszym uruchomieniu bazy. Można go
porównać do katalogu głównego dysku – dopie-
Listing 3. Dodawanie prostych obiektów do roota
ro do niego można dodawać własne hierarchie
obiektów. ZODB obsługuje model utrwalania
przez dostępność (ang. persistence by reachabili- >>> root['opis'] = 'Baza odcinków serialu Dr House'
ty) – by zachować obiekt w bazie, wystarczy po- >>> root['aktualny sezon w TVP'] = 4
wiązać go z już zapisanym obiektem (jako wła- >>> # items() to standardowa metoda słowników
sność czy element w przypadku list i słowni- >>> # w pythonie, zwraca listę par (klucz, wartość)
ków). Na początku w bazie jest tylko root, więc >>> root.items()
siłą rzeczy to z nim należy powiązać struktury [('opis', 'Baza odcink\xc3\xb3w serialu Dr House'),
przeznaczone do utrwalenia. ('aktualny sezon w TVP', 4)]
Aby uzyskać dostęp do roota, trzeba stwo- >>> len(root)
rzyć trzy obiekty: 2

• storage, zajmujący się niskopoziomową se-


Listing 4. Zapisywanie w bazie mutowalnych obiektów
rializacją obrabianych danych;
• bazę danych, stworzoną do koordynacji
połączeń oraz do wykonywania operacji >>> from malloc.zodb.modele import Scenarzysta, Odcinek, Sezon
porządkowych i analitycznych; >>> from persistent.mapping import PersistentMapping
• połączenie, które utrzymuje cache obiek- >>> david_shore = Scenarzysta('David', 'Shore')
tów z bazy w pamięci i zajmuje się ich >>> lawrence_kaplow = Scenarzysta('Lawrence', 'Kaplow')
wczytywaniem i zapisywaniem. >>> root['scenarzysci'] = PersistentMapping({
... 'David Shore': david_shore,
Najczęściej wykorzystywanym typem storage ...'Lawrence Kaplow': lawrence_kaplow})
jest FileStorage, który po prostu zapisuje obiek- >>> sz1 = Sezon('I')
ty we wskazanym pliku na dysku. To obecnie >>> sz1[1] = Odcinek(u'Pilot', (david_shore, ))
najwydajniejszy i najbardziej dopracowany en- >>> sz1[2] = Odcinek(u'Ojcostwo', (lawrence_kaplow, ))
>>> root['sezony'] = PersistentMapping({'I': sz1})

Listing 1. Instalacja aplikacji >>> transaction.commit()


>>> odc_1_1 = root['sezony']['I'][1]
python bootstrap.py >>> odc_1_1.tagi.add('pilot')
bin/buildout >>> odc_1_1.tagi.add('tasiemiec')
lub >>> odc_1_1._p_changed = True
bin\buildout.exe (pod Windows) >>> transaction.commit()

www.sdjournal.org 55
Bazy danych

świeżo wprowadzone zmiany, wystarczy ją za- mentów nie zostanie zauważone przez ZODB. W tej sytuacji szybkość aplikacji korzysta-
twierdzić: Z punktu widzenia bazy, wszystkie operacje na jącej z ZODB zależy w głównej mierze od za-
tagach to tylko odczyt obiektu odcinek_1_1 , projektowania odpowiedniej struktury danych:
>>> import transaction który nie powoduje ustawienie jego flagi _p_ nie ma tu optymizera znanego z baz relacyj-
>>> transaction.commit() changed. Obiekt dziedziczący po Persistent, nych, cały plan zapytań trzeba przygotować sa-
który przed zatwierdzeniem transakcji ma usta- memu. Z jednej strony utrudnia to tak popu-
I voila, stworzone przed chwilą obiekty zostały wioną własność _p_changed na False, nie zo- larne w RDBMSach przeglądanie bazy zapy-
zapisane w bazie. Gdyby z jakiś powodów trze- stanie zapisany w bazie, co skutkuje pustym taniami ad-hoc i nie udostępnia jednego, stan-
ba było anulować wprowadzone zmiany, wy- zbiorem tagów przy ponownym wczytaniu od- dardowego sposobu implementacji, z drugiej
starczy wywołać: cinka (linie 114-156 skryptu demo pokazują daje możliwość bardzo niskopoziomowego tu-
w praktyce ten problem). ningu. Co prawda istnieją rozwiązania wspo-
>>> transaction.abort() Podsumowując, wszędzie, gdzie jest to moż- magające indeksowanie i wyszukiwanie obiek-
liwe, warto używać klas takich jak persistent tów takie jak Plone'owy Catalog [Plone.ZCa-
i obiekty utrwalone w bazie automagicznie po- .list.PersistentList zamiast list czy persi- talog] (swoją drogą świetny materiał na kolej-
wrócą do stanu sprzed uruchomienia trans- stent.mapping.PersistentMapping zamiast ny artykuł), jednak programista ma tu zupeł-
akcji. słowników, a własne klasy po prostu wywodzić nie wolną rękę i to od niego zależy, czy będzie
Prawda, że proste? Normalna praca z ZODB z persistent.Persistent. Na szczęście ta za- je wykorzystywał, czy wszystkie zapytania na-
tak właśnie wygląda. Trzeba jednak pamiętać, leżność nie jest specjalnie uciążliwa i nie wyma- pisze samemu. W efektywnym przetwarzaniu
by wszystkie mutowalne obiekty, które ma- ga żadnych dodatkowych prac, co można zoba- dużych ilości danych pomagają również dosto-
ją być efektywnie zapisywanie w ZODB, dzie- czyć na przykładzie definicji Scenarzysty z pli- sowane do potrzeb ZODB B-drzewa z pakietu
dziczyły po klasie persitent.Persistent. Zwykłe ku modele.py: BTree. Udostępniają interfejs słowników, ale róż-
klasy, słowniki czy listy nie są traktowane przez Domyślam się, że w tym momencie wszyscy nią się od nich:
ZODB jako odrębna całość, są zapisywane z naj- są już nieco znudzeni czytaniem o tym, jak efek-
bliższą instancją podklasy Persistent (w skraj- tywnie zapisywać obiekty w ZODB, i chcieliby • efektywniejszym formatem zapisu na
nym przypadku z rootem). Może to prowadzić wreszcie zobaczyć, w jaki sposób się je odczytu- dysk;
do trudnych do uchwycenia błędów (takich jak je i przetwarza. Osoby, które liczyły na demon- • brakiem konieczności załadowania całego
np. niezapisywanie zmian czy tworzenie nieza- strację jakiejś egotycznej odmiany OQLa, mu- obiektu do pamięci;
leżnych kopii obiektu zamiast referencji), więc szę rozczarować: głównym językiem zapytań • zapisywaniem w bazie tylko zmienionych
należy się tego, o ile jest możliwe, wystrzegać. ZODB jest... Python. Tak jak wspominałem fragmentów, nie całej kolekcji;
W przypadku, gdy użycie zwykłego mutowal- wcześniej, to, co składuje się w ZODB, to zwy- • zoptymalizowanymi implementacjami
nego obiektu jest niezbędne, po jego zmianie kłe Pythonowe obiekty, które można przetwa- z ustalonym typem klucza i wartości (np.
należy ustawić własność _p_changed powiąza- rzać tak samo, jak by istniały wyłącznie w RA- IOBTree – słownika obiektów indeksowa-
nego z nim trwałego obiektu na True, co wymu- Mie. Na przykład, na listingu 5 można zoba- nego liczbami całkowitymi czy OIBTree
si zapisanie całej struktury do bazy. czyć, jak wyświetlić wszystkie odcinki pierw- służącym do zapisywania liczb całkowi-
W przykładzie zaprezentowanym w Listin- szego sezonu House, listing 6 zawiera kod po- tych indeksowanych obiektami Pythona).
gu 4, własność tagi, obiektu odcinek_1_1 jest kazujący wszystkie odcinki, których scenarzy-
zwykłym zbiorem i proste dołożenie do niej ele- stą jest David Shore. W aplikacji napisanej na potrzeby tego artyku-
łu B-drzewa są wykorzystywane do implemen-
Listing 5. Zwracanie wszystkich zapisanych odcinków I sezonu tacji Sezonu z pliku modele.py:

>>> for odcinek in root[‘sezony’][‘I’].values(): from BTrees.IOBTree import Btree


... print ‘\t’, odcinek class Sezon(BTree):
<Odcinek „Pilot”> def __init__(self, nazwa,
<Odcinek „Ojcostwo”> odcinki=None):
self.nazwa = nazwa
if odcinki:
Listing 6. Zwracanie odcinków ze scenariuszem Davida Shore
self.append(odcinki)
>>> david_shore = root[‘scenarzysci’][‘David Shore’]
>>> for sezon in root[‘sezony’].values(): Na tym, ze względu na szczupłość miejsca,
... for odcinek in sezon.values(): muszę zakończyć to wprowadzenie do ZODB.
... if david_shore in odcinek.scenarzysci: Mam nadzieję, że zainteresowałem czytelni-
... print odcinek ków na tyle, by przynajmniej zapoznali się bli-
<Odcinek „Pilot”> żej z tą pythonową bazą danych, a może nawet
użyli ją w którymś z projektów nie związanych
bezpośrednio z Zope lub Plone. Udanych eks-
Listing 7. Zwracanie odcinków ze scenariuszem Davida Shore
perymentów!
>>> david_shore = root['scenarzysci']['David Shore']
>>> for sezon in root['sezony'].values(): MICHAŁ WĘGRZYNEK
... for odcinek in sezon.values(): Konsultant i programista zajmujący się wdraża-
... if david_shore in odcinek.scenarzysci: niem systemów ERP i dostosowywaniem ich do
... print odcinek potrzeb swoich klientów. Pythona używa do pisa-
<Odcinek "Pilot"> nia intranetowych aplikacji i obróbki danych.
michal.wegrzynek@malloc.com.pl

56 05/2010
Bazy danych

Sieć dziś i jutro


Rozpowszechnienie Internetu zmieniło na zawsze sposób,
w jaki pracujemy, odpoczywamy i komunikujemy się ze sobą
Po pierwszej rewolucji Internetu przyszła jej kolejna faza: Web 2.0 i dzięki
powstaniu serwisów społecznościowych wciągnęła do sieci miliony
nowych użytkowników. Co przyniesie ze sobą trzecia fala? Zapraszamy
do czytania.

Trochę teorii
Dowiesz się: Powinieneś wiedzieć: Kluczem do rozumienia przez ludzi in-
• Co to są sieci semantyczne; • Podstawowa znajomość baz danych; formacji zawartych w Internecie jest zdol-
• Jak będzie wyglądał Internet przyszłości; • Otwartość na nowe struktury danych. ność interpretacji tekstu pisanego języ-
• Jak już dzisiaj można poznać technologie kiem naturalnym. Znaczenie słowa „za-
semantyczne. mek” (w drzwiach czy zamek na skarpie)
potrafimy wychwycić z kontekstu wypo-
wiedzi i nie musimy się w tym celu posługi-
wać odniesieniem do wystąpienia tego sło-
Okazuje się, że znalezienie odpowiedzi wa w słowniku. Niestety, mimo znacznego
na te pytania wymaga ogromnego nakła- postępu w interpretacji języka naturalnego
Poziom du ręcznej pracy. Co więcej, wynik otrzy- przez komputery, przetwarzanie informacji
trudności many z angielskojęzycznej wersji serwisu w postaci czysto tekstowej stanowi dla nich
będzie istotnie różny od polskiej. Nie jest w dalszym ciągu znaczne wyzwanie. Zatem
to jednak problem samej Wikipedii. Jeżeli spróbujmy pomóc maszynom w zrozumie-
spojrzymy na serwisy generowane automa- niu naszych intencji. Zaczniemy od proste-

M
niej więcej rok temu Google tycznie w oparciu o bazy danych, to w dal- go zdania „Krzysztof jest ojcem Michała”.
ogłosił, że liczba zindeksowa- szym ciągu ujrzymy dane prezentowane Aby sformalizować nasz przekaz, skorzysta-
nych stron przekroczyła jeden w postaci stron HTML. Odbudowanie na my ze specyfikacji opisu metadanych, zwa-
bilion (10^12). Przeglądając zasoby Inter- ich podstawie zbioru danych źródłowych nej RDF (Resource Description Framework).
netu, mamy wrażenie, że w sieci znalazło wymaga złożonego ‘reverse engineeringu’, Informacja o zasobach jest reprezentowana
się już wszystko. Czym zatem może ona nas a w niektórych wypadkach bywa wręcz za pomocą zdania złożonego z trzech ele-
jeszcze zaskoczyć? Okazuje się, że wbrew niemożliwe. mentów: podmiotu, predykatu i obiektu
pozorom dzisiejsza sieć ma wciąż wiele Fakt, że mimo ogromnej liczby informa- (ang. Subject, Predicate, Object). Warto tu za-
ograniczeń. W obecnej postaci World Wide cji znajdujących się w sieci, odpowiedź na znaczyć, że RDF nie narzuca konkretnej for-
Web jest zbiorem stron i dokumentów po- zadane pytania jest bardzo trudna, zain- my zapisu takiej trójki. Popularnymi forma-
łączonych za pomocą odnośników oraz apli- spirował grupę badaczy do opracowania tami serializacji są XML i N3. Możemy też
kacji, z których na co dzień korzystamy. Jest koncepcji tzw. sieci semantycznej. Arty- ująć naszą relację w postaci tabeli lub rów-
to naturalną konsekwencją faktu, że sieć by- kuł opublikowany w miesięczniku Scien- noważnego grafu:
ła w swoim zamyśle stworzona przez ludzi tific American (m.in. przez współtwór- Taka „trójka” (ang triple) może być da-
i dla ludzi. cę usługi WWW Timothy’ego Berner- lej przetwarzana przez komputer. Jednak
Spójrzmy na jeden z najciekawszych zbio- sa-Lee) stał się podstawą wizji, w której in- aby współdzielić jej rozumienie z innymi
rów informacji umieszczonych w sieci – Wi- teligentne agenty „rozumiejące” znaczenie komputerami w sieci, konieczne jest wpro-
kipedię. Znajdziemy tam ponad 3 000 000 umieszczonych w sieci informacji i usług wadzenie struktury pozwalającej na po-
haseł. Spróbujmy zatem odpowiedzieć na kil- będą potrafiły wyręczyć nas w skompli- grupowanie naszych pojęć. Taką struktu-
ka, wydawać by się mogło, prostych pytań: kowanych zadaniach. Np. zaplanują po- rą jest schema RDF (RDFS). Umożliwia
dróż i dokonają rezerwacji niezbędnych ona przede wszystkim zdefiniowanie klas
• Którzy malarze urodzili się w Warsza- biletów, oczywiście porównując przed za- (rdfs:Class) oraz użycie ich do defini-
wie przed 1950 rokiem? kupem ich ceny. Zanim jednak będziemy cji dziedzin (rdfs:domain) i przeciwdzie-
• Jakie filmy zostały nakręcone przez re- mogli oddać się upragnionemu wypoczyn- dzin (rdfs:range) dla naszych właściwo-
żyserów urodzonych w Krakowie? kowi w tropikach, spróbujmy przyjrzeć ści (rdf:Property). Skodyfikujmy więc na-
• Jakie gry komputerowe z gatunku FPS się teoretycznym podstawom sieci seman- szą wiedzę w postaci schemy RDF pokaza-
miały premierę w 2009 roku? tycznych. nej na Listingu 1.

58 05/2010
Sieć dziś i jutro

Jak widać, przemyciliśmy tu sporą dawkę za pomocą publicznie dostępnych Ontolo- i przetwarzanie ogromnej liczby zdań zło-
‘rozumienia’ relacji międzyludzkich. Każdy gii oraz nadaniu wszystkim zasobom unikal- żonych z trójki (Podmiot, Predykat, Obiekt)
Mężczyzna jest Osobą, oraz może być w re- nych identyfikatorów, możliwe będzie rze- oraz dostarczy nam implementacji języka za-
lacji jest_ojcem z inną Osobą. Łatwo zauwa- czywiste powiązanie wiedzy dziś rozproszo- pytań i wnioskowania.
żyć, że niewielkim nakładem pracy może- nej i uwięzionej w serwisach internetowych
my rozszerzać nasz aparat pojęciowy o kolej- w jedną całość. Przykładem takiej inicjatywy Oracle Semantic Technologies
ne klasy. Co więcej, RDFS pozwala na budo- jest projekt Linked Data. W ramach niego Oracle Semantic Technologies (OST) to
wę hierarchii klas (rdfs:subClassOf) i wła- działają dziesiątki witryn współdzielących zbiór narzędzi realizujących przetwarza-
ściwości (rdfs:subPropertyOf). Nie zagłę- dane w oparciu o standardy RDF i URI. Ilu- nie danych semantycznych. Funkcje prze-
biając się dalej w formalną specyfikację RDF stracja 2 przedstawia wielkość chmury da- twarzania OST są dostępne w bazie da-
i RDFS, polecam zapoznanie się z praktycz- nych z lipca 2009. nych Oracle Enterprise Edition wersji 11g,
nymi zastosowaniami, które zyskały już spo- Czego zatem potrzebujemy, aby zacząć z opcją Spatial (pierwsze moduły były już
rą popularność, jak np. języki RSS czy Du- przygodę z Linked Data? Oczywiście na- dostępne w wersji 10g) i Partitioning. W
blin Core. rzędzia, które pozwoli na przechowywanie systemach wymagających dużej wydajności
Ostatnim elementem naszego stosu spe-
cyfikacji potrzebnych komputerom do „głę- Tabela 1. Jedna z form zapisu informacji o zasobach
bokiego zrozumienia” informacji znajdują- Podmiot Predykat Obiekt
cej się w sieci jest Ontologia. Aby nie wkro- Krzysztof jest_ojcem Michał
czyć na ścieżkę rozważań filozoficznych, pro-
ponuję przyjąć na nasze potrzeby, że jest to po
prostu kolejny krok rozbudowy metajęzyka.
Dzięki temu możemy uchwycić subtelne re-
lacje pomiędzy koncepcjami, którymi posłu-
����������
gujemy się na co dzień, opisując wiedzę z da-
��������� ������
nej dziedziny. Zilustruje to najlepiej rozsze-
rzenie poprzedniego przykładu. Zamodeluj-
my (Listing 2.) dodatkowo fakty, że nie moż-
na być jednocześnie obiektem klasy Mężczy-
zna i Kobieta (owl:disjointWith), oraz że
relacja bycia rodzeństwem jest symetryczna Rysunek 1. Opis zasobu za pomocą relacji
(&owl;SymmetricProperty).
Dodatkowy nakład pracy zwróci nam się Listing 1. De�nicja klas
bardzo szybko. Od tej pory system będzie
mógł sam np. wywnioskować, że (A, jest_ro- <?xml version="1.0"?>
dzenstwem, B) na podstawie informacji, że <rdf:RDF xmlns:rdf="http://w3.org/1999/02/22-rdf-syntax-ns#"
(B, jest_rodzenstwem, A). xmlns:rdfs="http://w3.org/2000/01/rdf-schema#">
W zależności od naszych potrzeb może-
my wybrać mniej lub bardziej zaawanso- <rdfs:Class rdf:ID="Osoba"></rdfs:Class>
wany dialekt ontologii używanych w sieci <rdfs:Class rdf:ID="Mężczyzna">
(OWL-Lite, OWL-DL, OWL-Full). Cena, ja- <rdfs:subClassOf rdf:resource="#Osoba" />
ką płacimy za coraz większe możliwości wy- </rdfs:Class>
razu języka, którym się posługujemy, to ro- <rdf:Property rdf:ID="jest_ojcem">
snąca złożoność modelu koncepcyjnego na- <rdfs:domain rdf:resource="#Mężczyzna" />
szej dziedziny wiedzy. Jednym słowem ry- <rdfs:range rdf:resource="#Osoba" />
zykujemy, że im więcej mądrości będzie- </rdf:Property>
my chcieli zawrzeć w naszej ontologii, tym </rdf:RDF>
mniejsza szansa na znalezienie kogoś, kto
będzie się chciał z nami porozumieć. Nale-
Listing 2. Dodatkowe relacje pomiędzy klasami
ży również uwzględnić aspekt technologicz-
ny, który będzie się przekładał na tzw. „czas
pracy procesora”. ...
<owl:Class rdf:ID="Mężczyzna">
Sieć jutra już dziś <rdfs:subClassOf rdf:resource="#Osoba" />
Wracając do pytań zadanych w pierwszej <owl:disjointWith rdf:resource="#Kobieta" />
części artykułu, widzimy, że gdy poświęci- </rdfs:Class>
my czas na zbudowanie odpowiedniego me- ...
tamodelu dla naszej informacji, znalezienie <owl:ObjectProperty rdf:ID="jest_rodzenstwem">
odpowiedzi na zadane pytania stanie się ła- <rdf:type rdf:resource="&owl;SymmetricProperty" />
twiejsze. Co więcej, taką odpowiedź będzie <rdfs:domain rdf:resource="#Osoba" />
można wygenerować automatycznie. Na <rdfs:range rdf:resource="#Osoba" />
tym jednak nie kończą się możliwości Web </owl:ObjectProperty>
3.0. Dzięki zawarciu w naszych dokumen-
tach informacji o znaczeniu użytych pojęć

www.sdjournal.org 59
Bazy danych

i spełnienia zadanych norm bezpieczeństwa, W kolejnym kroku stwórzmy model seman- ns#type',
Oracle Semantic jest wspierany przez opcje tyczny: 'http://www.oracle.com/family/
Advanced Compression (zmniejszając na- Mężczyzna'));
wet o 75% gabaryty woluminów), Real Ap- execute SEM_APIS.create_rdf_
plication Cluster, Virtual Private Database model('family', Obiekt Osoba to klasa składająca się z dwóch
i Advanced Security. 'family_rdf_data', podklas Mężczyzny i Kobiety:
Integralną częścią rozwiązania OST jest 'triple');
repozytorium RDF (tzw. trójek) – będące INSERT INTO family_rdf_data VALUES (17,
w sferze przetwarzania semantycznego od- Wprowadźmy osoby i podstawowe relacje SDO_RDF_TRIPLE_S('family',
powiednikiem relacyjnego modelu danych. pomiędzy nimi: 'http://www.oracle.com/family/Person',
Do identyfikacji zasobów sieci semantycz- -- Waldemar jest ojcem Zuzanny 'http://www.w3.org/1999/02/22-rdf-syntax-
nej wykorzystywane są identyfikatory URI. ns#type',
Językiem zapytań stosowanym przy danych INSERT INTO family_rdf_data VALUES (1, 'http://www.w3.org/2000/01/rdf-
semantycznych jest SPARQL, którego im- SDO_RDF_TRIPLE_S('family', schema#Class'));
plementacja w bazie danych jest realizowa- 'http://www.oracle.com/family/Waldemar',
na przez funkcję SEM_MATCH (wcześniej 'http://www.oracle.com/family/fatherOf', Mężczyzna i Kobieta są podklasami Osoby:
SDO_RDF_MATCH). 'http://www.oracle.com/family/Zuzanna'));
Wyobraźmy sobie drzewo genealogiczne INSERT INTO family_rdf_data VALUES (18,
pewnej rodziny, które następnie opiszemy, ... SDO_RDF_TRIPLE_S('family',
korzystając z OST: 'http://www.oracle.com/family/Male',
Pracę z OST zacznijmy od stworzenia tabe- Określmy role społeczne - Michał jest męż- 'http://www.w3.org/2000/01/rdf-
li family_rdf_data przechowującej model se- czyzną: schema#subClassOf',
mantyczny rodziny: 'http://www.oracle.com/family/Person'));
INSERT INTO family_rdf_data VALUES (14,
CREATE TABLE family_rdf_data (id NUMBER, SDO_RDF_TRIPLE_S('family', INSERT INTO family_rdf_data VALUES (19,
triple SDO_RDF_ 'http://www.oracle.com/family/Michał', SDO_RDF_TRIPLE_S('family',
TRIPLE_S); 'http://www.w3.org/1999/02/22-rdf-syntax- 'http://www.oracle.com/family/Female',

Rysunek 2. Chmura danych Linked Data (żródło: Wikipedia)

60 05/2010
Sieć dziś i jutro

'http://www.w3.org/2000/01/rdf- END; ne są predefiniowane zbiory reguł (RULE-


schema#subClassOf', / BASE): RDFS, OWLSIF, RDFS++, OWLPri-
'http://www.oracle.com/family/Person')); me, SKOSCORE.
Możemy teraz wykonać ponownie zapy- Cechą prezentowanego rozwiązania jest
Przykład zapytań tanie: dodatkowo możliwość tworzenia własnych
Poniżej prezentujemy sposób wykorzystania reguł. Oto przykład:
funkcji SEM_MATCH w celu znalezienia SELECT m
odpowiednich zależności. FROM TABLE(SEM_MATCH( EXECUTE SEM_APIS.CREATE_RULEBASE('family_
Nasze pierwsze zapytanie (z wyłączonym '(?m rdf:type :Male)', rb');
silnikiem wnioskowania) zwróci obiekty kla- SEM_Models('family'),
sy „Mężczyzna”: SDO_RDF_Rulebases('RDFS'), INSERT INTO mdsys.semr_family_rb VALUES(
SEM_ALIASES(SEM_ALIAS('','http:// 'grandparent_rule',
SELECT m oracle.com/family/ '(?x :parentOf ?y) (?y :parentOf ?z)',
FROM TABLE(SEM_MATCH( ')), NULL,
'(?m rdf:type :Male)', null)); '(?x :grandParentOf ?z)',
SEM_Models('family'), SEM_ALIASES(SEM_ALIAS('','http:
null, Otrzymamy wynik: //www.oracle.com/
SEM_ALIASES(SEM_ALIAS('','http: family/')));
//www.oracle.com/ M
family/')), ---------------------------------- Prezentowane rozwiązanie, oferujące dodat-
null)); http://www.oracle.com/family/Michal kowe spojrzenie na dane poprzez analizę
http://www.oracle.com/family/Tomek pewnych zdefiniowanych zależności, posia-
Wynik: http://www.oracle.com/family/Waldemar da również wbudowane, wydajne mechani-
http://www.oracle.com/family/Grzegorz zmy ładowania dużych woluminów danych.
M http://www.oracle.com/family/Darek Są nimi: import poprzez API Java, operacje
---------------------------------- DML (INSERT, UPDATE) oraz ładowanie
http://www.oracle.com/family/Michal Proszę zwrócić uwagę, że silnik OST zna- hurtowe z plików płaskich.
http://www.oracle.com/family/Tomek lazł dodatkowych mężczyzn, dzięki wnio- Linki do dokumentacji, przykłady i ma-
skowaniu na podstawie reguły „Jeżeli ktoś teriały informacyjne znajdziemy na stro-
Wprowadźmy teraz regułę „Jeżeli ktoś jest jest czyimś bratem (brotherOf), to jest nie: http://www.oracle.com/technology/tech/
czyimś bratem (brotherOf), to jest męż- mężczyzną”. semantic_technologies/index.html
czyzną”: bądź prościej, wpisując w wyszukiwarce
Silniki wnioskowania hasło: Oracle Semantic Technologies.
INSERT INTO family_rdf_data VALUES (24, OWL i RDFS Prezentowany przykład został opra-
SDO_RDF_TRIPLE_S('family', Jak widać, sercem rozwiązań analiz seman- cowany na bazie dokumentacji dołączo-
'http://www.example.org/family/brotherOf', tycznych są mechanizmy dokonujące spraw- nej do produktu Oracle Semantic Tech-
'http://www.w3.org/2000/01/rdf- dzenia relacji pomiędzy zasobami, realizo- nologies dostępnej pod adresem: http:
schema#domain', wanymi za pomocą silników wnioskowa- //download.oracle.com/docs/cd/E11882_
'http://www.example.org/family/Male')); nia (ang. Entailment) RDF i wcześniej opi- 0 1 / a p p d e v. 1 1 2 / e 1 1 8 2 8 / s d o _ rd f _ c o n -
sanych dialektów ontologii OWL (bardziej cepts.htm#insertedID10
A następnie włączmy silnik wnioskowa- rozbudowanych reguł powstałych na bazie
nia: niedoskonałości RDF). Wnioskowanie jest
możliwe w oparciu o logiczne zależności po-
BEGIN między regułami (rules). Reguły to obiek-
SEM_APIS.CREATE_ENTAILMENT( ty wykorzystywane do oznaczania zależno-
'rdfs_rix_family', ści pomiędzy informacjami. Są nimi opera-
SEM_Models('family'), tory IF, filtry ograniczające wyniki operato-
SEM_Rulebases('RDFS')); ra IF i THEN. W Oracle Semantic wspiera-

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

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


Krzysztof Wysocki Paweł Korzec

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


����������������� ����������� ����������� ���������
PAWEŁ KORZEC,
�������������� �������������� �������������� ������������� KRZYSZTOF WYSOCKI
Paweł Korzec, Sales Consultant, Oracle Polska
Krzysztof Wysocki, Consulting Solution Manager,
Rysunek 3. Drzewo genealogiczne – przykład danych semantycznych Oracle Polska

www.sdjournal.org 61
Aplikacje biznesowe

Wdrożenia SAP –
droga przez mękę?
Co może się nie udać?
Wdrażanie systemu SAP jest przedsięwzięciem wymagających ścisłej
współpracy ze strony firmy wdrożeniowej i klienta. Rozwiązania typu
SAP posiadają z reguły gotową funkcjonalność podstawową ogólną lub
dedykowaną dla danej branży.
• Etap rozwoju rozwiązania biznesowego
Dowiesz się: Powinieneś wiedzieć: w systemie SAP.
• Jak wygląda proces wdrożenia systemu SAP • Podstawowa wiedza z zakresu zarządzania
Business One; projektem informatycznym; Każdy etap składa się z faz. I tak, etap
• Jakie problemy możesz napotkać w proce- • Podstawowa wiedza z zakresu wdrożeń sys- przedwdrożeniowy obejmuje dwie fazy:
sie wdrożenia SAP. temów klasy ERP
• Faza 0 - Przygotowanie sprzedaży sys-
temu. W tej fazie wykonywana jest
ocena projektu wdrożeniowego SAP
a produkty poszczególnych etapów uzgod- BO przez firmę wdrożeniową oraz po-
nione z klientem. dejmowana decyzja o zakupie syste-
Poziom Organizacja procesu wdrożeniowego jest mu. W wyniku fazy powinna powstać
trudności z reguły poniekąd narzucona przez produ- wstępna ocena projektu wdrożenio-
centa rozwiązania SAP BO – który, ba- wego – czyli m.in. dokument opisu-
zując na doświadczeniu wielu projektów jący zakres organizacyjny, opis proce-
wdrożeniowych oraz wypracowanych naj- sów biznesowych, które zostaną obję-

W
trakcie wdrożenia produkt ta- lepszych praktykach, udostępnia partne- te rozwiązaniem SAP oraz dokumenty
ki powinien być odpowiednio rom (czyli z punktu widzenia klienta, fir- zarządcze w postaci wstępnego harmo-
skonfigurowany, dostosowany mom wdrożeniowym) metodologię wdro- nogramu oraz budżetu.
do potrzeb danej organizacji i - jeśli zacho- żeniową. • Faza 1 – Określenie wymagań. Celem
dzi taka potrzeba - rozszerzony dodatko- W niniejszym artykule przedstawimy tej fazy jest pozyskanie wymagań klien-
wymi modułami. Dopiero wtedy realizuje opis metodyki wdrożenia systemu SAP Bu- ta co do zakresu i funkcjonalności roz-
procesy biznesowe klienta i w pełni spełnia siness One (oparty na dokumencie Zinte- wiązania SAP. Wymagania te będą sta-
oczekiwania użytkowników. growanej koncepcji wdrożenia i funkcjono- nowić podstawę projektu wdrożenio-
Zaniedbanie którejkolwiek z kluczo- wania opracowanej przez SAP AG). wego. Identyfikacja wymagań może
wych czynności przewidzianych w metody- być wykonana na dwa sposoby: poprzez
ce wdrożeniowej może spowodować nie tyl- Metodyka wdrażania SAP BO opracowanie dokumentu Opis wyma-
ko opóźnienie w realizacji projektu, ale i cał- Metodyka dzieli projekt wdrożeniowy na fa- gań lub przeprowadzenie szczegółowej
kowite jego fiasko. zy, w ramach których realizowane są kroki analizy, wyniku której powstaje doku-
Niniejszy artykuł przedstawia wybrane wdrożenia ze szczególnym uwzględnieniem ment Analizy Przedwdrożeniowej. Opis
problemy mogące pojawić się w trakcie re- kamieni milowych, związanych z powstawa- wymagań jest zestawieniem wszystkich
alizacji projektu oraz sugerowane sposoby niem konkretnych produktów projektu oraz wymagań klienta i obejmuje zazwyczaj:
ich rozwiązywania. ich odbiorem przez klienta. procesy biznesowe danej organizacji,
Podobnie jak w przypadku standardo- Jednym z kluczowych założeń realiza- które mają być wspomagane systemem
wych projektów wytwarzania oprogramo- cji projektu wdrożeniowego według przed- SAP, dokumenty tworzone w systemie,
wania, proces wdrażania nie może odbywać stawionej metodyki jest współpraca klienta raporty wykorzystywane przez użyt-
się ad hoc, bez określonych zasad, reguł i wy- (szczególnie grupy wdrożeniowej) z zespo- kowników końcowych, specyfikę da-
tycznych. Firma wdrożeniowa nie może po łem konsultantów firmy wdrożeniowej. nych przetwarzanych przez system.
prostu zainstalować produktu SAP w środo- Metodyka wdrożeniowa SAP Business
wisku klienta bez uprzedniej analizy wyma- One obejmuje trzy etapy: Analiza przedwdrożeniowa charakteryzu-
gań, zaprojektowania rozwiązania i przete- je się większym stopniem szczegółowości,
stowania go. Cały proces powinien być sta- • Etap przedwdrożeniowy; niż sam opis wymagań. Podstawowym jej
rannie zaplanowany, podzielony na etapy, • Etap wdrożenia; celem jest identyfikacja procesów bizneso-

62 05/2010
Wdrożenia SAP

wych oraz funkcjonalności objętych plano- dukty dostawcy wspomagające standar- wanie interfejsów oraz migrację danych
wanym wdrożeniem. Analiza ta skupia się dową funkcjonalność SAP). Prace insta- z dotychczasowych systemów. Dodat-
na określeniu procesów i powiązań mię- lacyjne dokumentowane są w Dokumen- kowo, dostawca (lub sam klient – zależ-
dzy nimi. Obejmuje nie tylko procesy, któ- tacji projektu klienta. nie od ustaleń) opracowuje dokumenta-
re będą objęte wdrożeniem i są realizowa- • Faza 3 – Szkolenie grupy wdrożeniowej cję dla użytkowników końcowych oraz
ne w standardzie SAP BO, ale i wymagają- (czyli użytkowników ze strony klienta). realizuje zaplanowane szkolenia. Wy-
ce specjalnych rozwiązań poza standardem Zakres szkolenia jest inny w zależności konywane są też całościowe testy roz-
SAP BO. W wyniku analizy przedwdroże- od odbiorców – cała grupa wdrożenio- wiązania celem weryfikacji popraw-
niowej określane są również interfejsy do wa otrzymuje ogólną prezentację syste- ności funkcjonalności. Zakończeniem
innych systemów oraz raporty i dokumen- mu SAP BO, natomiast specjaliści da- prac jest wykonanie audytów – przygo-
ty produkowane przez projekt wdrożenio- nego obszaru (np. Kadry i Płace) biorą towania użytkowników do pracy z sys-
wy. Analizę wykonuje zespół wdrożeniowy udział w warsztatach funkcjonalnych temem oraz samego systemu: jego goto-
(dostawca SAP BO), wymagana jest jednak przedstawiających dany obszar oraz po- wości do pracy w środowisku produk-
ścisła współpraca klienta. wiązania z innymi modułami rozwiąza- cyjnym.
W wyniku fazy 1 powstaje dokument nia. • Faza 6 – Nadzór nad pracą produktyw-
Opis wymagań lub dokument Anali- • Faza 4 – Przygotowanie rozwiązania ną systemu. Polega na wyłączeniu do-
za przedwdrożeniowa, uzgodniony przez biznesowego w SAP BO. Polega to na tychczasowych systemów (które zosta-
klienta i firmę wdrożeniową. Kolejnym eta- opracowaniu koncepcji rozwiązania ły zastąpione rozwiązaniem SAP BO)
pem jest etap wdrożenia. Obejmuje on na- biznesowego(rozumianego jako spo- i przejściu na obsługę procesów wdro-
stępujące fazy: sób realizacji procesów), odpowiedniej żonym systemem SAP. Zaleca się rów-
konfiguracji systemu SAP BO i ewentu- nież, by dostawca czuwał nad zamknię-
• Faza 1 – Organizacja projektu. Celem alnym przygotowaniu elementów roz- ciem pierwszego okresu rozrachunko-
tej fazy jest zorganizowanie projektu wiązania poza standardem SAP (w ra- wego w działaniu systemu. Zakończe-
wdrożeniowego – w zakresie zarządza- mach Dokumentacji projektu klienta), niem fazy jest protokół zamknięcia pro-
nia, zasobów, logistyki, etc. Faza ta roz- przygotowaniu scenariuszy testowych jektu wdrożeniowego SAP BO.
poczyna się określeniem Sponsora pro- i przetestowaniu gotowego systemu.
jektu oraz powołaniem przez klienta W zakres prac wchodzi też określenie Ostatnim etapem projektu wdrożeniowe-
Koordynatora projektu i grupy wdro- i skonfigurowanie ról oraz uprawnień go jest etap rozwoju rozwiązania bizneso-
żeniowej odpowiedzialnej za wdroże- użytkowników. Dostosowanie systemu wego w systemie SAP BO. Rozwój obejmu-
nie SAP BO w organizacji. Ze strony do wymagań oraz konfiguracja jest za- je jedną fazę:
dostawcy powoływany jest Kierownik daniem firmy wdrożeniowej; testy na-
Projektu oraz zespół konsultantów. Kie- tomiast powinny być wykonane przez • Faza 1 – Przygotowanie i uruchomie-
rownik Projektu opracowuje dokument klienta. nie funkcjonalności rozszerzonej SAP.
Karty Projektu wdrożenia SAP BO, któ- • Faza 5 – Przygotowanie systemu SAP Obejmuje to określenie zakresu funk-
ry obejmuje m.in. strategię wdrożenia, BO do pracy. Celem tej fazy jest przygo- cjonalności rozszerzonej i sporządze-
podstawowe i dodatkowe cele bizneso- towanie rozwiązania do produktywnej nie odpowiedniej umowy pomiędzy
we projektu oraz jego uzasadnienie biz- pracy w organizacji klienta. Zadanie to stronami, opracowanie funkcjonalności
nesowe, krytyczne czynniki powodze- obejmuje: sfinalizowanie przygotowa- rozszerzonej oraz procedur testowych,
nia projektu, ryzyka, zakres (na podsta- nia raportów i dokumentów, przygoto- przetestowanie rozwiązania i przeka-
wie wyników etapu przedwdrożenio-
wego np. Analizy Przedwdrożeniowej),
ramowy oraz szczegółowy harmono-
Analiza przedwdrożeniowa
Analiza przedwdrożeniowa realizowana jest w czterech krokach. Oto one:
gram, procedury oraz środowisko tech-
niczne projektu. Ponadto, Kierownik 1. Przygotowanie się klienta do wywiadów
Projektu inicjalizuje Dokumentację pro- Zanim firma wdrożeniowa przystąpi do wywiadów umożliwiających wykonanie analizy,
klient musi się odpowiednio przygotować. Obejmuje to zebranie następujących informacji:
jektu klienta (czyli rozwiązań projekto-
schemat organizacyjny przedsiębiorstwa klienta, przebieg procesów biznesowych, obieg
wych) oraz Dziennik Projektu (czyli do- dokumentów oraz raportów.
kument realizacji projektu). Dokumen-
ty te będą w dalszym ciągu uzupełnia- 2. Przeprowadzenie wywiadów
ne przez konsultantów. W fazie 1 okre- Przeprowadzenie wywiadów jest zadaniem firmy wdrożeniowej. Celem wywiadu jest zebra-
nie informacji niezbędnych do określenie procesów biznesowych i funkcjonalności objętych
ślane są również potrzeby szkoleniowe
wdrożeniem oraz interfejsów stałych, raportów, formularzy i dokumentów. W ramach anali-
grupy wdrożeniowej i użytkowników zy przedwdrożeniowej należy również ustalić wymagania sprzętowe dla wdrożenia systemu
końcowych systemu. SAP BO. Prowadzący wywiad powinni także umieć na bieżąco wychwycić niespójności oraz
• Faza 2 – Instalacja systemu SAP BO. próbować wyjaśnić ewentualne wątpliwości (np. co do zakresu wdrożenia).
Celem tej fazy jest zainstalowanie roz-
3. Opracowanie dokumentu Analizy przedwdrożeniowej
wiązania SAP w środowisku klienta. Informacje zebrane w trakcie wywiadów są podstawą do opracowania dokumentu Analizy
W tej fazie przygotowywane jest śro- przedwdrożeniowej. Przygotowanie dokumentu jest zadaniem firmy wdrożeniowej.
dowisko techniczne (na podstawie wy-
ników analizy potrzeb sprzętowych dla 4. Akceptacja dokumentu Analizy przedwdrożeniowej
Samo przygotowanie dokumentu Analizy przedwdrożeniowej nie stanowi podstawy do
wdrożenia systemu wykonanej w fazie
podjęcia dalszych prac projektowych. Dokument musi być zatwierdzony przez klienta oraz
przedwdrożeniowej), po czym insta- firmę wdrożeniową.
lowane oprogramowanie SAP BO oraz
ewentualnie inne aplikacje (np. pro-

www.sdjournal.org 63
Aplikacje biznesowe

zanie rozszerzenia do pracy na produk- kanie ewentualnych luk lub problemów (np. ści i ciągłości bieżącej pracy, pracownicy wy-
cji. W razie konieczności wykonywane procesów, których SAP nie wspiera, brakują- stępują jedynie w roli konsultantów, mogąc
jest też wyłączenie starych systemów, cych danych) i wspólne z klientem znalezie- poświęcić dostawcy wyznaczoną ilość cza-
zastępowanych przez funkcjonalność nie rozwiązania. su (i ani godziny więcej), wykonując jedno-
rozszerzoną. W wyniku fazy otrzymu- Ustalone i zaakceptowane wymagania cześnie swoje normalne obowiązki. W przy-
je się funkcjonalność rozszerzoną syste- stanowią podstawę do zaplanowania prac padku wdrożeń realizowanych w dużych or-
mu oraz protokół zamknięcia projektu i opracowania projektu rozwiązania – dla- ganizacjach, obejmujących wiele złożonych
wdrożenia funkcjonalności rozszerzo- tego też niezmiernie ważne jest, by były procesów biznesowych, może to nie wystar-
nej systemu SAP. określone prawidłowo i kompletnie. Odpo- czać – i firma wdrożeniowa skazana jest na
wiedzialność identyfikacji wymagań leży długie oczekiwanie na odpowiedź w kluczo-
Ryzyko w implementacji w głównej mierze po stronie firmy wdroże- wych kwestiach, lub na domyślanie się prawi-
systemu SAP BO niowej, jednak nie jest możliwa bez ścisłej dłowego rozwiązania.
Problemy z wdrożeniem systemu SAP BO współpracy klienta. I tu pojawia się kolejny Poniżej opisano dokładniej najczęściej po-
mogą pojawiać się na kilku płaszczyznach. problem – brak zaangażowania przedstawi- jawiające się problemy oraz możliwe sposo-
Najczęstszymi – i jednocześnie najbardziej cieli klienta w prace związane z projektem by przeciwdziałania im.
krytycznymi dla powodzenia projektu – są wdrożeniowym. Brak zaangażowania nieko-
zagrożenia związane z prawidłowym pozy- niecznie musi wynikać z lekceważenia całe- Brak zaangażowania
skaniem i zaimplementowaniem wymagań. go przedsięwzięcia lub negowania potrzeby przedstawicieli klienta
Określenie wymagań wymaga dogłębnego i zasadności wdrożenia – zazwyczaj wiąże Zdarzają się sytuacje, w których klient zle-
zrozumienia procesów biznesowych w orga- się po prostu z brakiem czasu pracowników ca dostawcy wdrożenie systemu SAP BO,
nizacji klienta, zidentyfikowanie procesów, klienta. Nie każda firma chcąca wdrożyć dostarcza wstępną listę wymagań, po czym
które mogą być objęte rozwiązaniem SAP SAP BO ma możliwość oddelegowania ze- uważa, że jego rola w procesie się skończy-
BO, zweryfikowanie, w jakim stopniu SAP społu pracowników do wspierania prac do- ła – a reszta należy już do firmy wdrożenio-
umożliwi realizację tych procesów, wyszu- stawcy – czasem, by nie zaburzać stabilno- wej. Zdarzają się również sytuacje, w któ-
rych klient nie zapewnia wystarczające-
go wsparcia swoich pracowników w proce-
sie analizy przedwdrożeniowej, wychodząc
z założenia, iż rolą dostawcy jest opracowa-
nie analizy lub – po prostu – nie chcąc od-
rywać swojego personelu od właściwych za-
dań. W wyniku takiego podejścia, dostawca
nie jest w stanie poprawnie zidentyfikować
wymagań i, co za tym idzie, zaimplemen-
tować rozwiązania odpowiadającego ocze-
kiwaniom odbiorców. Argumenty w stylu
„potrzebujemy wsparcia Waszych pracowni-
ków, by określić, co dokładnie system ma ro-
bić, jakie procesy wspierać, jakie dokumen-
ty i w jakiej postaci produkować” nie zawsze
odnoszą pożądany skutek.
Co można zrobić?
Najlepszą metodą jest po prostu uświa-
Rysunek 1. Etapy projektu wdrożeniowego
domić klientowi złożoność i mnogość do-
stępnych w SAP funkcji – wiele z nich nie
jest klientowi potrzebnych, inne muszą zo-
stać odpowiednio dostosowane do potrzeb
i oczekiwań użytkowników. Dostawca nie
jest w stanie przewidzieć wymagań wyni-
kających ze specyfiki danej branży i przed-
siębiorstwa – nawet jeśli posiada spore do-
świadczenie we wdrażaniu rozwiązań SAP
BO w danym obszarze. Może zaproponować
rozwiązanie, dostarczyć swoich uwag – ale
to klient jest stroną decydującą o ostatecz-
nym kształcie wymagań.
Dostawca powinien uświadomić kliento-
wi, iż bez jego wsparcia projekt jest z góry ska-
zany na niepowodzenie – określić ryzyko wy-
nikające z niepełnej lub niepoprawnej identy-
fikacji wymagań, jego późniejsze skutki w po-
staci zmian do funkcjonalności, opóźnień
wynikających z konieczności poprawy czy
Rysunek 2. Dokumenty projektowe zmiany dotychczasowych wymagań etc.

64 05/2010
Wdrożenia SAP

Nieadekwatna Wymagania powinny skupić się na tym, co nych w Excelu, a użytkownicy końcowi tra-
dokumentacja systemu system będzie robił – i to dość dokładnie. cą zaufanie do aplikacji.
Załóżmy, że jesteś Kierownikiem Projektu Organizacje, które przymierzają się do Co można zrobić?
mającego na celu wdrożenie systemu SAP wdrożenia SAP BO, często zaczynają od Jeśli organizacja, w której wdrażasz SAP BO,
BO u klienta. Twój zespół zaczyna groma- określania wymagań – zamiast najpierw wykonuje testy oparte na wymaganiach, za-
dzić wymagania systemu od użytkowni- zorientować się w funkcjonalności systemu proponuj narzędzie zarządzania wymaga-
ków. Po uzyskaniu wszystkich potrzebnych – i w efekcie wymagania mają się nijak do niami (Requisite Pro, Caliber-RM). Dopracuj
informacji, dochodzisz do wniosku, iż po- możliwości systemu SAP. wszystkie wymagania, upewnij się, że każde
siadasz wystarczające dane do implementa- Niektóre firmy mają w zwyczaju doku- jest wystarczająco zrozumiane i dla każdego
cji „docelowego” systemu. A ponieważ ro- mentować wymagania w postaci plików można określić atrybuty: wykonalność, ko-
zumiesz działanie „docelowego” systemu, Excel – to utrudnia śledzenie wymagań nieczność, spójność, kompletność, priory-
wiesz, jak ma funkcjonować i jakie są wyma- (zwłaszcza historii zmian), zmiany treści tet, poprawność, możliwość śledzenia, jed-
gania względem niego – zapominasz o udo- wymagań i efektywne komunikowanie ich noznaczność.
kumentowaniu „bieżącego” systemu (czy- do zaangażowanych osób, określanie właści- Zaprezentuj swoje (i zespołu wdroże-
li systemu, który będzie zastąpiony rozwią- cieli wymagań, tworzenie RTM (macierz śle- niowego) zrozumienie wymagań za pomo-
zaniem SAP). dzenia wymagań), wreszcie – zarządzanie cą diagramów przepływu procesu oraz po-
Podczas testów akceptacyjnych okazuje cyklem życia wymagań. przez sesje przeglądowe. Wymagania, które
się, że system nie spełnia oczekiwań użyt- Instytucja wdrażająca SAP jest później nie mogą być zaimplementowane, powinny
kowników końcowych, a uczestnicy testów obarczona zadaniem interpretacji wyma- być oznaczone jako wyłączenia. Wymagania
UAT nie są w stanie walidować Twojego roz- gań spisanych w Excelu, planowaniem im- spoza zakresu projektu wdrożeniowego na-
wiązania. Klient jest rozczarowany propono- plementacji wymagań i weryfikacji stopnia leży komunikować zespołowi .
wanym rozwiązaniem – a Ty musisz teraz pokrycia wymagań testami. Dostawca SAP Najprawdopodobniej wymagania nie osią-
udowodnić, że zaimplementowane rozwią- zamiast skupić się na uszczegóławianiu wy- gną nigdy stanu „perfekcji” (gdyż to mogło-
zanie SAP jest zgodne z potrzebami bizne- magań, traci wiele czasu na zarządzanie sa- by sparaliżować projekt), lecz powinny być
sowymi i wymaganiami. Znajdujesz się w sy- mą listą i niemal na ślepo próbuje imple- zdefiniowane jasno i zrozumiałe – tak, by ze-
tuacji, w której nie możesz wyjaśnić, w jaki mentować wymagania w treści określonej spół mógł kontynuować prace z akceptowal-
sposób nowe rozwiązanie SAP ma taką sa- przez klienta – nawet jeśli niektóre z nich są nym poziomem ryzyka (w przeciwieństwie
mą – lub rozszerzoną – funkcjonalność po- niepotrzebne, niezgodne z funkcjonalnością do prowadzenia prac implementacyjnych na
przedniego systemu. Padają pytania – jak SAP lub wręcz niemożliwe do realizacji. podstawie wymagań będącym jedynie hasła-
SAP zastępuje funkcjonalność starego syste- W czasie testów, lub później – po insta- mi). Po osiągnięciu akceptowalnego poziomu
mu, i czy w ogóle to robi? lacji systemu SAP BO, często rozpoczynają ryzyka, zespół funkcjonalny może rozpocząć
Co można zrobić? się debaty na temat funkcjonalności rozwią- konfigurację systemu, a zespół techniczny
Określ, czy istnieje dokumentacja w po- zania – które nie spełnia wymagań określo- – implementację nowych aplikacji.
staci specyfikacji funkcjonalnej, diagramów
architektury, diagramów przepływu proce-
su opisująca obecną funkcjonalność syste-
SAP – ale po co mi to? Korzyści.
SAP to nie tylko sprawniejsza rejestracja i wystawianie dokumentów. To nie tylko repozyto-
mu. Współpracuj z klientem – w szczegól- rium danych.
ności z programistami, którzy projektowali Sedno korzyści z systemu SAP polega na zupełnie nowej jakości i szybkości informacji, któ-
stary system – by zrozumieć niuanse i ob- re kierownictwo otrzymuje do dyspozycji. Dzięki tym danym można decydować o zmianach
szary wysokiego ryzyka w systemie, który cen, ofert, dostawców, można również zapobiegać zmniejszeniu płynności finansowej.
System SAP umożliwia wyraźną poprawę gospodarki środkami finansowymi. SAP wspiera za-
będzie zastępowany rozwiązaniem SAP. Do-
rządzanie budżetem poprzez prognozy kosztowe i przepływowe. Prognoza płynności wspo-
kumenty, które zgromadzisz, pozwolą po- maga decyzje w zakresie finansowania działalności bieżącej. Raporty prezentowane przez
znać obecny system oraz w dużym stopniu system mogą w dowolnym momencie dostarczyć informacji o planowanych datach wpły-
zdeterminować sposób zastąpienia starego wu należności i koniecznych płatnościach – co pozwala zarządzać bieżącymi rozrachunkami
systemu nowym. z klientami i dostawcami. Dzięki temu można świadomie i kompleksowo kształtować polity-
Opracuj wstępne przypadki testowe, któ- kę kredytu kupieckiego, bez obaw o utratę płynności.
Ogromną korzyścią rozwiązania SAP jest możliwość stworzenia kompleksowego, efektyw-
re w szczególności weryfikują, w jaki sposób
nego systemu kontrolingu, w odróżnieniu od tradycyjnych aplikacji księgowych, niezinte-
przetestować funkcje starego systemu zastą- growanych z obszarem zaopatrzenia i sprzedaży firmy. Dzięki SAP można w pełni realizo-
pione rozwiązaniem SAP. Przypadki te po- wać postulat kontrolingu – sterowanie wszystkimi działaniami w firmie, które dają podstawę
winny być skontrolowane przez uczestni- efektywnego podejmowania decyzji i w efekcie pozwalają na osiągnięcie zysku.
ków testów UAT. Dokumentuj każdą infor- System SAP zapewnia precyzyjne i aktualne informacje o rentowności poszczególnych pro-
duktów, usług, działów, segmentów rynku – dzięki kalkulacji kosztów i przychodów na nie
mację zwrotną od recenzentów i (w miarę
przypadających.
możliwości) postaraj się stworzyć prototyp „Ile kosztuje dany produkt?”, „Ile kosztuje dana usługa?”, „Jaki wpływ będzie miała zmiana
docelowego rozwiązania – tak, by umożli- cen produktów przez dostawców?” - to niektóre z pytań wpływających na stan finansowy
wić użytkownikom końcowym wgląd w no- i przyszłość firmy. Na te pytania SAP daje odpowiedź – poprzez zawarte w systemie mechani-
wą funkcjonalność i jak najszybsze dostar- zmy symulacji i kalkulacji kosztów produkcji oraz jej rentowności. Stosując różne modele wy-
czenie uwag co do stopnia spełnienia oczeki- ceny i alternatywne zestawy składników (produktu, usługi) kierownictwo danego przedsię-
biorstwa może precyzyjnie zaplanować koszty danego produktu lub usługi i na bieżąco mo-
wań wobec systemu.
nitorować rentowność działalności. Analiza rozbieżności (odchyleń danych rzeczywistych
od danych planowanych) umożliwia szybką identyfikację słabych punktów i podjęcie odpo-
Niedopracowane wymagania wiednich decyzji naprawczych.
Wiele organizacji (szczególnie związanych Dużym udogodnieniem są zestawy narzędzi typu business intelligence, czyli elastycznych
z administracją) produkuje setki wymagań dodatków umożliwiających samodzielne kreowanie raportów.
formułowanych jako „system powinien…”.

www.sdjournal.org 65
Aplikacje biznesowe

Wymagania powinny być określone dla Opracuj RTM, który wykaże, że wszystkie problemy z implementacją rozwiązania
każdego obszaru implementacji SAP BO wymagania mają pokrycie i są zmapowane SAP), relacje z klientem ulegają szybkiemu
– nie tylko dla funkcjonalności dotyka- na przypadki testowe. pogorszeniu – z punktu widzenia klienta
jących tej implementacji. Kategorie wy- system nie spełnia swojej roli, z perspektywy
magań obejmują: bezpieczeństwo, work Brak weryfikacji zakresu dostawcy wymagane prace zostały wykona-
flow, raporty, interfejsy, formy, wykona- Relacje pomiędzy firmą wdrażającą SAP BO ne poprawnie i według dokumentacji.
nie, archiwizację, użyteczność etc. Określ a klientem mogą ulec radykalnemu ochło- Co można zrobić?
wszystkich udziałowców oraz przydziel dzeniu, przerodzić się wręcz we wrogość Ustal produkty prac oraz kryteria odbio-
właścicieli wymagań dla każdego obszaru. – jeśli klient ma poczucie, że zaimplemento- ru. Klient weryfikuje i zatwierdza produk-
Wymagania, które spełnione są automa- wane rozwiązanie nie pasuje do jego potrzeb ty zgodnie z owymi kryteriami. Brak akcep-
tycznie (poprzez rozwiązanie produktowe biznesowych, a użytkownicy końcowi nie są tacji produktu lub zweryfikowanego już wy-
SAP) i nie wymagają tworzenia przypad- w stanie wykonać czynności, które wykony- magania, musi być udokumentowany i roz-
ków testowych, powinny być jasno przed- wali z łatwością za pomocą starego systemu. wiązany.
stawione klientowi (np. poprzez prezen- Problem pojawia się, gdy klient zgłasza Zdarzają się sytuacje, kiedy po implemen-
tację demo aplikacji). Należy jednak pa- defekty i usterki do systemu SAP BO, któ- tacji SAP wdraża się system o funkcjonalno-
miętać, iż samo zaprezentowanie kliento- re dotyczą obszarów czy funkcji nie będą- ści zgodnej z wymaganiami, podejmowana
wi sposobu, w jaki produkt SAP spełnia cych w zakresie prac wdrożeniowych, lub jest decyzja GO LIVE, system zostaje zain-
wymagania, nie wystarcza – należy upew- nieudokumentowanych w wymaganiach do stalowany w środowisku produkcyjnym, po
nić się, że akceptacja jest oficjalna i udoku- systemu. Kiedy firma wdrożeniowa identy- czym klient uskarża się, iż oprogramowanie
mentowana. fikuje takie błędy jako żądania zmian (a nie nie spełnia jego potrzeb – przy czym nie do-
starcza na to konkretnych dowodów. Stwier-
dzenia w stylu „system nie robi tego”, „sys-
tem nie jest tak dobry, jak poprzedni”, „sys-
tem jest skomplikowany” nie mówią nic.
Klient powinien przekazać konkretne przy-
kłady na to, że zaimplementowane rozwią-
zanie nie spełnia potrzeb biznesowych czy
wymagań przed podpisaniem zgody na
wdrożenie produkcyjne.
Firma wdrożeniowa oraz klient powin-
ni ustalić kryteria zakończenia (exit crite-
ria) dla fazy testowania oraz testów akcep-
tacyjnych. Umożliwi to uniknięcie proble-
mów z interpretacją wyników etapu testów
i pomoże w podjęciu decyzji co do dalsze-
Rysunek 3. Fazy etapu 1
go działania (np. decyzji GO LIVE). Zale-
ca się, by uczestnicy UAT wykorzystywali
część poprzednio użytych w testach integra-
cyjnych scenariuszy testowych. Tym sposo-
bem, wykonując testy akceptacyjne, weryfi-
kowana jest zarówno poprawność wyników
wcześniejszych faz testowania. UAT jest do-
skonałym momentem na wskazanie wszyst-
kich problemów zauważonych w rozwiąza-
niu SAP przed wdrożeniem na produkcję.
Mimo to nadal wiele organizacji nie przykła-
da do testów akceptacyjnych należytej uwa-
gi i woli raczej polegać na demo systemu ja-
ko dowodzie spełnienia wymagań użytkow-
ników – a przecież UAT to okazja, by udo-
stępnić aplikację prawdziwym użytkowni-
kom końcowym.

Nieudokumentowane założenia,
ryzyka, ograniczenia
Zdarzają się projekty, w których w fazie po-
czątkowej dokumentuje się ryzyka, założe-
nia i ograniczenia bardzo pobieżnie, w zasa-
dzie tylko pro forma. Takie – stworzone po-
niekąd z przymusu – dokumenty umiesz-
cza się gdzieś, zaś o miejscu ich przecho-
wywania, a czasem i o samej ich obecności,
Rysunek 4. Rezultaty wstępnej oceny projektu wdrożeniowego szybko się zapomina.

66 05/2010
Wdrożenia SAP

Kiedy projekt nabiera rozpędu i wcho- długi – przedłużający się – czas. Co wię- Ze swojej strony klient powinien wspólnie
dzi w kolejne fazy, nikt nie dokonuje sto- cej, w wyniku braku kontroli i zaangażo- z dostawcą ustalić priorytety i oczekiwane
sownych aktualizacji w dokumentacji ry- wania ze strony klientów, problemy te mo- daty rozwiązania problemów.
zyka, założeń i ograniczeń – które powin- gą zostać przez pomyłkę zamknięte – pod-
ny wyjaśniać, w jaki sposób podejmowano czas gdy w rzeczywistości nigdy ich nie Znikająca wiedza
decyzje zarządcze i co miało na nie wpływ rozwiązano. Z punktu widzenia klienta jest to istotny
(np. ograniczenie zakresu projektu w ja- Co można zrobić? problem i zagrożenie użytkowania wdrożo-
kimś stopniu ze względu na określone ry- Ustal „punkt kontaktu” – osobę odpowie- nego systemu. Klient zatrudnia kontrakto-
zyko). Często powoduje to chaos – dostaw- dzialną za kontakt z klientem. Osoba ta po- rów i konsultantów posiadających wiedzę
ca SAP nie jest w stanie obronić swoich de- winna dokumentować wszystkie próby roz- – z jednej strony o wdrażanym systemie SAP
cyzji czy działań wynikłych z braku odnie- wiązania danego problemu i wyniki owych – z drugiej o procesach biznesowych danej
sienia do udokumentowanych ograniczeń prób. Zadaniem osoby kontaktowej jest rów- organizacji. Ludzie ci odpowiadają za kon-
czy założeń. nież opracowywanie i dystrybucja codzien- figurację systemu, stworzenie interfejsów
Co można zrobić? nego raportu o wszystkich problemach do- pomiędzy różnymi systemami w przedsię-
Udokumentowanie zagrożeń, ograniczeń stawcy – a to w celu uniknięcia ryzyka od- biorstwie, testowanie i rozwiązywanie pro-
i założeń to początek – ale nie koniec prac suwania problemów na potem (w związku blemów zgłaszanych przez użytkowników
związanych z tym obszarem zarządzania z brakiem odpowiedzi ze strony klienta po końcowych.
projektem. Ryzyka powinny być stale pod- tym, jak dostawca zaproponuje rozwiązanie Zazwyczaj jednak terminy w projekcie
dawane ocenie, przeglądane i weryfikowa- problemu). oraz wysokie priorytety innych zadań po-
ne. To, że dane ryzyko – zidentyfikowane
na początku projektu – nie wystąpiło przez
pierwsze 3 miesiące, nie oznacza, że nie po-
jawi się w miesiącu 4.
Zgodnie z dobrymi zasadami zarządza-
nia ryzykiem, zagrożenia o wysokim priory-
tecie powinny być przeglądane co najmniej
raz w tygodniu. Na zapobieganie wystąpie-
nia ryzyka lub minimalizację jego skutków
należy określić odpowiedni budżet - pozwo-
li to elastyczniej poradzić sobie z ewentu-
alnym pojawieniem się problemu. Osoby,
w największym stopniu narażone na wpływ
ryzyka, powinny być na bieżąco informowa-
ne o statusie przeglądów i aktualnym stanie
zagrożeń w projekcie.
W przypadku założeń i ograniczeń obo-
wiązuje podobna zasada – zasada systema-
tycznych przeglądów, aktualizacji danych
i informowania o zmianach osób zaangażo-
wanych.

Problemy dostawcy
z oprogramowaniem
Podczas testowania lub utrzymywania syste-
mu SAP można znaleźć błędy, luki czy uster-
ki, które nie mogą być naprawione przez ze-
spół wdrożeniowy.
Takie błędy wynikają zwykle nie z posia-
dania nieprawidłowo zaimplementowane-
go rozwiązania SAP, lecz z niedoskonałości
oprogramowania dostawcy. W zależności od
powagi problemu, wpływ błędów na biznes
może przejawiać się w następujący sposób:

• Niezadowolenie klienta / użytkowni-


ków końcowych;
• Brak możliwości realizacji specyficznej
funkcjonalności systemu;
• Straty finansowe;
• Niestabilność systemu.

Problemy dostawcy z oprogramowaniem


mogą pozostawać nierozwiązane przez Rysunek 5. Fazy etapu 2

www.sdjournal.org 67
Aplikacje biznesowe

wodują, że kontraktorzy i konsultanci wy- ty wiedzy wraz z odejściem danego kontrak- przedyskutujecie obszary zwiększone-
konują swoją pracę w sposób – pod pew- tora czy konsultanta. W tym celu: go ryzyka. Zdobądź dane do ewentual-
nym względem – zdezorganizowany i nie- nego kontaktu z kontraktorem na wy-
ustrukturyzowany. Dezorganizacja ta doty- • Stwórz wspólne repozytorium do gro- padek pojawienia się konieczności kon-
czy dokumentacji wykonanych zadań oraz madzenia dokumentów, notatek, wszel- sultacji.
produktów. O ile sama praca może być zre- kich zapisów o przebiegu i wynikach
alizowana doskonale, o tyle już udokumen- prac. Opracuj standard nazywania pli- Lekceważenie
towanie jej może (z braku czasu) pozosta- ków (ułatwi to zorientowanie się w za- użytkowników końcowych
wiać wiele do życzenia. Skutek? Po jakimś wartości danego pliku). Jedną z najczęściej zaniedbywanych kwestii
czasie kontraktorzy i konsultanci opuszcza- • Powołaj zespół QA, którego zadaniem przy wdrożeniach systemów typu SAP czy
ją dany projekt, a klient pozostaje z niepełną będzie wprowadzenie i egzekwowanie ERP jest przetwarzanie danych w czasie rze-
wiedzą, jaką mu pozostawili. Pierwszy lep- standardów projektowych oraz opraco- czywistym. Prawidłowa modyfikacja danych
szy audyt wykonany na projekcie wdroże- wanie wytycznych dla poszczególnych w locie, realizowana z łatwością przez po-
niowym wykaże, że klient nie do końca wie, zadań. przednią aplikację, może nie być wykonalna
na czym polegały prace projektowe, jak zo- • Wymagaj raportów tygodniowych od w nowym systemie. Utrudnia to korzystanie
stały zrealizowane, jak i gdzie są udokumen- wszystkich kontraktorów. Raporty te z funkcjonalności i zaburza użyteczność no-
towane (o ile w ogóle są). powinny zawierać listę zrealizowanych wego rozwiązania.
Co można zrobić? zadań i ich wyniki (np. nazwy wytwo- Innym problemem dotykającym użytkow-
Częste zmiany ludzi w przypadku pracy rzonych dokumentów). ników końcowych jest kwestia znajdowa-
w formie body leasingu lub wynajmu kon- • W przypadku odejścia kontraktora z ze- nia danych w aplikacji, produkowania wła-
sultantów są poniekąd normalne. Można społu, zwołaj spotkanie (co najmniej 2, ściwych raportów, złożoność systemu, nie-
jednak zminimalizować ryzyko wynikające 3 dni przed odejściem pracownika), na prawidłowo skonstruowane przepływy work
z częstych zmian kadrowych i uniknąć utra- którym przejrzycie produkty prac oraz flow, brak procesów umożliwiających realiza-
cję krytycznych zadań, rejestrowanie danych
w różnych miejscach, niezgodnych z oczeki-
waniami i potrzebami użytkownika.
Zignorowanie rzeczywistych potrzeb
użytkowników może spowodować, że no-
wy system będzie skutecznie uniemożliwiać
wykonywanie standardowych, koniecznych
do prawidłowego funkcjonowania organiza-
cji, zadań – zamiast je wspierać i ułatwiać.
Co można zrobić?
Użytkownicy końcowi powinni zostać za-
angażowani w fazę pozyskiwania wymagań.
Dostawca musi upewnić się, iż wymagania
użytkowników są poprawnie zidentyfikowa-
ne i zrozumiane – w tym celu można zasto-
sować diagramy przepływu procesu, prezen-
tując i weryfikując poprawność projektowa-
nego rozwiązania przy współpracy użytkow-
Rysunek 6. Fazy etapu 3
ników. Wszelkie wymagania powinny być
oficjalnie zaakceptowane przez użytkowni-
ków końcowych, zanim dostawca przystąpi
do projektowania rozwiązania.
W przypadku złożonych systemów, obej-
mujących wiele procesów biznesowych,
przydatne jest zastosowanie podejścia opar-
tego o prototypowanie funkcjonalności
i interfejsów użytkownika. Pozyskiwanie
i uszczegóławianie wymagań jest o wiele ła-
twiejsze, jeśli dostawca ma możliwość zade-
monstrować użytkownikom projektowaną
funkcjonalność systemu, sposób użytkowa-
nia, ergonomię, sposób realizacji wymagań
biznesowych. Informacja zwrotna od użyt-
kowników umożliwia dostosowanie projek-
tu aplikacji do oczekiwań na bardzo wcze-
snym etapie – co znacznie zmniejsza kosz-
ty i ryzyko zmian.
Ponadto, użytkownicy końcowi powinni
czynnie uczestniczyć w przygotowaniu do
Rysunek 7. Ryzyko w projekcie wdrożeniowym testów akceptacyjnych – zwłaszcza w pro-

68 05/2010
Wdrożenia SAP

jektowaniu scenariuszy testowych. To dla on funkcji wykorzystywanej bardzo rzadko systemu – przez co nie można prawidłowo
nich wdrażany jest nowy system i ich potrze- – co znacznie zmniejsza ryzyko biznesowe wykorzystać ich potencjału.
by ma realizować – ścisła współpraca jest związane z pozostawieniem błędu bez po- Co można zrobić?
więc nieodzowna. prawki). Analiza wpływu może wykazać, Wszelkie dokumenty standardów, proce-
że rozwiązanie problemu jest zbyt kosztow- dur etc. powinny być gromadzone w okre-
Braki analizy wpływu ne w porównaniu do potencjalnych korzyści. ślonym, znanym całemu zespołowi repo-
i testów regresji Jednak fakt ten da się stwierdzić dopiero po zytorium, do którego dostęp mają wszyscy
Załóżmy, że użytkownicy końcowi zgłasza- wykonaniu analizy – dlatego też powinna członkowie zespołu. Kierownictwo projek-
ją do help desku problemy i błędy w funkcjo- być ona wykonywana zawsze. tu powinno ponadto wyznaczyć kilka osób
nowaniu systemu. Problemy te są następnie Jeśli jednak zespół kontroli zmian podej- do demonstracji i szkolenia zespołu odno-
przekazywane do zespołu utrzymania sys- mie decyzję o implementacji zmiany (po- śnie obowiązujących standardów i wytycz-
temu SAP celem rozwiązania. Osoby odpo- prawki), powinien on zapewnić możliwość nych – należy o tym pamiętać w szczególno-
wiedzialne za kontrolę zmian oraz integra- realizacji zmiany (dostępność zasobów etc. ści w przypadku nowych pracowników dołą-
cję w projekcie nie analizują istoty i wagi pro- ) oraz zaplanować środki weryfikacji jej po- czających do zespołu. Trenerzy ci powinni
blemu, nie dokonują oceny pracochłonności prawności (np. opracować scenariusze testo- systematycznie kontrolować jakość produk-
naprawy problemu ani weryfikacji, czy dany we dla wewnętrznych testów oraz testów in- tów i ich zgodność z ustalonymi wzorcami.
błąd dotyka funkcjonalności z zakresu pro- tegracji z systemem produkcyjnym). Produkty, które nie spełniają wymagań, po-
jektu lub czy rzeczywiście jest to błąd (odno- winny być oddane właścicielom (twórcom)
sząc się do udokumentowanych wymagań). Niedostosowane lub nieprzestrzegane do poprawki, wraz z sugestiami rozwiązania
Nie szacuje się całościowego kosztu rozwią- procedury i standardy i wskazanymi miejscami wystąpienia niepra-
zania problemu. Jak już wspomniano, zespół QA przy współ- widłowości.
Po naprawieniu błędu, poprawka insta- pracy CCB, analityków etc. może ustalić
lowana jest do systemu produkcyjnego bez standardy i procedury dla m.in.: Podsumowanie
sprawdzenia, jak wpłynie ona na poprzed- Rozwiązanie SAP umożliwia znaczną po-
nią funkcjonalność systemu i czy nie zabu- • Projektowania przypadków i scenariu- prawę działalności firmy. Umożliwia prowa-
rzy jego stabilności. Nie wykonuje się testów szy testowych; dzenie i kontrolowanie bieżącej działalno-
regresji i end to end na innych modułach, by • Tworzenia specyfikacji technicznych ści, planowanie zasobów, dostarcza informa-
upewnić się, że poprawka nie popsuje in- i funkcjonalnych; cji dla podejmowania decyzji zarządczych.
nych funkcjonalności. Rezultaty są łatwe do • Procesu kontroli zmian oraz zarządza- Wdrożenie systemu SAP BO nie jest pro-
przewidzenia – po wdrożeniu poprawki na nia zmianami; stą instalacją systemu z pudełka – wymaga
produkcję okazuje się, że przestają działać • Raportowania defektów oraz ich ob- poświęcenia pewnej ilości czasu na analizę
inne rzeczy, a użytkownicy nie mogą korzy- sługi. wymagań, dostosowanie możliwości pro-
stać z systemu. duktu SAP do określonych potrzeb, oczeki-
Co można zrobić? Jednak ustalone procedury czy standardy wań, procesów biznesowych danego przed-
Dobrym sposobem jest powołanie zespołu mogą nie być przestrzegane. Z wielu po- siębiorstwa. Czas ten jednak nie jest straco-
kontroli zmian (CCB – change control bo- wodów: ny na próżno – korzyści z działającego sys-
ard), którego zadaniem jest analiza wpły- Zespół funkcjonalny może nie zdawać so- temu z nawiązką rekompensują czas poświę-
wu zmian wynikających ze zgłoszonych pro- bie sprawy z istnienia i obowiązywania stan- cony na przygotowanie wdrożenia i imple-
blemów. Członkowie zespołu mają obowią- dardów nazewnictwa specyfikacji. Może też mentacji. Warto mieć świadomość tego, że
zek rozważenia każdej pojedynczej propo- nie potrafić prawidłowo pozyskiwać i doku- mimo iż wielogodzinne spotkania dotyczą-
zycji zmiany (zarówno zmian rozumianych mentować wymagań podczas warsztatów ce wymagań, analizy procesów biznesowych
jako poprawki błędów, jak i żądań zmian analitycznych. pozornie nie dostarczają firmie wymiernych
do zatwierdzonej funkcjonalności systemu) Zespół testowy może nie wiedzieć, jakie są korzyści, wartość gotowego, działające syste-
uwzględniając: priorytet, poziom wysiłku, kryteria wejścia i wyjścia dla poszczególnych mu, będzie ogromna – i będzie przynosić
pracochłonność testów, dostępność zaso- faz testowania i w wyniku tego nie może od- konkretne korzyści przez wiele lat.
bów, koszt i wpływ na harmonogram projek- powiednio zaprojektować scenariuszy dla
tu. Ważnym czynnikiem jest też konieczność kolejnych etapów.
zmiany – czyli analiza, na ile dana modyfi- Programiści – z braku czasu, roztargnie- KAROLINA ZMITROWICZ
kacja jest niezbędna dla prawidłowego funk- nia – mogą nie przestrzegać stosowania Pracuje na stanowisku Analityka biznesowego
cjonowania systemu (bowiem po dokład- określonej konwencji w tworzeniu kodu. w �rmie PROFI-DATA Sp z o.o. Karolina specjali-
nej analizie, może okazać się, że dany pro- Uczestnicy UAT mogą nie być świadomi zuje się obecnie w modelowaniu wymagań biz-
blem można tymczasowo obejść lub dotyczy swojej roli i odpowiedzialności w testowaniu nesowych. Wcześniej pracowała jako Manager
Quality Assurance w projektach informatycznych
w sektorze �nansowo – bankowym.
W Sieci Pro�-Data to producent oprogramowania spe-
• www.sap.com – oficjalna witryna producenta SAP. Zawiera mnóstwo informacji o samym cjalizujący się w budowie dedykowanych rozwią-
produkcie oraz wskazów przydatnych do wdrożenia systemu. zań informatycznych dla ubezpieczeń, banko-
• www.bedemiecsap.pl – porady dla menedżerów planujących wdrożenie systemu SAP. wości i administracji publicznej. Firma świadczy
• www.sap-img.com/sap-implementation.htm – informacje, wytyczne dla poprawnej i sku- usługi wdrożeń i konsultingu systemu SAP. Firma
tecznej implementacji SAP.
posiada certy�kat jakości ISO 9001:2008 w zakre-
• http://whitepapers.techrepublic.com.com/search.aspx?kw=sap+implementation – publika-
cje w tematyce wdrożenia SAP. sie produkcji oprogramowania i wdrażania goto-
• http://whitepapers.sapinsideronline.com - publikacje w tematyce wdrożenia SAP. wych rozwiązań informatycznych.
Kontakt z autorem: karolina_zmitrowicz@wp.pl

www.sdjournal.org 69
Aplikacje biznesowe

C++ Qt 4.5
Podstawy budowy aplikacji przy użyciu biblioteki Qt

W artykule zostanie zaprezentowana budowa bardzo prostej aplikacji


okienkowej w oparciu o bibliotekę Qt – będzie to zwykły kalkulator
z prostymi wyrażeniami arytmetycznymi.

instalujemy CDT. Pobieramy ze strony http:


Dowiesz się: Powinieneś wiedzieć: //qt.nokia.com/developer/eclipse-integration qt-
• Jak skonfigurować środowisko programi- • Jak programować w C++ w stopniu podsta- eclipse-integration – mamy do wyboru wersję
styczne dla Windows i Linux; wowym; 32 i 64 – rozpakowujemy archiwum do kata-
• Jak stworzyć graficzny interfejs użytkownika; • Jak obsługiwać program Eclipse. logu Eclipse, nadpisując go. Musimy również
• Jak programować obiekty umieszczone na zainstalować Qt SDK for Open Source C++ de-
formatce. velopment dla systemu Linux ze strony http:
//qt.nokia.com/download/sdk-linux-x11-32bit-
cpp lub http://qt.nokia.com/download/sdk-li-
Integracja Qt z Eclipse nux-x11-64bit-cpp w zależności od architek-
Przedstawię integrację Qt z Eclipse w systemie tury Twojego systemu. Ostatecznie urucha-
Poziom Windows oraz Linux. Zacznijmy w takim ra- miamy Eclipse z opcją -clean, co zapewni wy-
trudności zie od systemu Windows. czyszczenie cachu Eclipse.

Windows Planowanie
Ze strony http://www.eclipse.org/downloads/ Zaczynając tworzenie aplikacji komputero-

W
latach 90-tych, kiedy to ukazy- pobieramy Eclipse IDE for C/C++ Develo- wej, powinnyśmy rozpocząć od zaplanowania
wało się czasopismo Bajtek dla pers i instalujemy. Następnie ze strony http: aplikacji. Możemy to wykonać przy pomocy
mikrokomputerów takich jak //sourceforge.net/projects/mingw/files/ pobieramy specjalnego programu lub po prostu na kart-
Atari, ZX Spectrum, Commodore, Amiga, MinGW-5.1.6.exe i instalujemy. Teraz musimy ce papieru. Ważne jest, abyś sobie wizualnie
zaczęła się moja przygoda z programowa- pobrać Qt SDK for Open Source C++ develop- uzmysłowił sobie, co chciałbyś uzyskać. Przy-
niem – w tamtych czasach byłem bardzo ment ze strony http://qt.nokia.com/downloads/ kład bardzo prostego planu możesz zobaczyć
młody, gdyż miałem 9 lat – jednak miałem sdk-windows-cpp i instalujemy – zostanie za- na Rysunku 1.
szczęście; byłem posiadaczem małego kom- instalowany Qt Creator, Qt Linguist oraz naj- Dobrze, więc wiemy już, że będzie menu,
puterka Atari 130XE. W tamtym okresie nowsza biblioteka Qt. Kolejnym krokiem główne okno aplikacji oraz status bar.
mój starszy brat kupował to czasopismo, a ja będzie pobranie ze strony http://qt.nokia.com/
przeglądając je, widziałem często tzw. Listingi developer/eclipse-integration wersji instalacyjnej Projekt typu Qt Gui Project
z programami w Basicu. Nie rozumiałem za dla systemu Windows, czyli qt-eclipse-integra- Zatem po przełączeniu się do perspektywy
wiele z tych wszystkich instrukcji zawartych tion-win32-1.5.3.exe. Uruchamiamy instalację Qt C++ tworzymy nowy projekt typu Qt Gui
w Listingach. Zacząłem je po prostu przepisy- i w kolejnych krokach podajemy ścieżkę dostę- Project. Wpisujemy nazwę projektu Kalkula-
wać z ciekawości, aby zobaczyć, co będzie się pu do eclipse.exe oraz podajemy katalog z insta- tor i w następnym oknie w polu wyboru UI
działo, gdy uruchomię program. W ten spo- lacją MinGW. Następnie uruchamiamy Eclipse type wybieramy QmainWindow, jak na Ry-
sób nauczyłem się programować w języku przy pomocy Start Eclipse with MinGW, który sunku 2. W następnym oknie pozostawiamy
Basic. Pewnie drogi Czytelniku zastanawiasz został utworzony przez qt-eclipse-integration. domyślnie wybrane moduły Core i Gui. Mo-
się, do czego zmierzam, a być może już wiesz, duł Core jest to jądro biblioteki Qt, korzysta-
co chcę napisać dalej. Otóż najlepszą metodą, Linux ją z niego pozostałe moduły, natomiast drugi
aby nauczyć się programować, jest po prostu Ze strony http://www.eclipse.org/downloads/ moduł Gui zawiera komponenty graficznego
zacząć programować, gdyż z samego czytania pobieramy Eclipse IDE for C/C++ Developers interfejsu użytkownika.
nie nauczysz się tego – przynajmniej na sa- dla systemu Linux – mamy do wyboru wer- Klikamy dalej i jeśli pojawi się komunikat
mym początku. Oprócz tego ważna jest do- sję 32 i 64 bitową. Następnie uruchamia- taki jak: No default Qt version is set. Open the
ciekliwość i tzw. drążenie tematu. Wobec te- my eclipse, wybieramy Help>Install New So- Qt page in the preferences dialog and add a Qt
go zapraszam Cię, abyś zaczął czytać artykuł ftware i jako nową stronę wpisujemy http: version, to oczywiście w takim przypadku kli-
i jednocześnie wdrażał go w praktyce. //download.eclipse.org/tools/cdt/releases/galileo, kamy button Open prefferences. Otworzy się

70 05/2010
C++ Qt 4.5

okno preferencji pojektu. W drzewie po lewej Eclipse pod systemem Windows Xp. W na- dow. Możemy już zamknąć okno – na razie
klikamy opcję Qt, a następnie po prawej stro- stępnym polu Include Path ustawiamy kata- nie będzie nam potrzebne.
nie klikamy przycisk Add. W nowo otwartym log, który zawiera bibliotekę Qt dla programi- Jeśli spojrzymy do zakładki Project Explo-
oknie w pierwszym polu wpisujemy 4.5, czy- sty, czyli w moim przypadku jest to ścieżka C: rer, zobaczymy strukturę projektu Kalkula-
li wersję naszej biblioteki. W polu Bin Path \Qt\2009.04\qt\include, tak jak na Rysunku tor, która powinna zawierać Binaries, Inclu-
ustawiamy katalog, który zawiera program 3. Teraz zastosuj zmiany i jeśli pojawi się ko- des, debug, release, kalkulator.h, ui_kalkula-
qmake. W moim przypadku jest to katalog C: munikat typu: Some Projects` Qt versions have tor.h, kalkulator.cpp, main.cpp, Kalkulator. pro,
\Qt\2009.04\qt\bin, jako że uruchomiłem changed. A rebuild of the projects is required for kalkulator.ui, Makefile, Makefile.Debug, Ma-
changes to take effect. Do a full rebuild now?, to kefile.Release.
Listing 1. De�nicja slotów w klasie klikamy przycisk Yes.
Kalkulator – plik kalkulator.h Możemy teraz uruchomić projekt, klikając Ustawiamy główne okno
ikonkę Run na pasku Eclipse i jeśli pojawi się aplikacji, projektowanie menu
#ifndef KALKULATOR_H okno z prośbą ustawienia Debuggera, wybie- Klikamy dwa razy na pliku kalkulator.ui – zo-
#define KALKULATOR_H ramy np. opcję MinGW gdb Debugger. Uru- staniemy przełączeni do edytora Qt Designer.
chomi się puste okno z tytułem Main Win- Zmienimy teraz tytuł okna z MainWindow na
#include <QtGui/QMainWindow>
#include "ui_kalkulator.h"
��������������
class Kalkulator : public QMainWindow
���������������������������
{ ����������������������������������
Q_OBJECT
������������������
public: ��������� ������������������������
Kalkulator(QWidget *parent = 0);
~Kalkulator();

private slots: ����������


void dzialanie_ce_clicked(); ��������������������
�������������������������
void dzialanie_7_clicked();
void dzialanie_8_clicked();
void dzialanie_9_clicked(); Rysunek 1. Przykład prostego planu aplikacji komputerowej
void dzialanie_dzielenie_
clicked();
void dzialanie_4_clicked();
void dzialanie_5_clicked();
void dzialanie_6_clicked();
void dzialanie_mnozenie_clicked();
void dzialanie_1_clicked();
void dzialanie_2_clicked();
void dzialanie_3_clicked();
void dzialanie_odejmowanie_
clicked();
void dzialanie_0_clicked();
void dzialanie_separator_
dziesietny_
clicked();
void dzialanie_rownosc_clicked();
void dzialanie_dodawanie_
clicked();
void wyjscie_clicked();
void skopiuj_tekst_clicked();
void oprogramie_clicked();

private:
Ui::KalkulatorClass ui;
float wynik_dzialania;
};

#endif // KALKULATOR_H
};

#endif // KALKULATOR_H
Rysunek 2. Wybór QmainWindow w polu UI type

www.sdjournal.org 71
Aplikacje biznesowe

Kalkulator. W tym celu musimy otworzyć okno piuj tekst a następnie zmieniamy wartość w po- Line Edit z okna Qt C++ Widget na format-
o nazwie Qt C++ Property Editor, które może lu objectName na actionSkopiujTekst. Dodajemy kę i rozwiń opcję geometry, a następnie ustaw
być już umieszczone po prawej stronie Eclipse, również w pustym polu shortcut skrót klawiatu- x i y na 10 oraz Width na 380 a Height na 40.
jeśli jednak tak nie jest, to możemy je otworzyć, ry ctrl+c. Dodajemy jeszcze jedną pozycję w me- Zmień wartość pola font na większą czcionkę,
wybierając z menu Window>Show view>Othe- nu o nazwie &Pomoc, a w nim opcję &O progra- np. 16. W polu text ustaw wartość 0. Rozwiń
r>Qt>Qt C++ Property Editor. Odszukajmy na mie – zmieniamy wartość pola objectName na pole alignment, zmień opcję Horizontal na Ali-
liście windowTitle i zmieńmy nazwę MainWin- actionOProgramie. Jeśli chcesz zobaczyć, jak wy- gnRight. Zaznacz checkbox w polu readOnly –
dow na Kalkulator. Możemy jeszcze ustawić gląda twoje menu bez kompilacji kodu, kliknij dzięki temu pole edycji będzie tylko do odczy-
maksymalną szerokość i wysokość okna aplika- w puste miejsce na formatce, a następnie z me- tu. Ustaw również wartość w polu objectNa-
cji. W tym celu na liście znajdź opcję maximum- nu wybierz QtDesigner>Preview in>Windows
Size, rozwiń ją i ustaw opcję Width i Height na Xp – możesz zobaczyć, jak będzie wyglądać
400, tak jak na Rysunku 4. Teraz okno będzie Twoje okno w różnych środowiskach.
mogło być skalowane maksymalnie do 400 px Mając już całe menu, możemy dodać opis
szerokości i wysokości. Możesz również ustawić do paska informacji Status Bar. W tym celu wy-
minimalną szerokość i wysokość, ale w naszym bierz na formatce opcję Wyjście i w oknie Qt
przypadku nie będzie to potrzebne, jednak gdy- C++ Property Editor opcję statusTip i jako war-
byś chciał to zmienić, to wystarczy odszukać na tość wpisz Wyjście z kalkulatora. Dalej wybierz
liście opcję minimumSize i dokonać odpowied- opcję z menu Skopiuj tekst i w wartości opcji sta-
nich zmian. tusTip wpisz Skopiuj wynik kalkulatora. Na koń-
Teraz utworzymy proste menu. Na format- cu wybierz opcję O programie i ustaw statusTip
ce w miejscu napisu Type Here kilkamy dwa razy na Informacje o programie. Jeśli chcesz zobaczyć,
i wpisujemy &Kalkulator, gdzie znak '&' ozna- jak wyświetlają się informacje, wybierz z menu
cza, że po wciśnięciu kombinacji klawiszy alt+K QtDesigner>Preview in>Windows Xp.
rozwinie się lista Kalkulator w menu. W opcji Na koniec można byłoby dodać linię od-
Kalkulator w miejscu Type Here klikamy po- dzielającą Status Bar od reszty aplikacji.
nownie dwa razy i dodajemy opcję &Wyjście. W tym celu kliknij na formatce w pustym
Zaznaczamy opcję Wyjście w menu i w oknie Qt miejscu i z okna komponentów Qt C++ Wid-
C++ Property Editor sekcji QObject zmieniamy get Box przeciągnij i upuść Horizontal Line na
wartość objectName na actionWyjscie. W sekcji formatkę, a następnie ustaw ją nad Status Bar Rysunek 4. Ustawienie maksymalnej szerokości
i wysokości aplikacji. Opcja maximumSize
QAction odnajdujemy shortcut, klikamy lewym i rozciągnij na całą szerokość aplikacji.
klawiszem myszy na pustym polu wartości
i wciskamy kombinację klawiszy ctrl+x. W ten Projektowanie
sposób przypiszemy skrót klawiatury do opcji głównej zawartości okna
Wyjście. Następnie tworzymy obok opcji Kalku- Zaprojektujemy teraz przyciski i pole wyni-
lator opcję &Edycja, gdzie dodajemy opcję Sko- kowe naszej aplikacji. W tym celu przeciągnij

Rysunek 5. Projektowanie przycisków i pola


wynikowego kalkulatora

Rysunek 6. Po wybraniu opcji Lay out in a grid


Rysunek 3. Ustawienie wersji Qt, ścieżki Bin Path oraz Include Path oraz Adjust size

72 05/2010
C++ Qt 4.5

Listing 2. Główna funkcjonalność aplikacji – plik kalkulator.cpp

#include "kalkulator.h" }
#include <stdio.h> /*
#include <QMessageBox> * Dodanie do pola wynik cyfry 7 lub liczby 777...
#include <QTextCodec> */
#include <QClipboard> void Kalkulator::dzialanie_7_clicked()
Kalkulator::Kalkulator(QWidget *parent) {
: QMainWindow(parent) if(ui.wynik->text() == "0" || ui.wynik->text() == "")
{ {
ui.setupUi(this); ui.wynik->setText("7");
wynik_dzialania = 0; }
// definiujemy sloty dla akcji actionWyjscie, else
actionOProgramie i actionSkopiujTekst {
connect(ui.actionWyjscie, SIGNAL(triggered()), this, ui.wynik->setText(ui.wynik->text().append("7"));
SLOT(wyjscie_clicked())); }
connect(ui.actionOProgramie, SIGNAL(triggered()), this, }
SLOT(oprogramie_clicked())); /*
connect(ui.actionSkopiujTekst, SIGNAL(triggered()), this, * Dodanie do pola wynik cyfry 8 lub liczby 888...
SLOT(skopiuj_tekst_clicked())); */
} void Kalkulator::dzialanie_8_clicked()
Kalkulator::~Kalkulator() {
{ if(ui.wynik->text() == "0" || ui.wynik->text() == "")
} {
/* ui.wynik->setText("8");
* Metoda wyświetla okienko typu information po kliknięciu w }
menu pomoc -> o programie else
*/ {
void Kalkulator::oprogramie_clicked() ui.wynik->setText(ui.wynik->text().append("8"));
{ }
// definiowanie kodowania znaków w systemie }
QTextCodec::setCodecForCStrings(QTextCodec:: /*
codecForName("windows-1250")); * Dodanie do pola wynik cyfry 9 lub liczby 999...
// wyświetlenie okienka typu information */
QMessageBox::information(this, "Kalkulator","Prosty void Kalkulator::dzialanie_9_clicked()
kalkulator z podstawowymi\ {
ndziałaniami arytmetycznymi:\n+,-,*,/ if(ui.wynik->text() == "0" || ui.wynik->text() == "")
\n\nautor: Łukasz Klejnberg, IdealSol {
utions.pl",QMessageBox::Ok); ui.wynik->setText("9");
} }
/* else
* Metoda zamyka wszystkie okna {
*/ ui.wynik->setText(ui.wynik->text().append("9"));
void Kalkulator::wyjscie_clicked() }
{ }
QApplication::closeAllWindows(); /*
} * Dodanie do pola znaku dzielenia /
/* */
* Metoda kopiuje wynik kalkulatora do pamięci void Kalkulator::dzialanie_dzielenie_clicked()
*/ {
void Kalkulator::skopiuj_tekst_clicked() ui.wynik->setText(ui.wynik->text().append("/"));
{ }
QClipboard *kopiuj_wynik = QApplication::clipboard(); /*
kopiuj_wynik->setText(ui.wynik->text()); * Dodanie do pola wynik cyfry 4 lub liczby 444...
} */
/* void Kalkulator::dzialanie_4_clicked()
* Zerowanie pola wynik {
*/ if(ui.wynik->text() == "0")
void Kalkulator::dzialanie_ce_clicked() {
{ ui.wynik->setText("4");
ui.wynik->setText("0"); }
wynik_dzialania = 0;

www.sdjournal.org 73
Aplikacje biznesowe

Listing 2. Główna funkcjonalność aplikacji – plik kalkulator.cpp


else {
{ ui.wynik->setText("2");
ui.wynik->setText(ui.wynik->text().append("4")); }
} else
} {
/* ui.wynik->setText(ui.wynik->text().append("2"));
* Dodanie do pola wynik cyfry 5 lub liczby 555... }
*/ }
void Kalkulator::dzialanie_5_clicked() /*
{ * Dodanie do pola wynik cyfry 3 lub liczby 333...
if(ui.wynik->text() == "0") */
{ void Kalkulator::dzialanie_3_clicked()
ui.wynik->setText("5"); {
} if(ui.wynik->text() == "0")
else {
{ ui.wynik->setText("3");
ui.wynik->setText(ui.wynik->text().append("5")); }
} else
} {
/* ui.wynik->setText(ui.wynik->text().append("3"));
* Dodanie do pola wynik cyfry 6 lub liczby 666... }
*/ }
void Kalkulator::dzialanie_6_clicked() /*
{ * Dodanie do pola wynik znaku odejmowania -
if(ui.wynik->text() == "0") */
{ void Kalkulator::dzialanie_odejmowanie_clicked()
ui.wynik->setText("6"); {
} ui.wynik->setText(ui.wynik->text().append("-"));
else }
{
ui.wynik->setText(ui.wynik->text().append("6")); void Kalkulator::dzialanie_0_clicked()
} {
} if(ui.wynik->text() != "0")
/* {
* Dodanie do pola wynik znaku mnożenia * ui.wynik->setText(ui.wynik->text().append("0"));
*/ }
void Kalkulator::dzialanie_mnozenie_clicked() }
{ /*
ui.wynik->setText(ui.wynik->text().append("*")); * Dodanie do pola wynik znaku separatora dzięsiętnego .
} */
/* void Kalkulator::dzialanie_separator_dziesietny_clicked()
* Dodanie do pola wynik cyfry 1 lub liczby 111... {
*/ if(ui.wynik->text() != "")
void Kalkulator::dzialanie_1_clicked() {
{ ui.wynik->setText(ui.wynik->text().append("."));
if(ui.wynik->text() == "0") }
{ }
ui.wynik->setText("1"); /*
} * Obliczanie wyniku ciągu znaków z pola wynik
else */
{ void Kalkulator::dzialanie_rownosc_clicked()
ui.wynik->setText(ui.wynik->text().append("1")); {
} // tworzenie obietu typu QString i zapisanie wartosci z
} pola wynik
/* QString str = ui.wynik->text();
* Dodanie do pola wynik cyfry 2 lub liczby 222... // tworzenie obiektu typu QByteArray i zapisanie wartosci
*/ z obiektu str przekształconego
void Kalkulator::dzialanie_2_clicked() funkcją toUtf8()
{ QByteArray enc = str.toUtf8();
if(ui.wynik->text() == "0") // tworzenie wskaznika tab_dzialan na obiekt typu char

74 05/2010
C++ Qt 4.5

me na wynik. Kolejno przeciągnij 17 widgetów dzialanie_2, dzialanie_3, dzialanie_ wym klawiszem myszy na formatce i wybiera-
Push Button i nazwij je kolejno CE, 7, 8, 9, /, 4, odejmowanie, dzialanie_zero, dzialanie_ my z menu kontekstowego Lay out> Adjust si-
5, 6, x, 1, 2, 3, -, 0, ',', =, +, jak na Rysunku 5 (aby separator_dziesietny, dzialanie_rownosc, ze. Elementy umieszczone w oknie zostaną au-
zmienić nazwę przycisku, kliknij na nim pra- dzialanie_dodawanie. Dodaj również pod tomatycznie rozmieszczone oraz okno apli-
wym klawiszem myszy i wybierz opcję Chan- przyciskami Vertical Spacer. Możesz również kacji zostanie dopasowane do zawartości, jak
ge text...). W każdym z tych przypadków ustaw dostosować tekst na przyciskach, jak np. na na Rysunku 6. Ostatecznie wybieramy z me-
objectName na dzialanie_ce, dzialanie_7, Rysunku 5. Następnie klikamy prawym kla- nu Eclipse opcję Project>Clean z zaznaczoną
dzialanie_8, dzialanie_9, dzialanie_ wiszem myszy w pustym miejscu na formatce opcją build project. Zostanie wygenerowany no-
dzielenie, dzialanie_4, dzialanie_5, i z menu kontekstowego wybieramy opcję Lay wy plik ui_kalkulator.h, który będzie zawierał
dzialanie_6, dzialanie_x, dzialanie_1, out>Lay out in a grid. Klikamy jeszcze raz pra- ustawienia interfejsu użytkownika.

Listing 2. Główna funkcjonalność aplikacji – plik kalkulator.cpp


{
// tablica tworzona jest dynamicznie w zaleznosci od wynik_dzialania -= strtod(tablica_liczb[i].c_str(),
rozmiaru obiektu enc NULL);
char *tab_dzialan = new char[enc.size()+1]; }
// kopiowanie zawartosci enc do tablicy tab_dzialan else if(tablica_wyrazen[i] == '*')
strcpy(tab_dzialan,enc.data()); {
int j=0; wynik_dzialania *= strtod(tablica_liczb[i].c_str(),
// zliczanie ilosci wystapien działań arytmetycznych NULL);
for(int i=0;(enc.size())>=i;i++) }
if(tab_dzialan[i] == '+' || tab_dzialan[i] == '-' else if(tablica_wyrazen[i] == '/')
|| tab_dzialan[i] == '*' || tab_ {
dzialan[i] == '/') if( strtod(tablica_liczb[i].c_str(), NULL) != 0)
j++; {
// tworzenie obiektu typu string wynik_dzialania /= strtod(tablica_liczb[i].c_
std::string tablica_liczb[j+1]; str(), NULL);
// tworzenie obiektu typu char }
char tablica_wyrazen[j]; else
// rozdzielenie wyrażeń arytmetycznych i liczby na dwie {
odrębne tablice ui.statusbar->setWhatsThis("Blad dzielenia przez
for(int i=0,j=0;(enc.size())>=i;i++) 0!");
{ wynik_dzialania = 0;
if(tab_dzialan[i] == '+' || tab_dzialan[i] == '-' // definiowanie kodowania znaków w systemie
|| tab_dzialan[i] == '*' || tab_ QTextCodec::setCodecForCStrings(QTextCodec::
dzialan[i] == '/') codecForName("windows-1250"));
j++; // okienko typu warning z informacją o błędzie
if(tab_dzialan[i] == '+') dzielenia przez 0
tablica_wyrazen[j] = '+'; QMessageBox::warning(this, "Komunikat o
else if(tab_dzialan[i] == '-') błędzie","Błąd dzielenia przez
tablica_wyrazen[j] = '-'; 0!",QMessageBox::Ok);
else if(tab_dzialan[i] == '*') }
tablica_wyrazen[j] = '*'; }
else if(tab_dzialan[i] == '/') else
tablica_wyrazen[j] = '/'; wynik_dzialania = strtod(tablica_liczb[i].c_str(),
else NULL);
tablica_liczb[j] += tab_dzialan[i]; }
} // zapisanie nowego wyniku do pol wynik
// obliczanie wyniku // metoda number klasy QString powoduje zamianę liczby
// funkcja strtod() wykonuje zamiane stringu na float na string
// funkcja c_str() wykonuje zamiane stringu na char ui.wynik->setText(QString::number(wynik_dzialania));
for(unsigned i=0;(sizeof(tablica_liczb)/ wynik_dzialania = 0;
sizeof(char*))>i;i++) }
{ /*
if(tablica_wyrazen[i] == '+') * Dodanie do pola wynik znaku dodawania +
{ */
wynik_dzialania += strtod(tablica_liczb[i].c_str(), void Kalkulator::dzialanie_dodawanie_clicked()
NULL); {
} ui.wynik->setText(ui.wynik->text().append("+"));
else if(tablica_wyrazen[i] == '-') }

www.sdjournal.org 75
Aplikacje biznesowe

UWAGA: plik ui_kalkulator.h będzie za- dzialanie_1_clicked(), dzialanie_ sty, ale chodziło głównie o przybliżenie pod-
wsze nadpisany przy nowej kompilacji pro- 2_clicked(), dzialanie_3_clicked(), stawowych funkcji Qt. Listing jest opisa-
jektu. dzialanie_odejmowanie_clicked(), ny. Warto zwrócić uwagę na klasę QMessa-
dzialanie_0_clicked(), dzialanie_ geBox, dzięki której wyświetlamy dwa okna
Programowanie separator_dziesietny(), dzialanie_ informacyjne O programie oraz Błąd dziele-
funkcjonalności kalkulatora rownosc_clicked(), dzialanie_dodawanie_ nie przez 0! (Rysunek 8 i 9). Ciekawą meto-
Aby zaprogramować funkcjonalność naszych clicked(). Po zdefiniowaniu wszystkich dą jest również clipboard, która przynależy
przycisków, posłużymy się edytorem sygna- przycisków możemy wyjść z trybu edycji slo- do klasy QClipboard, dzięki niej stworzymy
łów i slotów. W tym celu należy kliknąć na tów i sygnałów, wybierając z menu Eclipse Qt- możliwość kopiowania wyniku kalkulatora
formatce, a następnie wybrać z menu Eclip- Designer>Editor Mode>Edit Widgets. do pamięci komputera (schowka).
se QtDesigner >Editor Mode>Edit Signals/Slots UWAGA: aby usunąć definicję sygnału i slo-
lub kliknąć na odpowiedniej ikonce o tej sa- tu z formatki, należy kliknąć na linii, a następ- Podsumowanie
mej nazwie. Zostaniemy przełączeni w spe- nie z menu kontekstowego wybrać opcję delete. Na przykładzie bardzo prostej aplikacji – kal-
cjalny tryb, gdzie przy pomocy myszki bę- Zdefiniowaliśmy sygnały i sloty, ale to nie kulator z podstawowymi działaniami arytme-
dziemy mogli zdefiniować po części zacho- wszystko, program sam nie będzie działał. tycznymi – przedstawiłem w skrócie ogrom-
wanie przycisków. Klikamy pierwszy przycisk Musimy teraz dodać zdefiniowane sloty do ne możliwości biblioteki Qt w połączeniu
CE lewym klawiszem myszy i nie puszczając pliku kalkulator.h. W tym celu w klasie Kal- z C++. Jeśli chcesz, możesz rozbudować kal-
go, przenosimy kursor myszy w puste miej- kulator tworzymy wpis private slots: a na- kulator o nowe funkcje – jak np. sprawdzanie
sce na formatce i puszczamy. Otworzy się stępnie dodajemy nasze sloty jak poniżej: liczby pod kątem separatora dziesiętnego, tak
okno z możliwością wybrania sygnału (po le- aby nie było możliwości dodawania dwóch
wej) i slotu (po prawej). W oknie po lewej wy- private slots: kropek obok siebie itp., możesz również za-
bieramy clicked(). Później zaznaczamy opcję void_dzialanie_ce_clicked(); blokować możliwość dodawania wielu wyra-
(checkbox) Show signals and slots inherited void_dzialanie_7_clicked(); żeń arytmetycznych obok siebie – wszystko
from Qwidget i klikamy przycisk edit w oknie zależy od Twojej wyobraźni, chęci poznania
po prawej. Otworzy się nowe okno z możli- na Listingu 1 zamieściłem definicje. wiedzy i nauczenia się czegoś nowego. W ar-
wością dodawania nowych slotów i sygnałów. Teraz musimy zdefiniować nasze nowe tykule nie została przedstawiona jeszcze jed-
Dodajemy nowy slot (kliknij ikonkę +), któ- metody (sloty) w pliku kalkulator.cpp, przy- na ważna cecha Qt, jakim są okna dialogowe
ry będzie się nazywał dzialanie_ce_clicked(). kładowo dla slotu dzialanie_ce_clicked() – tworzenie takich okien jest naprawdę bar-
Akceptujemy zmiany i zaznaczamy na liście wykonujemy taki wpis: dzo proste, a wywołanie okienka dialogowego
nasz nowy slot, a następnie ponownie akcep- wiąże się ze zdefiniowaniem odpowiedniego
tujemy zmiany. Teraz na formatce w miejscu void Kalkulator::dzialanie_ce_clicked() połączenia sygnału i slotu. Jeśli temat Qt zain-
definiowania slotu i sygnału pojawi się na- { teresował Cię, możesz wrócić do archiwalne-
pis na przycisku CE clicked() oraz na zakoń- ui.wynik->setText('0'); go numeru tego czasopisma z kwietnia 2009
czeniu strzałki dzialanie_ce_clicked(), tak jak } r., jest tam obszerny artykuł na temat Qt. Nie-
na Rysunku 7. Zdefiniowaliśmy pierwszy sy- stety na polskim rynku nie ma żadnej dobrej
gnał i slot. Proste, prawda? No dobrze, to te- Na Listingu 2 przedstawiłem całą funkcjo- książki o Qt. Dla ułatwienia w tabelce zamie-
raz dodamy pozostałe sygnały i sloty taką sa- nalność aplikacji. Kalkulator jest bardzo pro- ściłem kilka przydatnych adresów.
mą metodą. Dla ułatwienia podaję nazwy no-
wych slotów, które będziemy definiowali po
kolei: dzialanie_7_clicked(), dzialanie_
8_clicked(), dzialanie_9_clicked(),
dzialanie_dzielenie_clicked(),
dzialanie_4_clicked(), dzialanie_
5_clicked(), dzialanie_6_clicked(),
dzialanie_mnozenie_clicked(),

Rysunek 7. De�nicja sygnału i slotu dla Rysunek 8. Okienko wywołane przez Rysunek 9. Okienko wywołane przez
przycisku CE QMessageBox::warning() QMessageBox::information()

W Sieci ŁUKASZ KLEJNBERG


• http://qt.nokia.com – serwis www biblioteki Qt; Łukasz Klejnberg jest właścicielem �rmy Ideal So-
• http://qt.nokia.com/doc/4.5/index.html – dokumentacja biblioteki Qt; lutions zajmującej się projektowaniem aplikacji
• http://qt.nokia.com/4.4/tutorials-tutorial.html – przykładowe tutoriale; internetowych, jak i komputerowych. Kompute-
• http://cartan.cas.suffolk.edu/oopdocbook/opensource/ – książka w wersji online – Intro- rami zajmuje się od roku 1989. W zawodzie pro-
duction to Design Patterns in C++ with Qt4;
gramisty pracuje od 2000 roku.
• http://www.pdf-search-engine.com/qt4-pdf.html – różne przydatne pliki w pdf dotyczące
biblioteki Qt. Kontakt z autorem:
lukasz.klejnberg@idealsolutions.pl

76 05/2010
Efektywność pracy

Na kiedy?
Planowanie zadań programistycznych
Z opracowywaniem zadań programistycznych wiążą się dwa kluczowe
pytania: ile to zajmie? oraz na kiedy? Pierwsze pytanie dotyczy
szacowania zadań, czyli określania w jednostkach czasu, jak długo
potrwają prace. Drugie pytanie dotyczy planowania – czyli osadzania
oszacowanych czynności w kalendarzu. W artykule zajmujemy się tym
drugim pytaniem.
tym, co robić dalej. Taka praca przypomina tro-
Dowiesz się: Powinieneś wiedzieć: chę jazdę samochodem z uszkodzonym prze-
• Dlaczego warto planować swoją pracę i w • Tylko to, co już wiesz. wodem paliwowym: raz jedzie się płynnie, in-
jaki sposób to robić. nym razem samochód gaśnie co chwilę. Rzadko
kiedy jesteś pewien, co stanie się za chwilę.
Skoro przed planowaniem (w jakiejkolwiek
czaj przedostawania się do środowiska produk- formie) nie ma ucieczki, to korzystniej jest robić
cyjnego. Później już nikt nie ma czasu na popra- to świadomie, aby wykonywanie zadania prze-
Poziom wianie działających rozwiązań ad hoc. Nikt też biegało zgodnie z naszymi intencjami. Punk-
trudności ostatecznie nie pamięta, na jakich założeniach tem wyjścia dla tworzenia planu jest zadanie
były oparte – lepiej zatem ich nie dotykać. zdekomponowane na poszczególne kroki oraz
Część programistów uważa czynność plano- oszacowane (o technikach z tym związanych pi-
wania swojej pracy za niepotrzebną stratę cza- saliśmy w numerze 4/2010).

W
niektórych firmach panuje zwy- su. Twierdzą, że zadania programistyczne są tak
czaj, że menadżer/dyrektor/prezes oczywiste, że można od razu przystąpić do im- Terminy
od czasu do czasu przechadza się plementacji. Z pewnością za takim przekona- Bez względu na to, ile rzeczy można by jesz-
pomiędzy pracującymi programistami i dopy- niem kryją się pewne osobiste doświadczenia cze ulepszyć, każde zadanie trzeba będzie kie-
tuje ich o postęp prac. Najczęściej otrzymu- i mogą one dawać pomyślne rezultaty. Naszym dyś skończyć. Moment oddania zadania zazwy-
je odpowiedź w stylu: Nie można wywołać me- zdaniem w większości przypadków świadome czaj jest narzucony odgórnie i najczęściej jedyna
tod serwisu, jest też trochę problemów z dostaniem planowanie jest bardziej użyteczne niż jego brak. rzecz, na jaką mamy wpływ, to sposób pracy nad
się do sesji tamtego portletu... Z punktu widzenia Wyobraź sobie, że rozpoczynasz pracę nad zadaniem. Możemy programować dzień i noc,
programisty nie ma nic bardziej irytującego niż nowym zadaniem. Na pierwszy rzut oka wyda- rozpoczynając w ostatniej lub sensownie rozło-
opowiadanie o swojej pracy komuś, kto nie jest je się proste, więc bez większych przygotowań żyć prace w czasie. Cały kunszt dobrego plano-
w stanie zrozumieć większości interesujących implementujesz kolejne elementy. Po dwóch wania zawiera się w tej jednej wytycznej: wyko-
spraw i problemów, o których mowa. Nato- godzinach utkasz na jakiejś bardziej złożonej nać zlecone prace na określony termin i nie za-
miast menadżer chce się jedynie dowiedzieć, ja- kwestii, rozwiązujesz ją i znów brniesz dalej. Po programować się przy tym na śmierć.
ki jest postęp prac. Kłopot w tym, że programi- jakimś czasie znów zatrzymujesz się na na pew- Zakładamy, że z szacowań wynika, iż narzu-
sta często tego nie wie. nym istotnym szczególe. Działanie w tym try- cony termin ukończenia zadania jest w ogóle
bie skutkuje jednym z największych wrogów możliwy do osiągnięcia. Gdyby w programo-
Strata czasu efektywnej pracy – rozproszeniem. Nie bez waniu wszystko było przewidywalne, to mógł-
Nie ma absolutnie niczyjej winy w tym, że za- powodu metodyki z nurtu Agile zalecają stały byś planować prace w odniesieniu do terminu
dania programistyczne są zazwyczaj ciekawe. rytm pracy, stałą długość iteracji, stałą ilość go- zakończenia zadania. Z pewnością nie jeden raz
Nie ma też niczyjej winy w tym, że programi- dzin przepracowanych w ciągu dnia. Gdy prze- przekonałeś się, że dość często sprawy przybie-
ści zazwyczaj pasjonują się swoją pracą. Pomysł rywasz programowanie z powodu nieprzewi- rają niespodziewany obrót z powodu różnego
na zaimplementowanie jakiejś funkcjonalności dzianych trudności, gubisz rytm, a jego odzy- rodzaju zaskakujących okoliczności. Korzyst-
jest już sam w sobie tak fascynujący, że aż chce skanie pochłania sporo energii. Żeby kontynu- nie jest zarezerwować pewien bufor czasowy
się od razu zacząć programować. ować, musisz rozwiązać napotkane problemy na wypadek tych właśnie okoliczności. Z tego
Jeśli pierwszą czynnością, od której zdarza i zastanowić się nad następnymi krokami. Oto względu pierwszym krokiem jest wyznaczenie
nam się zaczynać programowanie, jest progra- sedno całej sprawy: nawet jeśli nie planujesz, wewnętrznego terminu zakończenia zadania.
mowanie, to jesteśmy w nie lada tarapatach. to planujesz – lokalnie! Opracowujesz zadanie Termin ten przypada przed ostatecznym termi-
Nie ma nic złego w budowaniu zrębów syste- w wąskim kontekście i zaczynasz programować. nem zakończenia, tworząc bufor bezpieczeń-
mu, aby określić wstępny jego kształt. Jednak Gdy już wykonasz te kilka przewidzianych kro- stwa. Na początek możesz przyjąć, że jego dłu-
tego typu zręby i prototypy mają złośliwy zwy- ków, zatrzymujesz się, żeby zastanowić się nad gość będzie wynosić 10% szacowanego czasu na

78 05/2010
Na kiedy?

wykonanie zadania. Z wewnętrznego terminu Ta sama zasada obowiązuje podczas plano- • zaznacz termin wewnętrzny;
jesteś odpowiedzialny sam przed sobą. Prakty- wania zadań. Wyznaczenie dobrego celu im- • oznacz początek zadania oraz punkty po-
kowanie wyznaczania tego terminu przyniesie plementacji to część sukcesu. Punkty pośred- średnie;
Ci następujące korzyści: nie prac pomogą Ci efektywnej go osiągnąć. • ilość dni, które zaznaczasz wynika z szaco-
Być może poniższe korzyści zachęcą Cię do tej wania;
• przeciwdziałasz konsekwencjom prawa praktyki: • uwzględnij ilość czasu, który możesz po-
Parkinsona, które mówi, że zadanie zaj- święcić na zadanie;
mie co najmniej tyle czasu, ile zostało nań • Zmierzasz do celu jak po nitce, odhaczając • postępuj podobnie przy każdym zadaniu,
przeznaczona; w tym przypadku próbu- kolejne osiągnięte punkty pośrednie; używając różnych kolorów.
jesz „ściskać” terminy; • Zawsze wiesz, na którym etapie obecnie
• ograniczając czas na wykonanie zadania, się znajdujesz; Przygotowany i opublikowany w widocznym
kierujesz swoją uwagę na to, co jest w nim • Zawsze wiesz, co jeszcze musisz zrobić, miejscu kalendarz jest Twoją mapą, dzięki któ-
najważniejsze i absolutnie konieczne; uni- aby zakończyć zadanie; rej sprawnie poruszasz się w kierunku ukoń-
kasz niekończącego się udoskonalania ko- • Wracając do zadania po dłuższej przerwie, czenia zleconych funkcjonalności. Jeśli teraz
du (nie mylić z refaktoryzacją!); szybciej wdrożysz się w temat. Twój menadżer lub prezes zechce Cię odwie-
dzić i zapytać o postęp prac, możesz oszczę-
Punkty pośrednie W kalendarzu dzić mu szczegółów, których pięknem i tak się
Pewnie jechałeś kiedyś autostradą. Prosta, mo- Elementem, który spina cały Twój pracowicie nie zachwyci. Po prostu sięgasz do kalendarza
notonna droga wydawała się nie mieć końca. przygotowany plan, będzie kalendarz. Konkret- i czytasz to, co jest tam napisane.
Gdyby nie oznaczenia zjazdów, to po pewnym na forma kalendarza jest bez znaczenia, wybierz
czasie straciłbyś orientację. Z upływem czasu taką, która najbardziej Ci odpowiada. Gdybyś Przegląd zadania
coraz trudniej byłoby Ci stwierdzić, jak dłu- jednak szukał inspiracji, to polecamy wydruk W omawianym procesie planowania i wykony-
go jedziesz, ile kilometrów zostało jeszcze do miesięczny z darmowego kalendarza Sunbird. wania zadań brakuje ostatniej domykającej rze-
końca podróży i gdzie właściwie się znajdujesz. Ważnym zadaniem kalendarza jest uwzględ- czy – sprzężenia zwrotnego. Żadne szacowa-
Dzieje się tak, ponieważ brakuje punktów od- nianie ilości czasu, które możesz poświęcić na nie i planowanie nie wniesie nic konkretnego
niesienia, które informowałyby Cię o kolejnych pracę nad planowanymi zadaniami. Jeśli jed- do Twojego warsztatu, jeśli nie zapewnisz sobie
etapach wycieczki. nym z Twoich dodatkowych obowiązków jest możliwie szybkiej pętli uczenia. Jak w opisywa-
W innym obrazku jedziesz krętą miejską dro- reagowanie na błędy właśnie wdrożonego sys- nych praktykach zazwyczaj sugerowaliśmy kon-
gą. Mijasz znajome budynki i skrzyżowania. Być temu i zajmuje Ci to 50% czasu pracy, to czas kretne rozwiązania, a wybór pozostawialiśmy
może w myślach odliczasz kolejne etapy: kino, wykonywania zadań wydłuża się. Na przykład tobie, tak teraz z całym naciskiem podkreślamy,
centrum handlowe, rondo, szpital. Czy taka jazda z szacowania wynika, że zadanie powinno za- że absolutnie musisz uczyć się na własnych błę-
nie upływa znacznie szybciej niż podróżowanie jąć jeden osobodzień, lecz Twoje obowiązki dach. Bez wyciągania wniosków i wdrażania ich
przez okolicę, w której brak jest jakichkolwiek sprawiają, że będziesz wykonywał je przez dwa w życie, nowe techniki na nic się nie przydadzą,
punktów odniesienia? To oczywiście złudze- dni. Teraz dokładnie widzimy ogromną różni- nie poprawią Twojej efektywności.
nie, gdyż czas (przynajmniej na Ziemi) jest bez- cę pomiędzy pytaniem ile to zajmie? a na kie- Prostym sposobem na uruchomienie pę-
względny i dla każdego upływa w ten sam spo- dy zrobisz? tli uczenia jest zarezerwowanie kilku chwil na
sób. Jedyna różnica pomiędzy opisanymi scena- Kalendarz możesz przygotować w następu- przeprowadzenie przeglądu zakończonego za-
mi polega na tym, że w drugiej jest na co czekać, jący sposób: dania (ang. after action review). Podczas przeglą-
a w pierwszej nie. Jadąc drugą trasą, miałeś nie- du zadaj sobie następujące pytania:
świadomie obrane punkty pośrednie, dzięki • wykreśl dni wolne od pracy i urlopy;
którym w dowolnym momencie wiedziałeś, na • zaznacz termin oddania wykonywanego • Czy szacowania zostały utrzymane? Jeśli
jakim etapie jesteś i kiedy osiągniesz cel. zadania; nie, to dlaczego?
• Czy bufor bezpieczeństwa został właści-
wie dobrany?
• Jakie problemy wystąpiły i jak im zaradzić
w przyszłości?
• Czego nowego się nauczyłem?

Wnioski z tak przeprowadzonego przeglądu


zastosuj od razu podczas wykonywania na-
stępnego zadania. Możesz również podzielić
Rysunek 1. Proces planowego wykonywania zadania. T – termin zakończenia zadania, Tw – termin się nimi i przedyskutować z resztą zespołu.
wewnętrzny, P1, P2 – punkty pośrednie
MICHAŁ BARTYZEL,
Planowanie zadania MARIUSZ SIERACZKIEWICZ
Trenerzy i konsultanci w �rmie BNS IT. Badają i roz-
• Na podstawie szacowań wyznacz termin oddania zadania – to termin, który zobowiązu- wijają metody psychologii programowania, po-
jesz się dotrzymać przed użytkownikiem; magające programistom lepiej wykonywać ich
• Ustal swój wewnętrzny termin zakończenia zadania – to termin, który zobowiązujesz się pracę. Na co dzień autorzy zajmują się zwiększa-
dotrzymać przed samym sobą, rezerwując bufor na nieprzewidziane okoliczności;
niem efektywności programistów poprzez szkole-
• Im bliżej wyznaczonych terminów, tym uważniej przyglądaj się postępowi prac;
• Im większa presja czasu, tym częściej zastanawiaj się, czy to, co robisz, jest tym, co powi- nia, warsztaty oraz coaching i trening.
nieneś robić; Kontakt z autorami:
m.bartyzel@bnsit.pl, m.sieraczkiewicz@bnsit.pl

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

Skontaktuj się z nami:


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

Opera Software Architektury systemów IT


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

Kei.pl Future Processing


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

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

Playsoft WSISiZ w Warszawie


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

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


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

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

Softline rozwiązania mobilne


Wiodący producent systemów mobilnych, do-
stawca aplikacji użytkowych dla biznesu (Sym-
Volantis jest uznanym na całym świecie dostawcą rozwiązań mobil-
bian OS, Windows Mobile, J2ME ) zaprasza do
nych dla firm udostępniających informacje oraz dane przez Internet
współpracy. Zostań naszym partnerem. Dołącz
(operatorów telefonii komórkowej, stacji tv, czasopism internetowych).
do zespołu.
Dzięki zasadzie „stwórz raz, uruchamiaj gdziekolwiek” nasze rozwią-
zania zmniejszają złożoność, koszt i czas dostarczenia na rynek ser-
wisów i aplikacji. Volantis jest członkiem organizacji W3C, a naszymi
http://www.softline.com.pl
klientami są światowi potentaci telekomunikacyjni.

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


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

Szanowni Czytelnicy,
Niedawno obchodziliśmy 15-lecie SDJ. 15 lat największego polskiego pisma dla programistów. Przez ten czas
zbudowaliśmy oddane grono czytelników i markę wśród największych firm branżowych na rynku. Nie chce-
my jednak stać w miejscu. Świat się zmienia a wraz z nim media. Dlatego chcielibyśmy z przyjemnością poin-
formować, że Software Developer’s Journal staje w awangardzie światówych mediów. Otwieramy się na przy-
szłośc, a ...„Przyszłośc leży on-line”.
Od następnego numeru ( 6/2010 ) Software Developer’s Journal będzie dostępny tylko w wersji elektro-
nicznej. Co ważniejsze będzie on pismem całkowicie darmowym! Jesteśmy przekonani, że zmiana formatu
wydawania magazynu, a także szersza dostępność sprawi, że SDJ stanie się jeszcze bardziej opiniotwórczym
medium o programowaniu w Polsce. Nadal będziemy prezentować aktualną, a także sprawdzoną wiedzę
z dziedziny programowania. Współpracując z najwiekszymi firmami na rynku, a także pasjonatami programo-
wania, uczelniami wyższymi itp chcemy dostarczac naszym czytelnikom wiedzy potrzebnej do pracy, a także
dalszego rozwoju osobistego.
Pierwszy elektroniczny numer SDJ pojawi się ostatniego dnia kwietnia. Każdy następny będzie dostępny
do pobrania ostatniego dnia miesiąca. Jednocześnie nie zapominamy o materiałach dodatkowych do artku-
łów. Wszelkie aplikacje, kody a także materiały video będą dostępne na naszej stronie www.
Mam głęboką nadzieję, że ta zmiana przypadnie Państwu do gustu. Chcemy aby SDJ jak najbardziej odpo-
wiadał Państwa oczekiwaniom, dlatego będziemy wdzięczni za wszelkie sugestie i uwagi dotyczące naszego,
wspólnego magazynu.

Redaktor naczelny SDJ


Łukasz Łopuszański

82 05/2010

You might also like