PyXMPP 2

Osiem lat temu coś mi odbiło i zacząłem tworzyć PyXMPP. Wtedy jeszcze właściwie nie było XMPP (specyfikacja dopiero powstawała, RFC 3920 wydano dopiero ponad rok później), tym bardziej żadnej biblioteki XMPP dla Pythona, czy nawet jakiejkolwiek implementacji XMPP. Było jakieś jabber.py, ale mnie nie zadowalało. Zacząłem więc pisać własną bibliotekę, najpierw z myślą o serwerze, potem dla mojego klienta – CJC.

Wtedy musiałem pisać wszystko od zera, SASL, Stringprep, jakieś sensowne StartTLS, bo dostępnych implementacji nie było, albo nie nadawały się do sensownego, czy bezpośredniego użycia. Język w którym pisałem (Python 2.2) nie przypominał bardzo dzisiejszego Pythona. Testować też nie było z czym, bo właściwie żaden serwer SASL czy StartTLS nie obsługiwał (dlatego myśląc o implementacji serwera musiałem też pisać kod klienta). Myślę, że były nawet czasy, gdy moje PyXMPP było „tą jedyną sensowną” biblioteką XMPP dla Pythona.

Niestety, niektóre moje decyzje zaczęły na projekcie ciążyć. W szczególności wykorzystanie libxml2. API zupełnie „niepythonowe”, gdzie trzeba pamiętać o zwalnianiu pamięci o tym który obiekt używa pamięci przydzielonej innemu obiektowi. To sprawiało nie tylko, że kod był brzydki, ale się po prostu czasem sypał w niewyjaśnionych okolicznościach, ciekł pamięcią i średnio nadawał się do integracji z czymkolwiek innym. Dodatkowo API libxml2 używało stringów zakodowanych UTF-8, gdzie w Pythonie używałoby się raczej obiektów unicode, co wymagało ciągłych konwersji. Mimo wszystko libxml2 miało swoje zalety, szczególnie nad alternatywami dostępnymi w tamtym czasie: było szybkie, obsługiwało przestrzenie nazw XML i serializowało XML do postaci strawnej przez implementacje XMPP (ElementTree sam z siebie wciąż tego nie umie).

Mijały miesiące i lata. PyXMPP rozwijało się, najpierw szybko, potem powoli, z ewentualnymi gwałtownymi zrywami. Stary kod coraz mniej mi się podobał, ale był i działał, szkoda było dużo zmieniać. Czasem próbowałem wprowadzić jakieś nowe pomysły (np. interfejsy z Zope), z średnim skutkiem. W końcu rozwój praktycznie zamarł, z wyjątkiem drobiazgów których czasem zachciałem w CJC (np. ostatnio IPv6)…

W między czasie pojawiło się wiele implementacji XMPP, także w Pythonie. Nie tylko biblioteki ale i całe popularne klient (chociażby Gajim). Pojawił się Python 3, wyszły nowe RFC dla XMPP. PyXMPP praktycznie w ogóle się teraz nie liczy… a mnie dwa miesiące temu znowu „odbiło”…

Postanowiłem spróbować przerobić stary kod na coś nowocześniejszego. Przede wszystkim miało wylecieć `libxml2` i być zastąpione przez ElementTree. Przy okazji chciałem wyczyścić API i w ogóle poprawić jakość kodu. W starym nie tylko były jeszcze miejscami konstrukcje z Pythona 2.2 (np. ‚0’ i ‚1’ zamiast ‚True’ i ‚False’), to jeszcze kiedyś miałem zwyczaj oszczędzania na spacjach, przez co kod był po prostu nieczytelny. Postanowiłem przepisać kod pod kątem Pythona 2.7 ale z myślą o obsłudze też 3.2.

Tak sobie grzebałem w tym przez ostatnie parę tygodni. W modułach które przerobiłem zmieniłem praktycznie każdą linijkę kodu. Miejscami wprowadziłem fundamentalne zmiany w całej wewnętrznej strukturze pakietu. Napisałem nowy framework pętli głównej i I/O. Wiem, wymyślanie na nowo koła, jest Twisted, ale przecież implementacje XMPP na Twisted też już są…

Powoli kod zaczął nawet być używalny… postarałem się go jakoś udokumentować, napisałem trzy przykładowe skrypty, jakiś tutorial na wiki… i wczoraj postanowiłem pokazać to światu.

