KomodoEdit i Pyflakes

Ponieważ PIDA zaczęła mnie wkurzać (co chwilę a to coś działa, a to nie działa), postanowiłem dać szansę KomodoEdit, mocno okrojonej, ale darmowej wersji niezłego Komodo IDE. Ponieważ mój nowy lapek ma 2GB RAM na pokładzie i mocny, dwurdzeniowy procesor, żerność Komodo nie była aż tak wielkim problemem jak dawniej. Obejrzałem dokładnie program i zacząłem zastanawiać się, jak do niego dołączyć to, do czego przyzwyczaiła mnie PIDA, to znaczy integrację z Pyflakes. Dla niezorientowanych: Pyflakes to program do statycznej analizy poprawności kodu Pythona, nieco mniej zaawansowany niż Pylint, jednak jednocześnie nie aż tak inwazyjny (oczywiście wiem, że Pylinta można tak skonfigurować, żeby nie sprawiał wrażenia faszystowskiego narzędzia).

Jak się szybko okazało, nie ma możliwości podpięcia Pyflakes tak, by uruchamiało się przy każdym zapisie bufora, jak dzieje się to w PIDA, jednak dla mnie ważniejsze było to, żeby działało, niż to, żeby działało identycznie. Postanowiłem przypiąć Pyflakes jako narzędzie zewnętrzne w Toolboksie Komodo. Oto skrócona recepta, jak to zrobić, żeby działało ładnie i produkowało fajne wyniki.

  1. Toolbox -> Add -> New Command
  2. Command (U): /usr/bin/pyflakes %F
  3. Run in: "Command Output Tab"
  4. [*] Parse output with: ^(?P<file>.+?):(?P<line>\d+): (?P<content>.*)$
  5. [*] Show parsed output as a list

A teraz opis słowno-muzyczny. Z menu Toolbox wybierz Add i następnie z podmenu New Command. Na zakładce Command w nowo otwartym okienku w pole Command wpisz polecenie uruchomienia Pyflakes ze ścieżką bieżącego bufora (u mnie: /usr/bin/pyflakes %F). Z listy Run in wybierz Command Output Tab. Zaznacz pole Parse output with i w pole polecenia parsującego wpisz wyrażenie regularne ^(?P<file>.+?):(?P<line>\d+): (?P<content>.*)$, które podzieli wyjście Pyflakes na 3 części. Zaznacz pole Show parsed output as a list, a Komodo wyświetli wyniki w postaci ładnej listy z 3 kolumnami — dwukrotne kliknięcie na każdej pozycji listy przeniesie kursor do odpowiedniej linii w edytorze.

Po tym wszystkim pozostaje jedynie przypisanie do tego jakiegoś wygodnego skrótu klawiszowego w tym samym okienku na zakładce Key Binding.

Archiwum is back

Poprawiono najbardziej denerwujący mnie błąd w Django z ostatnich czasów i dzięki temu wróciło archiwum. Oh, my...

Sława, sława!

http://oebfare.com/blog/2008/jun/24/django-code_swarm/

Około drugiej minuty, w prawym górnym rogu...

Zmiana planów w ostatniej chwili

Dosłownie w ostatniej chwili zdecydowałem się na zmianę dostawcy hostingu na djangohosting.ch, pomimo że byłem zdecydowany na coś innego. Po sugestii Thomasa (dzięki!) przyjrzałem się usłudze dokładniej i postanowiłem dać szansę. Wykupiłem najtańszą opcję, wypróbowałem one-click-django-installer i oczywiście zameldowałem się po SSH. Już pierwsze pół godziny sesji przekonało mnie, że jest tam o wiele przyjemniej niż na Alwaysdata — nie ma żadnych myków z przestawianiem $HOME, no i zwiększanie opcji jest bardziej granularne (oddzielnie procesy, porty, pamięć i przestrzeń dyskowa), a cała infrastruktura w dużej mierze przypomina to, co jest na MegiTeam.pl, z paroma udogodnieniami:

  • można uruchomić serwer developerski django i w razie problemów mieć dostęp do pełnego tracebacka;
  • pełna kontrola nad uruchamianiem FastCGI;
  • łatwiejszy dostęp do logów Lighttpd (chociaż jest w nich równie mało, jak w logach nginxa na megiteam).

