PIDA mnie rozczarowuje

Większość mojego kodu w Pythonie (a właściwie kodu w ogóle, włączając w to HTML i skrypty SQL) piszę w PIDA. Jak dla mnie to środowisko pozostawia mi ultrawygodnego Vima, dodając to, czego potrzebuję podczas pracy: zarządzanie grupą plików jako projektem, kilka podstawowych poleceń systemu kontroli wersji, przeglądarkę klas i integrację z pyflakes. Niestety, PIDA ma wciąż sporo błędów i — to jest prawdziwe niestety — nie są one w ogóle poprawiane (prawdopodobnie dlatego, że nie ma kto tego zrobić, i nie, ja też tego nie dam rady zrobić). Bardzo to wkurzające, przede wszystkim zważywszy fakt, że żaden z wolnodostępnych edytorów nie oferuje tego, co PIDA...

Tak łatwo to jeszcze nie było

Znalazłem kilka dni temu samouczek pisania własnych ramówek webowych w Pythonie w oparciu o WSGI i bibliotekę WebOb. Tak łatwo to chyba jeszcze nie było...

Na szczęście minęły czasy pączkujących ramówek (w tempie dwóch tygodniowo, strach było otworzyć lodówkę), ale może takie samouczki pokażą pretendentom, co ich czeka od strony kodu. Bo tego, co ich czeka od strony użytkowników to się nie da opisać żadnymi słowami. ;)

Gówniażeria

Co jakiś czas na pl.comp.lang.python pojawiają się ogłoszenia o pracy dla programistów w Pythonie. Abstrahując od dyskusyjnej właściwości tej grupy dla wysyłania ogłoszeń o pracy (niby jest pl.praca.oferowana, ale ogłoszeń o pracy dla Pythoniarzy nie jest aż tak wiele, więc ma to pewien walor...), to reakcje na takie ogłoszenia doprowadzają mnie do białej gorączki.

Przykład z ostatnich dni, pewna firma z Wrocławia zamieściła ogłoszenie o pracy. Napisali czym się zajmują, czego oczekują i tradycyjnie enigmatycznie co oferują. I od razu zaczęło się wydziwianie: a to że polszczyzna odbiega od wzorca metra prof. Miodka, a to że znowu nie podali proponowanych zarobków, a to że wymagają bardzo dobrej znajomości biblioteki standardowej. Takie pitu-pitu, żeby sobie tylko popyszczyć. Dużo osób narzeka, że gdzie indziej pracodawcy w ofercie podają kwoty, ale nikt jakoś nie zauważa, że dotyczy to ofert zamieszczanych w serwisach jobsowych, a nie w usenecie. I pewnie aby dopełnić obrazu nikt się nie pofatygował, żeby popatrzeć jak gdzie indziej wyglądają reakcje na takie ogłoszenia. Podpowiem — odpowiedzią jest milczenie.

QS-RF w trunku Django

Queryset-refactor zlądował w trunku Django. Wspominam z kronikarskiego obowiązku, bo nie zauważyłem żadnych problemów z moimi aplikacjami w związku z tym.

Kalkulator w dłoń i liczymy

Osłabiający się wciąż dolar sprawił, że postanowiłem sprawdzić, czy MegiTeam nadal jest konkurencją dla WebFaction, przynajmniej jeżeli chodzi o cenę. Kalkulator w dłoń i liczymy.

Ponieważ MegiTeam nie ma opcji płatności miesięcznej, policzymy dla okresów 3, 6 i 12 miesięcy, stosując wszystkie podstawowe zniżki i porównując plany taryfowe, które sobie odpowiadają. W przypadku WebFaction będzie to "Shared 1" (80MB RAM, 600GB transferu miesięcznie, 10GB przestrzeni dyskowej), z uwzględnieniem zniżek za przedpłacenie. W przypadku MegiTeam, które nie oferuje aż takiego transferu, użyta będzie maksymalna wielkość 50GB transferu miesięcznie. Ceny w USD zostaną przeliczone według kursu średniego NBP z dzisiaj.

3 miesiące

WebFaction: 3 * $9.50 * 1.175 (17.5% VAT) = $33.49, czyli 73.83 zł

MegiTeam: 139.00 zł

6 miesięcy

WebFaction: 6 * $9.50 * 1.175 (17.5% VAT) = $66.98, czyli 147.65 zł

MegiTeam: 269.00 zł

12 miesięcy

WebFaction: 12 * $8.50 * 1.175 (17.5% VAT) = $119.85, czyli 264.20 zł

MegiTeam: 521.00 zł

Jak widać, przy rocznym okresie rozliczeniowym MegiTeam jest dwukrotnie droższe od WebFaction. Jeżeli do października nie nastąpi jakaś katastrofa na rynku walutowym, to się przeniosę z hostingiem za ocean. Może nie będzie aż tak strasznie wolniej...

Korci mnie Django Dash

Django Dash to konkurs programistyczny podobny do Ludum Dare czy PyWeek — chodzi o to, żeby w 48 godzin wyprodukować kompletną, działającą aplikację w Django. Mam pewien pomysł i nawet wizję, jak to zrobić, ale nie jestem pewien, czy wytrzymam te 48 godzin, czy po prostu nie jestem za stary na takie kodowanie. ;)

Nie mam wizji na AppEngine