Nie wiem na co liczyłem, w końcu teraz to tylko „kolejna implementacja XMPP dla pythona”… ale może komuś się przyda… może w czymś jest jednak lepsza od istniejących. No i szkoda by było, jakby mój kod pisany od 2003 roku umarł jako to brzydkie stare PyXMPP (tak, to nie jest racjonalne myślenie)…

Od wczorajszego wydania ‚alpha’ znalazł się tylko jeden ‚obserwujący’ na GitHub, jedna odpowiedź na maila na liście dyskusyjnej i 30 pobrań pakietu… No cóż, kariery tym nie robię. ;-)

CJC i PyXMPP 1.0.1

Ostatnie wydanie CJC i PyXMPP było ponad trzy lata temu – w grudniu 2005 roku. Po tamtym wydaniu zacząłem poważne zmiany w API… i nigdy ich nie skończyłem, a niedokończonego dzieła wydawać nie chciałem. Potem przyszły kłopoty ze zdrowiem, pośrednio wynikłe też z mojego zaangażowania w Open Source (czyt. siedzenia całymi dniami przed kompem, świata nie widząc) i postanowiłem unikać angażowania się w kodowanie. Tak więc, planowane zmiany nigdy nie miały być dokończone.

W międzyczasie jednak w starym kodzie znajdowane były błędy, od czasu do czasu jakiś błąd poprawiłem, czasem ktoś podesłał patcha, to wrzucałem do SVN. Pojawiały się nowe wersje Pythona, czy M2Crypto, to kod dostosowywałem odpowiednio (CJC używam na co dzień, moja żona też, więc to musi działać). Właściwie, jak ktoś jeszcze używał PyXMPP albo CJC, to któryś z ostatnich snapshotów.

Ostatnio zastanawiałem się też, czy nie spróbować do CJC wreszcie dodać obsługi UTF-8. Wcześniej tego odmawiałem, bo Pythonowy moduł curses w ogóle nie ma obsługi Unicode, tylko start 8-bitowe API. I nic nie wskazuje na to, że to ktoś poprawi, ale uż jakiś czas temu jeden z użytkowników udowadniał mi, że to się jednak da zrobić, jeśli tylko moduł curses jest zlinkowany z biblioteką „libncursesw”. W PLD długo tak nie było, ale w Th już jest. To czemu by nie spróbować?

Wczoraj więc spróbowałem. Wyświetlanie UTF-8 działało bez żadnych zmian w kodzie, ale żeby wczytywać znaki Unicode z klawiatury musiałem dodać brzydkiego hacka. I w ogóle trochę obsługi klawiatury przerobić. Udało się. A skoro wreszcie się pojawiła funkcjonalność tak wyczekiwana przez użytkowników, to czemu by nie wydać nowej wersji? Resztę dnia spędziłem
przygotowując paczki z PyXMPP 1.0.1 (w tym jeszcze przed wydaniem poprawiłem jednego paskudnego babola) i CJC 1.0.1. Dzisiaj wysłałem informacje o wydaniach na listy mailowe dotyczące tych produktów. No to chyba udało mi się coś wydać. :-)

Po następne wersje zapraszam za trzy lata. ;-)

uinput_beeper, czyli jak zrobiłem sobie biperka w nowym laptopie

Podczas mojego pobytu w Reptach mój stary laptop umarł. Do zacinającej się klawiatury dołączyła wysiadająca grafika i w końcu zupełnie nie dało się z niego korzystać. No cóż, przeżył swoje. Tak więc w zeszłym tygodniu kupiłem sobie na allegro nowego, ślicznego i fajniusiego Della D620, a od poniedziałku już się nim bawię.

W laptopie właściwie wszystko działało od razu bez zarzutu. No, mały hack był potrzebny, żeby framebuffer działał w natywnej rozdzielczości. Niestety jeden feler wydał mi się poważniejszy: głośności pc-speakera nie da się kontrolować. Gdy nie załadowałem modułu pcspkr nie brzęczał w ogóle, gdy załadowałem – odzywał się na cały głos, co było nie do przyjęcia. Musiał zostać niezaładowany, ale bez biperka jest ciężko. Dla mnie konsola tekstowa to wciąż podstawowe narzędzie i mam tam np. odpalonego klienta Jabbera. I gdy przychodzi wiadomość, to klient pika… a mnie nie pikał. I było mi smutno. ;-)