Ogólnie wygląda to bardzo dobrze, a przy tym jest trochę taniej.

Sztuczny tłok

Dużo się ostatnio dzieje w Django — co chwilę ktoś commituje zmiany do repozytorium i można odnieść wrażenie, że opublikowanie daty wydania wersji 1.0 obudziło w developerach nowy zapał i chęć do posprintowania na zakończenie wyścigu.

To mylne wrażenie. Przytłaczająca większość pojawiających się w repozytorium zmian to są poprawki w dokumentacji, w docstringach oraz style fixes. A kod poprawiający rzeczywiste problemy czeka sobie na lepsze czasy.

Ten wpis był tytułem ochłodzenia emocji, gdyby ktoś widząc tempo commitów wnioskował z tego, jak dużo i szybko kod w Django jest poprawiany... ;)

Zdecydowałem się na dostawcę

To był tydzień pełen przemyśleń, ale w końcu doszedłem do jakichś wniosków. Mój najbliższy projekt będę hostował na Alwaysdata. Co prawda całość serwisu jest po francusku, ale jakoś daję sobie z tym radę.

Ujęło mnie to, że jest:

  • tanio (€ 6 za miesiąc w najtańszej opcji);
  • dobry support na forum (po angielsku!);
  • dość duża wolność, jak na shared plan;
  • krótki ping, serwery stoją w OVH w Roubaix (Francja).

W związku z małą ilością dostępnego miejsca na dysku, będę musiał media i uploady na S3, ale nie powinno być to jakoś szczególnie uciążliwe.

Konkurent (djangohosting.ch) przegrał głównie przez zerowy wybór w dziedzinie bazy danych (tylko MySQL, bez PostgreSQL), ale nie była to przegrana autorytatywna. Dam mu szansę następnym razem. ;)

Zdrada? To się dopiero okaże...

No i będę miał w pracy MacBooka. Niby zwykłego, ale tak nie do końca, bo czarnego. Nigdy nie miałem Maca, nigdy też go nie używałem, więc zacząłem od czytania, co też mnie czeka po przesiadce z linuksa. Nie zapowiada się różowo, głównie z powodu problemów z bibliotekami. Ale może jakoś to przeżyję...

Cierpię

Po raz kolejny cierpię, jak za każdym razem, gdy muszę zmontować jakiś layout dla serwisu. W tej dziedzinie mam dwie lewe ręce i zezowate oko, więc staram się (przynajmniej na początku) znaleźć coś gotowego. I ciągle mam ten sam problem — szablony które udaje mi się znaleźć mają w większości ustaloną szerokość circa about 800px, czasem pomijalnie większą. To jest rzecz, która dyga mnie za każdym razem, jak potrzebuję wygrzebać jakiś gotowy szablon: przytłaczająca większość szablonów jest robiona na fixed width, przez co masa przestrzeni się marnuje. Nie wspominając o tym, że wszystkie wyglądają jak odbite z jednej matrycy z niewielkimi zmianami.

Nie chce mi się już robić we webie.

Przede mną tydzień urlopu

Po miesięcznym zapieprzu związanym z zakończeniem kontraktu na aplikację, wziąłem tydzień wolnego od firmy. Zamierzam nie myśleć o pracy i zajmować się swoimi sprawami, w swoim tempie. Nie wiem jeszcze, co będę robił, niczego nie planuję. Jest wiele rzeczy, które mam ochotę zrobić — chcę sobie trochę poczytać, przećwiczyć parę sztuczek z javascriptem, może napisać trochę kodu na własne potrzeby.

Patch applied

W pracy używamy kilku różnych bibliotek third-party. W ogniu walki często okazuje się, że mają one jakieś mankamenty, albo brakujące funkcjonalności, od których zależy działanie naszej aplikacji. Czasem kończy się to zgłoszeniem błędu, ale częściej razem ze zgłoszeniem dostarczamy poprawkę. Czuję się szczególnie doceniony, gdy moja poprawka trafia do upstream — mam wtedy megalomańskie uczucie, że dzięki mnie świat staje się lepszy. Chociaż w niewielkim zakresie... ;)

