Wzmacnianie ekosystemu Rubiego - Merb
Opublikowane przez Jarosław Zabiełło
Przedwczoraj, w ramach MountainWest Ruby Conference 2008, miało miejsce ciekawe wystąpienie Ezry Zygmuntowicza na temat Merba, webowego frameworka stworzonego w języku Ruby. Wersja strumieniowa, pliki wideo oraz slajdy z wykładu, są do pobrania w internecie. Ezra w prosty sposób pokazał kilka interesujących cech Merba, które odróżniają go od konkurencyjnego Ruby on Rails.
Prostota jest lepsza od magii
Przede wszystkim, Merb zbudowano na założeniu że prostota jest lepsza od magii. Wiele osób nie znających zbytnio Rubiego, które zetknęły się z Railsami, myślą, że permanentnie magiczne (implicite) podejście do kodowania do jakaś integralna część samego języka Ruby. Tymczasem to nie jest problem Rubiego, ale filozofii zastosowanej w Rails. Sam Ruby (z założenia) pozwala na rozwiązanie tego samego problemu na bardzo wiele sposobow. W pełni zgadzam się z Ezrą, że operowanie na otwartych klasach Rubiego może być bardzo użyteczną techniką, ale z drugiej strony, nie powinna to być główna, ani najważniejsza, technika w arsenale narzędzi programisty Rubiego. W ostatecznym rozrachunku, łatwiej wrócić do kodu który jest prosty niż tylko ładny i magiczny z implementacją zaszytą głęboko w gdzieś includowanej bibliotece.
Ale Merb na tym się nie zatrzymuje. Jego mottem przewodnim jest nie ma szybszego kodu od braku kodu. Ezra nie zgadza się za bardzo z rozumowaniem prezentowanym przez DHH i Rails, że skoro czas programisty jest droższy od czasu serwera, to kto martwi się o wydajność, niech sobie dostawi… więcej serwerów. Nawiązuje to do permanentnie błędnej polityki ignorowania optymalizacji wydajnościowej w Rails na rzecz koncentrowania się na ciągle nowej funkcjonalności, “a wydajność poprawi się później, lub dostawi więcej sprzętu”. To prawda, że “przedwczesna optymalizacja jest korzeniem wielu problemów, komplikacji itp. itd” Prawdą jest jednakże i to, że “zbyt późna optymalizacja jest korzeniem wszystkich dodatkowych faktur do zapłacenia dla centrum hostingowego”. Merb od początku jest tworzony z uwzględnieniem wydajności, modularności, wielowątkowości i elastyczności.
Merb (licząc od wersji 0.9 która wnosi ogromne zmiany do wcześniejszej 0.5.x) został podzielony na kilka modułów. Rdzeń frameworka znajduje się w merb-core. Dodatkowe możliwości są dostępne w merb-more i merb-plugins. Nowy Merb jest zbudowany też na fundamencię Rack’a (wzorowanego na pythonowym WSGI, interfejsie dla aplikacji korzystających z protokołu HTTP). Merb może być uruchamiany z kilkoma serwerami: Ebb, asynchroniczny Mongrel (Evented Mongrel), FastCGI, wielowątkowy Mongrel (Merb, w przeciwieństwie do Rails, jest w pełni wielowątkowy), Thin czy Webrick.
Wielowątkowo czy asynchronicznie?
Ezra zwrócił uwagę na dosyć istotny aspekt wydajności dla adappterami asynchronicznymi (Ebb, Evented Mongrel, Thin) a wielowątkowym Mongrelem. Otóż nie zawsze adaptery asynchroniczne są szybsze. Tak jest tylko w wypadku krótko trwających zapytań. Jednakże jeśli mamy sytuację obsługi jakiegoś długiego (kilku sekundowego) requestu, to adapter asynchroniczny ma zablokowaną pętlę i w efekcie, jak to określił Erza, “pada na pysk”. Wielowątkowy Mongrel w takiej sytuacji, nie blokuje swojej pracy, ale odpala kolejny wątek dla obsługi następnych requestów. To, więc, co warto użyć zależy od charakteru aplikacji i można powiedzieć że wielowątkowy Mongrel jest najbardziej uniwersalnym, choć nie zawsze najszybszym, rozwiązaniem. Można ewentualnie mieszać podejścia i oczekiwane jako wolne, requesty kierować na Mongrela a resztę na Ebb, czy Thin. Osobiście tego jeszcze nie testowałem, ale wydaje się to rozsądnym podejściem.
Potężniejszy router adresów
Merb ma kompletnie inaczej napisany resolver adresów URL niż Rails. Po pierwsze, jest dużo szybszy ze względuna stosowaną prekompilację. Po drugie, jest dużo elastyczniejszy od Railsów (czy Django, gdzie który jest równie słaby). Przyjrzyjmy się poniższemu przykładowi.
Merb::Router.prepare do |r|
r.match(%r[^/foor(.+)], :user_agent => /(MSIE|Gecko)/).
to(:controller => "foo", :title => "[1]"),
:action => "show", :agent => ":user_agent[1]")
r.match("/bar/:baz").defer_to do |request, params|
if bar = Bar.find_by_baz params[:baz]
{ :controller => bar.controller,
:action => bar.action,
:bar => bar.to_param }
end
end
endW regule pierwszej widać, że router adresów zastosowany w Merbie pozwala filtrować po dowolnych nagłówkach. Np. może wiedzieć czy użyto przeglądarki Internet Explorer czy Firefox i stosownie do tego podejmuje dalsze działania. Drugi przykład jest jeszcze ciekawszy. Z adresu URL wyłuskiwana jest wartość którą Merb wykorzystuje aby odpytać bazę danych i na tej podstawie odpowiednio przekierować sterowanie.
Akcje o składni metod Rubiego
Mimo, że Merb pozwala, w podobny (do Rails) sposób, korzystać z hasza params, dodano tu trochę syntaktycznego lukru pozwalającego na pisanie kodu akcji w kontrolerze tak jak się pisze zwykłe metody w Rubim.
Merb.add_mime_type(:yaml, :to_yaml, %w[application/x-yaml text/yaml])
Merb.add_mime_type(:text, :to_text, %w[text/plain])
Merb.add_mime_type(:html, :to_html, %w[text/html application/xhtml+xml application/html])
Merb.add_mime_type(:xml, :to_xml, %w[application/xml text/xml application/x-xml], :Encoding => "UTF-8")
Merb.add_mime_type(:js, :to_json, %w[text/javascript application/javascript application/x-javascript])
Merb.add_mime_type(:json, :to_json, %w[application/json text/x-json])
#...
class Posts < Application
provides :json, :yaml, :xml
def show(id)
@post = Post.find id
display @post
end
def user(name="Jarek")
only_provides :html
@user = User.find_by_name name
end
endPrzekazywanie parametrów w metodzie zamiast w haszu, moim zdaniem, znacznie zwiększa czytelność kodu. Umożliwia też wygodne stosowanie wartości domyślnych.
Słowo wyjaśnienia należy się metodzie display(). Merb w inny (od Rails) sposób rozpoznaje typ MIME przekazany do metody. Zamiast przekazywać w akcji blok do respond_to, Merb definiuje tylko jakie metody mają być wywołane dla odpowiedniego MIME. Np. akcja odpalana dla adresu /posts/user przekazuje do metody user hasz params o wartości {:name => "Jarek"}. Pobiera rekord z bazy i zwraca do klienta kod HTML wywołany za pomocą metody to_html na obiekcie user. W wypadku metody show zwracanych jest wiele różnych reprezentacji zależnych od użytego MIME.
Trzeba też dodać, że Merb nie używa żadnych magicznych railsowych metod render które mogą być wywołane tylko jeden raz (sic!) na request. Merb może kolekcjonować output z kilku miejsc. Zaś jeśli chodzi o samą akcję kontrolera, to zwracane jest po prostu ostatnie wyrażenie (tak, jak w zwykłych metodach Rubiego). Np. można otworzyć plik i zwrócić stworzony obiekt IO w metodzie kontrolera, a Merb potraktuje to jako przesyłanie strumieniowe.
Git rządzi
Ezra podkreślił sporo korzyści jakie dało przejście na rozproszony system wersjonowania kodu (Git). Znacznie łatwiej można eksperymentować z kodem i zgłaszać poprawki niż w wypadku starego SVN’a. I co ciekawe, także Ruby on Rails zamierza też przejść na Git’a w przeciągu jakichś dwóch miesięcu.