Z wcześniejszego goolania wynikło, że to ograniczenie sterowników ALSA do tej wypasionej karty muzycznej HD, którą mam w laptopie i że właściwie powinienem się cieszyć, że mnie gra za głośno, albo wcale, bo innym tylko wcale.

Dzisiaj postanowiłem poszukać jakiejś alternatywy dla standardowego dźwięku, którego nie da się zciszyć. Uznałem, że powinno się dać podpiąć jakąś własną akcję w miejsce tego co robi moduł pcspkr. Okazało się, że mam rację. Jednak, o dziwo, wygodnego gotowca nie znalazłem. Znalazłem tylko dodatkowy moduł do kernela beeper, który współpracował z odpowiednimi demonami w userspace, ale z kompilacją dodatkowych modułów zawsze jest problem. A przecież dowiedziałem się też, że standardowy kernel ma już funkcjonalność potrzebną do obsługi bipania w userspace, bez potrzeby dodawania niestandardowych modułów. Można to zrobić przez interfejs uinput. Nawet znalazłem jakiś przykładowy kod.

Przykładowy kod okazał się być chyba pisanym z pamięci – brakowało includów itp. i się nawet nie kompilował. Do tego używał API esd, a to przecież bez sensu. Na szczęście przykładowy kod zawierał co najważniejsze i po przejrzeniu go i zerknięciu do źródeł kernela byłem w stanie napisać coś użytecznego.

Tak więc powstał uinput_beeper – prosty programik mojego autorstwa, który uruchamia zewnętrzny program za każdym razem, gdy terminal ma zabibczeć. Domyślnie jest to aplay beep.wav. I działa to świetnie, a przy okazji, z przygotowanym przeze mnie na szybko plikiem beep.wav, jest nawet zabawne (ale pewnie nie długo). :-) Kod oczywiście dostępny na GPL, może jeszcze komuś się przyda.

Odświeżenie bloga

Postanowiłem trochę odświeżyć mojego bloga. Najpierw zmieniłem moje
skrypty do generowania joggerowych szablonów – generowanie z XMLa
i automatyczne walidowanie wyniku było fajne w założeniach, ale w praktyce
chyba zbyt skomplikowane. Przesiadłem się na M4 i jest fajnie.
:-)

Później postanowiłem dodać trzecią kolumnę do layoutu. Archiwum
i kategorie chciałem przenieść na lewą stronę, a po prawej dać
linkownie. Szablon przerobiłem, ale efekt mi się nie podobał. Do tego,
gdy przyszedł czas na dodanie linków, stwierdziłem, że nie umiem się
zdecydować co tam wrzucić – wszystko co przeglądam, to za chwilę połowa
byłaby nieaktualne, a jeśli miałbym wybierać te najważniejsze, to niby
jak? W końcu zmiany w szablonie zachowałem sobie gdzieś na boku w postaci
łatki i wróciłem do starych, dobrych dwóch kolumn.

Czyli wizualnie byłem w punkcie wyjścia. A przecież chciałem coś
pozmieniać. Najbardziej mnie wkurzało archiwum – ciągnące się jak papier
toaletowy. Wczoraj, odrobiną magii w JavaScripcie, dodałem do niego
hierarchię, a dzisiaj zwijanie niepotrzebnych lat. Z efektu jestem bardzo
zadowolony – chyba całkiem nie źle, jak na kogoś, kto nie zna
JavaScriptu. :-)

Poza tym, dołożyłem linki do następnej/poprzedniej strony w szablonie
wpisów i do następnego/poprzedniego wpisu w szablonie komentarzy. A na końcu
dorzuciłem reklamy AdSense. Miałem tego na bloga nie dawać, ale na stronach
moich projektów niewiele te reklamy dawały – nic się tam nie dzieje, to
nikt nie zagląda. A na Joggerze kolejne osoby dodają sobie reklamy na bloga
i nikt na nich nie krzyczy, więc może i mnie czytelnicy wybaczą.
;-)

Rewolucja w kompie