jQuery mi się podoba

Po raz kolejny zastrzegam: to nie jest miłość (bo miłość może być tylko jedna). Ale jQuery mi się podoba.

Dzisiaj miałem zrobić taki pokręcony formularz z trzema select-ami, gdzie środkowy przyjmuje elementy z dwóch naokoło niego na kliknięcie. Biorąc pod uwagę moją niechęć (i co tu dużo ukrywać, nieznajomość też) do JavaScriptu, planowałem sobie to na co najmniej dzień roboty, a najprawdopodobniej półtora. Tymczasem usiadłem do roboty około 10, a o 12 miałem już to zrobione. 35 linijek kodu i żadnego znużenia. Więcej takich ułatwiaczy poproszę.

To dziwne czasy

Gdy kilkanaście lat temu zaczynałem pisać programy o nieco większym stopniu skomplikowania, obowiązującą mantrą było: przerzuć obliczenia na serwer bazy danych, on ma więcej mocy niż aplikacja. Stąd wzięły się wszystkie moje umiejętności optymalizacyjne, które dobrze robiły przez wiele lat. A teraz dowiedziałem się od naszego bazodanowca, że muszę chronić serwer przed przegrzaniem i jak najwięcej robić na serwerze aplikacyjnym, bo... serwer z bazą nie wyrabia.

Mam dysonans poznawczy. Wolałbym, żeby okazało się, że z powodów oszczędnościowych firma postawiła bazę na jakimś Celeronie 1.7GHz z 256MB RAM, niż że moje umiejętności optymalizacyjne nadają się do lamusa... ;)

Pasanie owieczek

Po ponad roku pracy z młodzieżą zebrało mi się na kilka refleksji dotyczących całej branży robienia softu. Raczej przygnębiających.

Po pierwsze, i najważniejsze, większość z programistów przed 30-tką, jakich spotkałem w ciągu tego roku, nie ma pojęcia o projektowaniu aplikacji. Umieją napisać kod, który robi to, co założyli, ale zazwyczaj cała aplikacja nie robi tego, co miała robić. Ich horyzont widzenia kodu zamyka się w jednym, najwyżej w dwóch modułach, więc każda większa zmiana skutkuje zwykle załamaniem się innego fragmentu aplikacji. A o czymś takim, jak zastanawianie się nad konsekwencjami zmian w kodzie zwykle sobie nie pozwalają. Powiedziałbym ogólnie, że myślenie nie jest ich najmocniejszą stroną, albo inaczej — są świetni w rozwiązywaniu problemów, które sami sobie stworzyli (by sparafrazować Kisiela). I to jest ta przygnębiająca konkluzja.

Przyczyna tego stanu rzeczy wydaje się leżeć głębiej, a jest ona chyba jeszcze bardziej przygnębiająca. Otóż, według mnie, głównym czynnikiem, który sprawia, że młodzi programiści nie dojrzewają do projektowania aplikacji, jest nacisk managementu na to, żeby jak najszybciej dostarczyć działający kod, byle by był. Management żyje w świecie złudzeń (podtrzymywanych przez samych programistów), jakoby zawsze można było poprawić źle działający kod później, ale z drugiej strony, żeby się z tych złudzeń wyleczyć, to trzeba napisać sporo kodu, którego nikt nigdy nie poprawił z powodu braku czasu. Autor nie poprawi, bo nie ma kiedy (zajmuje się przecież czymś innym, również na już), a jego następca też nie poprawi, bo kodu nie rozumie (autor mu nie wytłumaczy, bo nie ma czasu, zresztą prawdopodobnie sam już nie pamięta).

I co teraz? Założę się, że nic, będzie tak, jak poprzednio.

JavaScript może czuć się przeproszony

Nigdy nie lubiłem JavaScriptu. Syntaktycznie mi się ten język nie podobał, jego idea wydawała mi się poroniona (co najmniej), a różnice w implementacjach przez różne platformy zwyczajnie dyskredytujące. Tym niemniej zapoznałem się z nim przynajmniej na tyle, żeby znać go z widzenia. Ogólnie konieczność pisania kodu w JavaScripcie napawała mnie obrzydzeniem.