Dostałem to konto i po całym weekendzie zastanawiania się nie umiem sobie wyobrazić aplikacji, którą mógłbym napisać i odpalić na AppEngine. Ograniczenia są cokolwiek duże, ale sama perspektywa jest przez cały czas kusząca. Dam sobie jeszcze tydzień na przemyślenie, czy w ogóle w to brnąć.

Przez cały czas mam przeczucie, że to jest coś, co daje duże możliwości.

Got it, gonna try it over the weekend

Thanks for signing up to try Google App Engine! Your account has been activated, so you can begin building applications!

No to zobaczymy, co się z tego da wyciągnąć... Mam pod ręką kilka eksperymentalnych projektów, któryś z nich zląduje na AppEngine.

Nic za darmo

W dzień-dwa po tym, jak Google ujawniło swoje AppEngine, firma Joyent, która sprzedaje (dość tanio) wirtualki na OpenSolarisie, postanowiła udostępnić swoją infrastrukturę bezpłatnie (co nie znaczy za darmo, ale po kolei) pod projekty w Pythonie, które mogą się pochwalić odpowiednio dużym ruchem. Z wielkimi fanfarami i używając biblijnego słownictwa ogłosili program, który nazwali (a jakże) Garden of Eden.

Haczyk jest taki, że chcą... nielimitowanego dostępu do danych klientów tak hostowanych serwisów. Imiona, nazwiska, adresy, telefony, numery faksów i cały ten szpej. Warto? Owszem warto... zastanowić się, co ważniejsze.

No i chyba mnie ominęło

Wszystko wskazuje na to, że moje zgłoszenie do testowania Google AppEngine nie zostało wylosowane, 10000 kont zostało rozdanych, a mnie zostało czekanie na następny batch i ćwiczenie na lokalnym dev serwerze. Znajomy zaproponował, że da mi jedną ze swoich trzech przydziałowych aplikacji, żebym mógł sobie potestować, więc pewnie nie będzie to trzening tak całkiem na sucho...

W każdym razie już widać, że o ile z Django na AppEngine zostaje bardzo dużo, to modeli używać trzeba tych dostarczanych przez Google. Nie minęło wiele czasu, a już pojawiły się plany rozszerzenia zaplecza bazodanowego Django o obsługę API przechowywania danych na AppEngine. Może to zaowocować szybszym merge odgałęzienia queryset-refactor do głównej gałęzi rozwojowej Django.

W obecnej formie na AppEngine nie wszystko jest zaimplementowane (nie ma np. M2M), z niektórych rzeczy trzeba zrezygnować, jak z interfejsu administracyjnego, czy z djangowego mechanizmu sesji, ale i tak jest to na tyle ciekawe, żeby chcieć dostać sztukę dla dokładniejszego przyjrzenia się. :)

Hot! (znowu się spóźniłem)

Google wystrzeliło z nowym pomysłem — AppEngine to nowy (i z opisu wynika, że rewolucyjny) hosting aplikacji webowych w ścisłej integracji z usługami Google, na razie przede wszystkim w Pythonie. W domyślnej instalacji jest Django 0.96.1, ale można też wziąć sobie wersję z SVN. Na razie trochę niejasne jest, w jaki sposób połączyć implementację modeli by Django z API, którego używania wymaga Google, ale sądzę, że wszystko się wyjaśni wkrótce.

I jak zwykle się spóźniłem z zapisaniem, trafiłem na waitlistę...

Nowości z frontu walki z Akismet

Coś wygląda na nieźle spieprzone w usłudze sprawdzania komentarzy przez Akismet — podanie w komentarzu linku do strony na Grupach Google (obojętne, dyskusje czy pliki), zamiast spodziewanego "true" lub "false" zwraca "" (pusty ciąg znaków). Na razie nikt nie zwrócił uwagi na takie zachowanie Akismet, ale ja się zacząłem rozglądać za czymś innym. Na razie plany rozszerzenia CommentModerator obejmują LinkSleeve i Defensio.

Jak na razie wygląda na to, że nie da się zamieścić komentarza, który zawiera link do Google Groups. Wolałbym nie rezygnować z automatycznego moderowania komentarzy, ale jeżeli nie da się tego uniknąć, to będę moderował komentarze ręcznie. Oh, my...

Po WARPY #4

Zmieściłem się w czasie... prawie. ;)

Przeciągnąłem o 5 minut, ale obskoczyłem wszystko, pomimo problemów z warstwą prezentacyjną. Niestety, publiczność nie dopisała i mieliśmy pustki na sali.

Materiały są dostępne na stronie listy mailowej.

WARPY #4

Kolejne, 4 spotkanie w ramach WARPY odbędzie się tam, gdzie zawsze, o 19:15. Poopowiadam trochę o tłumaczeniu i lokalizacji programów w Pythonie. Będzie o modułach gettext i locale, a dodatkowo pokażę parę tricków z biblioteką Babel.

Nauczony poprzednią wpadką postaram się ograniczyć moje pływanie w dygresjach. ;)

To w końcu umierają, czy nie?

Umierają, umierają, żadna przecież nie trwa wiecznie. Idea WarPy okazała się jednak nieco bardziej żywotna, niż przypuszczałem — agonia potrwa co najmniej o 2 tygodnie dłużej.

27 marca Marcin Świderski (forgems) przedstawi wprowadzenie do Django, godzina i lokalizacja ta sama co zawsze (19:00 na "elce"). A tydzień później, czyli 3 kwietnia, w ramach nadrabiania zaległości, opowiem o tłumaczeniu i lokalizowaniu programów w Pythonie (czyli o i18n i l10n).