Niedawno pojawiło się nowe XFCE: 4.4.
Najpierw chciałem to w pracy sobie zainstalować, ale okazało się, że ani tego
nie ma w PLD Ac, ani nie da się w tym Ac zainstalować. Instalacji Th wolałem
nie ryzykować na maszynie która służy mi do pracy… co innego w domu, tam
ostatnio używam jedynie CJC i Firefoksa. Uznałem, że dwie aplikacje jakoś do
działania doprowadzę.

Upgrade nie był prosty. Masy rzeczy w repo Th brakuje. Wiele zależności
jest zepsutych. Cała masa pakietów zbudowanych w Ac wymaga X11-*, albo
XFree86-*, których w Th już nie ma (wystarczyłyby zależności od libX*, które
pociągnęłyby odpowiednie pakiety xorg-*). Dodatkowo, żeby nie było za prosto,
mam u siebie pomieszane pakiety 32- i 64-bitowe. Ale jakoś się udało…

Pierwsze co chciałem odpalić, to Xy. W końcu dla nowego XFCE jest ta cała
szopka… Poprzednio używałem 64-bitowego X-serwera i zamkniętych sterowników
ATI. Otwarte nie dawały akceleracji, a zamknięte nie działały, gdy X-serwer był
32-bitowy (generalnie większość systemu mam 32-bitowe), a kernel 64-bitowy (bo
tylko taki pozwala mi odpalać binarki i 32- i 64-bitowe). Teraz chciałem
spróbować z serwerem 32-bitowym i sterownikami Open Source, w końcu między X.org
7.0, a 7.2 coś mogło się zmienić…

Jedno się nie zmieniło – sterownik z X.org wciąż nie rozpoznaje mojej
karty (ATI Technologies Inc RV370 secondary [Sapphire X550 Silent]) i obsługuję
ją dopiero po dodaniu do xorg.conf: ChipId 0x5b60. Akceleracja 3D też nie
ruszyła, chociaż sterownik DRM w kernelu się załadował i kartę poprawnie
wykrył… logi sugerowały, że znowu może być coś z tymi bitami… Zainstalowałem
więc 64-bitowy X-serwer z 64-bitowymi sterownikami. DRI ruszyło. Rozszerzenie
„Composite” też. Mogłem podziwiać piękną przezroczystość w XFCE. Najpierw
działało to strasznie wolno, ale po poprawieniu paru opcji da się tego używać.
Jednak z OpenGL coś wciąż było nie tak… mimo że glxinfo pokazywało, że
wszystko jest OK i nawet Direct rendering: yes. To glxgears nie działało.
Znaczy się działało, ale nic nie wyświetlało. Podobnie wszystkie inne aplikacje
3D…

Spróbowałem więc zamkniętych sterowników… musiałem przebudować, bo w Th
były stare, niekompatybilne z nowymi Xami. Nowe się zbudowały, nawet działały,
ale bez akceleracji 3D. Linker dynamiczny nie mógł znaleźć jakiegoś symbolu od
DRI w modułach X-serwera… pewnie te zamknięte binarki nie są zgodne z naszym
buildem X.org… no cóż, tym razem lepiej wypadły sterowniki otwarte.

Wróciłem do otwartych sterowników i spróbowałem jeszcze czegoś:
zainstalowałem 64-bitowe glxgears… i ruszyło. Czyli tym razem, pod 64-bitowym
kernelem, nie tylko X-serwer musi być 64-bitowy, ale i wszystkie aplikacje
OpenGL. Przykre… ale chwilowo mogę z tym żyć. Ostatnio i tak wiele takich
aplikacji nie używam. Właściwie, to tylko StepManię.

Dzisiaj więc postanowiłem sobie skompilować StepManię na 64-bity. Środowisko
do budowania zrobiłem sobie w chroocie z czystym 64-bitowym Th. Zainstalowałem
co StepMania potrzebowała i zacząłem budowanie. Od razu się wykrzaczyło… SM
jest w C++, a C++ ma to do siebie, że kod napisany dla starszego kompilatora
często nie da się skompilować nowszym. W PLD Th mamy GCC 4.2 i to GCC kodu
StepManii nie polubiło. Jednak potrzebnych poprawek nie było dużo i większość
z nich była nawet dla mnie (nie znającego i nie lubiącego C++) oczywista.
W końcu się skompilowało. I nawet dało się uruchomić.