Do niedawna. Bo niedawno wypatrzyłem jQuery i całe moje podejście do JavaScriptu zmienniło się diametralnie. Miłością nie zapałałem (bo miłość może być tylko jedna), ale polubiłem JavaScript. Dziękujemy Ci, jQuery!

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. ;)

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.

Walki z SuSE (open) ciąg dalszy

Do pisania aplikacji w Django ten system się raczej nie nadaje — nie ma w nim całej masy bibliotek, a przede wszystkim nie ma psycopg.

Kicha.

Topre, topre

Some people would argue that not all developers are morons or assholes, but they are mistaken. For example, some people posit the existence of what I will call the “angel” developer. “Angels” read specs closely, write code, and then thoroughly test it against the accompanying test suite before shipping their product. Angels do not actually exist, but they are a useful fiction to make spec writers to feel better about themselves

(za diveintomark)

Po raz kolejny porażka

Nie pamiętam już ile razy przysiadałem (w celach czysto edukacyjnych, aby zrozumieć jak to działa) do zrobienia sobie wielokolumnowego układu dokumentu HTML, z kilkoma wymaganiami, które zdają się obecnie wykluczać:

  • kolumna główna o szerokości względnej, dopasowującej się do wielkości okna przeglądarki;
  • kolumny boczne o stałej szerokości, wyrażonej w jednostkach em;
  • kolumna główna zdefiniowana w kodzie HTML jako pierwsza;
  • bez gremlinów w typie poziomego paska przewijania w IE6;
  • i jak najmniej boilerplate (niestrukturalnych div-ów).

Nie ma tego wiele. Co jakiś czas przeglądam to, co znajduje mi Google, ale wciąż powtarzają się te same triki: a to kolumny boczne trzeba definiować jako pierwsze, a to nie da się ustalić ich szerokości, a to znowu coś innego. A jeżeli znajduję gdzieś gotowy, działający szablon, to jego kod jest tak pogmatwany, że tylko łapię się za głowę.

Jak dla mnie, dowodzi to tylko jednego: CSS, choćby nie wiem jak był użyteczny w innych dziedzinach, w obecnej postaci do tworzenia układów stron się nie nadaje. Gdy tylko chce się wyjść poza ustawianie wielkości czcionki, obramowania elementu czy koloru tła, okazuje się, że używanie do tego celu CSS przypomina dokręcanie śrubek przy użyciu łyżki. Ktoś mógłby argumentować, że web to nie gazeta i kolumny są wbrew naturze WWW, ale w takim razie oznaczałoby to tylko jedno: że WWW nie nadaje się do użycia sterowanego zapotrzebowaniem. Bo ewidentnie potrzeba dzielenia treści na kolumny istnieje, a wręcz ze zwiększaniem się rozdzielczości monitorów ta potrzeba staje się coraz bardziej naoczna.

Więc co? Flash? Dopiero Flash to nie jest web (gdzie tu dokument, połączony z innymi dokumentami systemem dowiązań?). Czekam od kilku lat na rozwiązanie tego problemu w sposób kompleksowy, pewnie będę czekał jeszcze długo, i wszystko wskazuje na to, że się nie doczekam.

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.

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

Jakiś problem z Akismet

Akismet robi jakieś hocki-klocki, gdy w komentarzu wpisuje się link do strony z plikami listy mailowej WARPY. Trzeba będzie to zbadać.

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. ;)

Gdybym mógł wybierać...