Jak umierają idee (w Polsce)

Idee w Polsce umierają po cichu.

Jesienią ubiegłego roku zaczęliśmy robić prelekcje o Pythonie w ramach WarPy. Odbyło się 3 spotkania, po czym współorganizator ze strony WO@PW i WarLug-a poprosił o przerwę z powodu sesji. Gdy sesja się skończyła, organizatorom i potencjalnym prelegentom z kolei zaczął się gorący okres w pracy.

WarPy ma swoją listę mailową, w żadnym przypadku nie jest organizacją zamkniętą, która w tajnych głosowaniach ustala kto i o czym ma opowiadać. Ja nie mam ostatnio czasu zadać pytania, czy są w ogóle jacyś chętni, a chętni sami się nie zgłaszają. W ten sposób po cichu i bez rozgłosu kończy się kolejna idea.

Wyczesane zarządzanie obiektowym keszem w Django

Bardzo, bardzo dokładnie przyglądam się wszystkiemu, co związane z cache na poziomie obiektów w Django (np. projektowi django-orm-cache). Znalazłem blogowy wpis (po rosyjsku, a jakże!), który opisuje rozwiązanie bardzo podobne do tego, którego i my używamy, ale o wiele bardziej kompletne. Wypadałoby to teraz gdzieś przetestować, ale w środowisku, w którym miałoby to jakikolwiek sens, nie za bardzo możemy — po prostu nie ma na to czasu...

Ku pamięci, jak to Aleksiej Koszeliew załatwił sprawę odświeżania obiektowego cache w Django. Polecam uwadze, jeżeli kogoś też interesuje to, jak inni dają sobie radę z wygaszaniem cache...

Hi, all, I'm official

Mój pierwszy commit do repozytorium Django, jako oficjalnego maintainera polskiego tłumaczenia.

Ludzie mają problemy

A my nie! (My, czyli kilka naszych aplikacji)

Iwan Sagalajew, pracujący dla yandex.ru, podzielił się kilkoma spostrzeżeniami po nieudanym odpaleniu nowego serwisu społecznego. Czytałem to z niekłamanym zadowoleniem — większość problemów, które tam opisał, nie ma nawet szans, żeby nas dotyczyć. Po kolei:

  • zbyt długi czas zapisu danych sesji, nie dotyczy nas, bo sesje trzymamy w memcache;
  • efekt "dog-pile", nie dotyczy nas, bo rzeczy kosztowne robimy poza aplikacją (poniekąd asynchronicznie);
  • pomimo nacisków naszego DB-speca, nie normalizujemy naszego modelu nadmiernie.

Nie mam złudzeń, że w pewnym momencie będziemy musieli troszkę przyciąć nasz radosny bałaganik, ale aplikacja została zaplanowana z tak dużym zapasem, że to na pewno nie nastąpi w ciągu najbliższych kilku miesięcy...

Mała aktualizacja, pod wpływem komentarza Bluszcza — to on to wymyślił. A żeby nie rozpłynął się w samozachwycie, to wymyślił też parę marnych rzeczy, ale tego co marne pozbędziemy się prędzej czy później...

Dziwne potrzeby, oczywiste rozwiązania: polib

Ktoś (imienia nie wymienię) wysłał klientowi teksty do przetłumaczenia... w Excelu. Klient zadowolony, że nie musi używać żadnych hackerskich narzędzi typu poEdit, oczywiście przetłumaczył teksty w tymże Excelu, a nam przyszło załamać ręce. Ale tylko na chwilę.

Dzięki bibliotece polib załatwiliśmy sprawę w pół godziny. A żeby zaoszczędzić stękań na przyszłość, następne partie tłumaczeń też będziemy wysyłać w Excelu. A co!

Jedno oko na Maroko

Jest kilka projektów związanych z Django, na które warto jest mieć oko, z różnych względów. Niektórych używam, więc z konieczności śledzę ich rozwój (m.in. django-registration i django-comment-utils), ale są też takie, które rokują rozwiązanie trapiących mnie problemów.

Jednym z takich projektów jest django-orm-cache, a problem, który ma on rozwiązać dotyczy każdego, kto używa cache na poziomie obiektów w Django. Został on opisany przez Davida Cramera (który także jest pomysłodawcą i jednym z developerów tego projektu). W skrócie chodzi o to, że używany na poziomie obiektów i ich grup cache staje się dodatkowym storage, w którym trzeba odzwierciedlić zmiany, wprowadzone w głównym storage (czyli w samych obiektach). Dobrego rozwiązania nie ma — można rygorystycznie pilnować wygaszania obiektów w cache przy każdej modyfikacji (przydają się tu sygnały), można wersjonować klucze przy użyciu jakiegoś znacznika, ale żadne z tych rozwiązań nie jest ani wygodne, ani łatwe. Django-orm-cache ma ułatwić życie, przejmując zadanie automatycznego wygaszania obiektów w cache przy każdej modyfikacji obiektu.

Projekt nie jest jeszcze w stanie nadającym się do użytku, ale widać w nim jakiś ruch i to dobrze wróży. Chciałbym już teraz mieć coś takiego w mojej narzędziówce w pracy...

Mówisz - masz

