<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/css" href="/stylesheets/rss.css"?>
<rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/">
  <channel>
    <title>Jaros&#322;aw Zabie&#322;&#322;o - BLOG: Tag django</title>
    <link>http://blog.zabiello.com/articles/tag/django</link>
    <language>en-us</language>
    <ttl>40</ttl>
    <description>moje notatki, linki, komentarze</description>
    <item>
      <title>Passenger bli&#380;ej - Rails, Rack i WSGI</title>
      <description>&lt;p&gt;Stworzony pierwotnie na u&#380;ytek Rails, aktualnie mod_passenger ju&#380; obs&#322;uguje nie tylko Rails ale tak&#380;e mas&#281; innych framework&#243;w u&#380;ywaj&#261;cych Rack&amp;#8217;a. W &lt;a href="http://tinyurl.com/6edmve"&gt;nowej dokumentacji&lt;/a&gt; wymienione s&#261; frameworki: &lt;a href="http://code.whytheluckystiff.net/camping"&gt;Camping&lt;/a&gt;, &lt;a href="http://halcyon.rubyforge.org/"&gt;Halcyon&lt;/a&gt;, &lt;a href="http://www.mackframework.com/"&gt;Mack&lt;/a&gt;, &lt;a href="http://merbivore.org/"&gt;Merb&lt;/a&gt;, &lt;a href="http://ramaze.net/"&gt;Ramaze&lt;/a&gt; i &lt;a href="http://sinatrarb.com/Home"&gt;Sinatra&lt;/a&gt;. W dokumentacji nie wymieniono jeszcze &amp;#8220;drugiej listy&amp;#8221;, zawieraj&#261;cej frameworki korzystaj&#261;ce z &lt;a href="http://www.wsgi.org/wsgi"&gt;&lt;span class="caps"&gt;WSGI&lt;/span&gt;&lt;/a&gt; i Pythona (np. &lt;a href="http://pylonshq.com/"&gt;Pylons&lt;/a&gt;, &lt;a href="http://djangoproject.com"&gt;Django&lt;/a&gt;, &lt;a href="http://turbogears.org/"&gt;TurboGears&lt;/a&gt; itp.). Chc&#261;c sprawdzi&#263; plotki wok&#243;&#322; tej sprawy, sprawdzi&#322;em, czy faktycznie mod_passenger pracuje nie tylko z Ruby, ale tak&#380;e z Pythonem. Sprawdzi&#322;em tak&#380;e jak to jest faktycznie z ob&#322;ug&#261; Rails i framework&#243;w na Rack&amp;#8217;u (tu sprawdzi&#322;em tylko Merba). Sprawdzi&#322;em te&#380; JRuby dla Rails i Merba.&lt;/p&gt;


	&lt;p&gt;Wszystkie testy by&#322;y wykonywane na laptopie MacBook Pro Core 2 Duo, 2.16GHZ, 4GB &lt;span class="caps"&gt;RAM&lt;/span&gt; (OSX 10.5.3 dla tego modelu widzi tylko 3GB) i dyskiem 200GB kr&#281;c&#261;cym si&#281; z szybko&#347;ci&#261; 7200 rpm. Ruby 1.8.6, Python 2.5.2, Apache 2.2.8 (mpm-prefork) by&#322;y instalowane z MacPort&#243;w. Passenger, mimo &#380;e instalowany &lt;a href="http://github.com/FooBarWidget/passenger/tree/master"&gt;ze &#378;r&#243;de&#322;&lt;/a&gt; w Apache&amp;#8217;u by&#322; wy&#347;wietlany jako &amp;#8220;Phusion_Passenger/1.1.0&amp;#8221; (by&#263; mo&#380;e wi&#281;c to nie jest jeszcze ta nowa wersja 2.0 o kt&#243;rej pisa&#322;em &lt;a href="http://blog.zabiello.com/articles/2008/06/04/passenger2-ruby-enterprise"&gt;wcze&#347;niej&lt;/a&gt;) Nie sprawdza&#322;em Linuksa, by&#263; mo&#380;e wyniki i wnioski b&#281;d&#261; wtedy inne.&lt;/p&gt;


	&lt;p&gt;Dla tych co chcieliby sami popr&#243;bowa&#263; podaj&#281; wpierw konfiguracj&#281; serwer&#243;w wirtualnych dla Apache&amp;#8217;a potrafi&#261;c&#261; unie&#347;&#263; razem: &lt;span class="caps"&gt;PHP&lt;/span&gt; (2.5.6), Rails (2.1), Merb (0.9.4 edge), i Django (edge).&lt;/p&gt;


	&lt;h2&gt;Konfiguracja Apache&amp;#8217;a  2.2.8&lt;/h2&gt;


&lt;div class="typocode"&gt;&lt;pre&gt;&lt;code class="typocode_apache "&gt;
# Ruby (Rails):
&amp;lt;VirtualHost *:80&amp;gt;     
  DocumentRoot &amp;quot;/opt/local/apache2/vhosts/rails_app/public&amp;quot;  
  ServerName rails_app
&amp;lt;/VirtualHost&amp;gt;

# Ruby (Merb):        
&amp;lt;VirtualHost *:80&amp;gt;  
  RailsAutoDetect off  
  DocumentRoot &amp;quot;/opt/local/apache2/vhosts/merb_app/public&amp;quot;    
  ServerName merb_app       
&amp;lt;/VirtualHost&amp;gt;

# Python (WSGI):
&amp;lt;VirtualHost *:80&amp;gt;          
  DocumentRoot &amp;quot;/opt/local/apache2/vhosts/wsgi_app/public&amp;quot;    
  ServerName wsgi_app
&amp;lt;/VirtualHost&amp;gt;      

# Django (mod_python)
&amp;lt;VirtualHost *:80&amp;gt;         
  DocumentRoot &amp;quot;/opt/local/apache2/vhosts/djangus/public&amp;quot;    
  ServerName django_modpython 
  &amp;lt;Location &amp;quot;/&amp;quot;&amp;gt;
    SetHandler python-program
    PythonHandler django.core.handlers.modpython
    SetEnv DJANGO_SETTINGS_MODULE djangus.settings
    PythonDebug On        
    PythonPath &amp;quot;['/opt/local/apache2/vhosts'] + sys.path&amp;quot;    
  &amp;lt;/Location&amp;gt;       
&amp;lt;/VirtualHost&amp;gt;   

# PHP:
&amp;lt;VirtualHost *:80&amp;gt;  
  RailsAutoDetect off  
  DocumentRoot &amp;quot;/opt/local/apache2/vhosts/php_app/public&amp;quot;        
  ServerName php_app   
&amp;lt;/VirtualHost&amp;gt;    &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

	&lt;p&gt;Wszystkie aplikacje korzystaj&#261;ce z mod_passengera musz&#261; posiada&#263; folder &lt;code&gt;public&lt;/code&gt; i &lt;code&gt;tmp&lt;/code&gt;. Gdy do katalogu &lt;code&gt;tmp&lt;/code&gt; dorzucimy jakikolwiek (mo&#380;e by&#263; pusty) plik o nazwie &lt;code&gt;restart.txt&lt;/code&gt;, to przy nast&#281;pnym prze&#322;adowaniu przegl&#261;darki nast&#261;pi restart aplikacji.&lt;/p&gt;


	&lt;p&gt;We wszystkich przypadkach u&#380;y&#322;em dosy&#263; banalnego kodu polegaj&#261;cego na wy&#347;wietleniu &amp;#8220;Hello World!&amp;#8221;. Z wynik&#243;w programu &lt;code&gt;ab&lt;/code&gt; wyci&#261;&#322;em nieistotne informacje.&lt;/p&gt;


	&lt;h2&gt;Rails (2.1)&lt;/h2&gt;


	&lt;h3&gt;Rails 2.1 + mod_passenger 1.1.0&lt;/h3&gt;


	&lt;p&gt;Rails obs&#322;ugiwane s&#261; w Passengerze praktycznie bezobs&#322;ugowo. Wystarczy wkopiowa&#263; pliki na serwer i to wszystko.&lt;/p&gt;