Jest kilka firm, w których chciałbym pracować. Na poniżej liście nie ma mojego obecnego pracodawcy, bynajmniej nie dlatego, że nie chcę już pracować w Sensisofcie, ale dlatego, po pierwsze jest to lista marzeń, a nie planów, a po drugie, gdybym tam nie chciał pracować, to już bym nie pracował.

  1. Google. To oczywiste. Każdy programista czy projektant chciałby pracować w Google, a ja nie jestem w tej dziedzinie wyjątkiem. Ta firma robi rzeczy wielkie, coś na miarę projektu Manhattan, ale w skali oprogramowania. Chciałbym (chociaż przez pewien czas) być jednym z nich.
  2. Xerox. Dziwnym może się wydać umieszczenie firmy Xerox już na drugim miejscu, bo dla większości ludzi oblatanych w IT kojarzy się ona z kopiarkami, potwornie drogimi drukarkami, a dla niektórych także z niezwykle innowacyjną historią Palo Alto Research Center (Xerox PARC). Jest jednak coś innowacyjnego w tej firmie także i dziś, ale niewiele osób o tym wie, bo jej najbardziej innowacyjne produkty mają wąskie grono odbiorców, jak np. VIPP. Poznałem VIPP dość dobrze i doceniłem jego klasę.
  3. Canonical. Robienie na linuksie jest dla mnie teraz tak oczywiste, że trudno mi sobie wyobrazić, że mógłbym w pracy używać innego systemu operacyjnego, a w dzisiejszych czasach coraz częściej jest tak, że mówisz linux, myślisz Ubuntu.
  4. IBM, Sun i Microsoft, ex aequo. Każda z tych firm robi ciekawe rzeczy, choć te, które mnie naprawdę interesują, stanowią margines ich działalności. Gdyby udało mi się popracować przy tych ciekawych rzeczach, to czemu nie?

Jak widać, nie ma tego szczególnie wiele. Jedyną nieoczywistą pozycją w tym zestawieniu wydaje się być Xerox, więc może jednak zostanę w Sensisofcie... ;)

Nowe na megiteam.pl

megiteam.pl (gdzie hostowany jest ten skromny serwis) wprowadziło w ramach nowości rozliczanie za używaną pamięć, zamiast rozliczania za procesy. Lepiej? Gorzej? Nie wiem, jak dla mnie to chyba drożej, bo drugą aplikację uruchomić będzie mi trudno (w sumie zostało mi ze 20MB pamięci, więc nawet na małego memkesza mi nie wystarczy), musiałbym sobie dodać jeszcze ze 20MB pamięci, a te aplikacje, które teraz powstają mają trochę większe oczekiwania, więc raczej pozastanawiam się jeszcze trochę nad dedykiem w hetzner.de.

Swoją drogą, ciekawe jest orientacyjne zestawienie, ile która ramówka potrzebuje dla aplikacji...

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!)...

Kolory się mienią

Sprawdzanie schematów kolorów do Vima bywa męczące. Czasem nawet bardzo. Dlatego strona, na której można zobaczyć kilkaset schematów w działaniu na raz, może być zbawieniem. Szkoda tylko, że nie można obejrzeć tam kodu w Pythonie, to by mi najbardziej ułatwiło życie...

Trick do Vima, który zmienia życie

Długo szukałem, aż wreszcie znalazłem. Jak zmieniać colorscheme w zależności od typu pliku i to tak, żeby działało to również przy przełączaniu między buforami z plikami różnego typu?

"colorschemes based on file type
augroup ColorSchemeOnFileType
    autocmd!
    autocmd BufEnter * if(&ft == 'htmldjango') | colorscheme oceandeep | else | colorscheme django | endif
augroup END

Udało się wreszcie... A już zaczynałem być zdesperowany. ;)

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

Już zapomniałem jak to jest...

Family going to bed at 10 PM is so much worse than jet lag.

Kiedyś było to dla mnie dość normalne... Czyżby dopadała mnie nostalgia za kawalerskimi czasami? ;)

Wygląd tego wpisu przekonuje mnie, że czym prędzej muszę się rozejrzeć za jeszcze szerszym szablonem, bo mi sie stripy z XKCD nie mieszczą...

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!

Rzeczy proste, rzeczy skomplikowane

Kiedyś o tym ktoś już napisał (może Joel Spolsky, a może ktoś inny, nie mogę sobie przypomnieć). A teraz dotknęło to mnie osobiście.

Są rzeczy proste i są rzeczy skomplikowane. Naturą rzeczy prostych jest to, że łatwo jest ich używać (my to nazywamy, że mają prosty interfejs). Są jednak także rzeczy, które są skomplikowane same z siebie. A jak jest z ich używaniem?