Bluszcz zażyczył sobie RSS-ów dla konkretnych kategorii, żeby odfiltrować offtopiki na planecie. Tradycyjnie na wyrost kazałem mu się zgłosić w przyszłym tygodniu, ale to nie byłaby aplikacja w Django, gdyby rzeczywiście miało to tyle trwać. I trwało w sumie 20 minut. Proszę, masz RSS-y z kategorii (u mnie się one nazywają etykietami). Tę, która Cię interesuje, znajdziesz na stronie z wpisami pod etykietą python.

Release early... Ale to nie my

Django zdaje się być całkiem w poprzek przyjętej zasadzie w świecie OS/FS: release early, release often. Ostatnie oficjalne wydanie Django miało miejsce 11 miesięcy temu, (23 marca 2007 roku). Rozumiałbym to, gdyby w projekcie niewiele się działo i rzeczywiście nie byłoby co wydawać, ale działo się wiele. Od tamtego czasu doprowadzono do używalności newforms, wprowadzono pełną wewnętrzną unikodowość, znacząco zmieniono także wyjście wprowadzając automatyczne eskejpowanie zmiennych podczas renderowania szablonów. Każde z tych wydarzeń (a pewnie i kilka innych) zasługiwałoby na wydanie, choćby po to, by nie powiększać przepaści pomiędzy kodem wydanym oficjalnie, a kodem rozwojowym.

Nie podoba mi się to.

Czego warto zazdrościć Javie

Na pewno nie średników i klamerek. ;)

Java jako język może nadawać się najwyżej do programowania pralek. Jako platforma może być przegniła do korzenia. Ale ma coś, czego co jakiś czas brak odczuwam bardzo mocno programując w Pythonie — zestaw specyfikacji do J2EE. Specyfikacja jak to specyfikacja, to suchy papier, może być bez sensu, ale złe są dopiero implementacje. Spośród tych wszystkich większość jest dość specyficzna dla Javy ("stwarzamy problemy by bohatersko je pokonywać", czy jakoś tak to było), ale są dwie, które ja uważam za perełki. I to są te dwie, których brakuje mi najbardziej:

  • JNDI, czyli uniwersalne usługi katalogowe;
  • JMS, czyli integracja komponentów aplikacji przez komunikaty.

Cała reszta może się schować, ale tych dwóch naprawdę mi brakuje. Nie to, żeby Python potrzebował takich specyfikacji, ja potrzebuję standardowych implementacji. O, jakby mi ułatwił życie taki serwer JMS z interfejsem w Pythonie (nie, ActiveMQ + Stomp to jeszcze nie jest to!)...

Mam kolejnego gadżeta

Tym razem zupełnie niechcący. Kończyła mi się umowa u komórkowców, więc ją sobie przedłużyłem, przy okazji wymieniając telefon na nowy. Dopiero po powrocie do domu, przeglądając instrukcję obsługi, znalazłem logo Symbiana i coś na temat S60... Czyli mam fona z S60! :D

Pierwszą rzeczą, którą sobie zainstalowałem był (a jakże inaczej) PyS60...

Jest nas dużo, ale wciąż za mało

Na Django People jesteśmy teraz na 4 miejscu, razem z Niemcami. Uważam to za całkiem niezły wynik. Przed nami są Brazylia, Wielka Brytania i US of A (w tym przypadku chyba bardziej sprawiedliwe byłoby liczenie według stanów, ale się nie upieram), więc raczej kraje albo dużo bardziej liczne ludnościowo od nas, albo bardziej ambitne, jeżeli chodzi o pokazanie się. Mogę się mylić (i pewnie się mylę), ale każde miejsce wśród pierwszych 7-8 powinno nas zadowalać, choćby z powodu tego, ile osób przychodzi na WARPY (w tym tygodniu zostało odwołane). Python zajął już poczesne miejsce w galerii języków programowania, a Django jest już powszechnie rozpoznawane.

To dobrze. Roboty jest dużo, a ten wózek musi się toczyć.

Tutoriale mnie dygają

W szczególności tutoriale do ramówek webowych. Każda ramówka w pewnym momencie dorabia się "20 minutes wiki tutorial" (czasem nawet w formie screencastu), ale w większości przypadków są one całkowicie bez sensu — nie pokazują tego, jak ramówka działa, nie uczą, jak jej używać, nie opisują jej komponentów. Zaczęło się od niesławnego screencastu RoR, a potem było już z górki. Pamiętam kilka lat temu, gdy w krótkim czasie wystartowały TurboGears i zaraz potem Django, że początkowo TG wygrywało popularnością właśnie z powodu posiadania takiego screencastu (i uzyskiwało opinię łatwiejszego do nauczenia). Lista mailowa TG pękała w szwach, zapowiadano nowe, ekscytujące możliwości kolejnych wydań ramówki, ale minęło kilka-kilkanaście miesięcy i to Django przejęło inicjatywę. Po kolejnych kilku-kilkunastu miesiącach TG uchroniło się przed zniknięciem, ale jak na pioniera radzi sobie coraz gorzej, już nie jest nawet numerem 2, bo w staraniach o przejęcie władzy nad sercami i umysłami developerów wyprzedziło je Pylons. Na szczęście, Pylons również posiada 20 minutes wiki tutorial, więc pozycja Django (które posiada jedynie nieoficjalny screeencast wiki na ShowMeDo) wydaje się być niezagrożona. ;)

Tak sobie właśnie przypomniałem... Jakiś czas temu prorokowałem, że z pierdyliarda ramówek webowych w Pythonie (był taki okres, kiedy powstawała jedna ramówka dziennie...), pozostanie nam 2-3 liderów i plankton — i tak się właśnie stało. Kto wymyśli tę, która zdetronizuje obecny numer 3 i stanie do wyścigu o pierwsze miejsce?