Skompilowana przez mnie StepMania działała, ale tak jakby nie do końca. Nie
dało się wejść do ustawień gry, a rozpoczętej gry nie dało się wygrać. Jak się
poprawnie przeszło którąś piosenkę, to maszyna puszczała ją od początku.
Można by się było zajechać ;-). Podczas kompilacji widziałem
warningi dotyczące, między innymi, strict aliasing rules, więc
postanowiłem spróbować kompilacji z innymi opcjami. Okazało się, że skrypt
configure StepManii na sztywno ma wpisane -O3. To już mogło sprawiać
problemy. Zmieniłem na -O2 i dodałem -fno-strict-aliasing i całość
skompilowałem od nowa. Podczas kompilacji ćwiczyłem sobie na tej niedorobionej
binarce – ciekawie się gra, gdy komputer się czasem zagapi i nie
zauważy
, że się strzałkę wcisnęło na czas. ;-)

Po kilkunastu minutach miałem nową 64-bitową binarkę gotową. I tym razem
działa dobrze. To sobie jeszcze kiedyś poskaczę. :-)

W kolejce czeka zbudowanie GComprisa dla
Krysi, bo stare wyleciało razem z Ac (w Th tego brak).

Jak homofobi zniszczyli geniusza

Dziwię się, że tej historii nie znałem wcześniej. O samym Alanie Turingu trudno
było nie słyszeć – maszyna Turinga i test Turinga, to terminy znane
każdemu informatykowi. Biografią tego naukowca nigdy się specjalnie nie
interesowałem, aż do dzisiaj, gdy przeczytałem wzmiankę o nim w
artykule o badaniach naukowych dotyczących seksualności owiec
.

Odkrycie zaskoczyło mnie na tyle, że od razu zajrzałem na Wikipedię, czy
tam ta historia też jest odnotowana. Jest.

Alan Turing, jeden z największych (jeśli nie największy) geniuszy
w historii Informatyki, był gejem. W tamtych czasach było to uznawane za
przestępstwo. Naukowca osądzono, skazano i postawiono przed wyborem: albo
podda się terapii, albo wyląduje w więzieniu. Niezależnie od tego, jako
skazany wyrokiem sądu, nie mógł już pracować jako kryptolog w rządowej
agencji.

Turing wybrał terapię. Polegała ona na przyjmowaniu estrogenów w celu
zmniejszenia libido. Nie trudno się domyślić działania estrogenów na organizm
mężczyzny: został impotentem i rozwinęły mu sie piersi. Niedługo później zmarł
zatruty cyjankiem – najprawdopodobniej popełnił samobójstwo, gdyż nie
mógł sobie poradzić z życiem po wyroku. Geniusz, który bardzo przyczynił się
do rozwoju Informatyki, został poniżony i popełnił samobójstwo przez głupie
uprzedzenia… W dwudziestym wieku… A ja myślałem, że palenie czarownic na
stosie to taka odległa historia…

Committed revision 666.

Mam dosyć sztywnego trzymania się niektórych zasad dobrego stylu
programowania. Pisząc CJC starałem się
w ogóle nie używać zmiennych globalnych, bo przecież każdy wie, że tak trzeba.
No i dało się, jednak z tak zrobionego kodu nie byłem zadowolony. Mam tam
takie trzy obiekty, właściwie singletony, do których dostęp potrzebny był
w bardzo wielu miejscach. No i dostęp ten odbywał się właściwie na dwa
sposoby: albo referencja do takiego obiektu była przekazywana w konstruktorze i potem
zapisywana w atrybucie obiektu który tego potrzebował, albo dostęp odbywał się
przez inne obiekty (np.: self.plugin.app.screen) –
jedno i drugie nie wyglądały najlepiej. Standardowym, Javowe,
rozwiązanie, w postaci statycznej metody zwracającej instancję singletona,
niespecjalnie mi pasowało – to takie niepythonowe odwoływać się do
klasy, gdy tylko jej instancja jest potrzebna. Do tego to więcej pisania by
było, a przecież miałem API uprościć.

W końcu zdecydowałem się na rozwiązanie proste i skuteczne –
zrobiłem moduł cjc_globals z trzema zmiennymi globalnymi. I wszystko
byłoby dobrze, gdyby nie komunikat przy commicie, wyraźnie sugerujący, że
za moją decyzją stoi Zło: Committed revision 666.
;-)

