<?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: Category SmallTalk</title>
    <link>http://blog.zabiello.com/articles/category/smalltalk</link>
    <language>en-us</language>
    <ttl>40</ttl>
    <description>moje notatki, linki, komentarze</description>
    <item>
      <title>Serwery kontynuacyjne - przysz&#322;o&#347;&#263; webu</title>
      <description>&lt;p&gt;Ka&#380;dy, kto zajmowa&#322; si&#281; kiedykolwiek programowaniem stron internetowych wie, &#380;e protok&#243;&#322; &lt;span class="caps"&gt;HTTP&lt;/span&gt; jest bezstanowy. Innymi s&#322;owy, ka&#380;de prze&#322;adowanie strony  internetowej generuje kompletnie niezale&#380;ne wywo&#322;anie serwera i nie ma on mo&#380;liwo&#347;ci aby powi&#261;za&#263; wywo&#322;anie z konkretnym klientem. Aby temu zaradzi&#263;, wprowadzono prost&#261; sztuczk&#281;. Wprowadzono tzw. mechanizm cookies (dos&#322;. ciasteczek), malutkich plik&#243;w kt&#243;re serwer mo&#380;e wysy&#322;a&#263; do klienta (tam i z powrotem). Ten unikalny identyfikator (sesji)  mo&#380;na te&#380; trzyma&#263; w adresie &lt;span class="caps"&gt;URL&lt;/span&gt;, ale ta metoda jest zdecydowanie odradzana z powodu &#322;atwo&#347;ci nadu&#380;y&#263; (&#322;atwo wykra&#347;&#263; taki numer i podszy&#263; si&#281; pod autora) Od strony klienta jedynym wymaganiem jest aby nie blokowa&#322; sobie w przegl&#261;darce mechanizmu cookies.&lt;/p&gt;


	&lt;p&gt;Serwer znaj&#261;c identyfikator sesji, mo&#380;e zwi&#261;za&#263; z nim szereg danych, np. aktualn&#261; list&#281; zamawianych produkt&#243;w w&#322;o&#380;onych do koszyka w sklepie internetowym. Dane te zwykle trzyma si&#281; w bazie lub w pami&#281;ci operacyjnej. Oczywi&#347;cie czas &#380;ycia danych jest ustalany przez serwet i w normalnym wypadku s&#261; one cyklicznie kasowane. (Z tym &amp;#8220;normalnym&amp;#8221; wypadkiem to r&#243;&#380;nie bywa, bo wiele framework&#243;w tego nie zapewnia i trzeba samemu o to zadba&#263;)&lt;/p&gt;


	&lt;p&gt;Mechanizm sesji jest dosy&#263; wydajny, bo zapytania wysy&#322;ane do serwera mog&#261; by&#263; obs&#322;ugiwane &lt;strong&gt;asynchronicznie&lt;/strong&gt;, czyli bez &#380;adnych blokad w oczekiwaniu na uko&#324;czenie obs&#322;ugi zapytania. Przez lata &amp;#8220;stanowo&#347;&#263;&amp;#8221; protoko&#322;u &lt;span class="caps"&gt;HTTP&lt;/span&gt; zapewnia&#322;o si&#281; w&#322;a&#347;nie za pomoc&#261; sesji.&lt;/p&gt;


	&lt;p&gt;Ten mechanizm ma jednak swoje wady. Najwi&#281;ksz&#261; jest &lt;strong&gt;z&#322;o&#380;ono&#347;&#263;&lt;/strong&gt; jak&#261; wprowadza po stronie skrypt&#243;w na serwerze. (I to nie jest wcale taka trywialna sprawa jak to mo&#380;na by&#322;o zaobserwowa&#263; u developer&#243;w frameworka CherryPy kt&#243;rzy miesi&#261;cami nie potrafili napisa&#263; stabilnie dzia&#322;aj&#261;cego mechanizmu obs&#322;ugi sesji.)&lt;/p&gt;


	&lt;h3&gt;Kontynuacje&lt;/h3&gt;


	&lt;p&gt;Kompletnie innym podej&#347;ciem jest skorzystanie z tzw. mechanizmu kontynuacji.  Mechanizm ten podobny jest do gracza, kt&#243;ry w dowolnym momencie mo&#380;e zapisa&#263; i wczyta&#263; stan gry.  Kontynuacje zapewniaj&#261; taki mechanizm zapisu stanu programu aby w dowolnym momencie p&#243;&#378;niej go przywr&#243;ci&#263;. Niekt&#243;rzy por&#243;wnuj&#261; to do maszyny czasu, bo mo&#380;na w dowolnym momencie przywr&#243;ci&#263; wcze&#347;niejszy stan aplikacji.&lt;/p&gt;


	&lt;p&gt;Zalet z takiego podej&#347;cia jest wiele. We&#378;my np. spraw&#281; obs&#322;ugi &amp;#8220;nie&#347;miertelnego&amp;#8221; przycisku Back w przegl&#261;darce. Obs&#322;uga tego przycisku sprawia spore problemy. Programi&#347;ci najch&#281;tniej w og&#243;le by go zablokowali. W wypadku kontynuacji ten problem w og&#243;le nie istnieje. Klikn&#261;&#322; kto&#347; Back aby cofn&#261;&#263; si&#281; do poprzedniej strony? &#379;aden problem. Serwer przywr&#243;ci ca&#322;y wcze&#347;niejszy stan aplikacji bez &#380;adnego problemu. I to w spos&#243;b &lt;strong&gt;przezroczysty&lt;/strong&gt; dla programisty! Programowanie stron webowych staje si&#281; &lt;strong&gt;znacznie prostsze&lt;/strong&gt;, niczym tworzenie aplikacji desktopowej w&#322;&#261;cznie z debugowaniem krok po kroku. Wg r&#243;&#380;nych prognoz, tak b&#281;dziemy programowa&#263; serwisy internetowe za kilka lat!&lt;/p&gt;


	&lt;p&gt;Sama idea nie jest najwyra&#378;niej jeszcze powszechnie znana, skoro w rozmowie z developerami irlandzkiego Google, zaskoczy&#322;em ich informacj&#261; na ten temat. Kto wie, czy Google mocniej nie zainwestuje w Rubiego (aktualnie mocno korzysta z Pythona, kt&#243;ry jest podstaw&#261; wi&#281;kszo&#347;ci ich skrypt&#243;w).&lt;/p&gt;


	&lt;h3&gt;Smalltalk i Seaside&lt;/h3&gt;


	&lt;p&gt;Smalltalk jest bardzo starym j&#281;zykiem bo jego pocz&#261;tki si&#281;gaj&#261; lat 70-tych. Od zawsze by&#322; j&#281;zykiem w pe&#322;ni obiektowym i dynamicznym. To m.in. Smalltalk pierwszy wymy&#347;li&#322; wirtualn&#261; maszyn&#281; kt&#243;rej to ide&#281; p&#243;&#378;niej skopiowali tw&#243;rcy Javy. W Smalltalku napisano najlepszy (w chwili obecnej) na &#347;wiecie &lt;strong&gt;serwer kontynuacyjny &amp;#8211; &lt;a href="http://www.seaside.st/"&gt;Seaside&lt;/a&gt;&lt;/strong&gt;.&lt;/p&gt;


	&lt;p&gt;Czy to spowoduje renesans na Smalltalka? Osobi&#347;cie w to w&#261;tpi&#281;. G&#322;&#243;wn&#261; wad&#261; Smalltalka jest jego monolityczno&#347;&#263; i hermentyczno&#347;&#263;. Uruchamiaj&#261;c &#347;rodowisko Smalltalak uruchamia si&#281; ca&#322;y, zamkni&#281;ty &#347;wiat Smalltalka. Np. nie ma tam dost&#281;pu do plik&#243;w z zewn&#261;trz tak, jak w innych j&#281;zykach. To spowodowa&#322;o, &#380;e j&#281;zyk ten, mimo pewnych sukces&#243;w, nigdy nie zdoby&#322; sobie powszechnego uznania. I moim zdanie, nigdy ju&#380; nie zdob&#281;dzie, bo w mi&#281;dzyczasie wyros&#322;a mu m&#322;oda, obiecuj&#261;ca konkurencja.&lt;/p&gt;


	&lt;h3&gt;Ruby&lt;/h3&gt;


	&lt;p&gt;Ruby jest j&#281;zykiem relatywnie m&#322;odym. Tzn. zosta&#322; po raz pierwszy udost&#281;pniony publicznie w tym samym roku co Java &amp;#8211; 1995. Ale przez wi&#281;kszo&#347;&#263; lat by&#322; ma&#322;o znany poza Japoni&#261; (sk&#261;d pochodzi jego tw&#243;rca).  Ruby jest tak&#380;e  jednym z tych nielicznych j&#281;zyk&#243;w, kt&#243;re (podobnie jak Smalltalk) posiadaj&#261; wbudowan&#261; obs&#322;ug&#281; kontynuacji. Istniej&#261; co prawda r&#243;&#380;ne pr&#243;by implementacji tego mechanizmu w Javie&lt;sup&gt;&lt;a href="#fn1"&gt;1&lt;/a&gt;&lt;/sup&gt;, ale tylko Ruby posiada ten mechanizm jako co&#347; naturalnego i nie trzeba stosowa&#263; &#380;adnych specjalnych sztuczek aby go emulowa&#263;. Z tego co pami&#281;tam, Seaside pierwotnie by&#322; tworzony w Ruby, ale w tamtym okresie, kontynuacje w Ruby by&#322;y jeszcze niedojrza&#322;e, wi&#281;c tw&#243;rcy przerzucili si&#281; na Smalltalka. Ruby jednak szybko si&#281; rozwija, nabiera dojrza&#322;o&#347;ci i moim zdaniem, ma bardzo du&#380;e szanse, aby wyprzedzi&#263; pozosta&#322;e j&#281;zyki przy tworzeniu serwis&#243;w internetowych nowej generacji, serwis&#243;w opartych na kontynuacjach.&lt;/p&gt;


	&lt;h3&gt;Przyk&#322;ad kontynuacji.&lt;/h3&gt;


	&lt;p&gt;Poni&#380;szy przyk&#322;ad&lt;sup&gt;&lt;a href="#fn2"&gt;2&lt;/a&gt;&lt;/sup&gt; pokazuje implementacj&#281; generatora za pomoc&#261; kontynuacji.&lt;/p&gt;