64MB RAM na Megiteam.pl

To mało czy dużo? Zależy... Moja aplikacja daje radę. Działa na jednym procesie FastCGI, swoje przydziałowe (?) 64MB RAM wykorzystuje w 100%. Szukałem jakichś wskazówek, jak ograniczyć apetyt aplikacji Django (uruchamianej na FastCGI) na RAM, ale znalazłem niewiele, a już na pewno nic nowego, nic, czego bym już nie wiedział. Być może nie jestem jeszcze aż tak bardzo zdesperowany, bo nie odczuwam, żeby aplikacji brakowało pamięci. Może to jest całkiem wystarczająca ilość, skoro aplikacja się jeszcze nie krztusi?

E, tam, nie mam chyba większych problemów... Jeszcze kilka lat temu nie przeszłoby mi przez myśl, że będzie mnie stać na hostowanie gdziekolwiek aplikacji w czymkolwiek innym, niż PHP. Zanim dorobiłem się hostingu na megiteam.pl nawet zastanawiałem się, czy nie iść na taniochę i nie przeprosić się z PHP. A tu — prawie jak spełnienie marzenia.

Aktualizacja z 18 stycznia: pani Magda Zarych, właścicielka megiteam.pl, uściśliła moje domysły. Aplikacja nie spożywa 64M, lecz w granicach 18M. Patrzyłem nie na to, co trzeba. Swoją drogą, przyjemnie, że firma wsłuchuje się w bicie serca klientów. ;)

Pylons zniechęca

Podkusiło mnie i postanowiłem zrobić tutorial Pylons, trochę z ciekawości, a trochę podążając za modą. Ogólne wrażenie było raczej... marne. Zarówno jeżeli chodzi o Pylons, jak i o sam tutorial.

Przede wszystkim, tutorial stanowił nie lada wyzwanie. W pewnym momencie zalecane do wykonania polecenie zakończyło się bardzo brzydkim tracebackiem, który niewiele mówił. Nie wiedząc, co zrobiłem źle, darowałem sobie dalsze przerabianie materiału, ale następnego dnia zaświtała mi pewna idea i po sprawdzeniu okazało się, że miałem rację — kilka sekcji dalej omówione zostało ustawienie konfiguracji, którego brakowało. Po pokonaniu tej przeszkody udało się dobrnąć do końca.

Teraz trochę o wrażeniu, jakie robi automatycznie wygenerowany szkielet aplikacji. Zawiera on dużo więcej, niż szkielet, jaki generuje Django. W prawie każdym pliku używana jest konstrukcja from package.module import * co powoduje, że właściwie nie wiadomo, skąd co pochodzi. Dodatkowo autor tutoriala ma zadziwiający zwyczaj używania jednoliterowych skrótów, jak np. "h" dla "helpers" czy "c" dla "context" (wygląda to na dość powszechny obyczaj). Ilość tekstu do napisania się zmniejsza, ale traci na tym czytelność. Do tego dokłada się jeszcze duża ilość modułów, które importowane są na wszelki wypadek, a przynajmniej bez jakiegokolwiek wytłumaczenia. Wszystko to składa się na ogólne wrażenie chaosu.

A teraz o samej ramówce, a raczej o tym, co jest zalecane jako jej elementy w wersji 0.9.6.1 (bieżącej w chwili pisania tego artykułu). SQLAlchemy jest potężne, skomplikowane i nieprzyjemne. Routes jest potężne, skomplikowane i nieprzyjemne. System szablonów Mako jest potężny, skomplikowany i nieprzyjemny. Paster jest potężny, skomplikowany i nieprzyjemny. W efekcie Pylons jako całość jest potężne, skomplikowane i nieprzyjemne. Zupełnie jak Spring. Na pewno można przy jego użyciu zrobić milion sprytnych rzeczy, ale nie chodzi o to, żeby robić sprytne rzeczy, tylko żeby zrobić co trzeba i mieć przy okazji trochę dobrej zabawy.

Konkluzja jest dość oczywista — dopóki nie będę musiał, nie porzucę Django dla Pylons. Z pracy przy projektach w Django mam przynajmniej sporą dozę radochy...

WARPY #3

Tym razem będę się produkował ja. :)

Opowiem trochę o programowaniu aplikacji GUI przy użyciu PyGTK, raczej od podstaw, niż dla bardziej zaawansowanych.

Próbowałem, poddałem się (na razie)

Chciałem podłączyć moją usługę (webservice zrobione na podstawie twisted.web) do serwera Zeroconf i okazało się, że to całkowicie niemożliwe w obecnej sytuacji. Jedyna dobra biblioteka do tego, czyli avahi, jest tak mocno zintegrowana z DBus, że wymaga... głównej pętli programu zrobionej na GObject, żeby móc działać asynchronicznie. Porażka. Znalazłem wstęp do implementacji usług związanych z mDNS przy użyciu Twisted, ale oczywiście niepełną.

Chyba trzeba będzie sobie wreszcie ubrudzić ręce trochę poważniejszym kodem...

Trafiony, zatopiony

Pół dnia spędziłem na szukaniu błędu, który ukrył się w poniższym fragmencie kodu:

try:
    contactsIndex = self.names.index('Contact')
    contacts = items[contactsIndex]
    mail = email_re.findall(contacts)[0]
    if mail:
        logger_main.debug('Email %s found within ad data' % mail)
        report_counters['ads_with_emails'] = report_counters['ads_with_emails'] + 1