Taki drobny „WTF?”

Dotychczas takie rzeczy spotykałem właściwie tylko na The Daily WTF,
jako fajne ciekawostki. Sam raczej unikałem grzebania w cudzym kodzie, najwyżej
zastanawiałem się jakie WTF przeżywają ci co przejmują lub kiedyś przejmą mój kod. ;-)

W obecnej robocie robię pewien system, w którym jako interfejs użytkownika
służy aplikacja webowa w Javie zbudowana na Strutsie. Do niedawna nawet mnie specjalnie
nie interesowało w jakiej to technologii i co to ten Struts. Ważne, że byłem
w stanie to uruchomić w swoim systemie i robiło to co trzeba – tworzyło różne pliki
i uruchamiało różne skrypty. Jednak ostatnio wyszło parę drobiazgów, które
należałby jak najszybciej naprawić.

Niestety Javowiec zajmujący się tą częścią kodu jest niedysponowany
(zdaje się, że się żeni) i nie dał rady tego zrobić, ani w najbliższym czasie
nie zrobi. Sprawa zrobiła się pilna, więc sam się za to zabrałem –
w sumie dobrze wiedzieć co w systemie siedzi. Najpierw poczytałem co to ten
Struts i gdzie mam szukać odpowiedniego kodu, potem zabrałem się za
poprawki…

Pierwsza rzecz banalna: zrobić stronę z komunikatem. Właściwie statyczną.
Znalazłem szablon wyświetlający coś podobnego. Skopiowałem. W środku znalazłem
miejsce na nagłówek i treść. Wypełniłem. Uruchomiłem aplikację… i treść jest,
bardzo brzydko ułożona (brak marginesów), ale jest. Nagłówka brak. Zaglądam do
źródła strony… kod paskudny, ale nagłówek jest. Zaglądam do CSS, a tam coś
takiego:

#titleBox p {
    background #FFFFFF;
    ....
    color: white;
}

No i miałem problem… co się stanie, jak zmienię kolor nagłówków na czarny…

Nie było źle… okazało się, że w całym interfejsie było dużo więcej opisów
niż wcześniej było widać, wyjaśniła się kwestia wolnej przestrzeni we
wszystkich formularzach. Ale oczywiście layout się popsuł, trudno to nawet było
wyjaśnić tą drobną zmianą koloru, ale poprawić było trzeba. No to podłubałem
jeszcze trochę w tym CSS i jest ok… ufff..

Potem chciałem dodać jeszcze parę komunikatów, w szczególność w przypadku
niepowodzenia pewnego skryptu… Zajrzałem do kodu a tam nie jest sprawdzany
kod wyjścia żadnego polecenia. A ja za cholerę nie wiem jak to ładnie w tym
Strutsie obsłużyć. Na razie poszedłem na łatwiznę i wszystkie niepowodzenia
przekierowuję na statyczną stronę z Operation failed. Przy okazji wyszła
kupa innych problemów… tym razem to już chyba tylko Javę można za to skląć,
ech…

Update: Zacząłem czytać dzisiejszy The Daily WTF i poprawiłem tytuł wpisu :-)

Okularków nie będzie, przenosiny w pełni

Dzisiaj wybrałem się do okulisty (przy optyku) w celu dobrania okularów.
Ten mnie zbadał, próbował dobrać odpowiednie szkła… i właściwie nic to nie
dawało. Na siłę okularów sprawiał sobie nie będę – to by mi mogło
bardziej zaszkodzić niż pomóc. To co zaobserwowałem u okulistki podczas badań
kontrolnych najprawdopodobniej było tylko złudzeniem spowodowanym
powiększającym działaniem szkieł. Dzisiaj więc zamiast recepty na okulary
odebrałem receptę na krople do oczu. Zresztą podobne to tych co już mam –
do Starazolinu, który wychwalałem już w zeszłym roku.

W związku ze zmianą pracy (do nowej już w czwartek) przenoszę różne
rzeczy. Listy dyskusyjne moich projektów (CJC, PyXMPP, Transport GG)
przeniosłem na swój własny serwerek (lists.jajcus.net), a z rozpędu zabrałem
się za przenoszenie do siebie reszty tych projektów z JabberStudio (które najwyraźniej
umiera). To ostatnie jeszcze trochę potrwa, bo to większa robota, ale pewnie
w tym tygodniu skończę – wtedy dam znać co i jak, a przede wszystkim,
gdzie.