&lt;div class="typocode"&gt;&lt;pre&gt;&lt;code class="typocode_ruby "&gt;&lt;span class="keyword"&gt;class &lt;/span&gt;&lt;span class="class"&gt;Generator&lt;/span&gt;

  &lt;span class="keyword"&gt;def &lt;/span&gt;&lt;span class="method"&gt;initialize&lt;/span&gt;
    &lt;span class="ident"&gt;do_generation&lt;/span&gt;
  &lt;span class="keyword"&gt;end&lt;/span&gt;

  &lt;span class="keyword"&gt;def &lt;/span&gt;&lt;span class="method"&gt;next&lt;/span&gt;
    &lt;span class="ident"&gt;callcc&lt;/span&gt; &lt;span class="keyword"&gt;do&lt;/span&gt; &lt;span class="punct"&gt;|&lt;/span&gt;&lt;span class="ident"&gt;here&lt;/span&gt;&lt;span class="punct"&gt;|&lt;/span&gt;
      &lt;span class="attribute"&gt;@main_context&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="ident"&gt;here&lt;/span&gt;&lt;span class="punct"&gt;;&lt;/span&gt;
       &lt;span class="attribute"&gt;@generator_context&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;call&lt;/span&gt;
    &lt;span class="keyword"&gt;end&lt;/span&gt;
  &lt;span class="keyword"&gt;end&lt;/span&gt;

   &lt;span class="ident"&gt;private&lt;/span&gt;

   &lt;span class="keyword"&gt;def &lt;/span&gt;&lt;span class="method"&gt;do_generation&lt;/span&gt;
     &lt;span class="ident"&gt;callcc&lt;/span&gt; &lt;span class="keyword"&gt;do&lt;/span&gt; &lt;span class="punct"&gt;|&lt;/span&gt;&lt;span class="ident"&gt;context&lt;/span&gt;&lt;span class="punct"&gt;|&lt;/span&gt;
       &lt;span class="attribute"&gt;@generator_context&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="ident"&gt;context&lt;/span&gt;&lt;span class="punct"&gt;;&lt;/span&gt;
       &lt;span class="keyword"&gt;return&lt;/span&gt;
     &lt;span class="keyword"&gt;end&lt;/span&gt;
     &lt;span class="ident"&gt;generating_loop&lt;/span&gt;
   &lt;span class="keyword"&gt;end&lt;/span&gt;

   &lt;span class="keyword"&gt;def &lt;/span&gt;&lt;span class="method"&gt;generate&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="ident"&gt;value&lt;/span&gt;&lt;span class="punct"&gt;)&lt;/span&gt;
     &lt;span class="ident"&gt;callcc&lt;/span&gt; &lt;span class="keyword"&gt;do&lt;/span&gt; &lt;span class="punct"&gt;|&lt;/span&gt;&lt;span class="ident"&gt;context&lt;/span&gt;&lt;span class="punct"&gt;|&lt;/span&gt;
       &lt;span class="attribute"&gt;@generator_context&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="ident"&gt;context&lt;/span&gt;&lt;span class="punct"&gt;;&lt;/span&gt;
       &lt;span class="attribute"&gt;@main_context&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;call&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="ident"&gt;value&lt;/span&gt;&lt;span class="punct"&gt;)&lt;/span&gt;
     &lt;span class="keyword"&gt;end&lt;/span&gt;
   &lt;span class="keyword"&gt;end&lt;/span&gt;