except:
    mail = False

Wszystko wydawało się w porządku, ale nie było. Klauzula except bez wyspecyfikowania wyjątku zachowuje się tak, że wyłapuje wszystko. Dopiero zapisanie jej w postaci except Exception, e: i zalogowanie wyjątku pokazało, gdzie tak naprawdę ten błąd był. Zupełnie nie tam, gdzie się spodziewałem — klucz słownika report_counters wcale nie nazywał się 'ads_with_emails' (mniejsza o to, jak się nazywał).

Po prostu się nie spodziewałem. Perfidia.

Książki, książki

Po Pro Django, Web Development Done Right szykuje się kolejna książka o tej ramówce — James Bennet zaanonsował, że pisze książkę, która omawia Django od strony praktycznej. Książka jest już listowana na Amazon.com, więc sprawa wygląda na poważną. Wypada się tylko cieszyć. Przyda się taka książka wszystkim początkującym.

Jednym z zagadnień przez tę książkę poruszanych ma być pierwsza aplikacja w Django, czyli właśnie silnik blogowy. Ja swój napisałem w ciągu kilku wieczornych sesji, właśnie jako projekt szkoleniowy z migracji na nową wersję Django (choć wcale nie był pierwszą aplikacją, moją pierwszą aplikację można już podziwiać od dłuższego czasu w Rumunii, na Węgrzech i w Wielkiej Brytanii). Trudno jednak wymagać, by ktokolwiek zaczynał zaznajamianie się z Django od dużego, komercyjnego projektu na zlecenie międzynarodowego klienta...

Co z tym Django?

Coraz bardziej niecierpliwię się tym, że Django wciąż nie ma oficjalnego wydania wersji, która miałaby pełne wsparcie dla unikodu i działające newforms. Pojawiły się pogłoski, że następne wydanie to nie będzie oczekiwane przez wszystkich 0.97, ale od razu 1.0 — to by oznaczało, że ilość rzeczy, jakie trzeba będzie zrobić podczas migracji będzie podobna, jak przy 0.91. Tutaj nie ma to wielkiego znaczenia, ale w pracy będziemy mieli dylemat...

WARPY #2

Dziś na PW kolejny wykład w ramach WARPY. Z powodów osobistych się nie wybiorę, niestety.

Następny wykład będzie 10 stycznia 2008, o ile nie zajdą jakieś nieprzewidziane okoliczności. I będę się starał wygłosić prelekcję o PyGTK.

Dobre wieści, Django znowu działa

Mądrzejsi ode mnie znaleźli błąd, poprawili i Django znowu działa przez FastCGI. Chwała nam i naszym kolegom, wiadomo komu precz!

Buggy weekend

Dwa straszliwe bugi objawiły się w projektach, które są mi z różnych powodów bardzo bliskie. Mało tego, żaden nie został jeszcze poprawiony.

Gajim ma problem z GnuPG — pewnym obejściem jest używanie gpg-agent (w sumie i tak powinienem go używać, ale chyba nie jestem jeszcze aż takim paranoikiem), ale jest możliwość doprowadzenia swojej konfiguracji do takiego stanu, że Gajim nie da się uruchomić. Wystarczy odhaczyć w ustawieniach konta "Używaj gpg-agent" i mieć wybrany jakiś klucz GPG do szyfrowania. Gajim daje segfaulta podczas uruchamiania. Sprawdzę jutro w pracy, czy ma to coś wspólnego z oprogramowaniem, jakie mam na domowej maszynce.

Django z powodu przeciekającego skądś obiektu SafeString zwraca nieprawidłową zawartość HttpResponse. Z tego powodu Flup odmawia współpracy i ogólnie w tej chwili trunk Django nie nadaje się do użycia przez FastCGI. Sprawdziłem to tymi rękami, na tym sajcie — nie działa. Nie jestem aż tak dobrze obeznany z internalsami Django, żebym zabierał się za zmiany w kodzie, zwłaszcza, że byłoby to grzebanie w HttpResponse... Nie da rady, trzeba czekać.

WAR-PY

Albo WARPY, albo może WarPy... Nie wiem, jaka jest oficjalna pisownia tego dziwnego skrótowca, nawet pomimo tego, że w jego powstawaniu brałem udział kilka tygodni temu w pubie Wetlina. Dość, że robocza nazwa staje się powoli nazwą oficjalną.

We czwartek 29 listopada o 19.00 na Politechnice Warszawskiej w sali AL odbędzie się pierwsza prelekcja, którą wspólnymi siłami (Grono.net, Sensisoft, WARLUG i WO@PW) urządzamy celem popularyzacji Pythona. Zacznie Marek Pułczyński z Grona, od standardów pisania kodu w Pythonie. Z agendy wnoszę, że będzie głównie opowiadał o trzymaniu się konwencji, dokumentowaniu kodu przy użyciu docstrings i budowaniu pakietów, ale temat może odpłynąć, bo zagadnienie jest... dość nośne. Kolejne spotkania będą się odbywać co dwa tygodnie.

Na prelekcję za dwa tygodnie ostrzy sobie zęby Rafał Zawadzki, więc ja się wstrzelę pewnie dopiero za 6 tygodni. Na razie planuję opowiedzieć coś o PyGTK, ale przecież wszystko może się odmienić...

Practicality beats purity