Dzisiaj walczyłem jeszcze z dwie godziny z przenoszeniem kontaktów ze
starego telefonu komórkowego (firmowego) na mój własny, prywatny. Ta marna
namiastka IrDA/OBEX w moim Samsungu nie ułatwiała sprawy, ale stary laptop
z IRDA, Multisync, trochę Pythona, trochę ręcznego grzebania w plikach
wizytówek (bez tego, przy próbie importu czterech z moich kontaktów telefon
się po prostu rebootował) i jakoś się udało. BTW: jak ktoś ma mój stary numer,
a chciałby aktualny, to niech się do mnie zgłosi.

Z przenosin czeka mnie jeszcze wyniesienie swoich fizycznych zabawek (talerz,
słuchawki, puszka na herbatę, kalendarz z gołymi babami itp.) ze starej roboty
i zaniesienie sprzętu (komputer, monitor, telefony) do nowej. Z mniej
materialnych rzeczy – posprzątanie po sobie na serwerach w starej firmie
(wszelkie konta, aliasy, skrypty itp. zabawki) i podczepienie się do nowej
(też se będę musiał jakiegoś majla założyć). System niby sobie już na nowym
kompie zainstalowałem, ale nie pamiętam w jakim jest stanie… więc może
jeszcze to mi trochę czasu zająć… a pracodawca pewnie będzie chciał już
pierwszego dnia widzieć wyniki… ;-)

Pythonowe frameworki…

(wpis z wczoraj)

Pierwszy Pythonowy framework dla aplikacji webowych jaki poznałem to był Zope 2. Potrzebne mi było coś takiego do
stworzenia interfejsu użytkownika dla naszego systemu zarządzania siecią. W PHP
babrać się nie miałem zamiaru, a robienie całości jako CGI to byłaby mordęga.
Padło na Zope’a, nic innego nie było, a przynajmniej nic na tyle popularnego,
żeby obiło mi się o uszy. Zope, z jednej strony potężna maszyna, z drugiej
wkurzające monstrum. W szczególności, że źle się za niego zabrałem. Wszystkie
szablony robiłem w DTML (bo wyczytałem w ZopeBook, że równie dobrze jak ZPT,
a dla programistów nawet lepsze), a cały kod rozwijałem through the web,
a więc to było bardziej skryptowanie a’la PHP, niż poważne tworzenie aplikacji.
W końcu przekonałem się do ZPT (bardzo porządny język szablonów, pozwalający
w miarę dobrze oddzielać logikę od prezentacji i utrudniający tworzenie
niepoprawnego XHTML), ale kod dalej rozwijany jest TTW, bo zmiana tego, to byłoby pisanie aplikacji (sporej już) od
zera.

Widząc słabości Zope zacząłem się rozglądać za alternatywami. Żeby
alternatywę poznać to trzeba spróbować, postanowiłem więc pobawić się czymś
innym. Po wstępnym rozpoznaniu tego co jest na rynku, postanowiłem spróbować od
CherryPy. Próba polegała na
przeportowania mojego generatora i przeglądarki statystyk dla Joggera (ta
czerwona kropa poniżej) na ten framework. Wcześniej to było zrealizowane
w postaci skryptów CGI z prymitywnymi printami. Zrezygnowałem
z języka szablonów wbudowanego w CherryPy, bo znając ZPT nie chciałem się
babrać w czymś nie opartym o XML (nie pilnującym składni generowanego kodu),
użyłem więc SimpleTAL. Sportowałem tak dużą część tego generatora statystyk,
z błędami i dałem sobie spokój (zająłem się innymi rzeczami). CherryPy na
początku zrobiło niezłe wrażenie jak prosto się w tym aplikację WWW
buduje
, a potem okazało się raczej prymitywne. Architektura CherryPy wręcz
wymuszała bałagan, zamiast porządkować kod (to IMHO jedna z funkcji
frameworków) — na dłuższą metę reprezentacja hierarchii URL poprzez
atrybuty obiektów to niezbyt dobry pomysł. Do tego stan aplikacji (aktualne
żądanie, odpowiedź, etc.) trzymany w zmiennej globalnej (i dostępny przez tę
zmienną)… wiem że to działa, ale wydaje się niezbyt eleganckie. Krótko mówiąc
CherryPy mnie nie zachwycił.