&lt;span class="keyword"&gt;end&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

	&lt;p&gt;A oto oparty na nim generator ci&#261;gu liczb Fibbonacciego:&lt;/p&gt;


&lt;div class="typocode"&gt;&lt;pre&gt;&lt;code class="typocode_ruby "&gt;&lt;span class="keyword"&gt;class &lt;/span&gt;&lt;span class="class"&gt;FibGenerator&lt;/span&gt; &lt;span class="punct"&gt;&amp;lt;&lt;/span&gt; &lt;span class="constant"&gt;Generator&lt;/span&gt;
  &lt;span class="keyword"&gt;def &lt;/span&gt;&lt;span class="method"&gt;generating_loop&lt;/span&gt;
    &lt;span class="ident"&gt;generate&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="number"&gt;1&lt;/span&gt;&lt;span class="punct"&gt;)&lt;/span&gt;
    &lt;span class="ident"&gt;a&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="ident"&gt;b&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="number"&gt;1&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="number"&gt;1&lt;/span&gt;
    &lt;span class="ident"&gt;loop&lt;/span&gt; &lt;span class="keyword"&gt;do&lt;/span&gt;
      &lt;span class="ident"&gt;generate&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="ident"&gt;b&lt;/span&gt;&lt;span class="punct"&gt;)&lt;/span&gt;
      &lt;span class="ident"&gt;a&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="ident"&gt;b&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="ident"&gt;b&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="ident"&gt;a&lt;/span&gt;&lt;span class="punct"&gt;+&lt;/span&gt;&lt;span class="ident"&gt;b&lt;/span&gt;
    &lt;span class="keyword"&gt;end&lt;/span&gt;
  &lt;span class="keyword"&gt;end&lt;/span&gt;
&lt;span class="keyword"&gt;end&lt;/span&gt;