Podobnie jak z rzeczami prostymi, rzeczy skomplikowane są... skomplikowane w użyciu. Rzeczy skomplikowane mają skomplikowany interfejs właśnie dlatego, że ze swej natury są skomplikowane i ich funkcji nie da się wyrazić w sposób uproszczony. Można to porównać do dwóch narzędzi, które służą do wyciągania gwoździ: obcęgów i tzw. łapki. Obcęgi są dość skomplikowanym narzędziem, które spełnia kilka funkcji (na kilka sposobów), więc jego interfejs jest nieco bardziej skomplikowany, niż łapki. Oczekiwanie, że obcęgi będą miały prostszy interfejs, doprowadzi do degeneracji obcęgów do poziomu łapki. Podobnie, nikomu nie wpadnie do głowy, by żądać od 50-tonowej lokomotywy, by miała interfejs Hondy Civic.

A teraz zdążam na skróty ku poincie. Dużo ludzi uważa, że zadaniem nas, czyli developerów, jest zapewnianie prostego interfejsu. Abstrahując od tego, że jest to piramidalną bzdurą, jest to także niemożliwe. Rzeczy skomplikowane nie mogą mieć prostego interfejsu, dopóki są skomplikowane. I nie będą miały prostszego interfejsu, dopóki będą realizować skomplikowane funkcje w skomplikowany sposób. A takie działanie jest chyba immanentne dla aplikacji webowych...

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.

Platforma dla programisty

Używam linuksa (jak to się teraz modnie mawia: lennoxa) od wielu lat. Od wielu lat słyszę, jakoby system był nieprzyjazny, nieintuicyjny i wiele innych nie na jego temat. Nie będę się teraz rozpisywał, jak to z gruntu fałszywe są to opinie (bo mam jeden dowód na to w domu w postaci żony i drugi w bloku naprzeciwko w postaci mojej matki). Są jednak tacy ludzie, dla których linux jest jedną z najbardziej przyjaznych platform.

Programiści.

Niezliczone ilości narzędzi (darmowych!), biblioteki do prawie każdego zadania i języka, jakie tylko można sobie zamarzyć. Kod źródłowy, który może służyć za przykład, nie zawsze najwyższej jakości, ale przecież jest. Żyć nie umierać, tylko pisać kod. Nie powiem, pisałem programy na własne potrzeby i dla własnej przyjemności także i wtedy, gdy używałem najpopularniejszego systemu operacyjnego, ale zawsze było to trochę utrudnione — a to nie działało to czy tamto, a to jakiejś biblioteki nie było sportowanej, a zdarzały się dziwne zachowania programu wynikające z idiosynkrazji tego innego systemu operacyjnego.

A najgorsze było to, że Vim działał jakoś dziwnie na tym całym Windows®...

Ü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.

Budzi się pragnienie

Powoli budzi się we mnie pragnienie (a może i potrzeba) wymiany laptoka na nową sztukę. Mój obecny HP nx6110 z najniższej półki wciąż jeszcze mi dobrze służy (chyba przede wszystkim dlatego, że mam niewielkie wymagania...), ale zaczynam już odczuwać potrzebę poprawienia mojej sytuacji życiowej. Lepsze jest wrogiem dobrego, a już na pewno jest wrogiem słabego.

  • 15' matryca mojego HP jest chyba jedną z najgorszych, jakie były produkowane dwa lata temu; wiem, że są gorsze (mają je np. najtańsze Acery z tamtego okresu), ale wcale nie zmienia to faktu, że kolory odwzorowuje tragicznie, szczególnie na bitmapach;
  • procesor Celeron-M360J (1.4GHz) nie jest demonem prędkości i nie ma co się nad tym rozwodzić;
  • dysk 40GB dawno już został zapełniony i muszę się posiłkować dodatkowym dyskiem podłączanym przez USB;
  • 3 kilogramy na ramieniu potrafią przygiąć do ziemi każdego.

Nie za bardzo mam ochotę kupować sobie MacBooka, wolałbym jakieś fajne HP z matrycą 13.1'... Ale takich nie ma. Przynajmniej na moją kieszeń.

W każdym razie, i tak muszę poczekać do przyszłego roku. Obiecałem, że w tym roku nie kupię sobie komputera...

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... ;)