Może to wersja developerska (pobrałem z git’a 0.9.2), ale code generations nie do końca działa. Zrobienie resource skończyło się fiaskiem.
@greno: nie podajesz żadnych szczegółów więc nie wiem o co chodzi. Mnie tam działa. Jeśli chcesz przedyskutować problem, to kieruj to do właściwego miejsca, czyli na kanał IRC #ruby.pl lub grupę dyskusyjną pl.comp.lang.ruby
no niech tylko wyjdzie potem ładna książka do merb’a tak jak wyszły do railsów..
Do Railsów też długo była tylko jedna książka. Teraz można mówić o bumie na książki o RoR.
Bardzo ciekawy post. Co do GITa to polecam prezentację Randalla Schwartza: http://video.google.com/videoplay?docid=-3999952944619245780
Boom na książki o Rails. Może. Tylko co coś dorwę, opisuje w najlepszym przypadku Edge -> 2.0. Za szybko to się rozwija by papierowe wydawnictwa nadążały.
Merb rozwija się jeszcze szybciej. Może więc za wcześnie na knigi? Ale kilka dobrych manuali na stronie by się przydało. “Beznadziejnie skomplikowane frameworki javove” takie jak Spring często są nie takie beznadziejnie skomplikowane dzięki dobrej dokumentacji…
Może Ezra też zauważy, że obok kosztu dostawiania serwerów, całkiem dobrym i prostym do redukcji jest czas grzebania w kodzie by nauczyć się “tego” używać, bo framework jest genialny. Niestety, frameworki powstają z myślą o “programistach użytkownikach” a nie osobach o mentalności hackerów, którzy (jak ja) znajdują przyjemność w grzebaniu się w czyimś kodzie :P
Sam zacząłem pisać coś na temat Merba ale nie wiem czy kiedykolwiek ujrzy to światło dzienne – praca, praca magisterska, dziecko, drugie dziecko i jeszcze kiedyś trzeba na piwo wyskoczyć…