Każdy, kto programuje w Pythonie dłużej niż kilka godzin, na pewno kiedyś zetknął się z tym:

Python 2.5.1 (r251:54863, Oct  5 2007, 13:36:32) 
[GCC 4.1.3 20070929 (prerelease) (Ubuntu 4.1.2-16ubuntu2)] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> import this
The Zen of Python, by Tim Peters

Beautiful is better than ugly.
Explicit is better than implicit.
Simple is better than complex.
Complex is better than complicated.
Flat is better than nested.
Sparse is better than dense.
Readability counts.
Special cases aren't special enough to break the rules.
Although practicality beats purity.
Errors should never pass silently.
Unless explicitly silenced.
In the face of ambiguity, refuse the temptation to guess.
There should be one-- and preferably only one --obvious way to do it.
Although that way may not be obvious at first unless you're Dutch.
Now is better than never.
Although never is often better than *right* now.
If the implementation is hard to explain, it's a bad idea.
If the implementation is easy to explain, it may be a good idea.
Namespaces are one honking great idea -- let's do more of those!

Często zdarza mi się zapomnieć o jednej z tych zasad: że practicality beats purity. Mamy teraz taki drobiazg do zrobienia, przydałoby się wyjąć z jednego modelu wszystko, co jest związane z jego wyświetlaniem. Oczywiście, nie tylko dlatego, że to łamie podstawową zasadę MVC i miesza model z jego wyświetlaniem — z tego powodu jest to tylko brzydkie, a poza tym to jest też dość niezręczne w zarządzaniu. Wiele już myślałem nad tym, jak wyjąć konfigurację wyświetlania tego modelu żeby wyglądało to ładnie no i chyba właśnie wygrało to practicality — zrobimy oddzielny model na DisplayProperties.

Übersatan

Niejaki problem z Flupem

Jak wiadomo, Django używa pakietu Flup żeby uruchamiać aplikacje w środowisku serwera oferującego FastCGI (Apache + mod_fastcgi, nginx, lighttpd). Trafiłem na coś, czego jeszcze do tej pory nie widziałem na oczy. Nigdzie i nigdy.

Nasza aplikacja nigdy nie wyrzuca błędu. Nie mówię o 500, w końcu istnieją aplikacje doskonałe, ale nawet 404, i to pomimo tego, że w kodzie w wielu miejscach leci wyjątek django.http.Http404. W takiej sytuacji aplikacja wyświetla jakąś statyczną stronę (nie ma to nic wspólnego z naszym szablonem 404.html czy 500.html) i zwraca 200. Dogrzebałem się, że jest to efekt działania ErrorMiddleware z Flupa, który w ten sposób próbuje zwrócić na siebie uwagę (przy okazji wysyła maila do administratora, ale u nas to nie występuje...). Podobno występuje to wtedy, gdy błąd taki nie zostanie obsłużony przez aplikację, co w naszym przypadku jest o tyle dziwne, że podobno przecież Django obsługuje wszystkie wyrzucone wyjątki przy użyciu odpowiedniej dla typu wyjątku funkcji.

Co ciekawsze, okazało się, że najnowsza wersja Flup-a (1.0) nie zawiera już tego middleware, więc gdyby się okazało, że Django bez problemu działa z tą wersją, to może oznaczać tylko głębokie problemy z naszą konfiguracją na styku mod_fastcgi i Django.

Cache obiektów w Django - jak się nie zgubić?

Zdarza się tak, że domyślny sposób buforowania, używany przez Django (buforowanie całych stron, buforowanie całego serwisu) nie wystarcza i trzeba buforować pojedyncze obiekty lub ich listy. Gdy się już zacznie, trudno jest przestać i wtedy okazuje się, że nie sposób dojść do tego, pod jakim kluczem co jest zbuforowane. Sytuacja komplikuje się dodatkowo, gdy używa się memcache, a już całkiem, gdy w buforze trzyma się dane sesji. Najłatwiej byłoby zrestartować memcached, ale przecież polecą sesje użytkowników... Zaczyna się gorączkowe szukanie klucza i strzelanie w ciemno, ale to naprawdę głupiego robota, bo klient memcache zawsze zwraca 1, gdy nie wystąpi żaden krytyczny błąd. Rozwiązaniem byłoby przejrzenie listy kluczy (np. przeiterowanie przez nie), ale czegoś takiego nie ma.

Wpadłem na pomysł prostego rejestru kluczy w postaci zbioru (set). Zdaje się to działać na tym serwisie (który jest trochę poligonem...), a jak działa w naprawdę dużym serwisie, to się dopiero okaże jutro, jak sprawdzę to w pracy. Na razie jestem dobrej myśli, bo idea zdaje się nie mieć słabych punktów... ;)

Wartości domyślne zdają się nie być tym, czym są...

Subtelna różnica, która może okazać się zdradliwa… Gdy definiuje się wartość domyślną dla któregoś z atrybutów modelu w Django, jest ona ustawiana w momencie kompilowania modułu. Niepotrzebna para nawiasów w tym miejscu spowoduje, że zamiast wyniku wywołania jakiejś funkcji w momencie tworzenia egzeplarza klasy, wstawiona zostanie stała wartość, obliczona w momencie kompilacji modułu (czyli najczęściej przy uruchomieniu aplikacji). Warto jest się zastanowić, czy właśnie tego się chce, bo default=datetime.datetime.now daje inny wynik, niż default=datetime.datetime.now().