Są pewne plusy

National Blog Posting Month to idiotyzm, ale dzięki temu James Bennet dzieli się z czytelnikami swoją bezcenną wiedzą na temat Django w tempie jednego postu dziennie. Warto sobie dopisać gdzie trzeba i śledzić.

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.

Duma i niezadowolenie

Zawsze mnie zastanawiało, skąd się biorą badziewne serwisy WWW, zrobione na zasadzie prawie jak…, po których natychmiast widać, że są marną podróbką czegoś-tam. Wydawało mi się, że pomimo różnic w przymiotach intelektualnych (nie, nie jesteśmy sobie równi pod tym względem), istnieje pewien minimalny poziom dobrego smaku połączony z minimalnym poziomem rozsądku, którym posługuje się przytłaczająca większość ludzkości i takie wpadki nie są wynikiem celowego działania, bo przecież nikt specjalnie nie strzelałby sobie w stopę. No i właśnie niedawno doznałem zderzenia z rzeczywistością. Nie ma czegoś takiego. Zasada wydaje się prosta—jeżeli jest jakaś głupota, której klient może sobie zażyczyć, to sobie zażyczy. Można próbować mu wyperswadować taki pomysł, można próbować podsuwać mu rozsądne rozwiązania, które zmniejszą poziom głupoty jego propozycji, ale trzeba założyć, że skutek tego będzie żaden. W dodaku, raz wszedłszy na ścieżkę produkcji g*wna, nie da się z niej zejść tak łatwo i dodawanie kolejnych ficzerów powoduje tylko narastanie tej sterty. W takim przypadku trzeba się cofnąć o te kilka kroków, naprawić popełnione wcześniej błędy (najczęściej przez usunięcie tego, co kontrowersyjne) i dopiero wtedy można mówić o uwolnieniu się.

Jestem rozgoryczony, to prawda. Niewiele brakowało, a byłby serwis WWW, którym mógłbym się pochwalić znajomym i być z niego dumny na zasadzie jam ci to sprawił. I g*wno. Z powodu idiotycznych żądań klienta musieliśmy zrobić z niego koszmarek i nie dało się tego wyperswadować, nie dało się też przekonać klienta do naszych propozycji. Patrząc od strony biznesowej wszystko niby jest w porządku, pieniądze przepłynęły z jednego konta na drugie, klient jest zadowolony, firma jest zadowolona—ale ja nie jestem. Przez cały czas mam wrażenie, że przyłożyłem rękę do produkcji szajsu. którego jeszcze długo będę się wstydził, bo przecież nikogo tak naprawdę nie interesuje, ile włożyłem w to zaangażowania i pracy, przecież tak naprawdę liczy się efekt końcowy. W tym przypadku—opłakany i jest to oczywiste dla każdego, kto w internecie spędza trochę więcej czasu, niż trzeba na przejrzenie newsów na BBC, CNN czy Onecie. Pół roku pracy bez efektu, z którego można być zadowolonym już raz doprowadziło do tego, że zmieniłem pracę (a warunki na rynku pracy wtedy były znacznie gorsze niż teraz). Niestety, po około 10 latach pracy w branży nie spodziewam się, by gdziekolwiek sytuacja przedstawiała się lepiej. No, może tylko w Google, ale też pewien nie jestem…

A co gorsza, utknąłem w tym szajsie na dobre, trochę przez swoje wcześniej wspomniane zaangażowanie, a trochę z powodu braku zasobów. Pociesza mnie tylko to, że to wciąż Python.

More power to the people

Będąc code junkie (jak o nas mawiają marketoidy), nie mogę się powstrzymać, żeby czegoś nie ulepszyć (co wcale nie jest zepsute). Przyszło mi do głowy, że mógłbym poćwiczyć z OpenID, więc należy się spodziewać, że wkrótce gdzieś na stronie pojawi się charakterystyczny symbol i posiadacze OpenID będą mogli się wcielić w jakąś specjalną rolę w serwisie. Jeszcze nie wiem jaką, ale będę musiał coś wymyślić, żeby wynagrodzić im wszystkie trudy… ;)

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.