To nie jest wprowadzenie do pisania aplikacji na Google AppEngine, ani tym bardziej samouczek Pythona. Nie zamierzam też uprawiać ewangelizacji (choć w przypadku Pythona na pewno by nie zaszkodziło). O co więc chodzi?
Gdy około rok temu (w kwietniu 2008 roku) Google udostępniło swoją nową usługę, wszystkim opadły szczęki — run your application on Google infrastructure wydawało się obietnicą killer feature. Minął rok, ekscytacja opadła, w tym czasie Google znacznie rozwinęło swój produkt (i rozwija go nadal), zaczęło też pobierać opłaty za jego używanie i zapowiedziało znaczną redukcję tego, co będzie dostępne za darmo. Nie łudźmy się, nadal jest to produkt w stadium beta, którego nikt poważnie nie będzie traktował, jeżeli chodzi o uruchamianie poważnych aplikacji w tym środowisku. Obietnica niegraniczonej skalowalności jest jednak wciąż kusząca i choćby z tego powodu warto się chwilę zastanowić, czy napisanie aplikacji w Pythonie na to środowisko nie byłoby rozsądnym rozwiązaniem. W tym artykule mam nadzieję przybliżyć kilka idei, które ułatwią podjęcie takiej decyzji i postaram się zrobić to w miarę bezstronnie.
Vendor lock-in
Wszyscy chyba wiedzą, co to takiego. Jak sobie przypominam z czasów, kiedy jeszcze używałem Windows®, niemal codziennie oskarżano o to Microsoft, Oracle, IBM i chyba wszystkich dużych na runku oprogramowania. Tym razem sytuacja jest podobna do pewnego stopnia, ale nie identyczna. Platforma AppEngine jest bardzo specyficzna, ale to co jest specyficzne to są rzeczy dodatkowe względem aplikacji — nie dotykają one jej zasadniczego działania.
Przede wszystkim, standardowe jest środowisko uruchomieniowe kodu: jest to WSGI, które już na dobre zadomowiło się w świecie Pythona. Poczynając od sprawy najprostszej, Hello, World! w wykonaniu WSGI można bez żadnych zmian uruchomić zarówno na Google AppEngine jak i w dowolnym środowisku WSGI, jak np. mod_wsgi pod Apache2 czy też używając bramki FastCGI/WSGI jak Flup. Gdzie jest haczyk? Na razie nie ma, ale zrobienie aplikacji bazującej tylko na tym mija się z celem i sensem (nie wspominając już o tym, że byłoby bardzo nużące i pracochłonne). Czas wybrać sobie trochę narzędzi ułatwiających życie. Schody zaczynają się właśnie tutaj, bynajmniej nie z powodu ograniczeń, ale z powodu nadmiaru możliwości.
Standardowo Google wraz z SDK dostarcza kilka narzędzi, które mogą ułatwić pisanie aplikacji i jest ich wbrew pozorom całkiem sporo.
-
poziom najniższy, WSGI: AppEngine działa z Pythonem 2.5, więc jest dostępna referencyjna implementacja WSGI w postaci wsgiref;
-
podstawowa narzędziówka WSGI, WebOb: dostarcza wrapperów odzwierciedlających żądanie i odpowiedź HTTP, wraz z całą maszynerią parsowania nagłówków, payloadów oraz paroma niezbędnymi podklasami;
-
niby-ramówka aplikacyjna WebApp: maksymalnie uproszczona, a jednak działająca;
-
Django 0.96: w chwili obecnej mocno przestarzała wersja sprzed kilku lat (powoli zbliżamy się do wydania wersji 1.1), ale wciąż spełniająca świetnie swoją rolę.
Jak widać, na każdym poziomie abstrakcji coś się znajdzie. Z tych wszystkich wymienionych narzędzi, tylko WebApp nie jest standardowe (to znaczy — nie jest używane poza AppEngine). Biorąc dodatkowo pod uwagę to, że do aplikacji można dołączać dodatkowe biblioteki i moduły (z pewnymi ograniczeniami), to sytuacja wciąż wygląda dobrze, więc gdzie jest haczyk?
Czego nie ma, a co udaje że jest
Pierwszy haczyk jest w tym, że nie wszystkie moduły biblioteki standardowej są na AppEngne tym, czym na pierwszy rzut oka zdają się być, a inne w tajemniczy sposób nie istnieją. Część modułów jest importowalna lecz pusta, część jest podmieniona na takie, których jedynym zadaniem jest wyrzucać wyjątek przy próbie wykonania dowolnego kodu. Google w ten sposób zabezpiecza się przed możliwością wywalenia w kosmos środowiska (które przecież ma być współdzielone) i poprosiło swoich inżynierów, żeby pochowali co bardziej niebezpieczne zabawki. Dodatkowo dochodzą ograniczenia platformy systemowej w postaci systemu plików tylko do odczytu i dość restrykcyjnych limitów na wykonanie kodu (czas i zasoby CPU).
Najlepszy storage pod słońcem?
Kolejny haczyk to storage, czyli system przechowywania danych. Nierelacyjny, w dużym stopniu bezschematowy, oparty na własnym wynalazku Google, czyli słynnej BigTable. W porównaniu do zwykłych baz danych można powiedzieć, że składa się właściwie z samych ograniczeń:
-
nie ma złączeń, jedynie referencje (dość miękkie);
-
zwraca najwyżej 1000 dokumentów (wolę takie okreslenie, niż wiersze);
-
nie umie liczyć;
-
nie umie wymusić unikalności danych;
-
transakcyjność jest w dużym stopniu ograniczona (wymaga grupowania dokumentów) i działa bardzo restrykcyjnie — blokowane są wszystkie dokumenty w grupie;
-
bardzo nierównomierne traktowanie odczytów i zapisów — zapisy są o wiele, wiele bardziej kosztowne i zdarzaja się zapaści.
Co dostajemy w zamian? Google powtarza swoją mantrę o niegraniczonej skalowalności (zakładam, że mówią prawdę), więc jeżeli to jest to, czego potrzebujesz, to wymienione ograniczenia nie będą czynnikiem powstrzymującym. W każdym innym przypadku czeka długi i żmudny proces przestawiania myślenia z relacyjnego na nieco bardziej płaskie struktury. Koniecznie muszę nadmienić, że wszystkie wymienione przeze mnie problemy są rozwiązywalne innymi sposobami, ale są one zupełnie nieintuicyjne dla kogoś, kto polega na swoim doświadczeniu z relacyjnymi bazami danych.
Zapomnij
Są rzeczy, które trzeba dopisać w kategorii "zapomnij", to znaczy takie, do których nie ma i nie będzie dostępu, a jedyne, czego można się spodziewać, to jakiejś namiastki:
-
dostęp z kodu do zasobów statycznych aplikacji;
-
standardowy cron (będzie namiastka, ale oczywiście nie wiadomo kiedy);
-
nieograniczone przetwarzanie wsadowe (namiastka crona będzie operować w ramach limitów czasu wykonywania kodu).
Jak z tego widać, Google nie uważa, żeby aplikacja webowa miała potrzebę wykonywania jakichkolwiek operacji offline i na boku (osobiście mało takich widziałem, ale może mam zbyt ograniczone pojęcie...).
Mindset, czyli czego nie widać
Jak dla mnie najważniejszą rzeczą, o której trzeba pomyśleć zanim podejmie się decyzję, czy robić aplikację na AppEngine, czy pozostać w sferze bardziej tradycyjnych platform, jest to, jak sobie z tym poradzą programiści. W odróżnieniu od zwykłych środowisk webowych, AppEngine wybacza niewiele, co z kolei narzuca konieczność bardzo starannego pisania kodu i projektowania aplikacji tak, by nie doprowadzić do wyczerpania dostępnych zasobów w krótkim czasie. Przez cały czas trzeba też mieć na uwadze ograniczenia platformy (szczególnie w kontekście egzotyczności storage).
To w końcu jest czy nie ma tego lock-in?
Do pewnego stopnia jest, ale porównując to do zarzutów stawianych np. Microsoftowi, to skala jest jednak zupełnie nieporównywalna. Nadal można uruchomić aplikację w innym środowisku, choć wymaga to pewnego (zależnego od wybranych narzędzi) zachodu. Istnieją narzędzia, które ułatwiają migrowanie aplikacji w Django z AppEngine do zwykłych środowisk i może to być pewnym ułatwieniem, ale nie ma takich narzędzi dla innych ramówek, które można uruchomić na AppEngine.
A ile wysiłku (czasu, kodowania itd.) trzeba włożyć w to, żeby aplikacja jednak była przenośna? To temat na oddzielny artukuł i na pewno go wkrótce napiszę...
Konkluzje? Jakie konkluzje?!
Za nikogo nie podejmę decyzji, więc nie będę też teraz niczego konkludował. AppEngine ma swoje dobre i złe strony — z jednej strony narzuca wiele ograniczeń, ale z drugiej wymaga rzeczy, które i tak powinny być elementarzem każdego programisty webowego. Jak dla mnie to warto spróbować, o ile aplikacja mieści się w przewidzianym (przez Google!) zakresie tego, co mogą robić aplikacje webowe. Na pewno jest to pouczające doświadczenie, ale dla aplikacji, dla której celem jest zostać sprzedaną to marny argument za. ;)