Kolejny był Nevow, oparty o Twisteda. Od początku wydawał się
bardziej skomplikowany niż CherryPy. Ale po doświadczeniach z prostotą
(prymitywizmem) CherryPy to mnie nie zrażało. Nevow intensywnie korzysta
z interfejsów i adapterów (jak się później okazało, zapożyczonych od Zope3), ma
własny, ciekawy język szablonów — oparty o XML i jeszcze bardziej niż ZPT
oddzielający prezentację od logiki (w szablonach nie ma nawet pętli).
Portowanie prostego CGI do Nevowa to była droga przez mękę, bo trzeba było się
nauczyć nowego, skomplikowanego narzędzia. Niektóre rzeczy w tym frameworku
okazywały się ostatecznie proste i logiczne, przy innych trzeba było się
nakombinować. Doprowadziłem conieco (prezentację listy wejść) do działania, ale
nie rozwiązałem wszystkich problemów i walka z Nevow mi się znudziła.
Ostateczne wrażenie raczej pozytywne, chociaż miejscami było pod górkę.
Doceniłem też wsparcie na IRCu.

Jakiś czas temu na grupie pl.comp.lang.python przeczytałem
sporo dobrego o Zope3. Wtedy to było
jeszcze eksperymentalne Zope-X3. Framework przepisany od zera, docelowo mający
zapewniać częściową kompatybilność wstecz (czy raczej wsparcie dla portowania
starych aplikacji) z Zope2. Co do tego że Zope należało przepisać od zera, nie
miałem wątpliwości. W to, że w Zope krył się potencjał też. Więc, gdy pojawiły
się release candidate Zope 3.1, postanowiłem spróbować.
Poczytałem dokumentację, zacząłem łapać o co w tych interfejsach i adapterach
(dużo intensywniej używanych niż w Nevow) chodzi i zabrałem się za portowanie
statystyk. Znowu początki były ciężkie, ale prawie na każdy problem Zope
oferował jakieś fajne rozwiązanie. Wszystko w postaci przejrzystego obiektowego
podejścia. W przeciwieństwie do takiego CherryPy Zope3 zachęca do porządku
i przemyślenia co jest obiektem, co jego prezentacją. Daje potężne mechanizmy
kontroli dostępu, bezpieczeństwa kodu, i18n, skórkowania, tworzenia i walidacji
formularzy i wielu innych rzeczy które w aplikacji są potrzebne. Jest to
architektura i zestaw narzędzi, czyli to czym framework powinien być. I się
sprawdza. Dzisiaj skończyłem portowanie statystyk i efekt jest lepszy niż
oryginał, a ewentualny dalszy rozwój będzie banalnie prosty (prostszy niż
w przypadku CGI).

Już po rozpoczęciu swojej zabawy z Zope3 stwierdziłem, że warto to
zastosować w firmie zamiast Zope2. Większość systemu (interfejs administratora,
serwisu, BOKu) zostanie na starym Zope’ie, bo przepisanie tego to znowu byłoby
wiele miesięcy, ale już interfejs użytkownika końcowego robię na Zope3. Tego
jest niewiele i i tak muszę to przepisać od zera. Obie części komunikują się
przez bazę danych i chodzą na różnych maszynach, więc zastosowanie dwóch
Zope’ów nie jest problemem. Mam nadzieję, że tej decyzji nie będę za jakiś czas
żałował, jak tego, że wpakowałem się z Zope2 i aplikację rozwijaną
TTW. No i to, że w ogóle wpakowałem się w kodowanie zamiast
adminowania…

Jest jeszcze wiele innych frameworków i, do tego, ciągle powstają nowe.
Części w ogóle nie znam, o części poczytałem w sieci i zrezygnowałem, bo ich
założenia mi nie pasowały. Niektóry zdawały się zbytnio iść w kierunku PHP,
którego przecież celowo unikam, inne miały jakąś dziwną architekturę, np.
Webware składające się z iluś komponentów, w których nie udało mi się ujrzeć
spójnej całości. Ciekawe co wygra — na świecie i wśród moich narzędzi.