Web3.0? Nie, dziękuję.

Spotkałem się w niedzielę z pewnym człowiekiem… Zaproponował mi wzięcie udziału w dużym, celującym wysoko międzynarodowym projekcie serwisu, oczywiście nie za darmo. Sama propozycja bardzo mile podłechtała moją próżność (podobnie jak kilka miesięcy wcześniejsza propozycja wzięcia udziału w rekrutacji do Google), więc bardzo się nie opierałem przed osobistym spotkaniem, pomimo tego, że miało ono nastąpić w sobotę lub w niedzielę. Katalizatorem dobrego nastawienia do propozycji było to, że człowiek ten przyjechał specjalnie w niedzielę z Krakowa, żeby spotkać się ze mną i z jeszcze jedną osobą z nieodległej firmy (technologicznie i geograficznie), którą też chciał w ten projekt wciągnąć. Umówiliśmy się na 17:00 w Złotych Tarasach, żeby omówić projekt i kilka wstępnych ustaleń.

Człowiek okazał się bardzo miłym młodzieńcem, naprawdę zapalonym do swojego pomysłu. Przedstawił swoją wizję dość klarownie, jednak próba pokazania mi działającego dema zakończyła się katastrofą i nie zobaczyłem nic, oprócz strony z debugiem błędu w Django. Pierwsze skojarzenie, jakie mi się nasunęło, to katastrofa, której doznaliśmy w lipcu, gdy próbowaliśmy pokazać klientowi aplikację na Węgrzech—wtedy przez 5 minut było OK, ale potem wszystko zaczęło się walić. Tutaj nie było nawet tych pięciu minut, co przy założeniu, że aplikacja ma być gotowa za miesiąc, oznaczać może tylko jedno—stan aplikacji jest bardziej niż niepokojący. Z innych rzeczy pozaproduktowych, kwestię finansową przemilczę, bo moja matka twierdzi, że przewróciło mi się w głowie i straciłem kontakt z rzeczywistością. Wystarczy że napiszę, że nie miałbym lepiej, niż mam teraz.

A teraz o samym produkcie. Nie poruszyła mnie jego idea. Być może jestem za stary na takie gwizdki, być może przez cały czas myślę jak człowiek z trzeciego świata, ale faktem jest, że nie poruszyła mnie wizja milionów ludzi płacących po $10 rocznie za coś, co tylko podbudowuje ich ego. Bardzo możliwe, że w ten sposób działają nastolatki, bardzo też możliwe, że postępujące otumanienie społeczeństw konsumpcyjnych idzie w parze z zatrzymaniem rozwoju mentalnego na poziomie nastolatków. Wiem, że można na tym robić pieniądze (vide przykład MySpace czy Facebook) i to nawet ogromne, jednak nie przekonuje mnie to. Wydaje mi się, że na długi czas zatrzymałem się na poziomie Web1.0 i z dużym trudem doszlusowałem do poziomu Web2.0, nie połykając go w całości jak leci, a jedynie przyswajając sobie kluczowe idee. Z każdą kolejną iteracją główna idea internetu wydaje mi się odchodzić w kierunku coraz głębszego autyzmu, a projekt przedstawiony przez tego człowieka wydaje mi się tak autystyczny, że bardziej już nie można. Więcej o filozoficznych podstawach mojego poglądu na rozwój internetu pewnie jeszcze kiedyś napiszę.

Konkudując w skrócie, mam jeszcze kilka godzin na zastanowienie się, ale nie przypuszczam, żeby cokolwiek było w stanie zmienić moją decyzję. Nie wchodzę w to.

Trzy kolory

Jeśli edytor, to wiadomo: Vim. A jeśli pisanie w nim kodu, to wiadomo, co jest jedną z podstaw: podświetlanie składni tak, żeby wszystko było dobrze widoczne, a jednocześnie w takim zestawie kolorów, który nie męczy oczu, nawet wtedy, gdy trzeba patrzeć w ekran po kilka godzin. W takich przypadkach wygrywają zestawy raczej mało kontrastowe i raczej te z ciemnym tłem. Oto trzej moi faworyci, w kolejności niekoniecznie przypadkowej:

  • oceandeep, utrzymany w zielono-niebieskiej tonacji, prawie bez mankamentów;
  • desert, brązowo-beżowy, cokolwiek nudny, ale bardzo spokojny;
  • zenburn, faworyt wielu, dla mnie trochę więcej niż akceptowalny, jakoś nie przekonuje mnie aż tak niski kontrast, ale czasem (szczególnie późno w nocy) jest ukojeniem dla oczu.

Pali się, moja panno

Ja muszę być jakimś fanatykiem, czy innym zboczeńcem… Kiedy kilka tygodni temu zastanawialiśmy się z moim PM-em, czy mam zająć się nowym projektem, czy może pozostać w obecnym i trzymać go za mordę, sam zaproponowałem, że zostanę, bo znam go dobrze i szkoda byłoby marnować taki kawał wiedzy. Teraz mam za swoje—na trzech instancjach produkcyjnych ciągły pożar, w planie rozwoju dwa duże kawały kodu do napisania, a ja spędzam większość czasu robiąc jako administrator i release manager jednocześnie, z otwartymi kilkunastoma sesjami SSH.

Ale spoko, jest dobrze. Większość kodu to Python + Django, więc i tak jest lepiej, niż w Generali. Pod względem ilości pracy sytuacja tam była dość luksusowa, ale co to była za praca… ;)