&lt;div class="typocode"&gt;&lt;pre&gt;&lt;code class="typocode_bash "&gt;ab -n 1000 -c 1 http://rails/ 
...
Concurrency Level:      1
Failed requests:        0
Write errors:           0
Total transferred:      582000 bytes
HTML transferred:       12000 bytes
Requests per second:    430.20 [#/sec] (mean)
Transfer rate:          244.35 [Kbytes/sec] received

ab -n 1000 -c 4 http://rails/
...
Concurrency Level:      4
Failed requests:        239
   (Connect: 0, Length: 239, Exceptions: 0)
Write errors:           0
Total transferred:      488073 bytes
HTML transferred:       9132 bytes
Requests per second:    520.75 [#/sec] (mean)
Transfer rate:          247.88 [Kbytes/sec] received&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt; 

	&lt;p&gt;Szybko&#347;&#263; nie jest najgorsza, ale niepokoj&#261;ca jest du&#380;a lista b&#322;&#281;dnych request&#243;w w wypadku zapyta&#324; r&#243;wnoleg&#322;ych. Jak si&#281; dalej okazuje, ten problem dotyczy tak&#380;e ob&#322;ugi Rack jak i &lt;span class="caps"&gt;WSGI&lt;/span&gt;. Albo to jaka&#347; specyfika &lt;span class="caps"&gt;OSX&lt;/span&gt;, albo wcale nie jest tak dobrze ze stabilno&#347;ci&#261; mod_passengera dla r&#243;wnoleg&#322;ych zapyta&#324;. Trzeba by by&#322;o te&#380; zbada&#263;, czy ten efekt wyst&#281;puje tak&#380;e dla Linuksa. Zdziwi&#322;bym si&#281; gdyby tam by&#322;o podobnie skoro Dreamhost ju&#380; oferuje hosting z mod_rails&amp;#8230;&lt;/p&gt;


	&lt;p&gt;Dla por&#243;wnania Rails u&#380;ywaj&#261;cy Mongrela, Thin oraz Ebb. Mo&#380;na by pokusi&#263; aby odpali&#263; Ebb i Thina na uniksowych socketach (Ebb te&#380; to ju&#380; potrafi!), ale wtedy musia&#322;bym zestawia&#263; klaster i uruchamia&#263; to przez proxy. Jak kto&#347; chce to niech si&#281; sam pobawi. Dla prostoty u&#380;y&#322;em port&#243;w &lt;span class="caps"&gt;TCP&lt;/span&gt;. Sprawdzi&#322;em te&#380; JRuby.&lt;/p&gt;


	&lt;h3&gt;Rails 2.1 + Ebb 0.2.0&lt;/h3&gt;


&lt;div class="typocode"&gt;&lt;pre&gt;&lt;code class="typocode_bash "&gt;ebb_rails -e production start

ab -n 1000 -c 1 http://127.0.0.1:3000/
...
Concurrency Level:      1
Failed requests:        0
Write errors:           0
Requests per second:    488.95 [#/sec] (mean)

ab -n 1000 -c 4 http://127.0.0.1:3000/
..
Concurrency Level:      4
Failed requests:        0
Write errors:           0
Requests per second:    533.22 [#/sec] (mean)&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt; 

	&lt;p&gt;Szybko&#347;&#263; wi&#281;ksza od mod_passengera i co wa&#380;niejsze, zero jakichkolwiek b&#322;&#281;d&#243;w przy pracy r&#243;wnoleg&#322;ej.&lt;/p&gt;


	&lt;h3&gt;Rails 2.1 + Thin 0.8.1&lt;/h3&gt;


&lt;div class="typocode"&gt;&lt;pre&gt;&lt;code class="typocode_bash "&gt;thin start -e production              

ab -n 1000 -c 1 http://127.0.0.1:3000/
...
Concurrency Level:      1
Failed requests:        0
Write errors:           0
Requests per second:    485.95 [#/sec] (mean)

ab -n 1000 -c 4 http://127.0.0.1:3000/
...              
Concurrency Level:      4
Failed requests:        0
Write errors:           0
Requests per second:    506.21 [#/sec] (mean)&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

	&lt;p&gt;Szybko&#347;&#263; troch&#281; mniejsza od Ebb, ale stabilno&#347;&#263; b. dobra.&lt;/p&gt;


	&lt;h3&gt;Rails 2.1 + Mongrel 1.1.5&lt;/h3&gt;


&lt;div class="typocode"&gt;&lt;pre&gt;&lt;code class="typocode_bash "&gt;script/server -e production

ab -n 1000 -c 1 http://127.0.0.1:3000/
...
Concurrency Level:      1
Failed requests:        0
Write errors:           0
Requests per second:    373.74 [#/sec] (mean)

ab -n 1000 -c 4 http://127.0.0.1:3000/
...
Concurrency Level:      4
Failed requests:        0
Write errors:           0
Requests per second:    360.46 [#/sec] (mean)&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

	&lt;p&gt;Stabilno&#347;&#263; bez zarzutu, wydajno&#347;&#263; jednak mniejsza od serwer&#243;w pracuj&#261;cych asynchronicznie.&lt;/p&gt;


	&lt;h3&gt;Rails 2.1 + JRuby 1.1.2&lt;/h3&gt;


	&lt;p&gt;W wypadku JRuby trzeba go troch&#281; &amp;#8220;rozgrza&#263;&amp;#8221;. Pe&#322;na wydajno&#347;&#263; Javy pojawia si&#281; po jakim&#347; czasie pracy. Wynika to ze specyfiki i mo&#380;liwo&#347;&#263;i &lt;span class="caps"&gt;JVM&lt;/span&gt; kt&#243;ra dokonuje dynamicznych optymalizacji kodu w trakcie jego dzia&#322;ania (z tego powodu Java potrafi przewy&#380;szy&#263; wydajno&#347;ci&#261; C++). &amp;#8220;Dla rozgrzewki&amp;#8221; przepu&#347;ci&#322;em Rails przez 30 tys. request&#243;w co spowodowa&#322;o &#380;e pocz&#261;tkowych 137 req/s zrobi&#322;o si&#281; 257 req/s.&lt;/p&gt;


&lt;div class="typocode"&gt;&lt;pre&gt;&lt;code class="typocode_bash "&gt;jruby script/server -e production    

ab -n 1000 -c 1 http://127.0.0.1:3000/
...
Concurrency Level:      1
Failed requests:        0
Write errors:           0
Requests per second:    200.48 [#/sec] (mean)

ab -n 1000 -c 4 http://127.0.0.1:3000/
...
Concurrency Level:      4
Failed requests:        0
Write errors:           0
Requests per second:    257.05 [#/sec] (mean)&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

	&lt;p&gt;JRuby jest stabilny ale z wydajno&#347;ci&#261; dla Rails jeszcze jest troch&#281; do poprawienia. Dorzucenie opcji optymalizacyjnych, czyli odpalenie Rails przez&lt;/p&gt;


&lt;div class="typocode"&gt;&lt;pre&gt;&lt;code class="typocode_bash "&gt;  
jruby -J-server -J-Djruby.compile.frameless=true script/server -e production&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

	&lt;p&gt;troch&#281; poprawi&#322;o wynik: 273 req/s, ale generalnie nie jest to wielka r&#243;&#380;nica. JRuby 1.1.x ju&#380; ma domy&#347;lnie pow&#322;&#261;czane optymalizacje.&lt;/p&gt;


	&lt;h3&gt;Rails &amp;#8211; wnioski&lt;/h3&gt;


	&lt;p&gt;mod_passenger dla Rails faktycznie jest wydajny, cho&#263; trzeba jeszcze by zbada&#263; dlaczego zwraca tyle b&#322;&#281;dnych request&#243;w dla r&#243;wnoleg&#322;ych zapyta&#324; i czy ten problem wyst&#281;puje te&#380; na Linuksie. Dlatego na razie najwydajniejszym i najstabilniejszym rozwi&#261;zaniem dla Rails wci&#261;&#380; pozostaje kombinacja nginx + proxy do ebb lub thin. mod_passenger kusi g&#322;&#243;wnie prostot&#261; konfiguracji (w&#322;a&#347;ciwie brakiem konfiguracji). No i chyba ja to testowa&#322;em dla mod_passengera w wersji 1.1, a nie 2.0 (przynajmniej taka si&#281; wy&#347;wietla w Apache).&lt;/p&gt;


	&lt;h2&gt;Merb 0.9.4 edge&lt;/h2&gt;


	&lt;h3&gt;Merb 0.9.4 edge + mod_passenger 1.1.0&lt;/h3&gt;


	&lt;p&gt;Aby u&#380;y&#263; frameworka Rack z Passengerem trzeba w katalogu projektu tworzy&#263; plik &lt;code&gt;config.ru&lt;/code&gt; zawieraj&#261;cy konfiguracj&#281; Rack&amp;#8217;a. W wypadku Merba b&#281;dzie to&lt;/p&gt;


&lt;div class="typocode"&gt;&lt;pre&gt;&lt;code class="typocode_ruby "&gt;&lt;span class="ident"&gt;require&lt;/span&gt; &lt;span class="punct"&gt;'&lt;/span&gt;&lt;span class="string"&gt;rubygems&lt;/span&gt;&lt;span class="punct"&gt;'&lt;/span&gt;
&lt;span class="ident"&gt;require&lt;/span&gt; &lt;span class="punct"&gt;'&lt;/span&gt;&lt;span class="string"&gt;merb-core&lt;/span&gt;&lt;span class="punct"&gt;'&lt;/span&gt;

&lt;span class="constant"&gt;Merb&lt;/span&gt;&lt;span class="punct"&gt;::&lt;/span&gt;&lt;span class="constant"&gt;Config&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;setup&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="symbol"&gt;:merb_root&lt;/span&gt;   &lt;span class="punct"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;&lt;span class="string"&gt;.&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;,&lt;/span&gt;
                   &lt;span class="symbol"&gt;:environment&lt;/span&gt; &lt;span class="punct"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="constant"&gt;ENV&lt;/span&gt;&lt;span class="punct"&gt;['&lt;/span&gt;&lt;span class="string"&gt;RACK_ENV&lt;/span&gt;&lt;span class="punct"&gt;'])&lt;/span&gt;
&lt;span class="constant"&gt;Merb&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;environment&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="constant"&gt;Merb&lt;/span&gt;&lt;span class="punct"&gt;::&lt;/span&gt;&lt;span class="constant"&gt;Config&lt;/span&gt;&lt;span class="punct"&gt;[&lt;/span&gt;&lt;span class="symbol"&gt;:environment&lt;/span&gt;&lt;span class="punct"&gt;]&lt;/span&gt;
&lt;span class="constant"&gt;Merb&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;root&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="constant"&gt;Merb&lt;/span&gt;&lt;span class="punct"&gt;::&lt;/span&gt;&lt;span class="constant"&gt;Config&lt;/span&gt;&lt;span class="punct"&gt;[&lt;/span&gt;&lt;span class="symbol"&gt;:merb_root&lt;/span&gt;&lt;span class="punct"&gt;]&lt;/span&gt;
&lt;span class="constant"&gt;Merb&lt;/span&gt;&lt;span class="punct"&gt;::&lt;/span&gt;&lt;span class="constant"&gt;BootLoader&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;run&lt;/span&gt;

&lt;span class="ident"&gt;run&lt;/span&gt; &lt;span class="constant"&gt;Merb&lt;/span&gt;&lt;span class="punct"&gt;::&lt;/span&gt;&lt;span class="constant"&gt;Rack&lt;/span&gt;&lt;span class="punct"&gt;::&lt;/span&gt;&lt;span class="constant"&gt;Application&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;new&lt;/span&gt;  &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;div class="typocode"&gt;&lt;pre&gt;&lt;code class="typocode_bash "&gt;Concurrency Level:      1
Failed requests:        0
Write errors:           0
Requests per second:    762.62 [#/sec] (mean)

Concurrency Level:      4
Failed requests:        247
   (Connect: 0, Length: 247, Exceptions: 0)
Write errors:           0
Requests per second:    985.15 [#/sec] (mean) &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

	&lt;p&gt;Merb jest wci&#261;&#380; du&#380;o szybszy od Rails. Podobnie jak dla Rails, wiele r&#243;wnoleg&#322;ych zapyta&#324; nie zosta&#322;o poprawnie wykonanych. Na produkcyjne u&#380;ycie Passengera dla Merba jest jeszcze troch&#281; za wcze&#347;nie.&lt;/p&gt;


	&lt;h3&gt;Merb 0.9.4 edge + ebb 0.2.0&lt;/h3&gt;


&lt;div class="typocode"&gt;&lt;pre&gt;&lt;code class="typocode_bash "&gt;merb -e production -a ebb  
...                              
Concurrency Level:      4
Failed requests:        0
Write errors:           0
Requests per second:    1463.69 [#/sec] (mean)

Concurrency Level:      10
Failed requests:        0
Write errors:           0
Requests per second:    1560.60 [#/sec] (mean)&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;  

	&lt;p&gt;Merb na Ebb deklasuje wydajno&#347;ci&#261; wszystkie inne rozwi&#261;zania. Tylko czysty &lt;span class="caps"&gt;PHP&lt;/span&gt; jest w stanie mu dor&#243;wna&#263;, ale por&#243;wnywanie &lt;span class="caps"&gt;PHP&lt;/span&gt; z ca&#322;ym, z&#322;o&#380;onym frameworkiem Rubiego jest troch&#281; bez sensu. Z tego co m&#243;wi&#322; ostatnio (na kanale &lt;span class="caps"&gt;IRC&lt;/span&gt;) Ezra Zygmuntowicz, podpi&#281;cie Ebb na czystym Rack&amp;#8217;u, daje nawet &lt;strong&gt;7 tys req/s&lt;/strong&gt; i deklasuje (rzekomo) szybkiego &lt;span class="caps"&gt;PHP&lt;/span&gt;. Gadanie o wy&#380;szej wydajno&#347;ci &lt;span class="caps"&gt;PHP&lt;/span&gt; jest po prostu g&#322;upie. Mo&#380;na si&#281; za&#322;o&#380;y&#263;, &#380;e jakiekolwiek por&#243;wnanie frameworka naprzeciw frameworka, tj. Merba z Symfony czy Cake &lt;span class="caps"&gt;PHP&lt;/span&gt;, obna&#380;y bezlito&#347;nie s&#322;abo&#347;ci &lt;span class="caps"&gt;PHP&lt;/span&gt; &lt;a href="http://blog.zabiello.com/articles/2006/07/14/django-i-rails-bij%C4%85-php"&gt;tak, jak to zrobi&#322; Django&lt;/a&gt; w jednym ze starszych test&#243;w.&lt;/p&gt;


	&lt;h3&gt;Merb 0.9.4 edge + thin 0.8.1&lt;/h3&gt;


&lt;div class="typocode"&gt;&lt;pre&gt;&lt;code class="typocode_bash "&gt;merb -e production -a thin 
...
Concurrency Level:      1
Failed requests:        0
Write errors:           0
Requests per second:    1147.78 [#/sec] (mean)

Concurrency Level:      4
Failed requests:        0
Write errors:           0
Requests per second:    1234.82 [#/sec] (mean)&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;  

	&lt;p&gt;Wydajno&#347;&#263; r&#243;wnie dobra, cho&#263; troch&#281; s&#322;absza od Ebb. Sporo wi&#281;cej od Rails i zero problem&#243;w ze stabilno&#347;ci&#261;.&lt;/p&gt;


	&lt;h3&gt;Merb 0.9.4 edge + mongrel 1.1.5&lt;/h3&gt;


&lt;div class="typocode"&gt;&lt;pre&gt;&lt;code class="typocode_bash "&gt;merb -e production -a mongrel
...
Concurrency Level:      1
Failed requests:        0
Write errors:           0
Requests per second:    868.10 [#/sec] (mean)

Concurrency Level:      4
Failed requests:        0
Write errors:           0
Requests per second:    837.01 [#/sec] (mean)&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;   

	&lt;p&gt;Mongrel jest wolniejszy od serwer&#243;w asynchronicznych ale i tak wyra&#378;nie szybszy od Rails.&lt;/p&gt;


	&lt;h3&gt;Merb 0.9.4 edge + JRuby 1.1.2&lt;/h3&gt;


&lt;div class="typocode"&gt;&lt;pre&gt;&lt;code class="typocode_bash "&gt; 
jruby -S merb -e production 
...
Concurrency Level:      1
Failed requests:        0
Write errors:           0
Requests per second:    449.52 [#/sec] (mean)

Concurrency Level:      4
Failed requests:        0
Write errors:           0
Requests per second:    505.52 [#/sec] (mean)&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

	&lt;p&gt;Merb na &amp;#8220;rozgrzanym&amp;#8221; (30 tys. req) JRuby osi&#261;ga wydajno&#347;&#263; tak&#261; jak najszybsze rozwi&#261;zania dla Rails z u&#380;yciem asynchronicznego Ebb! To znaczy, &#380;e u&#380;ycie produkcyjne Merba w systemach Javy ma jak najbardziej sens.&lt;/p&gt;


	&lt;h2&gt;Passenger &amp;#38; &lt;span class="caps"&gt;WSGI&lt;/span&gt;&lt;/h2&gt;


	&lt;p&gt;Pora na przyjrzenie si&#281; temu jak mod_passenger daje sobie rad&#281; z Pythonem. W katalogu ze &#378;r&#243;d&#322;ami Passengera le&#380;y gotowa, prosta aplikacja &lt;span class="caps"&gt;WSGI&lt;/span&gt;. Dzieki dobrej dokumentacji Django, uda&#322;o mi si&#281; uruchomi&#263; ten framework pod Passengerem. Gorzej by&#322;o z Pylons. Nie uda&#322;o mi si&#281; stworzy&#263; poprawnego pliku passenger_wsgi.py, niezb&#281;dnego do tego aby Passenger uruchomi&#322; aplikacj&#281; &lt;span class="caps"&gt;WSGI&lt;/span&gt;.&lt;/p&gt;


	&lt;h3&gt;Django edge&lt;/h3&gt;


	&lt;p&gt;Django, mimo swych zalet, stosuje bardzo g&#322;upi&#261; polityk&#281; nie wypuszczania kolejnych wersji kodu. Dost&#281;pna na stronie wersa 0.96 jest stara i generalnie zaleca si&#281; aby u&#380;ywa&#263; nowsz&#261; wersj&#281;, kt&#243;ra istnieje tylko w repozytorium Subversion. Oparcie kodu produkcyjnego o wersj&#281; edge jest troch&#281; ryzykowne i szybko sprowadza si&#281; do z&#322;ej praktyki ci&#261;g&#322;ego  &#322;atania kodu.&lt;/p&gt;


	&lt;p&gt;W wypadku Django plik &lt;code&gt;passenger_wsgi.py&lt;/code&gt; zawiera kod:&lt;/p&gt;


&lt;div class="typocode"&gt;&lt;pre&gt;&lt;code class="typocode_ruby "&gt;&lt;span class="ident"&gt;import&lt;/span&gt; &lt;span class="ident"&gt;os&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="ident"&gt;sys&lt;/span&gt;
&lt;span class="ident"&gt;sys&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;path&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;append&lt;/span&gt;&lt;span class="punct"&gt;('&lt;/span&gt;&lt;span class="string"&gt;/bezwl/sciezka/do/nazwaprojektu&lt;/span&gt;&lt;span class="punct"&gt;')&lt;/span&gt; 
&lt;span class="ident"&gt;os&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;environ&lt;/span&gt;&lt;span class="punct"&gt;['&lt;/span&gt;&lt;span class="string"&gt;DJANGO_SETTINGS_MODULE&lt;/span&gt;&lt;span class="punct"&gt;']&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="punct"&gt;'&lt;/span&gt;&lt;span class="string"&gt;nazwaprojektu.settings&lt;/span&gt;&lt;span class="punct"&gt;'&lt;/span&gt;
&lt;span class="ident"&gt;import&lt;/span&gt; &lt;span class="ident"&gt;django&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;core&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;handlers&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;wsgi&lt;/span&gt;
&lt;span class="ident"&gt;application&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="ident"&gt;django&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;core&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;handlers&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;wsgi&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;WSGIHandler&lt;/span&gt;&lt;span class="punct"&gt;()&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;div class="typocode"&gt;&lt;pre&gt;&lt;code class="typocode_bash "&gt;  ab -n 10000 -c 10            
  ...   
  apr_poll: The timeout specified has expired (70007)&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

	&lt;p&gt;Test pad&#322; po 9tys requestach. Dalej nie mo&#380;na by&#322;o uruchomi&#263; Django. Dopiero restart calego Apache&amp;#8217;a pom&#243;g&#322;. Dla ni&#380;szej ilo&#347;ci r&#243;wnoleg&#322;ych zapyta&#324; (ab -n 1000 -c 4) Django nie pad&#322;o, ale by&#322;o du&#380;o b&#322;&#281;dnych request&#243;w. Okaza&#322;o si&#281;, &#380;e problem wynika&#322; z r&#243;wnoczesnej obecno&#347;ci modu&#322;u mod_python i mod_passenger. Nie mo&#380;na ich razem w&#322;&#261;cza&#263;.&lt;/p&gt;


	&lt;p&gt;Usuni&#281;cie mod_passengera i zostawienie samego mod_pythona pomog&#322;o. (Albo jest jaki&#347; konflikt mi&#281;dzy nimi, albo (co bardziej jest prawdopodobne) trzeba poczeka&#263; na opcj&#281; wy&#322;&#261;czaj&#261;c&#261; passengera dla serwera wirtualnego u&#380;ywaj&#261;cego mod_pythona. Dla Rails i Rack s&#261; takie opcje (RailsAutoDetect, RackAutoDetect), dla &lt;span class="caps"&gt;WSGI&lt;/span&gt; nie mog&#322;em nic takiego znale&#378;&#263; w kodzie &#378;r&#243;d&#322;owym. Modu&#322;u mod_wsgi nie sprawdza&#322;em, bo nie by&#322;o go dost&#281;pnego w portach &lt;span class="caps"&gt;OSX&lt;/span&gt;.)&lt;/p&gt;


	&lt;p&gt;Po zablokowaniu mod_passenger&amp;#8217;a tym razem mod_python nie zwraca&#322; &#380;adnego b&#322;&#281;dnego requestu.&lt;/p&gt;


&lt;div class="typocode"&gt;&lt;pre&gt;&lt;code class="typocode_bash "&gt;Concurrency Level:      1
Failed requests:        0
Write errors:           0
Requests per second:    934.87 [#/sec] (mean)

Concurrency Level:      4
Failed requests:        0
Write errors:           0
Requests per second:    1240.26 [#/sec] (mean)&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

	&lt;p&gt;Nie jest &#378;le. Django jest tu wyra&#378;nie szybsze od Rails (co nikogo nie dziwi), ale jest wolniejsze od Merba, co dla mi&#322;o&#347;nik&#243;w Pythona mo&#380;e by&#263; przykr&#261; niespodziank&#261;. Wi&#281;kszo&#347;&#263; krytyki Rubiego oparta jest na krytyce (s&#322;abszej) wydajno&#347;ci Rails&#243;w. Okazuje si&#281;, &#380;e winny nie jest Ruby, ale s&#322;abo zoptymalizowany Rails. Merb jest dowodem na to, &#380;e mo&#380;na napisa&#263; w Rubim framework, kt&#243;ry nie tylko b&#281;dzie partnerem dla rozwi&#261;zan Pythona, ale nawet potrafi je przewy&#380;sza&#263; wydajno&#347;ciowo.&lt;/p&gt;


	&lt;p&gt;Zobaczmy jak wypadnie &lt;strong&gt;mod_passenger&lt;/strong&gt;.&lt;/p&gt;


&lt;div class="typocode"&gt;&lt;pre&gt;&lt;code class="typocode_bash "&gt;Concurrency Level:      1
Failed requests:        0
Write errors:           0
Requests per second:    904.60 [#/sec] (mean)

Concurrency Level:      4
Failed requests:        240
   (Connect: 0, Length: 240, Exceptions: 0)
Write errors:           0
Requests per second:    497.51 [#/sec] (mean)&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

	&lt;p&gt;W pracy jednoprocesowej nie mo&#380;na mie&#263; zastrze&#380;e&#324;. Szybko&#347;&#263; jest niez&#322;a. Niestety praca r&#243;wnoleg&#322;a to pora&#380;ka. Du&#380;o request&#243;w nie zosta&#322;o obs&#322;u&#380;onych. Gorzej, za drugim razem (tylko dla 4 rownoleg&#322;ych zapyta&#324;) Django kompletnie si&#281; za&#322;ama&#322;o i zwr&#243;ci&#322;o wyj&#261;tek &amp;#8220;apr_poll: The timeout specified has expired (70007)&amp;#8221;. Nie mo&#380;na by&#322;o go d&#322;u&#380;ej u&#380;ywa&#263;. Wymagany by&#322; restart Apache&amp;#8217;a.&lt;/p&gt;


	&lt;p&gt;Aby sprawdzi&#263; czy to tylko problem Django czy og&#243;lnie implementacji &lt;span class="caps"&gt;WSGI&lt;/span&gt; dla mod_passengera, uruchomi&#322;em test na prostej aplikacji &lt;span class="caps"&gt;WSGI&lt;/span&gt;. Niestety sytuacja jest ta sama.&lt;/p&gt;


	&lt;p&gt;&lt;strong&gt;Wniosek&lt;/strong&gt;: mod_passenger dla Pythona wymaga dopracowania pracy r&#243;wnoleg&#322;ej. Jeszcze za wcze&#347;nie aby go u&#380;ywa&#263; z Pythonem. Ale z drugiej strony uruchomi&#322;em mod_passengera z &lt;span class="caps"&gt;WSGI&lt;/span&gt;  troch&#281; przedwcze&#347;nie. Nie ma przecie&#380; w manualu ani jednego zdania o tym, &#380;e Passenger dzia&#322;a z &lt;span class="caps"&gt;WSGI&lt;/span&gt;. Opar&#322;em si&#281; tylko na pog&#322;oskach i wygrzeba&#322;em t&#261; opcj&#281; ze &#378;r&#243;de&#322;. Wi&#281;c jeszcze wszystko mo&#380;e si&#281; tu zmieni&#263;. To samo dotyczy Rack&amp;#8217;a. Tw&#243;rcy musz&#261; przyjrze&#263; si&#281; problemom zwi&#261;zanym z obs&#322;ug&#261; r&#243;wnoleg&#322;ych zapyta&#324;.&lt;/p&gt;


	&lt;h3&gt;Update&lt;/h3&gt;


	&lt;p&gt;Jednak dobrze si&#281; domy&#347;la&#322;em, Apache nie oszukiwa&#322;. W tek&#347;cie testowa&#322;em starszego Passengera 1.1. Tak&#380;e nie by&#322; to Ruby Enterprise. &lt;span class="caps"&gt;NOWY&lt;/span&gt; Passenger 2.0RC1 oraz Ruby Enterprise zosta&#322; dopiero niedawno &lt;a href="http://blog.phusion.nl/2008/06/09/phusion-passenger-20-rc-1-and-ruby-enterprise-edition-released/"&gt;opublikowany&lt;/a&gt;. Co ciekawe, dodano obs&#322;ug&#281; Apache &lt;span class="caps"&gt;MPM&lt;/span&gt; &lt;strong&gt;Worker&lt;/strong&gt; a nie &lt;span class="caps"&gt;MPM&lt;/span&gt; Prefork, co dodatkowo zmniejsza zu&#380;ycie pami&#281;ci. Niestety Passenger 2.0RC1 jest na razie dost&#281;pny tylko w wersji na Linuksa.&lt;/p&gt;</description>
      <pubDate>Sat, 07 Jun 2008 15:24:00 +0200</pubDate>
      <guid isPermaLink="false">urn:uuid:1dc84c82-1634-41dd-9aa1-9c744a876dff</guid>
      <author>Jaros&#322;aw Zabie&#322;&#322;o</author>
      <link>http://blog.zabiello.com/articles/2008/06/07/passenger-rack-wsgi</link>
      <category>rails</category>
      <category>ruby</category>
      <category>python</category>
      <category>django</category>
      <category>merb</category>
      <category>apache</category>
      <category>benchmark</category>
      <category>jruby</category>
    </item>
    <item>
      <title>Sprz&#261;tanie po PHP czyli Passenger 2.0 i Ruby Enterprise 1.0</title>
      <description>&lt;p&gt;Sta&#322;o si&#281;! &lt;a href="http://www.phusion.nl/"&gt;Tw&#243;rcy&lt;/a&gt; &#347;wietnego modu&#322;u Apache&amp;#8217;a &amp;#8211; &lt;a href="http://www.modrails.com/"&gt;mod_rails&lt;/a&gt; &amp;#8211; zmieniaj&#261; jego nazw&#281; na &lt;strong&gt;mod_passenger&lt;/strong&gt;, bo mod_rails nie jest ju&#380; wi&#281;cej modu&#322;em tylko dla &lt;a href="http://rubyonrails.pl"&gt;Rails&lt;/a&gt;. W nowej wersji 2.0 (ktora ma wyj&#347;&#263;&#160;&lt;a href="http://groups.google.com/group/phusion-passenger/browse_thread/thread/a2b63650c1b9394"&gt;na dniach&lt;/a&gt;) dodano pe&#322;ne wsparcie dla &lt;a href="http://blog.zabiello.com/articles/2008/03/04/frameworki-rubiego-rack-wsgi"&gt;Rack&lt;/a&gt; i tym samym mod_passenger 2.0 obs&#322;uguje wszystkie pozosta&#322;e frameworki u&#380;ywaj&#261;ce Rack&amp;#8217;a (ze &#347;wietnym &lt;a href="http://merbivore.com"&gt;Merbem&lt;/a&gt; w&#322;&#261;cznie).&lt;/p&gt;


	&lt;p&gt;Drugim, ciekawym projektem firmy &lt;a href="http://www.phusion.nl/"&gt;Phusion&lt;/a&gt; jest &lt;a href="http://www.rubyenterpriseedition.com/"&gt;Ruby Enterprise&lt;/a&gt; (wersja 1.0 ma by&#263; dost&#281;pna lada dzie&#324; razem z Passenger 2.0). Jest to podrasowana wersja interpretera Rubiego (MRI) powoduj&#261;ca nie tylko przy&#347;pieszenie ale tak&#380;e znaczne zmniejszenie zu&#380;ycia pami&#281;ci &lt;span class="caps"&gt;RAM&lt;/span&gt; (dodano technik&#281; copy-on-write do garbage collectora interpretera &lt;span class="caps"&gt;MRI&lt;/span&gt;, dok&#322;adniej opisano to na &lt;a href="https://dl.getdropbox.com/u/26205/railsconf.pdf"&gt;slajdach&lt;/a&gt;). Wg tego co twierdz&#261; ludzie z Phusion, uzyskano zmniejszenie o 33% zu&#380;ycia pami&#281;ci przez Rails. To bardzo dobra wiadomo&#347;&#263;, bo pami&#281;&#263; mimo, &#380;e jest generalnie tania, nie jest tania w ofertach hostingowych &lt;span class="caps"&gt;VPS&lt;/span&gt;.&lt;/p&gt;


	&lt;p&gt;Passenger wprowadza now&#261; jako&#347;&#263; dla framework&#243;w Rubiego. Coraz wi&#281;cej firm hostingowych to docenia i przechodzi na Passenger&amp;#8217;a (z tych bardziej znanych, &lt;a href="http://blog.dreamhost.com/2008/05/13/passenger-for-ruby-on-rails/"&gt;Dreamhost ju&#380; tego u&#380;ywa&lt;/a&gt;). Sam modu&#322;&#160;mod_passenger jest nie tylko trywialny w u&#380;yciu, jest te&#380; bardzo szybki i stabilny. Chyba nadchodz&#261; ci&#281;&#380;kie chwile dla tych, co trzymali si&#281; &lt;span class="caps"&gt;PHP&lt;/span&gt; g&#322;&#243;wnie z powodu jego taniego hostingu i prostoty uruchomiania serwerze. Rails i Merb mog&#261; wkr&#243;tce troch&#281; pozamiata&#263; po &lt;span class="caps"&gt;PHP&lt;/span&gt;. :)&lt;/p&gt;


	&lt;p&gt;Szybko&#347;&#263; mod_passenger&amp;#8217;a robi wra&#380;enie. Bije wydajno&#347;ci&#261; kombinacj&#281; &lt;a href="http://nginx.net/"&gt;Nginx&lt;/a&gt; + asynchroniczny &lt;a href="http://code.macournoyer.com/thin/"&gt;Thin&lt;/a&gt; u&#380;ywaj&#261;cy szybkich, uniksowych socket&#243;w. Jest te&#380; szybszy od komercyjnego &lt;a href="http://litespeedtech.com/"&gt;Litespeed&amp;#8217;a&lt;/a&gt;.&lt;/p&gt;


	&lt;p&gt;&lt;img src="http://blog.zabiello.com/images/passenger_vs_thin.png" alt="" /&gt;&lt;/p&gt;


	&lt;p&gt;&lt;img src="http://blog.zabiello.com/images/passenger_vs_litespeed.png" alt="" /&gt;&lt;/p&gt;


	&lt;p&gt;Co ciekawe, mod_passenger obs&#322;uguje interfejs &lt;strong&gt;&lt;span class="caps"&gt;WSGI&lt;/span&gt; do Pythona&lt;/strong&gt;! Jeden modu&#322; pozwoli wi&#281;c na odpalanie Rails, Merb&amp;#8217;a i Django r&#243;wnocze&#347;nie. Ma&#322;o tego, je&#347;li mod_passenger dla Pythona b&#281;dzie dzia&#322;a&#322; tak sprawnie jak dla Rails, to b&#281;dziemy mie&#263; trywialne prze&#322;adowywanie aplikacji Django bez konieczno&#347;ci restartu ca&#322;ego Apache&amp;#8217;a.&lt;/p&gt;


	&lt;p&gt;Vide:&lt;/p&gt;


	&lt;ul&gt;
	&lt;li&gt;&lt;a href="http://www.railsjedi.com/posts/52-The-Holy-Grail-for-Rails-Deployment"&gt;The Holy Grail for Rails Deployment&lt;/a&gt;&lt;/li&gt;
	&lt;/ul&gt;


	&lt;ul&gt;
	&lt;li&gt;&lt;a href="http://www.rubyinside.com/28_mod_rails_and_passenger_resources-899.html"&gt;28 mod_rails / Passenger Resources To Help You Deploy Rails Applications Faster&lt;/a&gt;&lt;/li&gt;
	&lt;/ul&gt;


	&lt;ul&gt;
	&lt;li&gt;&lt;a href="http://github.com/FooBarWidget/passenger/tree/master"&gt;Passenger 2.0 na GitHub.com&lt;/a&gt; dla tych, co chc&#261; ju&#380; teraz zainstalowa&#263; mod_passenger 2.0 (ja ju&#380; to zainstalowa&#322;em)&lt;/li&gt;
	&lt;/ul&gt;


	&lt;h3&gt;Update&lt;/h3&gt;


	&lt;p&gt;&lt;em&gt;2008-06-25&lt;/em&gt;&lt;/p&gt;


&lt;object width="400" height="225"&gt;    &lt;param name="allowfullscreen" value="true" /&gt;    &lt;param name="allowscriptaccess" value="always" /&gt;    &lt;param name="movie" value="http://www.vimeo.com/moogaloop.swf?clip_id=1198020&amp;amp;server=www.vimeo.com&amp;amp;show_title=1&amp;amp;show_byline=1&amp;amp;show_portrait=0&amp;amp;color=&amp;amp;fullscreen=1" /&gt;    &lt;embed src="http://www.vimeo.com/moogaloop.swf?clip_id=1198020&amp;amp;server=www.vimeo.com&amp;amp;show_title=1&amp;amp;show_byline=1&amp;amp;show_portrait=0&amp;amp;color=&amp;amp;fullscreen=1" type="application/x-shockwave-flash" allowfullscreen="true" allowscriptaccess="always" width="400" height="225"&gt;&lt;/embed&gt;&lt;/object&gt;&lt;br /&gt;&lt;a href="http://www.vimeo.com/1198020?pg=embed&amp;#38;sec=1198020"&gt;Phusion Passenger 2.0 and Ruby Enterprise Edition&lt;/a&gt; from &lt;a href="http://www.vimeo.com/user519957?pg=embed&amp;#38;sec=1198020"&gt;Carl Youngblood&lt;/a&gt; on &lt;a href="http://vimeo.com?pg=embed&amp;#38;sec=1198020"&gt;Vimeo&lt;/a&gt;

	&lt;ul&gt;
	&lt;li&gt;&lt;a href="http://blog.dmilith.pl/2008/06/25/ruby-enterprise-edition-32bit-na-debianie-etch-64bit"&gt;Ruby Enterprise Edition 32bit na debianie etch 64bit?&lt;/a&gt;&lt;/li&gt;
	&lt;/ul&gt;</description>
      <pubDate>Wed, 04 Jun 2008 01:40:00 +0200</pubDate>
      <guid isPermaLink="false">urn:uuid:77d6b3df-2b86-4365-b5de-d4fd9b153ecc</guid>
      <author>Jaros&#322;aw Zabie&#322;&#322;o</author>
      <link>http://blog.zabiello.com/articles/2008/06/04/passenger2-ruby-enterprise</link>
      <category>mod_rails</category>
      <category>ruby</category>
      <category>rails</category>
      <category>merb</category>
      <category>rack</category>
      <category>apache</category>
      <category>php</category>
      <category>django</category>
      <category>python</category>
    </item>
    <item>
      <title> Google App Engine</title>
      <description>&lt;p&gt;Od niedawna Google oferuje dosy&#263; atrakcyjn&#261; mo&#380;liwo&#347;&#263; pisania aplikacji webowych wykorzystuj&#261;cych pot&#281;g&#281; ich infrastruktury &amp;#8211; &lt;a href="http://code.google.com/appengine/"&gt;Google App Engine&lt;/a&gt;. Us&#322;uga jest darmowa i jeszcze testowa. Mo&#380;na stworzy&#263; do 3 aplikacji z kt&#243;rych ka&#380;da mo&#380;e u&#380;ywa&#263; do 500MB danych trzymanych w BigTable i Google obiecuje &#380;e bez problemu b&#281;dzie mo&#380;na uzyska&#263; do 5 mln ods&#322;on miesi&#281;cznie i niez&#322;y traffic 10 TB/m-c.&lt;/p&gt;


	&lt;p&gt;W tej chwili jedynym j&#281;zykiem dost&#281;pnym jest Python ale maj&#261; przyby&#263; kolejne. Wykorzystywany jest &lt;span class="caps"&gt;WSGI&lt;/span&gt;. Dost&#281;pny jest te&#380; &lt;a href="http://code.google.com/appengine/articles/django.html"&gt;okrojony framework Django&lt;/a&gt; (nie mo&#380;na u&#380;ywa&#263; djangowego &lt;span class="caps"&gt;ORM&lt;/span&gt;&amp;#8217;a ani wszystkich mo&#380;liwo&#347;ci jakie daj&#261; djangowe szablony).&lt;/p&gt;


	&lt;p&gt;To co si&#281; bardzo zmienia, to podej&#347;cie do bazy danych. Baza kolumnowa &lt;a href="http://en.wikipedia.org/wiki/Bigtable"&gt;BigTable&lt;/a&gt; &lt;strong&gt;nie jest baz&#261; relacyjn&#261;&lt;/strong&gt; (nie istnieje tam poj&#281;cie join&#243;w). Trzeba wi&#281;c troch&#281;&#160;inaczej przemy&#347;le&#263; spos&#243;b tworzenia swoich danych. Pewnym problemem mo&#380;e by&#263; nie tylko uzale&#380;nienie od infrastruktury Google ale te&#380; trudno&#347;&#263; z p&#243;&#378;niejszym przeniesienia tak sk&#322;adowanych danych na inn&#261; platform&#281; (cho&#263; istnieje z drugiej strony open-source&amp;#8217;owy odpowiednik BigTable &amp;#8211; &lt;a href="http://hadoop.apache.org/hbase/"&gt;HBase&lt;/a&gt;). W zamian jednak u&#380;ycie platformy Google daje bardzo wysok&#261; wydajno&#347;&#263;&#160;i odporno&#347;&#263; na b&#322;&#281;dy (jak padnie jeden serwer to jego prac&#281; przejmuje automatycznie inny). Troch&#281; nie jest dla mnie jeszcze jasne jak sk&#322;adowa&#263; i usuwa&#263; dane z plikami statycznymi (obrazki, style kaskadowe, flash itp) skoro Google nie daje dost&#281;pu do systemu plik&#243;w. Zablokowane s&#261;&#160;te&#380; sockety, w&#261;tki, u&#380;ywanie modu&#322;&#243;w napisanych w C, mo&#380;liwo&#347;&#263;&#160;odpalania podproces&#243;w, mo&#380;liwo&#347;ci u&#380;ywania innych baz ni&#380; BigTable.&lt;/p&gt;</description>
      <pubDate>Sun, 13 Apr 2008 21:12:00 +0200</pubDate>
      <guid isPermaLink="false">urn:uuid:b7f3ea40-77de-4b1d-b122-3799c876ab80</guid>
      <author>Jaros&#322;aw Zabie&#322;&#322;o</author>
      <link>http://blog.zabiello.com/articles/2008/04/13/google-app-engine</link>
      <category>google</category>
      <category>python</category>
      <category>django</category>
    </item>
    <item>
      <title>Django on Jython</title>
      <description>&lt;p&gt;Pythonistas chyba pozazdro&#347;cili mo&#380;liwo&#347;ci odpalenia &lt;a href="http://rubyonrails.org"&gt;Rails&#243;w&lt;/a&gt; w &lt;a href="http://jruby.codehaus.org/"&gt;JRuby&lt;/a&gt;. Trwaj&#261; prace nad uruchomieniem frameworka &lt;a href="http://djangoproject.com"&gt;Django&lt;/a&gt; w &lt;a href="http://www.jython.org/Project/index.html"&gt;Jythonie&lt;/a&gt;, implementacji Pythona w czystej Javie.&lt;/p&gt;


	&lt;p&gt;Zapyta&#322;em si&#281; na kanale &lt;a href="irc://irc.eu.freenode.net/pylons"&gt;#pylons&lt;/a&gt; odno&#347;nie podobnego ruchu ze strony &lt;a href="http://pylonshq.com"&gt;Pylons&lt;/a&gt;, ale okazuje si&#281; &#380;e Jython jest dosy&#263; zacofany. Od czasu przej&#347;cia jego tw&#243;rcy do Microsoftu i pracy na &lt;a href="http://www.codeplex.com/Wiki/View.aspx?ProjectName=IronPython"&gt;IronPythonem&lt;/a&gt; projekt dosy&#263; powoli si&#281; rozwija. Jython zatrzyma&#322; si&#281; na implementacji Pythona 2.2. To dosy&#263; stara wersja zwa&#380;aj&#261;c, &#380;e w mi&#281;dzyczasie wysz&#322;y wersje 2.3, 2.4 i 2.5. Pylons wymaga zgodno&#347;ci min. z Pythonem 2.4. Nie wiem jak ten problem rozwi&#261;&#380;&#261; przy przenoszeniu Django, bo co&#347; nie chce mi si&#281; wierzy&#263; &#380;e jest w pe&#322;ni zgodny ze starym Pythonem 2.2.&lt;/p&gt;</description>
      <pubDate>Tue, 08 Jan 2008 04:34:00 +0100</pubDate>
      <guid isPermaLink="false">urn:uuid:4159d4c3-fcd0-442c-9d15-f96ae24099ea</guid>
      <author>Jaros&#322;aw Zabie&#322;&#322;o</author>
      <link>http://blog.zabiello.com/articles/2008/01/08/django-on-jython</link>
      <category>django</category>
      <category>python</category>
      <category>jython</category>
      <category>java</category>
    </item>
    <item>
      <title>Uko&#324;czono Django Book</title>
      <description>&lt;p&gt;Po roku pisania, zebraniu 2.5 tys uwag online od u&#380;ytkownik&#243;w, &lt;a href="http://www.djangoproject.com/weblog/2007/dec/16/book/"&gt;zosta&#322;a uko&#324;czona&lt;/a&gt; ksi&#261;&#380;ka o pythonowym frameworku webowym &lt;a href="http://djangoproject.com"&gt;Django&lt;/a&gt;. Wersja papierowa ma by&#263; w sprzeda&#380;y w przysz&#322;ym tygodniu. &lt;a href="http://www.djangobook.com/"&gt;Wersja online&lt;/a&gt; jest dost&#281;pna za darmo.&lt;/p&gt;</description>
      <pubDate>Wed, 19 Dec 2007 01:07:00 +0100</pubDate>
      <guid isPermaLink="false">urn:uuid:611a5558-cc73-4884-9819-5512ee9bc191</guid>
      <author>Jaros&#322;aw Zabie&#322;&#322;o</author>
      <link>http://blog.zabiello.com/articles/2007/12/19/uko%C5%84czono-django-book</link>
      <category>django</category>
      <category>python</category>
    </item>
    <item>
      <title>Django ograniczeniem w rozwoju?</title>
      <description>&lt;p&gt;&lt;a href="http://djangoproject.com"&gt;Django&lt;/a&gt; do dobry i szybki framework do wi&#281;kszo&#347;ci zastosowa&#324;. Jednak&#380;e ci, kt&#243;rzy chc&#261; za jego pomoc&#261; stworzy&#263; stworzy&#263; wi&#281;kszy projekt, mog&#281; mie&#263; p&#243;&#378;niej problemy z dalszym jego rozwojem&amp;#8230;&lt;/p&gt;


	&lt;p&gt;Jednym z wi&#281;kszych polskich projekt&#243;w stworzonych w Django jest serwis spo&#322;eczno&#347;ciowy &lt;a href="http://grono.net"&gt;grono.net&lt;/a&gt;. Niedawno w jednym z blog&#243;w ukaza&#322; si&#281; &lt;a href="http://www.pydev.pl/?p=127"&gt;wywiad&lt;/a&gt; z dyrektorem dzia&#322;u IT tego serwisu &amp;#8211;  Albertem Szybi&#324;skim. Grono.net pierwotnie u&#380;ywa&#322;o Javy, lecz to si&#281; nie sprawdzi&#322;o. Java zosta&#322; zast&#261;piona pythonowym frameworkiem &lt;a href="http://djangoproject.com"&gt;Django&lt;/a&gt;. Pocz&#261;tkowo wszystko by&#322;o dobrze, ale serwis si&#281; rozrasta&#322; i&amp;#8230;&lt;/p&gt;


	&lt;blockquote&gt;
		&lt;p&gt;&amp;#8220;Doszli&#347;my ju&#380; do takiego poziomu, w kt&#243;rym Django zacz&#261;&#322; by&#263; dla nas problemem. W czasie tworzenia portalu by&#322; to bardzo dobry framework, ale przy obecnym stopniu zaawansowania, Django sta&#322; si&#281; dla nas ograniczeniem w rozwoju i sami musimy go modyfikowa&#263;.&amp;#8221;&lt;/p&gt;
	&lt;/blockquote&gt;


	&lt;p&gt;Czyli potwierdzi&#322;o si&#281; to co &lt;a href="http://blog.zabiello.com/articles/2007/08/25/aplikacja-webowa-wybor-technologii"&gt;pisa&#322;em wcze&#347;niej o Django&lt;/a&gt;. To system zbyt monolityczny i zdecydowanie za ma&#322;o elastyczny. Django ci&#261;gnie za sob&#261; dziedzictwo &lt;span class="caps"&gt;CMS&lt;/span&gt; &lt;a href="http://www.ellingtoncms.com/"&gt;Elington&lt;/a&gt; z jakiego wyr&#243;s&#322;. Mo&#380;e dobrze sprawdza si&#281; w projektach typu &amp;#8220;wertykalny portal dla wydawnictwa&amp;#8221;, ale jak ju&#380; chcemy co&#347; nietypowego, zaczynaj&#261; si&#281; problemy.&lt;/p&gt;


	&lt;p&gt;Na pytanie &amp;#8220;Czy posiadaj&#261;c tak&#261; wiedz&#281; jak&#261; macie dzi&#347;, czy zdecydowaliby&#347;cie si&#281; na zaimplementowanie Grono.net ponowie wykorzystuj&#261;c Django, czy mo&#380;e co&#347; innego?&amp;#8221; pad&#322;o wskazanie na &lt;a href="http://pylonshq.com"&gt;Pylons&lt;/a&gt;. Mo&#380;e nie ma tak &#322;adnie zgrupowanych modu&#322;&#243;w w jednym miejscu jak Django, ale na pewno ma wi&#281;kszy potencja&#322; do tworzenia nietypowych czy skomplikowanych serwis&#243;w.&lt;/p&gt;


	&lt;p&gt;To nie Django jest prawdziw&#261; pythonow&#261; konkurencj&#261; dla popularnego &lt;a href="http://rubyonrails.org"&gt;Ruby on Rails&lt;/a&gt; (&#380;e nie wspomn&#281; frameworki pehapowe). Moim zdaniem, bardziej gro&#378;n&#261; dla nich konkurencj&#261; jest &lt;strong&gt;Pylons&lt;/strong&gt;.&lt;/p&gt;</description>
      <pubDate>Sat, 27 Oct 2007 16:31:00 +0200</pubDate>
      <guid isPermaLink="false">urn:uuid:39425c6c-58e5-4fc6-b40f-12de8d5e4be6</guid>
      <author>Jaros&#322;aw Zabie&#322;&#322;o</author>
      <link>http://blog.zabiello.com/articles/2007/10/27/django-ograniczeniem-w-rozwoju</link>
      <category>pylons</category>
      <category>django</category>
      <category>python</category>
    </item>
    <item>
      <title>Aplikacja webowa - wyb&#243;r technologii</title>
      <description>&lt;p&gt;Do&#347;&#263; cz&#281;sto spotykam si&#281; z pro&#347;b&#261; o to, jak&#261; technologi&#281; (i framework) bym poleci&#322; do tworzenia aplikacji webowych. Dziedzina aplikacji webowych rozwija si&#281; bardzo pr&#281;&#380;nie i trudno tak naprawd&#281; przewidzie&#263;, co b&#281;dzie najlepszym wyborem za par&#281; lat. Niniejszy artyku&#322; stanowi kr&#243;tkie podsumowanie moich do&#347;wiadcze&#324; w tej dziedzinie na dzie&#324; &lt;em&gt;dzisiejszy&lt;/em&gt;.&lt;/p&gt;


	&lt;h3&gt;Nie wierz&#281; w przysz&#322;o&#347;&#263; architektur webowych opartych na j&#281;zykach kompilowanych,  statycznie typowanych.&lt;/h3&gt;


	&lt;p&gt;Na ten temat mo&#380;na by du&#380;o dyskutowa&#263;. Po prostu nie wierz&#281; w przysz&#322;o&#347;&#263; budowania aplikacji webowych w j&#281;zykach C# czy Java. Ka&#380;da zmiana kodu wymaga rekompilacji, wymiany dll itp. Mam z&#322;e do&#347;wiadczenia z &lt;span class="caps"&gt;ASP&lt;/span&gt;.NET. Bardzo wolno i mozolnie si&#281; tworzy i debuguje kod. Z kolei Java (tzn. aplikacja webowa pisana napisana w tym j&#281;zyku) jest ci&#281;&#380;ka i skomplikowana. Aplikacje webowe s&#261; dosy&#263; specyficzne. Znacznie lepiej sprawdzaj&#261; si&#281; tam j&#281;zyki wysokopoziomowe i &lt;em&gt;interpretowane&lt;/em&gt;. Nie trzeba nic restartowa&#263;, rekompilowa&#263;, efekty zmian s&#261; prawie natychmiastowo dost&#281;pne. My&#347;l&#281;, &#380;e wi&#281;kszo&#347;&#263; aplikacji webowych, szczeg&#243;lniej ma&#322;ej i &#347;redniej klasy z&#322;o&#380;ono&#347;ci, zostanie opanowana przez j&#281;zyki interpretowane. Po cz&#281;&#347;ci ju&#380; to uczyni&#322; &lt;span class="caps"&gt;PHP&lt;/span&gt;. Jednak&#380;e&amp;#8230;&lt;/p&gt;


	&lt;h3&gt;Nie wierz&#281; w przysz&#322;o&#347;&#263; &lt;span class="caps"&gt;PHP&lt;/span&gt;.&lt;/h3&gt;


	&lt;p&gt;Na temat wszystkich wad &lt;span class="caps"&gt;PHP&lt;/span&gt; m&#243;g&#322;bym du&#380;o pisa&#263;. W ka&#380;dym razie nie mog&#281; si&#281; nadziwi&#263;, dlaczego jego tworcy wci&#261;&#380; inspiruj&#261; si&#281; sk&#322;adni&#261; Perla i Javy zamiast wzorowa&#263; si&#281; na prostocie i elegancji Pythona czy Ruby.  &lt;span class="caps"&gt;PHP&lt;/span&gt; nie nadaje si&#281; do modularyzacji, tworzenia komponent&#243;w. Pr&#243;bowa&#322;em ju&#380; kiedy&#347; uzyska&#263; efekt komponent&#243;w w &lt;a href="http://smarty.php.net/"&gt;Smarty&lt;/a&gt;. Nie da si&#281;. G&#322;&#243;wnym problemem jest kolizja nazw klas i funkcji. Przestrze&#324; nazw mia&#322;a by&#263; dodana w &lt;span class="caps"&gt;PHP5&lt;/span&gt;. Nie dodali, bo nie umieli. &lt;span class="caps"&gt;PHP&lt;/span&gt; brnie wi&#281;c nadal w swoim chaosie wielkiej, wsp&#243;lnej przestrzeni nazw dla swych wszystkich, chaotycznie nazwanych funkcji o niesp&#243;jnej kolejno&#347;ci przekazywanych parametr&#243;w. Czy w &lt;span class="caps"&gt;PHP&lt;/span&gt; nie da si&#281; napisa&#263; dobrej aplikacji? Owszem, da. Jak kto&#347; si&#281; uprze to i w Assemblerze tak&#261; napisze. Tylko jakim kosztem&amp;#8230; Kierunek rozwoju tego j&#281;zyka wygl&#261;da na przypadkowy. Sam j&#281;zyk jest &#378;le zaprojektowany. Nie wierz&#281; w jego przysz&#322;o&#347;&#263; tym bardziej, &#380;e wyros&#322;a mu powa&#380;na konkurencja.&lt;/p&gt;


	&lt;h3&gt;Fenomem Ruby on Rails.&lt;/h3&gt;


	&lt;p&gt;Powodem rosn&#261;cej popularno&#347;ci &lt;a href="http://rubyonrails.org"&gt;Ruby on Rails&lt;/a&gt;, wbrew zazdrosnym opiniom co niekt&#243;rych, na pewno nie jest &lt;em&gt;tylko&lt;/em&gt; efekt dobrego marketingu. To tak&#380;e efekt pewnej, nowej filozofii w podej&#347;ciu do tematu. Rails mocno postawi&#322; na prostot&#281; i elegancj&#281; kodu po&#322;&#261;czon&#261; z kompleksowo&#347;ci&#261; rozwi&#261;zania. Do tego dobrze dobrane warto&#347;ci domy&#347;lne (ograniczaj&#261;ce ilo&#347;&#263; niezb&#281;dnych konfiguracji) plus wygodne generatory kodu prowadz&#261; cz&#322;owieka dos&#322;ownie za r&#281;k&#281;. Rails doczeka&#322; si&#281; te&#380; &lt;a href="http://deadlock.netbeans.org/hudson/job/ruby/"&gt;dobrego &lt;span class="caps"&gt;IDE&lt;/span&gt;&lt;/a&gt; co powoduje, &#380;e w tym frameworku pracuje si&#281; dosy&#263; przyjemnie. Jest przejrzysty i czytelnie zorganizowany. Zainspirowa&#322; i znalaz&#322; ju&#380; wielu na&#347;ladowc&#243;w, ale nigdy nie uzyskaj&#261; one jego elegancji i prostoty z prostej przyczyny: si&#322;&#261; Rails jest prostota i dynamika j&#281;zyka &lt;a href="http://ruby-lang.org"&gt;Ruby&lt;/a&gt;. Dynamika wi&#281;ksza nawet od &lt;a href="http://python.org"&gt;Pythona&lt;/a&gt;. Sukces Rails&#243;w wzmacnia tak&#380;e &lt;a href="http://weblog.rubyonrails.org/2007/5/7/ruby-and-rails-continues-book-bonanza"&gt;lawinowo rosn&#261;ca ilo&#347;&#263; ksi&#261;&#380;ek&lt;/a&gt;.&lt;/p&gt;


	&lt;p&gt;Rails zaczyna si&#281; wdziera&#263; do rozwi&#261;za&#324; korporacyjnych. Nie zast&#261;pi on z pewno&#347;ci&#261; Javy, ale na pewno lepiej od niej nadaje si&#281; do szybkiego stworzenia dynamicznych interfejs&#243;w webowych. Z chwil&#261; okrzepni&#281;cia JRuby (javowej implementacji Rubiego), Rails oparty na Javie (ale ze sk&#322;adni&#261; Rubiego) mo&#380;e zrobi&#263; jeszcze sporo zamieszania.&lt;/p&gt;


	&lt;p&gt;Jednak&#380;e, jest technologia, mo&#380;e nie a&#380; tak prosta, ale na pewno pod wieloma wzgl&#281;dami dojrzalsza i szybsza.&lt;/p&gt;


	&lt;h3&gt;Django i Pylons.&lt;/h3&gt;


	&lt;p&gt;Tak jak Rails, &lt;a href="http://djangoproject.com"&gt;Django&lt;/a&gt; powsta&#322; na bazie aplikacji zastosowywanej komercyjnie. Podobnie te&#380; do  Rails, stara si&#281; podchodzi&#263; kompleksowo podaj&#261;c na tacy okre&#347;lony (autorski) &lt;span class="caps"&gt;ORM&lt;/span&gt;, system szablon&#243;w i spos&#243;b rozwi&#261;zywania adres&#243;w &lt;span class="caps"&gt;URL&lt;/span&gt;. Django jest  szybsze od Rails&#243;w. Wynika to dw&#243;ch rzeczy. Python (jako j&#281;zyk) jest szybszy od Rubiego oraz Django od pocz&#261;tku by&#322;o projektowane z my&#347;l&#261; o optymalizacji wydajno&#347;ciowej. (Rails skupia&#322; si&#281; od pocz&#261;tku na uzyskaniu funkcjonalno&#347;ci, zrzucaj&#261;c optymalizacj&#281; na p&#243;&#378;niej). O zaletach Django &lt;a href="http://blog.zabiello.com/articles/2006/05/27/django-wy%C5%BCszy-poziom-abstrakcji"&gt;pisa&#322;em rok temu&lt;/a&gt;. Django po&#380;era te&#380; wyra&#378;nie mniej pami&#281;ci ni&#380; Rails odpalany na &lt;a href="http://mongrel.rubyforge.org/"&gt;mongrelach&lt;/a&gt;.&lt;/p&gt;


	&lt;p&gt;Niestety, mo&#380;na si&#281; przyczepi&#263; do kilku rzeczy. G&#322;&#243;wna krytyka Django dotyczy jego zbytniej monolityczno&#347;ci i mniejszej elastyczno&#347;ci. Rails pozwala podpina&#263; si&#281; do wielu baz, Django tylko do jednej. Rails posiada migracje do kontrolowania ewolucji struktury bazy. Django nic takiego nie posiada (tzn. jest w fazie rozwojowej gdzie&#347; w bocznych ga&#322;&#281;ziach repozytorium &lt;span class="caps"&gt;SVN&lt;/span&gt;). Rails posiada &#347;wietne helpery do  generowania adres&#243;w &lt;span class="caps"&gt;URL&lt;/span&gt;. Djangowy system adres&#243;w jest znacznie gorszy. Nie ma mo&#380;liwo&#347;ci zmiany struktury aplikacji i wygenerowania zmienionych link&#243;w we wszystkich szablonach. Rails, dzi&#281;ki helperom to umo&#380;liwia. Rails posiada &#347;wietne helpery i specjalne szablony uproszczaj&#261;ce korzystanie z &lt;span class="caps"&gt;AJAX&lt;/span&gt;&amp;#8217;a, Django nic tu nie oferuje.&lt;/p&gt;


	&lt;p&gt;Wiele z wymienionych wy&#380;ej wad nie posiada pythonowy konkurent Django &amp;#8211; &lt;a href="http://pylonshq.com"&gt;Pylons&lt;/a&gt;. Pisalem o tym &lt;a href="http://blog.zabiello.com/articles/2006/03/04/pylons-czyli-si%C5%82a-myghty-i-wygoda-rubyonrails"&gt;ponad roku temu&lt;/a&gt;,  &#380;e Pylons skopiowa&#322; prawie wszystkie helpery jakie posiada Rails. Rozwi&#261;zuje adresy te&#380; w podobny spos&#243;b umo&#380;liwiaj&#261;c bardziej elastyczne modyfikowanie struktury kontroler&#243;w. Wszystkie zale&#380;ne adresy &lt;span class="caps"&gt;URL&lt;/span&gt; s&#261; generowane za pomoc&#261; helper&#243;w w spos&#243;b podobny do Rails. Pylons w zasadzie to taka sklejanka zewn&#281;trznych bibliotek Pythona. Wykorzystuj&#261;c standardowy mechanizm &lt;a href="http://www.python.org/dev/peps/pep-0333/"&gt;&lt;span class="caps"&gt;WSGI&lt;/span&gt;&lt;/a&gt;, Pylons pozwala na wymian&#281; prawie ka&#380;dego swojego elementu, od &lt;span class="caps"&gt;ORM&lt;/span&gt;, po system szablon&#243;w czy resolver adres&#243;w &lt;span class="caps"&gt;URL&lt;/span&gt;.&lt;/p&gt;


	&lt;p&gt;Wiele z element&#243;w, jakie domy&#347;lnie oferuje Pylons przewy&#380;sza elastyczno&#347;ci&#261; i mo&#380;liwo&#347;ciami to, co dost&#281;pne jest w Django.  Np. Pylons korzysta domy&#347;lnie z &lt;a href="http://www.sqlalchemy.org/"&gt;SQLAlchemy&lt;/a&gt;, kt&#243;ry jest pot&#281;&#380;niejszy od tego w Rails i Django&lt;sup&gt;&lt;a href="#fn1"&gt;1&lt;/a&gt;&lt;/sup&gt;. Nie tylko bez problemu pozwala podpi&#261;&#263; si&#281; do kilku baz, ale tak&#380;e do bardziej skomplikowanych struktur&lt;sup&gt;&lt;a href="#fn2"&gt;2&lt;/a&gt;&lt;/sup&gt;. Domy&#347;lny system szablon&#243;w &lt;a href="http://makotemplates.org"&gt;Mako&lt;/a&gt; jest najlepszym systemem jaki znam. Oferuje rozbudowan&#261;&lt;sup&gt;&lt;a href="#fn3"&gt;3&lt;/a&gt;&lt;/sup&gt; obiektowo&#347;&#263;, prost&#261; sk&#322;adni&#281;, doskona&#322;y cache dowolnego fragmentu i wg dowolnych zasad. Co&#347;, o czym np. Rails mo&#380;e tylko pomarzy&#263;&lt;sup&gt;&lt;a href="#fn4"&gt;4&lt;/a&gt;&lt;/sup&gt;. No i Pylons udost&#281;pnia szybki, wielow&#261;tkowy serwer &lt;span class="caps"&gt;HTTP&lt;/span&gt; kt&#243;ry mo&#380;na bez problemu u&#380;ywa&#263; zar&#243;wno do deweloperki jak i produkcyjnie. Ani Django ani Rails nie obs&#322;uguj&#261; wielow&#261;tkowo&#347;ci. Pylons obs&#322;uguje, dzi&#281;ki czemu te&#380; ma mniejsze zapotrzebowanie na pami&#281;&#263;.&lt;/p&gt;


	&lt;p&gt;Pylons oferuje wi&#281;c wi&#281;cej mo&#380;liwo&#347;ci, ale kosztem wi&#281;kszej z&#322;o&#380;ono&#347;ci. Django jest troch&#281; prostszy do opanowania. Ca&#322;a dokumentacja jest w jednym miejscu. Nauka Pylons wymaga si&#281;gni&#281;cia do oddzielnej dokumentacji SQLAlchemy, Mako czy &lt;a href="http://routes.groovie.org/"&gt;Routes&lt;/a&gt;. Sam SQLAlchemy jest te&#380; bardzo rozbudowany i trudniejszy do opanowania.&lt;/p&gt;


	&lt;h3&gt;Zope 3 &amp;#8211; najwy&#380;sza poprzeczka.&lt;/h3&gt;


	&lt;p&gt;Napisany w Pythonie, obiektowy, wielow&#261;tkowy serwer aplikacyjny &lt;a href="http://zope.org"&gt;Zope&lt;/a&gt; od dawna uchodzi&#322; za &amp;#8220;zab&#243;jcz&#261; aplikacj&#281;&amp;#8221; Pythona. Powsta&#322;o do niego tysi&#261;ce plugin&#243;w. Jednym z najs&#322;ynniejszych jest &lt;a href="http://plone.org"&gt;Plone &lt;span class="caps"&gt;CMS&lt;/span&gt;&lt;/a&gt; (wg mnie najlepszy &lt;span class="caps"&gt;CMS&lt;/span&gt; jaki napisano). Zope 2.x by&#322; jednak&#380;e krytykowany za zbytni&#261; z&#322;o&#380;ono&#347;&#263; i ba&#322;agan w &lt;span class="caps"&gt;API&lt;/span&gt;. Nauczenie si&#281; Zope wymaga&#322;o sporo wysi&#322;ku tak&#380;e z powodu s&#322;abej dokumentacji. Wi&#281;kszo&#347;&#263; lekkich framework&#243;w Pythona powsta&#322;o troch&#281; na bazie kontestacji Zope. Na szcz&#281;&#347;cie, tw&#243;rcy wyci&#261;gn&#281;li lekcj&#281; z Zope 2 i kod dla wersji 3 zosta&#322; napisany od zera. Znacznie uproszczono i uporz&#261;dkowano &lt;span class="caps"&gt;API&lt;/span&gt;.&lt;/p&gt;


	&lt;p&gt;Rails, Django czy Pylons s&#261; gro&#378;n&#261; konkurencj&#261; przede wszystkim dla popularnego &lt;span class="caps"&gt;PHP&lt;/span&gt;. To jest mniej wi&#281;cej dziedzina ich zastosowa&#324;. Zope za&#347; to troch&#281; inna filozofia i inna  grupa docelowa. Zope ma ambicj&#281; aby konkurowa&#263; z najpowa&#380;niejszymi zastosowaniami klasy enterprise opanowanymi g&#322;&#243;wnie przez Jav&#281;.&lt;/p&gt;


	&lt;p&gt;Przede wszystkim Zope to serwer aplikacyjny w pe&#322;ni obiektowy i o budowie komponentowej. Ka&#380;dy komponent ma &#347;ci&#347;le zdefiniowane interfejsy&lt;sup&gt;&lt;a href="#fn5"&gt;5&lt;/a&gt;&lt;/sup&gt;. Zope korzysta standardowo z &lt;a href="https://launchpad.net/zodb"&gt;prawdziwej bazy obiektowej&lt;/a&gt;. Nie potrzebuje &#380;adnego wspierania si&#281; wrapperami &lt;span class="caps"&gt;ORM&lt;/span&gt;. Baza obiektowa zapisuje ca&#322;e obiekty Pythona w spos&#243;b transparentny i stanowi naturalne przed&#322;u&#380;enie pisanego kodu. Zope 3 ma oczywi&#347;cie wbudowane wszystko co potrzebuje typowa aplikacja webowa, dobry cache, wbudowane mechanizmy bezpiecze&#324;stwa, przep&#322;ywu danych, lokalizacji interfejsu (i18n, l10n) itp. Pozwala te&#380; na prze&#322;adowywanie komponent&#243;w bez restartu serwera. Je&#347;li potrzeba nowej funkcjonalno&#347;ci, wystarczy napisa&#263; nowy komponent i podpi&#261;&#263; do serwera. Nie ma znaczenia czy tym komponentem b&#281;dzie &amp;#8220;artyku&#322;&amp;#8221;, czy &amp;#8220;plik graficzny&amp;#8221; czy ca&#322;y system redakcyjny, b&#261;d&#378; &lt;span class="caps"&gt;CMS&lt;/span&gt;.&lt;/p&gt;


	&lt;p&gt;Te mo&#380;liwo&#347;ci jednak nie s&#261; bez wad. Do najwi&#281;kszych zaliczy&#322;bym s&#322;ab&#261; promocj&#281; (to w og&#243;le jaka&#347; przypad&#322;o&#347;&#263; Pythona i jego aplikacji) oraz wci&#261;&#380; za s&#322;ab&#261; dokumentacj&#281;. Na szcz&#281;&#347;cie ta ostatnia rzec si&#281; troch&#281; poprawi&#322;a. Nawet s&#261; ju&#380; ksi&#261;&#380;ki dedykowane &lt;a href="http://worldcookery.com/"&gt;specjalnie dla Zope 3.3&lt;/a&gt;. Zope potrzebuje te&#380; znacznie wi&#281;cej pami&#281;ci ni&#380; taki Django czy Pylons.&lt;/p&gt;


	&lt;h3&gt;Ku przysz&#322;o&#347;ci.&lt;/h3&gt;


	&lt;p&gt;Dziedzina aplikacji webowych rozwija si&#281; bardzo dynamicznie i trudno co&#347; przewidzie&#263; w dalszej przysz&#322;o&#347;ci. W zwi&#261;zku z dynamicznym rozwojem procesor&#243;w wielordzeniowych, kto wie, czy renesansu nie prze&#380;yje j&#281;zyk &lt;a href="http://pl.wikipedia.org/wiki/Erlang_%28j%C4%99zyk_programowania%29"&gt;Erlang&lt;/a&gt; (bo doskonale si&#281; nadaje do programowania wsp&#243;&#322;bie&#380;nego). By&#263; mo&#380;e renesans prze&#380;yj&#261; serwery kontynuacyjne, kt&#243;re zapewniaj&#261; zachowanie stanu dla aplikacji webowej eliminuj&#261;c potrzeb&#281;  u&#380;ywania sesji. W serwerze kontynuacyjnym, pisanie kodu dla aplikacji webowej, czy desktopowej, prawie niczym si&#281; nie r&#243;&#380;ni. Na razie najbardziej znanym serwerem tego typu jest napisany w Smalltalku &amp;#8211; &lt;a href="http://en.wikipedia.org/wiki/Seaside_%28software%29"&gt;Seaside&lt;/a&gt;. Du&#380;y potencja&#322; ma te&#380; Ruby, bo posiada wbudowan&#261; obs&#322;ug&#281; kontynuacji.&lt;/p&gt;


	&lt;p&gt;Na pewno obawa co do znalezienia pracy w Rails czy Pythonie raczej nie ma du&#380;ego uzasadnienia. Jest wiele firm u&#380;ywaj&#261;cych Pythona. Najlepszym przyk&#322;adem jest Google, kt&#243;ry prawie wszystko ma oparte na Pythonie. Od czasu do czasu pojawiaj&#261; si&#281; w Polsce dramatyczne ;) wo&#322;ania o programist&#243;w Pythona, wi&#281;c cho&#263; ofert nie ma tyle co dla Javy i .NET, to mo&#380;na co&#347; wyszuka&#263;. Je&#347;li chodzi o Ruby on Rails, to ofert zaczyna by&#263; coraz wi&#281;cej, jest ju&#380; troch&#281; wi&#281;cej ni&#380; dla Pythona. Rails p&#281;dzi na pe&#322;nej szybko&#347;ci i dzi&#281;ki dobre promocji wdziera si&#281; coraz szerzej do &#347;wiadomo&#347;ci programist&#243;w g&#322;&#243;wnego nurtu. Sam pracuj&#281; w firmie gdzie g&#322;&#243;wny system oparty jest na Springu i Hibernate, technologiach Javy. Jednak&#380;e do tworzenia aplikacji webowej zosta&#322; wybrany Ruby on Rails.&lt;/p&gt;


	&lt;p&gt;&lt;strong&gt;Podsumowuj&#261;c&lt;/strong&gt; powiedzia&#322;bym, &#380;e wsp&#243;&#322;czesny programista musi operowa&#263; kilkoma j&#281;zykami i technologiami. Dzisiaj pracuje si&#281; w heterogenicznym &#347;rodowisku i wykorzystuje mieszane technologie. Kto my&#347;li, &#380;e nauczy si&#281; tylko jednego, doskona&#322;ego j&#281;zyka i tylko jednego frameworka, pewnie mocno si&#281; rozczaruje w zderzeniu z rzeczywisto&#347;ci&#261;&lt;sup&gt;&lt;a href="#fn6"&gt;6&lt;/a&gt;&lt;/sup&gt;.&lt;/p&gt;


	&lt;p&gt;Do lekkich webowych interfejs&#243;w z du&#380;&#261; ilo&#347;ci&#261; &lt;span class="caps"&gt;AJAX&lt;/span&gt;&amp;#8217;a wybra&#322;bym Rails. Tak&#380;e dla os&#243;b pocz&#261;tkuj&#261;cych, pragn&#261;cych nabra&#263; dobrych nawyk&#243;w, wybra&#322;bym Rails&lt;sup&gt;&lt;a href="#fn7"&gt;7&lt;/a&gt;&lt;/sup&gt;.  Tam, gdzie wymagane jest jednak dobre wsparcie dla Unicode oraz gdzie wydajno&#347;&#263; jest bardziej kluczowa, wybra&#322;bym Pylons&lt;sup&gt;&lt;a href="#fn8"&gt;8&lt;/a&gt;&lt;/sup&gt;. Z kolei, je&#347;li chcemy uderzy&#263; w rynek bardziej kompleksowych rozwi&#261;za&#324; dla biznesu, Zope 3 b&#281;dzie raczej trudny do pobicia. I w ko&#324;cu, tam, gdzie potrzebujemy gotowego, dobrego forum i taniego hostingu najlepiej sprawdzi si&#281; &lt;span class="caps"&gt;PHP&lt;/span&gt; (tak, najlepsze, gotowe do u&#380;ycia forum s&#261; napisane w &lt;span class="caps"&gt;PHP&lt;/span&gt;).&lt;/p&gt;


	&lt;p&gt;&lt;em&gt;Apendix&lt;/em&gt;: Jest dost&#281;pne &lt;a href="http://www.makotemplates.org/trac"&gt;kolorowanie sk&#322;adni&lt;/a&gt; Mako dla kilku edytor&#243;w (TextMate, Emacs, Vim i Komodo). &lt;small&gt;(2007-09-12)&lt;/small&gt;&lt;/p&gt;


&lt;hr size="1" /&gt;

	&lt;p id="fn1"&gt;&lt;sup&gt;1&lt;/sup&gt; Tak w og&#243;le to kwestia por&#243;wnania Active Record, SQLAlchemy i Django nie jest taka oczywista. Ka&#380;dy posiada co&#347;, czego nie posiada drugi. Np. Active Record posiada eleganckie walidatory, kt&#243;rych nie ma w SQLAlchemy. Z kolei Django nie umie podpi&#261;&#263; si&#281; do wielu baz, ale posiada wygodne, wysokopoziomowe pola w modelu. SQLAlchemy za&#347; podepnie si&#281; do najbardziej pogmatwanej struktury, wielu baz i to wszystko w elegancki, obiektowy spos&#243;b, a nie z brutalnymi wstawkami kodu &lt;span class="caps"&gt;SQL&lt;/span&gt;, jak ma miejsce w Active Record. Poza tym SQLAlchemy potrafi optymalizowa&#263; zapytania tak, aby kilka polece&#324; wykona&#263; mo&#380;liwe najmniejsz&#261; ilo&#347;ci&#261; kwerend i po&#322;&#261;cze&#324; z baz&#261;.&lt;/p&gt;


	&lt;p id="fn2"&gt;&lt;sup&gt;2&lt;/sup&gt; Rails nie ma problemu podpi&#281;cia si&#281; do wielu baz. Za&#347; struktury takie jak z&#322;o&#380;one klucze g&#322;&#243;wne potrafi obs&#322;u&#380;y&#263; za pomoc&#261; &lt;a href="http://compositekeys.rubyforge.org/"&gt;odpowiednich plugin&#243;w&lt;/a&gt;.&lt;/p&gt;


	&lt;p id="fn3"&gt;&lt;sup&gt;3&lt;/sup&gt; Mako pozwala na wi&#281;cej ni&#380; proste dziedziczenie tak jak ma Django. Pozwala na &lt;a href="http://www.makotemplates.org/docs/inheritance.html#inheritance_next"&gt;kaskad&#281; dziedziczenia&lt;/a&gt;.&lt;/p&gt;


	&lt;p id="fn4"&gt;&lt;sup&gt;4&lt;/sup&gt; Rails ma s&#322;abe mo&#380;liwo&#347;ci w zakresie buforowania danych. Np. nie potrafi buforowa&#263; fragment&#243;w szablon&#243;w w oparciu o unikalny klucz (z parametr&#243;w adresu &lt;span class="caps"&gt;URL&lt;/span&gt; lub w oparciu o inne kryteria).&lt;/p&gt;


	&lt;p id="fn5"&gt;&lt;sup&gt;5&lt;/sup&gt; Sam Python nie posiada wbudowanej sk&#322;adni do tworzenia interfejs&#243;w czy klas abstrakcyjnych. Autorzy Zope 3 jednak je cz&#281;&#347;ciowo zasymulowali korzystaj&#261;c z tego, co oferuje j&#281;zyk.&lt;/p&gt;


	&lt;p id="fn6"&gt;&lt;sup&gt;6&lt;/sup&gt; W tym wszystkim za ma&#322;o pad&#322;o o znajomo&#347;ci JavaScript. Nie jest to zbyt prosty i intuicyjny j&#281;zyk, a ma spore mo&#380;liwo&#347;ci i jest bardzo dynamiczny. Jego znajomo&#347;&#263; jest absolutnie niezb&#281;dna dla ka&#380;dej osoby chc&#261;cej tworzy&#263; aplikacje internetowe. &lt;span class="caps"&gt;O CSS&lt;/span&gt; i &lt;span class="caps"&gt;XHTML&lt;/span&gt; nie wspominam, bo to oczywiste podstawy.&lt;/p&gt;


	&lt;p id="fn7"&gt;&lt;sup&gt;7&lt;/sup&gt; Rozpoczynanie przygody z tworzeniem aplikacji webowych od &lt;span class="caps"&gt;PHP&lt;/span&gt; jest najgorsz&#261; rzecz&#261; jak&#261; mo&#380;emy zrobi&#263;. &lt;span class="caps"&gt;PHP&lt;/span&gt; za bardzo zach&#281;ca i utrwala z&#322;e nawyki programistyczne. To w&#322;a&#347;nie mia&#322; na my&#347;li &lt;span class="caps"&gt;DHH&lt;/span&gt;, tw&#243;rca Rails, kiedy por&#243;wna&#322; &lt;span class="caps"&gt;PHP&lt;/span&gt; do&amp;#8230; diab&#322;a. :)&lt;/p&gt;


	&lt;p id="fn8"&gt;&lt;sup&gt;8&lt;/sup&gt;  A co z Django? Je&#347;li mam wybiera&#263; mi&#281;dzy Django a Pylons, to wol&#281; Pylons. Ma wi&#281;ksze mo&#380;liwo&#347;ci i osi&#261;gn&#261;&#322; wystarczaj&#261;c&#261; dojrza&#322;o&#347;&#263; aby podwa&#380;y&#263; dominacj&#281; i popularno&#347;&#263; Django w kr&#281;gach pythonistas. Jedn&#261; z polskich firm, kt&#243;ra wdro&#380;y&#322;a i u&#380;ywa z sukcesem Pylons&#243;w jest firma, w kt&#243;rej sp&#281;dzi&#322;em par&#281; lat i gdzie wdro&#380;y&#322;em kiedy&#347; Pythona &amp;#8211; &lt;a href="http://www.muratordom.pl"&gt;Wydawnictwo Murator&lt;/a&gt;. Pozdrowienia dla ekipy. :)&lt;/p&gt;</description>
      <pubDate>Sat, 25 Aug 2007 21:22:00 +0200</pubDate>
      <guid isPermaLink="false">urn:uuid:f173a45f-730a-4ea9-97f1-330d88a27cc0</guid>
      <author>Jaros&#322;aw Zabie&#322;&#322;o</author>
      <link>http://blog.zabiello.com/articles/2007/08/25/aplikacja-webowa-wybor-technologii</link>
      <category>python</category>
      <category>ruby</category>
      <category>php</category>
      <category>rails</category>
      <category>django</category>
      <category>pylons</category>
    </item>
    <item>
      <title>MySQLdb i problem polskich znak&#243;w</title>
      <description>&lt;p&gt;W ko&#324;cu pojawi&#322;a si&#281; wersja stabilna pythonowej biblioteki &lt;a href="http://sourceforge.net/project/showfiles.php?group_id=22307&amp;#38;package_id=15775"&gt;MySQLdb 1.2.2&lt;/a&gt;. Co ciekawsze, jest dost&#281;pna instalacja w formie pakieru &lt;a href="http://peak.telecommunity.com/DevCenter/PythonEggs"&gt;egg&lt;/a&gt; zar&#243;wno dla Pythona 2.4 jak i 2.5. Nie trzeba te&#380; ju&#380; wi&#281;cej u&#380;ywa&#263; instalator&#243;w binarnych pod windoz&#261;. Wystarczy (zak&#322;adaj&#261;c &#380;e mamy zainstalowane &lt;a href="http://peak.telecommunity.com/dist/ez_setup.py"&gt;setuptoolsy&lt;/a&gt;) wykona&#263; komend&#281;:&lt;/p&gt;


&lt;div class="typocode"&gt;&lt;pre&gt;&lt;code class="typocode_ruby "&gt;&lt;span class="ident"&gt;easy_install&lt;/span&gt; &lt;span class="punct"&gt;-&lt;/span&gt;&lt;span class="constant"&gt;U&lt;/span&gt; &lt;span class="constant"&gt;MySQL_python&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

	&lt;p&gt;Osoby u&#380;ywaj&#261;ce &lt;a href="http://djangoproject.com"&gt;Django&lt;/a&gt; i MySQL5 musz&#261; pami&#281;ta&#263; aby doda&#263; dodatkow&#261; opcj&#281; do settings.py.&lt;/p&gt;


	&lt;p&gt;W wypadku wersji edge (z &lt;span class="caps"&gt;SVN&lt;/span&gt;), nale&#380;y doda&#263;:&lt;/p&gt;


&lt;div class="typocode"&gt;&lt;pre&gt;&lt;code class="typocode_ruby "&gt;&lt;span class="constant"&gt;DATABASE_OPTIONS&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="punct"&gt;{'&lt;/span&gt;&lt;span class="string"&gt;use_unicode&lt;/span&gt;&lt;span class="punct"&gt;':&lt;/span&gt; &lt;span class="constant"&gt;True&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="punct"&gt;'&lt;/span&gt;&lt;span class="string"&gt;charset&lt;/span&gt;&lt;span class="punct"&gt;':&lt;/span&gt; &lt;span class="punct"&gt;'&lt;/span&gt;&lt;span class="string"&gt;utf8&lt;/span&gt;&lt;span class="punct"&gt;'}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

	&lt;p&gt;W przypadku starszego kodu to nie pomaga&#322;o. Musia&#322;em wy&#322;&#261;czy&#263; zwracanie wynik&#243;w w postaci obiekt&#243;w unikodowych Pythona. W tym wypadku podzia&#322;a&#322;a opcja:&lt;/p&gt;


&lt;div class="typocode"&gt;&lt;pre&gt;&lt;code class="typocode_ruby "&gt;&lt;span class="constant"&gt;DATABASE_OPTIONS&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="punct"&gt;{'&lt;/span&gt;&lt;span class="string"&gt;use_unicode&lt;/span&gt;&lt;span class="punct"&gt;':&lt;/span&gt; &lt;span class="constant"&gt;False&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="punct"&gt;'&lt;/span&gt;&lt;span class="string"&gt;charset&lt;/span&gt;&lt;span class="punct"&gt;':&lt;/span&gt; &lt;span class="punct"&gt;'&lt;/span&gt;&lt;span class="string"&gt;utf8&lt;/span&gt;&lt;span class="punct"&gt;'}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

	&lt;p&gt;Widz&#281;, &#380;e Django najwyra&#378;niej idzie w tym samym kierunku co Pylons, tzn. my&#347;li aby wszystkie stringi i prac&#281; z baz&#261; oprze&#263; na obiektach unikodowych a nie stringach &lt;span class="caps"&gt;UTF&lt;/span&gt;-8. W wypadku &lt;a href="http://pylonshq.com"&gt;Pylons&#243;w&lt;/a&gt;, ich najnowszy system szablon&#243;w &lt;a href="http://makotemplates.org"&gt;Mako&lt;/a&gt; standardowo ju&#380; pracuje wewn&#281;trznie na czystych obiektach unikodowych Pythona.&lt;/p&gt;


	&lt;p&gt;Uwaga! Django ma troch&#281; niedopracowanego kodu. Np. panel admina si&#281; sypie jak ustawiona jest powy&#380;sza opcja z w&#322;&#261;czonym unikodem. Trzeba j&#261; &lt;strong&gt;wy&#322;&#261;czy&#263;&lt;/strong&gt;. Ale wtedy z kolei &#378;le si&#281; wy&#347;wietla cz&#281;&#347;&#263; tekst&#243;w zawieraj&#261;ca polskie znaki (np. imi&#281; czy nazwisko redaktora). Jednak lepsza to ni&#380; w og&#243;le brak mo&#380;liwo&#347;ci edycji rekord&#243;w. Wniosek: dla Django u&#380;ywaj drugiej opcji.  Aktualnie kod Django jeszcze nie dor&#243;s&#322; do tego, aby u&#380;ywa&#263; pe&#322;nego unikodu z baz&#261; MySQL.&lt;/p&gt;</description>
      <pubDate>Fri, 16 Mar 2007 02:36:00 +0100</pubDate>
      <guid isPermaLink="false">urn:uuid:29066297-2244-4a17-8e9b-e565744d5f6d</guid>
      <author>Jaros&#322;aw Zabie&#322;&#322;o</author>
      <link>http://blog.zabiello.com/articles/2007/03/16/django-encoding</link>
      <category>mysql</category>
      <category>python</category>
      <category>django</category>
    </item>
    <item>
      <title>Por&#243;wnanie wydajno&#347;ci framework&#243;w</title>
      <description>&lt;p&gt;Ciekawe i dosy&#263; dok&#322;adne  &lt;a href="http://www.alrond.com/en/2007/jan/25/performance-test-of-6-leading-frameworks/"&gt;por&#243;wnanie wydajno&#347;ci&lt;/a&gt; paru framework&#243;w:&lt;/p&gt;


	&lt;ul&gt;
	&lt;li&gt;&lt;a href="http://www.codeigniter.com/"&gt;CodeIgniter&lt;/a&gt; (PHP)&lt;/li&gt;
		&lt;li&gt;&lt;a href="http://www.catalystframework.org/"&gt;Catalyst&lt;/a&gt; (Perl)&lt;/li&gt;
		&lt;li&gt;&lt;a href="http://djangoproject.com"&gt;Django&lt;/a&gt; (Python)&lt;/li&gt;
		&lt;li&gt;&lt;a href="http://djangoproject.com"&gt;Django&lt;/a&gt; (Python + Psyco)&lt;/li&gt;
		&lt;li&gt;&lt;a href="http://rubyonrails.org"&gt;RubyOnRails&lt;/a&gt; (Ruby)&lt;/li&gt;
		&lt;li&gt;&lt;a href="http://www.symfony-project.com/"&gt;Symfony&lt;/a&gt; (PHP)&lt;/li&gt;
		&lt;li&gt;&lt;a href="http://www.turbogears.org/"&gt;TurboGears&lt;/a&gt; (Python)&lt;/li&gt;
	&lt;/ul&gt;


	&lt;p&gt;Django bez trudu zdeklasowa&#322;o konkurencj&#281;. Szkoda, &#380;e w por&#243;wnaniu nie uwzgl&#281;dniono &lt;a href="http://pylonshq.com"&gt;Pylons&#243;w&lt;/a&gt; i &lt;a href="http://www.cakephp.org/"&gt;CakePHP&lt;/a&gt;. Bardzo te&#380; dziwne, &#380;e nowy Rails 1.2.1 w tych testach jest mocno wolniejszy od starszej wersji 1.1.6. Frameworki pehapowe okaza&#322;y si&#281; najwolniejsze. Najgorszy okaza&#322; si&#281; pehapowy &lt;a href="http://www.symfony-project.com/"&gt;Symfony&lt;/a&gt;. Jest skomplikowany i wolny, 35x wolniejszy od &lt;a href="http://djangoproject.com"&gt;Django&lt;/a&gt;!&lt;/p&gt;</description>
      <pubDate>Sun, 04 Feb 2007 22:54:00 +0100</pubDate>
      <guid isPermaLink="false">urn:uuid:778b23bb-3fe6-4d3c-a715-f75c2f2c8dc8</guid>
      <author>Jaros&#322;aw Zabie&#322;&#322;o</author>
      <link>http://blog.zabiello.com/articles/2007/02/04/por%C3%B3wnanie-wydajno%C5%9Bci-framework%C3%B3w</link>
      <category>django</category>
      <category>rails</category>
      <category>symfony</category>
      <category>turbogears</category>
      <category>catalist</category>
      <category>python</category>
      <category>php</category>
      <category>perl</category>
      <category>ruby</category>
    </item>
    <item>
      <title>Szablony i wzorzec MVC - cz. III</title>
      <description>&lt;p&gt;W &lt;a href="http://blog.zabiello.com/articles/2007/01/06/templates-and-mvc-2"&gt;poprzedniej cz&#281;&#347;ci&lt;/a&gt; om&#243;wiono szablony dedykowane g&#322;&#243;wnie do wsp&#243;&#322;pracy z designerami boj&#261;cymi si&#281; programowa&#263;. By&#322;y to albo szablony wk&#322;adaj&#261;ce swoj&#261; logik&#281; do znacznik&#243;w &lt;span class="caps"&gt;XML&lt;/span&gt;/XHTML (ZPT, SimpleTAL, Kid, Genshi, MasterView, &lt;span class="caps"&gt;PHP TAL&lt;/span&gt;), albo szablony posiadaj&#261;ce sw&#243;j w&#322;asny, specjalizowany j&#281;zyk (Smarty, Django, Jinja, Liquid). W za&#322;o&#380;eniu taki j&#281;zyk mia&#322; by&#263; prostym substytutem j&#281;zyka u&#380;ywanego w warstwie kontrolera. Szablony tego typu mo&#380;e s&#261; wygodne dla designera, ale na pewno nie dla programisty, kt&#243;ry musi je &lt;strong&gt;przygotowa&#263;&lt;/strong&gt;. Po pierwsze, trzeba si&#281; uczy&#263; kolejnego j&#281;zyka&amp;#8230; szablon&#243;w. Po drugie, wszystkie tego typu j&#281;zyki s&#261; ograniczaj&#261;ce dla programisty. Mimo &#380;e pozornie prostsze, w praktyce s&#261; bardziej z&#322;o&#380;one i to nawet dla designera. Np. szablony Django i Jinja nie posiadaj&#261; &#380;adnej sk&#322;adni na okre&#347;lenie trywialnego warunku wi&#281;kszo&#347;ci, mniejszo&#347;ci:&lt;/p&gt;


&lt;div class="typocode"&gt;&lt;pre&gt;&lt;code class="typocode_django "&gt;{{ x }} jest 
{% if x &amp;gt; y %} 
    wi&#281;ksze 
{% else %} 
    mniejsze 
{% endif %} 
od {{ y }}&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

	&lt;p&gt;Powoduje to mas&#281; k&#322;opot&#243;w dla programisty&lt;sup&gt;&lt;a href="#fn1"&gt;1&lt;/a&gt;&lt;/sup&gt;. Prymitywna sk&#322;adnia szablonu wymusza wi&#281;c kup&#281; dodatkowej pracy. O ile&#380; pro&#347;ciej jest u&#380;y&#263; po prostu pe&#322;nej sk&#322;adni j&#281;zyka tak jak to robi&#261; szablony Cheetah:&lt;/p&gt;


&lt;div class="typocode"&gt;&lt;pre&gt;&lt;code class="typocode_cheetah "&gt;$x jest 
# if x &amp;gt; y 
    wi&#281;ksze 
# else 
    mniejsze 
# endif  
od $y&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

	&lt;p&gt;Dochodzimy tu wi&#281;c do sytuacji kiedy by&#347;my chcieli co&#347; bardziej elastycznego &amp;#8211; pe&#322;nego dost&#281;pu do j&#281;zyka programowania. Taka sytuacja jest po&#380;&#261;dana wtedy kiedy i tak szablony buduj&#261; programi&#347;ci na podstawie dostarczonego czystego kodu &lt;span class="caps"&gt;HTML&lt;/span&gt; od designer&#243;w.&lt;/p&gt;


	&lt;h2&gt;&lt;span class="caps"&gt;PHP&lt;/span&gt;&lt;/h2&gt;


	&lt;p&gt;J&#281;zyk &lt;span class="caps"&gt;PHP&lt;/span&gt; jest dosy&#263; specyficzny, bo w istocie jest to j&#281;zyk szablon&#243;w. Tzn. pierwotnie tak zosta&#322; stworzony, ale z czasem si&#281; skomplikowa&#322; &#380;e dost&#261;pi&#322; miana j&#281;zyka skryptowego. Ale jego korzenie wida&#263; w sk&#322;adni, kt&#243;ra z definicji jest zagnie&#380;d&#380;aniem instrukcji &lt;span class="caps"&gt;PHP&lt;/span&gt; wewn&#261;trz kodu &lt;span class="caps"&gt;HTML&lt;/span&gt;. Id&#261;c tym tropem, niekt&#243;rzy pomy&#347;leli, &#380;e nie ma sensu wymy&#347;la&#263; dodatkow&#261; sk&#322;adni&#281;. Wystarczy u&#380;y&#263; &lt;span class="caps"&gt;PHP&lt;/span&gt; w odpowiedni spos&#243;b. I tak powsta&#322;y szablony &lt;a href="http://phpsavant.com/yawiki/"&gt;&lt;strong&gt;Savant&lt;/strong&gt;&lt;/a&gt;.&lt;/p&gt;


	&lt;p&gt;W&#322;a&#347;ciwie to Savant nie powinny nazywa&#263; si&#281; szablonami, bo to nic innego jak &lt;span class="caps"&gt;PHP&lt;/span&gt; u&#380;yty w taki spos&#243;b, aby rozdzieli&#263; warstw&#281; prezentacji, od wartwy logiki biznesowej. A skoro to &lt;span class="caps"&gt;PHP&lt;/span&gt;, to odpada nauka dodatkowej sk&#322;adni oraz potrzeby kompilacji specjalizowanego j&#281;zyka szablon&#243;w do ko&#324;cowego kodu &lt;span class="caps"&gt;PHP&lt;/span&gt; (jak to ma miejsce w szablonach &lt;a href="http://smarty.php.net"&gt;Smarty&lt;/a&gt;).&lt;/p&gt;


	&lt;p&gt;Czy takie podej&#347;cie jest lepsze, czy gorsze, to ju&#380; ka&#380;dy mo&#380;e sobie oceni&#263;. Moim zdaniem &lt;span class="caps"&gt;PHP&lt;/span&gt; ma na tyle m&#281;tn&#261; sk&#322;adni&#281;, &#380;e warstwa prezentacji u&#380;ywaj&#261;ca Smarty&lt;sup&gt;&lt;a href="#fn2"&gt;2&lt;/a&gt;&lt;/sup&gt; jest bardziej czytelna ni&#380; czysty &lt;span class="caps"&gt;PHP&lt;/span&gt; jaki u&#380;ywaj&#261; Savant.&lt;/p&gt;


	&lt;h2&gt;Ruby&lt;/h2&gt;


	&lt;p&gt;Kiedy m&#243;wimy o Ruby w kontek&#347;cie stron internetowych to najcz&#281;&#347;ciej mamy na my&#347;li jego najs&#322;ynniejszy framework &amp;#8211; &lt;a href="http://rubyonrails.org"&gt;Rails&lt;/a&gt;. Ruby sam w sobie nie jest zwi&#261;zany z &lt;span class="caps"&gt;HTML&lt;/span&gt; tak jak &lt;span class="caps"&gt;PHP&lt;/span&gt;. Rails do szablon&#243;w u&#380;ywa biblioteki &lt;a href="http://www.ruby-doc.org/stdlib/libdoc/erb/rdoc/"&gt;&lt;strong&gt;ERb&lt;/strong&gt;&lt;/a&gt; (ang. &amp;#8220;embed Ruby&amp;#8221;,  czyli &amp;#8220;zagnie&#380;d&#380;ony Ruby&amp;#8221;) Sk&#322;adnia jest bardzo podobna do &lt;span class="caps"&gt;PHP&lt;/span&gt;, &lt;a href="http://java.sun.com/products/jsp/"&gt;&lt;span class="caps"&gt;JSP&lt;/span&gt;&lt;/a&gt; czy &lt;span class="caps"&gt;ASP&lt;/span&gt;. Ruby jest tu j&#281;zykiem zagnie&#380;d&#380;onym w &lt;span class="caps"&gt;HTML&lt;/span&gt;.&lt;/p&gt;


&lt;div class="typocode"&gt;&lt;pre&gt;&lt;code class="typocode_ruby "&gt;&lt;span class="punct"&gt;&amp;lt;%=&lt;/span&gt;&lt;span class="string"&gt; x %&amp;gt; jest 
&amp;lt;% if x &amp;gt; y %&amp;gt; 
    wi&#281;ksze 
&amp;lt;% else %&amp;gt;
    mniejsze 
&amp;lt;% end %&amp;gt;
od &amp;lt;%&lt;/span&gt;&lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="ident"&gt;y&lt;/span&gt; &lt;span class="punct"&gt;%&amp;gt;&lt;/span&gt;&lt;span class="string"&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

	&lt;h2&gt;Python&lt;/h2&gt;


	&lt;p&gt;Je&#347;li chodzi o Pythona to istnieje &lt;a href="http://wiki.python.org/moin/Templating"&gt;ca&#322;a masa system&#243;w szablonowych&lt;/a&gt;. Ogranicz&#281; si&#281; do paru, tych bardziej interesuj&#261;cych.&lt;/p&gt;


	&lt;h3&gt;Spyce&lt;/h3&gt;


	&lt;p&gt;Szablony &lt;a href="http://spyce.sourceforge.net/"&gt;Spyce&lt;/a&gt; zosta&#322;o stworzone jako pythonowa konkurencja dla &lt;span class="caps"&gt;PHP&lt;/span&gt;. Podobnie potrafi&#261; przeplata&#263; j&#281;zyk (tu: Pythona) z tagami &lt;span class="caps"&gt;HTML&lt;/span&gt;. Najbardziej oczywista przewaga Spyce wynika z faktu u&#380;ywania j&#281;zyka &lt;a href="http://python.org"&gt;Python&lt;/a&gt;, kt&#243;ry jest znacznie lepiej zaprojektowany i posiada du&#380;o wi&#281;cej mo&#380;liwo&#347;ci ni&#380; &lt;span class="caps"&gt;PHP&lt;/span&gt;. Spyce potrafii budowa&#263; w&#322;asne znaczniki (custom tags, podobnie jak to potrafi&#261; javowe &lt;span class="caps"&gt;JSP&lt;/span&gt;) oraz &#322;atwiej w nich zbudowa&#263; komponenty, kod  do wielokrotnego u&#380;ytku.&lt;/p&gt;


	&lt;h3&gt;Myghty&lt;/h3&gt;


	&lt;p&gt;Szablony &lt;a href="http://myghty.org"&gt;Myghty&lt;/a&gt; powsta&#322;y pierwotnie jako pythonowa implementacja systemu komponentowego &lt;a href="http://masonhq.com"&gt;Mason&lt;/a&gt; dla &lt;a href="http://www.perl.org/"&gt;Perla&lt;/a&gt;. Mimo wielu podobie&#324;stw, Myghty s&#261; znacznie pot&#281;&#380;niejsze o Masona, np. intensywnie wykorzystuj&#261; &lt;strong&gt;obiektowo&#347;&#263;&lt;/strong&gt; Pythona (zobacz &lt;a href="http://www.myghty.org/docs/technical.myt#technical_differences"&gt;r&#243;&#380;nice&lt;/a&gt;). Od pocz&#261;tku Myghty powsta&#322;o z my&#347;l&#261; o du&#380;ych obci&#261;&#380;eniach, ci&#281;&#380;kich, profesjonalnych zastosowaniach. Maj&#261; doskona&#322;y w&#322;asny cache, s&#261; bardzo szybkie, odporne na w&#261;tki, &#347;wietnie si&#281; nadaj&#261; do tworzenia komponent&#243;w.&lt;/p&gt;


	&lt;p&gt;Programi&#347;ci Pythona bardzo ceni&#261; sobie filozofi&#281; tego j&#281;zyka (kt&#243;ra podkre&#347;la prostot&#281;, oczywisto&#347;&#263; i elegancj&#281; sk&#322;adni).  Problem w tym, &#380;e Myghty dla pythonowc&#243;w jest zbyt podobne do Perla. S&#261; za ma&#322;o &amp;#8220;pythonic&amp;#8221; &amp;#8211; pythonowe. Dodatkowo, poprzez podkre&#347;lanie swojej komponentowo&#347;ci, Myghty niekt&#243;rym zbyt kojarzy si&#281; z filozofi&#261; komponentow&#261; frameworku &lt;span class="caps"&gt;ASP&lt;/span&gt;.NET (a wzorzec &lt;span class="caps"&gt;MVC&lt;/span&gt; wydaje si&#281; by&#263; bardziej przejrzysty ni&#380; wzorzec sterowanych zdarzeniami komponent&#243;w).  Myghty, jako system komponentowy, mo&#380;e by&#263; u&#380;ywane w stylu &lt;span class="caps"&gt;MVC&lt;/span&gt;, ale nie jest to takie naturalne i oczywiste. (Na szcz&#281;&#347;cie, wszystko zmieni&#322; &lt;a href="http://pylonshq.com"&gt;Pylons&lt;/a&gt; kt&#243;ry zapewnia przejrzyst&#261; prac&#281; zgodn&#261; z wzorcem &lt;span class="caps"&gt;MVC&lt;/span&gt; i Myghty s&#261; tam zredukowane tylko do obs&#322;ugi szablon&#243;w szablon&#243;w. Sterowaniem zajmuj&#261; si&#281; kontrolery Pylonsa a nie Myghty).&lt;/p&gt;


	&lt;h3&gt;Cheetah&lt;/h3&gt;


	&lt;p&gt;Szablony &lt;a href="http://cheetahtemplate.org"&gt;Cheetah&lt;/a&gt; posiadaj&#261; jedn&#261; z najbardziej czytelnych i eleganckich sk&#322;adni. Autorzy wzorowali si&#281; troch&#281; na javowych Velocity i Webmacro. Tym, kt&#243;rzy ceni&#261; sobie czysto&#347;&#263; Pythona z prostot&#261; sk&#322;adni szablon&#243;w z pewno&#347;ci&#261; Cheetah mog&#261; przypa&#347;&#263; do gustu. Przez d&#322;u&#380;szy czas by&#322;y moimi ulubionymi szablonami i do te pory lubi&#281; ich klarowno&#347;&#263;. Cheetah posiadaj&#261; eleganck&#261; sk&#322;adni&#281; obiektowego budowania szablon&#243;w potomnych na bazie ju&#380; istniej&#261;cych. Myghty te&#380; to potrafi, ale Cheetah to ma bardzo czytelnie zrobione. Cheetah s&#261; r&#243;wnie&#380; bardzo szybkie.&lt;/p&gt;


	&lt;h3&gt;Mako&lt;/h3&gt;


	&lt;p&gt;&lt;a href="http://makotemplates.org"&gt;Mako&lt;/a&gt; to najm&#322;odsze dziecko stworzone przez programist&#243;w &lt;a href="http://pylonshq.com"&gt;Pylons&#243;w&lt;/a&gt;. Powsta&#322;y na bazie do&#347;wiadcze&#324; i najlepszych cech szablon&#243;w Myghty, Cheetah, Django/Jinja czy Smarty. Najwi&#281;ksz&#261; ich zalet&#261; jest &lt;strong&gt;ogromna szybko&#347;&#263; i pythonowa filozofia pracy&lt;/strong&gt;. Programi&#347;ci Pythona mog&#261; zauwa&#380;y&#263;, &#380;e sk&#322;adnia Mako jest bardzo bliska sposobowi pracy w samym j&#281;zyku Python. Mako posiadaj&#261; wielk&#261; &#322;atwo&#347;&#263; tworzenia komponent&#243;w, ale w spos&#243;b bardzo podobny do tego jak Python wykorzystuje swoje modu&#322;y. Szablony mo&#380;na tak&#380;e rozszerza&#263; na drodze obiektowego dziedziczenia. Dziedziczenie szablon&#243;w mo&#380;e by&#263; okre&#347;lane w spos&#243;b dynamiczny (tego ju&#380; nie potrafi&#261; np. Cheetah). Dowolny fragment szablonu mo&#380;na r&#243;wnie&#380; zamieni&#263; na komponent z w&#322;asnym cache. Mako posiadaj&#261; tak&#380;e sk&#322;adni&#281; modyfikator&#243;w, kt&#243;re spopularyzowane zosta&#322;y przez Smarty. Dzia&#322;aj&#261; one jak uniksowe pipes (${zmienna|filter}.&lt;/p&gt;


	&lt;p&gt;Mako automatycznie kompiluj&#261; sw&#243;j kod do modu&#322;&#243;w Pythona. Mo&#380;na je wi&#281;c debugowa&#263; tak jak zwyk&#322;y kod Pythona (Cheeatah wymaga r&#281;cznej kompilacji). Mo&#380;na je bez problemu u&#380;ywa&#263; jako niezale&#380;n&#261; bibliotek&#281;. Nie s&#261; one zale&#380;ne od jakiegokolwiek frameworku. Mo&#380;na je zintegrowa&#263; z dowolnym frameworkiem u&#380;ywaj&#261;cym standardu&lt;sup&gt;&lt;a href="#fn3"&gt;3&lt;/a&gt;&lt;/sup&gt; &lt;span class="caps"&gt;WSGI&lt;/span&gt;. U&#380;ytkownicy frameworka &lt;a href="http://pylonshq.com"&gt;Pylons&lt;/a&gt; prawie nic nie musz&#261; robi&#263;, bo Mako s&#261; ju&#380; tam przygotowane do pracy.&lt;/p&gt;


	&lt;p&gt;Og&#243;lnie rzecz bior&#261;c, &lt;strong&gt;Mako&lt;/strong&gt; to &amp;#8211; moim zdaniem &amp;#8211; najlepszy aktualnie istniej&#261;cy system szablon&#243;w dla Pythona.&lt;/p&gt;


	&lt;p&gt;Za&#347; co do framework&#243;w&amp;#8230; to coraz bardziej zaczynam nabiera&#263; pewno&#347;ci, &#380;e przysz&#322;o&#347;&#263; nie nale&#380;y ani do Django, ani do Rails&#243;w. Nic nie mo&#380;e r&#243;wna&#263; si&#281; z mo&#380;liwo&#347;ciami czystego, 100%  frameworka &lt;span class="caps"&gt;WSGI&lt;/span&gt;. Takim jest np. &lt;a href="http://pylonshq.com"&gt;Pylons&lt;/a&gt;. Ale o tym, i o &amp;#8220;bitwie&amp;#8221; Pylons vs. Django i Rails, napisz&#281; ju&#380; innym razem.&lt;/p&gt;


	&lt;p&gt;Appendix 2007-01-29: Zobacz te&#380; &lt;a href="http://blog.zabiello.com/articles/2007/01/27/haml-nast%C4%99pna-generacja-szablon%C3%B3w"&gt;szablony Haml&lt;/a&gt;
.&lt;/p&gt;


&lt;hr /&gt;

	&lt;p id="fn1"&gt;&lt;sup&gt;1&lt;/sup&gt; Poprawnie rzecz m&#243;wi&#261;c, powinien napisa&#263; swojego helpera. Je&#347;li wi&#281;c chcemy wy&#347;wietli&#263; w p&#281;tli rekordy z bazy, a widok jest czu&#322;y na zawarto&#347;&#263; tych danych, to powinni&#347;my ca&#322;a list&#281; rekord&#243;w wrzuci&#263; do helplera, przeiterowa&#263; w p&#281;tli, doda&#263; dodatkow&#261; zmienn&#261; i dopiero tak zmodyfikowan&#261; list&#281; przekaza&#263; do szablonu.&lt;/p&gt;


	&lt;p id="fn2"&gt;&lt;sup&gt;2&lt;/sup&gt; Smarty mimo posiadania w&#322;asnej sk&#322;adni pozwala na odpalanie pe&#322;nego j&#281;zyka &lt;span class="caps"&gt;PHP&lt;/span&gt;: {php}print phpinfo();{/php}. Tak praktyka jest jednak odradzana, bo wprowadza jeszcze wi&#281;kszy ba&#322;agan ni&#380; ju&#380; jest w &lt;span class="caps"&gt;PHP&lt;/span&gt;.&lt;/p&gt;


	&lt;p id="fn3"&gt;&lt;sup&gt;3&lt;/sup&gt; Zobacz artyku&#322; &lt;a href="http://www.xml.com/pub/a/2006/09/27/introducing-wsgi-pythons-secret-web-weapon.html"&gt;Introducing &lt;span class="caps"&gt;WSGI&lt;/span&gt;: Python&amp;#8217;s Secret Web Weapon&lt;/a&gt; oraz &lt;a href="http://www.groovie.org/articles/2006/09/18/wsgi-paste-pylons-and-all-that"&gt;prezentacj&#281; koncepcji &lt;span class="caps"&gt;WSGI&lt;/span&gt;&lt;/a&gt; na video.&lt;/p&gt;</description>
      <pubDate>Sun, 14 Jan 2007 04:25:00 +0100</pubDate>
      <guid isPermaLink="false">urn:uuid:85bc8794-3490-4af9-9c34-8cd949244305</guid>
      <author>Jaros&#322;aw Zabie&#322;&#322;o</author>
      <link>http://blog.zabiello.com/articles/2007/01/14/templates-and-mvc-3</link>
      <category>templates</category>
      <category>savant</category>
      <category>spyce</category>
      <category>myghty</category>
      <category>cheetah</category>
      <category>mako</category>
      <category>django</category>
      <category>jinja</category>
      <category>pylons</category>
      <category>rails</category>
      <category>python</category>
      <category>ruby</category>
      <category>php</category>
      <category>mvc</category>
    </item>
  </channel>
</rss>