&lt;span class="ident"&gt;fib&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="constant"&gt;FibGenerator&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;new&lt;/span&gt;
&lt;span class="number"&gt;15&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;times&lt;/span&gt; &lt;span class="punct"&gt;{&lt;/span&gt; &lt;span class="ident"&gt;print&lt;/span&gt; &lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;&lt;span class="string"&gt;&lt;span class="expr"&gt;#{fib.next}&lt;/span&gt; &lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;&lt;/span&gt; &lt;span class="punct"&gt;}&lt;/span&gt;
&lt;span class="comment"&gt;#wynik: 1 1 2 3 5 8 13 21 34 55 89 144 233 377 610 &lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

	&lt;p id="fn1"&gt;&lt;sup&gt;1&lt;/sup&gt; Np. &lt;a href="http://rifers.org/"&gt;Riff&lt;/a&gt; lub &lt;a href="http://jetty.mortbay.org/jetty/"&gt;Jetty 6&lt;/a&gt;.&lt;/p&gt;


	&lt;p id="fn2"&gt;&lt;sup&gt;2&lt;/sup&gt; Przyk&#322;ad z ksi&#261;&#380;ki &amp;#8220;The Ruby Way&amp;#8221;, 1ed.&lt;/p&gt;</description>
      <pubDate>Wed, 22 Nov 2006 02:26:00 +0100</pubDate>
      <guid isPermaLink="false">urn:uuid:c15ba4a7-3852-452b-af70-9f5ea30a4702</guid>
      <author>Jaros&#322;aw Zabie&#322;&#322;o</author>
      <link>http://blog.zabiello.com/articles/2006/11/22/serwery-kontynuacyjne-przysz%C5%82o%C5%9B%C4%87-webu</link>
      <category>Ruby</category>
      <category>Java</category>
      <category>SmallTalk</category>
      <category>ruby</category>
      <category>smalltalk</category>
      <category>java</category>
      <category>continuations</category>
    </item>
    <item>
      <title>Dlaczego Ruby on Rails jest wyj&#261;tkowy?</title>
      <description>&lt;p&gt;Niekt&#243;rym osobom stykaj&#261;cym si&#281; z po raz pierwszy z &lt;a href="http://rubyonrails.com"&gt;Railsami&lt;/a&gt; wydaje si&#281;, &#380;e jest to tylko jakie&#347; kolejne, tradycyjne &#347;rodowisko developerskie pracuj&#261;ce wg wzorca projektowego &lt;a href="http://en.wikipedia.org/wiki/Model-view-controller"&gt;&lt;span class="caps"&gt;MVC&lt;/span&gt;&lt;/a&gt; (model-widok-kontroler). Przywi&#261;zani do swoich j&#281;zyk&#243;w i framework&#243;w czasami si&#281; dziwi&#261;, dlaczego temat Rails&#243;w wywo&#322;uje od jakiego&#347; czasu tyle emocji i  komentarzy. 
Na pewno po cz&#281;sci jest tak pewnie dlatego, &#380;e RoR jest bardzo &lt;em&gt;dobrze wypromowany&lt;/em&gt;. Dobra &lt;a href="http://rubyonrails.com"&gt;strona g&#322;&#243;wna&lt;/a&gt;, dobra dokumentacja, ksi&#261;&#380;ki, filmy, bardzo aktywna spo&#322;eczno&#347;&#263; &amp;#8211; nic tylko na&#347;ladowa&#263;. Z drugiej strony, trzeba te&#380; przyzna&#263;, &#380;e jest to &#347;rodowisko &#347;wietnie zaprojektowane &amp;#8211; w Railsach sie pracuje po prostu &lt;em&gt;komfortowo&lt;/em&gt;.&lt;/p&gt;


	&lt;p&gt;Nie dziwi&#261; wi&#281;c ci&#261;g&#322;e pr&#243;by na&#347;ladowania Rails&#243;w w innych j&#281;zykach (PHP, Python, Java, C# itp) Jednak&#380;e mi&#281;dzy nimi a Railsami b&#281;dzie ci&#261;gle pewna, trudna do osi&#261;gni&#281;cia, je&#347;li nie w og&#243;le niemo&#380;liwa &amp;#8211; bariera. Railsy posiadaj&#261; nie tylko wszystko, co potrzeba do bardzo produktywnego tworzenia aplikacji internetowych, ale s&#261; przy tym r&#243;wnocze&#347;nie bardzo &lt;strong&gt;eleganckie i czytelne&lt;/strong&gt;. Eleganckie i czytelne czyli &#322;atwe do nauki. Tak, nauka Rubiego nie jest przeszkod&#261;. Przekona si&#281; o tym ka&#380;dy, kto troch&#281; bli&#380;ej przyjrzy si&#281; jak dzia&#322;a RoR.&lt;/p&gt;


	&lt;p&gt;Mia&#322;em okazj&#281; por&#243;wnywa&#263; ze sob&#261; kilka r&#243;&#380;nych framework&#243;w. Gdy chcia&#322;em przekona&#263; si&#281; do kt&#243;rego&#347; z nich, zawsze ostatecznie wraca&#322;em z powrotem do RoR. Po prostu &#380;aden z nich nie jest jak elegancki i prosty w u&#380;yciu&lt;sup&gt;&lt;a href="#fn1"&gt;1&lt;/a&gt;&lt;/sup&gt;. Co jest  g&#322;&#243;wn&#261; przyczyn&#261; takiego wra&#380;enia?   Tw&#243;rca Rails&#243;w, David Heinemeier Hansson powiedzia&#322; kiedy&#347;, &#380;e gdyby nie &lt;a href="http://ruby-lang.org"&gt;Ruby&lt;/a&gt; to nie powsta&#322;by &lt;a href="http://rubyonrails.com"&gt;Ruby on Rails&lt;/a&gt;. Powiedzia&#322; tak&#380;e, &#380;e uwa&#380;a i&#380; w &#380;adnym innym j&#281;zyku nie da si&#281; napisa&#263; tak eleganckiego i pi&#281;knego kodu. Zatem mo&#380;na powiedzie&#263;, &#380;e prawdziw&#261; &lt;strong&gt;si&#322;&#261; Rails&#243;w jest Ruby&lt;/strong&gt;. Razem tworz&#261; nieroz&#322;&#261;czn&#261; par&#281; i ta &#322;&#261;czno&#347;&#263; nie dotyczy bynajmniej tylko nazwy. ;) Ruby posiada bowiem pewne unikalne cechy, kt&#243;re pozwoli&#322;y stworzy&#263; RoR w postaci, kt&#243;ra jest raczej ma&#322;o nieosi&#261;galna dla innych j&#281;zyk&#243;w. Ju&#380; to wyja&#347;niam.&lt;/p&gt;


	&lt;p&gt;Panuje powszechnie mniemanie, &#380;e Ruby to po&#322;&#261;czenie cech &lt;a href="http://python.org"&gt;Pythona&lt;/a&gt; i &lt;a href="http://www.perl.org/"&gt;Perla&lt;/a&gt;. Ruby (podobnie jak Perl) posiada np. wbudowan&#261; w sk&#322;adni&#281; obs&#322;uge wyra&#380;e&#324; regularnych. Posiada tak&#380;e (podobnie jak Python) pe&#322;n&#261; obiektowo&#347;&#263; i bardzo eleganck&#261;, czyteln&#261; (cho&#263; nie tak&#261; sam&#261;) sk&#322;adni&#281;. Pewnym odkryciem by&#322;o dla mnie to, &#380;e j&#281;zykie, do kt&#243;rego Ruby ma najwi&#281;cej podobie&#324;stw to innego j&#281;zyka &amp;#8211;  &lt;strong&gt;&lt;a href="http://pl.wikipedia.org/wiki/Smalltalk"&gt;Smalltalk&lt;/a&gt;&lt;/strong&gt;. Lektura cech, filozofii (i nawet do pewnego stopnia sk&#322;adni) Smalltalka pokazuje zdumiewaj&#261;ce podobie&#324;stwo do Rubiego. Mo&#380;na wr&#281;cz odnie&#347;&#263; wra&#380;enie, &#380;e Ruby to swego rodzaju przer&#243;bka Smalltalka&lt;sup&gt;&lt;a href="#fn2"&gt;2&lt;/a&gt;&lt;/sup&gt;. Podobie&#324;stw jest bardzo wiele. Od s&#322;&#243;w kluczowych po symbole, spos&#243;b tworzenia instancji klas, bloki kodu (ang. &lt;em&gt;closures&lt;/em&gt;), kontynuacje&lt;sup&gt;&lt;a href="#fn3"&gt;3&lt;/a&gt;&lt;/sup&gt; itp. Jak kto&#347; jeszcze nie rozumie filozofii Rubiego, jego modelu obiektowego i powodu istnienia otwartych klas, powinien poczyta&#263; sobie troch&#281; o Smalltalku.&lt;/p&gt;


	&lt;p&gt;Ruby jak i Smalltalk posiadaj&#261; bardzo podobny model obiektowy. Wszystkie obiekty (na drodze dziedziczenia) wywodz&#261; si&#281; z jednej, ostateczniej klasy Object. Oba j&#281;zyki maj&#261; zaimplementowan&#261; pe&#322;n&#261; obiektowo&#347;&#263;. Nie ma (tak ja w Javie) podzia&#322;u na prymitywy i typy referencyjne. Wszystko jest obiektem i wszystko posiada metody. Dotyczy to nie tylko liczb i napis&#243;w ale tak&#380;e obiektu nil, true czy false. Ka&#380;dy obiekt mo&#380;na przeci&#261;&#380;y&#263; i/lub zmodyfikowa&#263; wewnetrznie (dynamicznie dodaj&#261;c lub usuwaj&#261;c jego metody w trakcie pracy programu)&lt;/p&gt;


	&lt;p&gt;Z tego wynika, &#380;e w&#322;a&#347;ciwie to mo&#380;na modyfikowa&#263; sam j&#281;zyk. Daje to mo&#380;liwo&#347;ci zupe&#322;nie nieosi&#261;galne nawet dla tak dobrego i obiektowego j&#281;zyka jakim jest &lt;a href="http://python.org"&gt;Python&lt;/a&gt;. Ruby pozwala na &#322;atwe dodawanie nowych metod do liczb czy napis&#243;w. Pozwala na tak&#261; modyfikacj&#281; samego siebie, aby optymalnie nadawa&#322; si&#281; do realizacji pewnych, specyficznych zada&#324;. Ruby umo&#380;liwia zatem tworzenie tego, co si&#281; okre&#347;la mianem &lt;a href="http://en.wikipedia.org/wiki/Domain_Specific_Language"&gt;j&#281;zyk&#243;w domenowych&lt;/a&gt; (Domain-specific Programming Languages). S&#261; to j&#281;zyki, kt&#243;re w przeciwie&#324;stwie do j&#281;zyk&#243;w og&#243;lnego zastostosowania, zosta&#322;y zaprojektowane do wykonywania specyficznego zadania/zada&#324;. Zar&#243;wno Smalltalk jak i Ruby pozwalaj&#261; na tworzenie j&#281;zyk&#243;w domenowych.&lt;/p&gt;


	&lt;blockquote&gt;
		&lt;p&gt;&lt;a href="http://rubyonrails.com"&gt;Ruby on Rails&lt;/a&gt; to nic innego jak framework napisany za pomoc&#261; Rubiego zmodyfikowanego w celu uzyskania wysoce produktywnego  &#347;rodowiska do tworzenia nowoczesnych aplikacji internetowych.&lt;/p&gt;
	&lt;/blockquote&gt;


	&lt;p&gt;Przyk&#322;adowe helpery dost&#281;pne w Rails, kt&#243;re korzystaj&#261; z nowych metod nie b&#281;d&#261;cych standardow&#261; cz&#281;&#347;ci&#261; Rubiego. Poni&#380;sze przyk&#322;ady pochodz&#261; z 1-g wydania ksi&#261;&#380;ki &lt;a href="http://www.pragmaticprogrammer.com/titles/rails/"&gt;Agile Web Development in Rails&lt;/a&gt;.&lt;/p&gt;


&lt;div class="typocode"&gt;&lt;pre&gt;&lt;code class="typocode_ruby "&gt;&lt;span class="ident"&gt;puts&lt;/span&gt; &lt;span class="number"&gt;20&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;bytes&lt;/span&gt; &lt;span class="comment"&gt;#=&amp;gt; 20&lt;/span&gt;
&lt;span class="ident"&gt;puts&lt;/span&gt; &lt;span class="number"&gt;20&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;kilobytes&lt;/span&gt; &lt;span class="comment"&gt;#=&amp;gt; 20480&lt;/span&gt;
&lt;span class="ident"&gt;puts&lt;/span&gt; &lt;span class="number"&gt;20&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;megabytes&lt;/span&gt; &lt;span class="comment"&gt;#=&amp;gt; 20971520&lt;/span&gt;
&lt;span class="ident"&gt;puts&lt;/span&gt; &lt;span class="number"&gt;20&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;gigabytes&lt;/span&gt; &lt;span class="comment"&gt;#=&amp;gt; 21474836480&lt;/span&gt;
&lt;span class="ident"&gt;puts&lt;/span&gt; &lt;span class="number"&gt;20&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;terabytes&lt;/span&gt; &lt;span class="comment"&gt;#=&amp;gt; 21990232555520&lt;/span&gt;
&lt;span class="ident"&gt;puts&lt;/span&gt; &lt;span class="number"&gt;20&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;minutes&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;ago&lt;/span&gt; &lt;span class="comment"&gt;#=&amp;gt; Tue May 10 16:43:43 CDT 2005&lt;/span&gt;
&lt;span class="ident"&gt;puts&lt;/span&gt; &lt;span class="number"&gt;20&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;hours&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;from_now&lt;/span&gt; &lt;span class="comment"&gt;#=&amp;gt; Wed May 11 13:03:43 CDT 2005&lt;/span&gt;
&lt;span class="ident"&gt;puts&lt;/span&gt; &lt;span class="number"&gt;20&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;weeks&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;from_now&lt;/span&gt; &lt;span class="comment"&gt;#=&amp;gt; Tue Sep 27 17:03:43 CDT 2005&lt;/span&gt;
&lt;span class="ident"&gt;puts&lt;/span&gt; &lt;span class="number"&gt;20&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;months&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;ago&lt;/span&gt; &lt;span class="comment"&gt;#=&amp;gt; Thu Sep 18 17:03:43 CDT 2003&lt;/span&gt;
&lt;span class="ident"&gt;now&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="constant"&gt;Time&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;now&lt;/span&gt;
&lt;span class="ident"&gt;puts&lt;/span&gt; &lt;span class="ident"&gt;now&lt;/span&gt; &lt;span class="comment"&gt;#=&amp;gt; Tue May 10 17:15:59 CDT 2005&lt;/span&gt;
&lt;span class="ident"&gt;puts&lt;/span&gt; &lt;span class="ident"&gt;now&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;ago&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="number"&gt;3600&lt;/span&gt;&lt;span class="punct"&gt;)&lt;/span&gt; &lt;span class="comment"&gt;#=&amp;gt; Tue May 10 16:15:59 CDT 2005&lt;/span&gt;
&lt;span class="ident"&gt;puts&lt;/span&gt; &lt;span class="ident"&gt;now&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;at_beginning_of_day&lt;/span&gt; &lt;span class="comment"&gt;#=&amp;gt; Tue May 10 00:00:00 CDT 2005&lt;/span&gt;
&lt;span class="ident"&gt;puts&lt;/span&gt; &lt;span class="ident"&gt;now&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;at_beginning_of_month&lt;/span&gt; &lt;span class="comment"&gt;#=&amp;gt; Sun May 01 00:00:00 CDT 2005&lt;/span&gt;
&lt;span class="ident"&gt;puts&lt;/span&gt; &lt;span class="ident"&gt;now&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;at_beginning_of_week&lt;/span&gt; &lt;span class="comment"&gt;#=&amp;gt; Mon May 09 00:00:00 CDT 2005&lt;/span&gt;
&lt;span class="ident"&gt;puts&lt;/span&gt; &lt;span class="ident"&gt;now&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;at_beginning_of_year&lt;/span&gt; &lt;span class="comment"&gt;#=&amp;gt; Sat Jan 01 00:00:00 CST 2005&lt;/span&gt;
&lt;span class="ident"&gt;puts&lt;/span&gt; &lt;span class="ident"&gt;now&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;at_midnight&lt;/span&gt; &lt;span class="comment"&gt;#=&amp;gt; Tue May 10 00:00:00 CDT 2005&lt;/span&gt;
&lt;span class="ident"&gt;puts&lt;/span&gt; &lt;span class="ident"&gt;now&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;change&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="symbol"&gt;:hour&lt;/span&gt; &lt;span class="punct"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="number"&gt;13&lt;/span&gt;&lt;span class="punct"&gt;)&lt;/span&gt; &lt;span class="comment"&gt;#=&amp;gt; Tue May 10 13:00:00 CDT 2005&lt;/span&gt;
&lt;span class="ident"&gt;puts&lt;/span&gt; &lt;span class="ident"&gt;now&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;last_month&lt;/span&gt; &lt;span class="comment"&gt;#=&amp;gt; Sun Apr 10 17:15:59 CDT 2005&lt;/span&gt;
&lt;span class="ident"&gt;puts&lt;/span&gt; &lt;span class="ident"&gt;now&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;last_year&lt;/span&gt; &lt;span class="comment"&gt;#=&amp;gt; Mon May 10 17:15:59 CDT 2004&lt;/span&gt;
&lt;span class="ident"&gt;puts&lt;/span&gt; &lt;span class="ident"&gt;now&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;midnight&lt;/span&gt; &lt;span class="comment"&gt;#=&amp;gt; Tue May 10 00:00:00 CDT 2005&lt;/span&gt;
&lt;span class="ident"&gt;puts&lt;/span&gt; &lt;span class="ident"&gt;now&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;monday&lt;/span&gt; &lt;span class="comment"&gt;#=&amp;gt; Mon May 09 00:00:00 CDT 2005&lt;/span&gt;
&lt;span class="ident"&gt;puts&lt;/span&gt; &lt;span class="ident"&gt;now&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;months_ago&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="number"&gt;2&lt;/span&gt;&lt;span class="punct"&gt;)&lt;/span&gt; &lt;span class="comment"&gt;#=&amp;gt; Thu Mar 10 17:15:59 CST 2005&lt;/span&gt;
&lt;span class="ident"&gt;puts&lt;/span&gt; &lt;span class="ident"&gt;now&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;months_since&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="number"&gt;2&lt;/span&gt;&lt;span class="punct"&gt;)&lt;/span&gt; &lt;span class="comment"&gt;#=&amp;gt; Sun Jul 10 17:15:59 CDT 2005&lt;/span&gt;
&lt;span class="ident"&gt;puts&lt;/span&gt; &lt;span class="ident"&gt;now&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;next_week&lt;/span&gt; &lt;span class="comment"&gt;#=&amp;gt; Mon May 16 00:00:00 CDT 2005&lt;/span&gt;
&lt;span class="ident"&gt;puts&lt;/span&gt; &lt;span class="ident"&gt;now&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;next_year&lt;/span&gt; &lt;span class="comment"&gt;#=&amp;gt; Wed May 10 17:15:59 CDT 2006&lt;/span&gt;
&lt;span class="ident"&gt;puts&lt;/span&gt; &lt;span class="ident"&gt;now&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;seconds_since_midnight&lt;/span&gt; &lt;span class="comment"&gt;#=&amp;gt; 62159.215938&lt;/span&gt;
&lt;span class="ident"&gt;puts&lt;/span&gt; &lt;span class="ident"&gt;now&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;since&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="number"&gt;7200&lt;/span&gt;&lt;span class="punct"&gt;)&lt;/span&gt; &lt;span class="comment"&gt;#=&amp;gt; Tue May 10 19:15:59 CDT 2005&lt;/span&gt;
&lt;span class="ident"&gt;puts&lt;/span&gt; &lt;span class="ident"&gt;now&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;tomorrow&lt;/span&gt; &lt;span class="comment"&gt;#=&amp;gt; Wed May 11 17:15:59 CDT 2005&lt;/span&gt;
&lt;span class="ident"&gt;puts&lt;/span&gt; &lt;span class="ident"&gt;now&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;years_ago&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="number"&gt;2&lt;/span&gt;&lt;span class="punct"&gt;)&lt;/span&gt; &lt;span class="comment"&gt;#=&amp;gt; Sat May 10 17:15:59 CDT 2003&lt;/span&gt;
&lt;span class="ident"&gt;puts&lt;/span&gt; &lt;span class="ident"&gt;now&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;years_since&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="number"&gt;2&lt;/span&gt;&lt;span class="punct"&gt;)&lt;/span&gt; &lt;span class="comment"&gt;#=&amp;gt; Thu May 10 17:15:59 CDT 2007&lt;/span&gt;
&lt;span class="ident"&gt;puts&lt;/span&gt; &lt;span class="ident"&gt;now&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;yesterday&lt;/span&gt; &lt;span class="comment"&gt;#=&amp;gt; Mon May 09 17:15:59 CDT 2005&lt;/span&gt;
&lt;span class="ident"&gt;puts&lt;/span&gt; &lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;&lt;span class="string"&gt;cat&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;.&lt;/span&gt;&lt;span class="ident"&gt;pluralize&lt;/span&gt; &lt;span class="comment"&gt;#=&amp;gt; cats&lt;/span&gt;
&lt;span class="ident"&gt;puts&lt;/span&gt; &lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;&lt;span class="string"&gt;cats&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;.&lt;/span&gt;&lt;span class="ident"&gt;pluralize&lt;/span&gt; &lt;span class="comment"&gt;#=&amp;gt; cats&lt;/span&gt;
&lt;span class="ident"&gt;puts&lt;/span&gt; &lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;&lt;span class="string"&gt;erratum&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;.&lt;/span&gt;&lt;span class="ident"&gt;pluralize&lt;/span&gt; &lt;span class="comment"&gt;#=&amp;gt; errata&lt;/span&gt;
&lt;span class="ident"&gt;puts&lt;/span&gt; &lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;&lt;span class="string"&gt;cats&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;.&lt;/span&gt;&lt;span class="ident"&gt;singularize&lt;/span&gt; &lt;span class="comment"&gt;#=&amp;gt; cat&lt;/span&gt;
&lt;span class="ident"&gt;puts&lt;/span&gt; &lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;&lt;span class="string"&gt;errata&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;.&lt;/span&gt;&lt;span class="ident"&gt;singularize&lt;/span&gt; &lt;span class="comment"&gt;#=&amp;gt; erratum&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

	&lt;p&gt;Z racji tego, &#380;e Railsy zmodyfikowa&#322;y Rubiego do realizacji swoich zada&#324;, uwa&#380;am, &#380;e pr&#243;ba sklonowania tego &#347;rodowiska w jakim&#347; innym j&#281;zyku (poza Smalltalkiem), jest z g&#243;ry skazana na niepowodzenie. Po prostu nigdy to nie b&#281;dzie tak pi&#281;kny kod jak Ruby dla Rails&#243;w. Na otarcie &#322;ez dla pythonistas, mog&#281; powiedzie&#263;, &#380;e przy wszystkich zaletach Rubiego, nadal uwa&#380;am &#380;e Python (jako j&#281;zyk) jest nie tylko &#322;atwiejszy do opanowania ale tak&#380;e bardziej produktywny. Ale je&#347;li chodzi o frameworki, to Rails jest nie do pobicia je&#347;li chodzi o komfort, mo&#380;liwo&#347;ci i &lt;span class="caps"&gt;DRY&lt;/span&gt;[4].&lt;/p&gt;


	&lt;p&gt;&lt;del&gt;&amp;#8212;&lt;/del&gt;&lt;/p&gt;


	&lt;p id="fn1"&gt;&lt;sup&gt;1&lt;/sup&gt; Zupe&#322;nie identyczne wra&#380;enia prostoty jak z Railsami mia&#322;em w przypadku szukania dobrego systemu &lt;a href="http://pl.wikipedia.org/wiki/Content_Management_System"&gt;&lt;span class="caps"&gt;CMS&lt;/span&gt;&amp;#8217;a&lt;/a&gt;.  Taki np. pythonowy &lt;a href="http://plone.org"&gt;Plone&lt;/a&gt; w por&#243;wnaniu do &lt;a href="http://ez.no"&gt;ezPublish&lt;/a&gt; i ca&#322;ej masy innych, pehapowych rozwi&#261;za&#324; jest nie tylko pote&#380;niejszy ale tak&#380;e niezr&#243;wnanie prostszy i wygodny (po 5 minutach od instalacji, praktycznie bez czytania dokumentacji i bez znajomo&#347;ci Pythona, mo&#380;na stworzy&#263; prosty serwis o ca&#322;kiem przyzwoitej, podstawowej funkcjonalno&#347;ci)&lt;/p&gt;


	&lt;p id="fn2"&gt;&lt;sup&gt;2&lt;/sup&gt; Smalltalk posiada tylko 5 s&#322;&#243;w kluczowych i proste zasady: wszystko jest obiektem, wszystkie operacje polegaj&#261; na przesy&#322;aniu metod (nazywanych tu: wiadomo&#347;ciami) mi&#281;dzy obiektami. Moim zdaniem Smalltalk troch&#281; przesadzi&#322; z t&#261; zasad&#261;, bo nawet bo zamiast do sterowania  kontrol&#261; kodu u&#380;ywane s&#261; tak&#380;e wiadomo&#347;ci. Mo&#380;e jest jest sp&#243;jne, ale troch&#281; dziwnie wygl&#261;da. Osobi&#347;cie bardziej podobaj&#261; mi si&#281; mo&#380;liwo&#347;ci Smalltalka ale wyra&#380;one w sk&#322;adni &amp;#8230;Rubiego. :) Zobacz te&#380; &lt;a href="http://c2.com/cgi/wiki?RubyInsteadOfSmalltalk"&gt;Ruby Instead of Smalltalk&lt;/a&gt;&lt;/p&gt;


	&lt;p id="fn3"&gt;&lt;sup&gt;3&lt;/sup&gt; Kontynuacje s&#261; jedn&#261; z wbudowanych cech Rubiego o kt&#243;rej mo&#380;e by&#263; za jaki&#347; czas g&#322;o&#347;no. Umo&#380;liwiaj&#261; bowiem budowanie tzw. internetowych &lt;em&gt;serwer&#243;w kontynuacyjnych&lt;/em&gt;,  kt&#243;re w pe&#322;ni zachowuj&#261; stan pomi&#281;dzy requestami i ogromnie upraszczaj&#261; prace programist&#243;w. W tej chwili najlepiej opracowanym frameworkiem tego typu jest smalltalkowy &lt;a href="http://www.seaside.st/"&gt;Seaside&lt;/a&gt;.&lt;/p&gt;


	&lt;p id="fn4"&gt;&lt;sup&gt;4&lt;/sup&gt; DRY to skr&#243;t od ang. &lt;em&gt;Dont&amp;#8217;t Repeat Yourself&lt;/em&gt;. Railsy zosta&#322;y napisane z wr&#281;cz obsesyjn&#261; ;) cech&#261; unikania powtarzania kodu. Mniej powt&#243;rze&#324; to nie tylko mniej niepotrzebnej, dodatkowej pracy ale tak&#380;e mniejsze ryzyko pope&#322;niania b&#322;&#281;du.&lt;/p&gt;</description>
      <pubDate>Sun, 14 May 2006 06:22:00 +0200</pubDate>
      <guid isPermaLink="false">urn:uuid:beeaaf91-c2da-4a15-94f2-b8ddab63d9d5</guid>
      <author>Jaros&#322;aw Zabie&#322;&#322;o</author>
      <link>http://blog.zabiello.com/articles/2006/05/14/dlaczego-ruby-on-rails-jest-wyj%C4%85tkowy</link>
      <category>Ruby on Rails</category>
      <category>Ruby</category>
      <category>SmallTalk</category>
      <category>ruby</category>
      <category>rails</category>
      <category>smalltalk</category>
    </item>
  </channel>
</rss>
