Mówiąc o aplikacji bazodanowej mamy na myśli kompletne rozwiązanie wdrożenia pewnego systemu zarządzania bazami danych (tj. w naszym przypadku RDBMS) do obsługi określonego zagadnienia wiążącego się z przechowywaniem, udostępnianiem i aktualizacją pewnej kolekcji danych. Przykładami takich (mini) aplikacji (a raczej zadaniami, których rozwiązania stanowią małe aplikacje) są proponowane zadania zaliczeniowe do niniejszego kursu.
W modelu klient-serwer, który nas tu głównie interesuje, aplikacja taka składa się typowo z następujących elementów:
W modelu klient-serwer interfejs użytkownika stanowi program bądź programy uruchamiane na komputerach dostępnych dla użytkowników bazy danych, i komunikujące się z jednej strony -- bezpośrednio z użytkownikiem, otrzymując od niego informacje niezbędne do autoryzacji dostępu do serwera bazy danych, polecenia określające charakter żądanej operacji, oraz parametry konieczne do sformułowania tej operacji (typowo w postaci polecenia lub ciągu poleceń SQL). Z drugiej strony, program ten (program kliencki) ,,potrafi'' nawiązać komunikację z serwerem bazy danych (najczęściej korzystając z mechanizmów komunikacji sieciowej, np. TCP/IP), przetworzyć polecenia i dane otrzymane od użytkownika na instrukcje SQL, zakomunikować te instrukcje serwerowi, odebrać dane i komunikaty stanowiące odpowiedź serwera na wydane mu instrukcje, oraz zaprezentować te odpowiedzi w postaci czytelnej dla użytkownika.
Podział na zadania klienta (interakcja z użytkownikiem, prezentacja danych, sterowanie przebiegiem sesji -- składającej się z ciągu instrukcji SQL wykonywanych w ramach jednego połączenia z serwerem) i zadania serwera (kontrola dostępu, zarządzanie faktycznym zapisem danych, wykonywanie operacji wyszukiwania i modyfikacji) nie jest jednak w pełni jednoznaczny. Wpływ na to mają np. takie cechy funkcjonalne danego RDMBS jak obsługa transakcji czy możliwość definiowania funkcji i procedur jako części schematu danych, o których była mowa przy omawianiu RDBMS Oracle 8, i które nieco zacierają ten prosty podział.
Przede wszystkim zwróćmy uwagę na to, że podstawowa składnia SQL (jak np.
w implementacji MySQL) nie zawiera w zasadzie takich elementów, właściwych
proceduralnym językom programowania, jak zmienne, pętle czy instrukcje
warunkowe (w odróżnieniu od klauzul warunkowych instrukcji np. SELECT).
Instrukcje SQL przetwarzane są w zasadzie sekwencyjnie, każda z nich stanowi
oddzielną operację (modyfikującą dane lub zwracającą pewną tabelę wynikową
zbudowaną na podstawie zawartości bazy danych) -- niezależnie od tego, że
zakres tej operacji może obejmować wiele wierszy szeregu różnych tabel. Gdy
zachodzi potrzeba np. uzależnienia parametrów kolejnej operacji od wyniku
operacji poprzedniej -- i być może jeszcze odpowiedzi użytkownika -- konieczne
staje się skorzystanie z dodatkowych narzędzi programistycznych. Zewnętrznych
(w stosunku do SQL) narzędzi wymaga też oczywiście obsługa interakcji z użytkownikiem,
np. prezentacja wyniku zapytania w postaci wydruku sformatowanej tabeli czy
wykresu, zapytanie użytkownika o parametry żądanej operacji poprzez
przedstawienie pełnoekranowego formularza z polami do wypełnienia lub menu
z dostępnymi opcjami, itp.
Do zadań oprogramowania klienckiego należy więc m. in. uwolnienie użytkownika od potrzeby szczegółowej znajomości składni SQL (oraz logicznej struktury bazy danych), oraz ewentualnie sterowanie przebiegiem sesji użytkownika w zależności od wyników dotychczasowych operacji. Standardowym rozwiązaniem tego problemu jest tworzenie programów klienckich w którymś ze ,,zwykłych'', proceduralnych języków programowania, z wykorzystaniem bibliotek czy modułów zawierających funkcje lub procedury umożliwiające obsługę komunikacji z serwerem baz danych. Biblioteki takie są specyficzne dla danego RDBMS i zazwyczaj są dostarczane razem z nim przez producenta. W takim przypadku do stworzenia interfejsu obsługującego interakcję z użytkownikiem oraz prezentację danych wykorzystuje się możliwości dostępne w danym języku programowania -- biblioteki GUI (graficznych, tj. okienkowych interfejsów użytkownika) lub biblioteki obsługi interakcji pełnoekranowej (np. ncurses).
Innym godnym uwagi rozwiązaniem problemu interfejsu użytkownika jest skorzystanie z możliwości protokołu HTTP i języka HTML, będących podstawą sieci WWW. Temat ten był zresztą jednym z przedmiotów ćwiczeń. Zwróćmy tu uwagę, że skorzystanie z tych mechanizmów nie musi pociągać za sobą udostępnienia danych z naszej bazy ,,całemu światu'': istnieje wiele sposobów ograniczenia dostępu do stron WWW stanowiących interfejs naszej bazy danych, w tym najprostszy -- połączenie serwera ze stacjami klienckimi siecią lokalną niepołączoną (fizycznie) z Internetem, lub połączoną w sposób zapewiający selekcję dozwolonych połączeń (firewall).
Interfejs typu WWW do bazy danych może być zrealizowany na szereg różnych sposobów. Najprostszy (w zasadzie) to posłużenie się mechanizmem tzw. skryptów lub programów CGI, będących programami wykonywanymi na maszynie serwera w odpowiedzi na określone żądania HTTP, generującymi dynamicznie zawartość stron w HTML -- w rozważanym przypadku, na podstawie wyników instrukcji SQL posyłanych do serwera bazy danych, po ewentualnym dalszym przetworzeniu tych wyników (formatowaniu, itp.). Informacje o tym jakie instrukcje mają być wykonane i o ich parametrach pobierane są od użytkownika poprzez wykorzystanie możliwości dostępnych w języku HTML (gł. formularze). Programy CGI mogą być pisane w zasadzie w dowolnym języku programowania dostępnym na serwerze -- począwszy od C lub C++, skończywszy na skryptach w języku shella unixowego, poprzez różne języki interpretowane w rodzaju Perl, Python lub Java. W zależności od wybranego języka programów CGI komunikacja z serwerem bazy danych może być obsługiwana poprzez funkcje odp. bibliotek (jak wyżej), lub wręcz przez wywołania programu typu SQL-shell (np. program mysql). Natomiast wykorzystanie HTML do budowy interfejsu interakcji z użytkownikiem i prezentacji danych stanowi znaczne ułatwienie dla kogoś, kto nie posiada doświadczenia w programowaniu interfejsów graficznych. Ponadto np. obsługa wydruku raportów jest zapewniona automatycznie, dzięki funkcji drukowania dostępnej w standardowych przeglądarkach WWW. Jeszcze jedną zaletą takiej strategii budowy interfejsu jest jego niezależność od platformy stacji klienckich -- jednolity sposób dostępu do bazy jest zapewniony niezależnie od tego, czy użytkownik korzysta z komputera PC + MS Windows, z unixowej stacji roboczej, czy np. z Macintosha.
Istnieje również szereg rozwiązań interfejsu WWW zbliżonych do CGI, lecz nie posługujących się standardem CGI. Na ogół polegają one na możliwości zagnieżdżania instrukcji pewnego języka skryptowego bezpośrednio w tekście stron HTML; instrukcje te są bądź interpretowane przez sam serwer HTTP, a raczej jego odpowiedni moduł (taką możliwość oferuje np. serwer Roxen), bądź przez program zewnętrzny, do wywoływania którego dla odpowiednich typów plików skonfigurowano serwer, który to program dokonuje przetworzenia zagnieżdżonych instrukcji, zastępując je zwróconymi danymi, i daje w wyniku stronę w standardowym HTML gotową do wysłania do przeglądarki klienta. Przykładem jest program PHP, ostatnio zyskujący sporą popularność jako szczególnie łatwy w użyciu. Zarówno Roxen jak i PHP posiadają własne moduły do obsługi komunikacji z serwerem MySQL (oraz kilkoma innymi RDBMS).
Oparcie interfejsu aplikacji bazodanowej na mechanizmach WWW, choć jest rozwiązaniem względnie łatwym do wdrożenia, również pociąga za sobą pewne trudności. Problemem może być zapewnienie bezpieczeństwa (w sensie autoryzacji dostępu do danych, jak i odporności na ,,podsłuch''). Problem ten należy brać pod uwagę również w sieciach wewnętrznych, dobrze zabezpieczonych przed nieautoryzowanym dostępem z zewnątrz firmy czy instytucji (choć zapewne naprawdę dobrze zabezpieczone sieci są rzadkością!) -- w końcu to wewnątrz samej organizacji mogą się znaleźć osoby szczególnie zainteresowane dostępem do danych nie dla nich przeznaczonych. Inny problem wiąże się z ,,bezstanowością'' protokołu HTTP. Oznacza to, że każda transakcja HTTP (żądanie -- odpowiedź serwera) stanowi odrębną jednostkę przetwarzania, a śledzenie tożsamości użytkownika na przestrzeni kilku transakcji wymaga dodatkowych zabiegów. Nie jest to problem nie do rozwiązania, ale prostota budowy interfejsu na tym cierpi.
Wracając do bardziej ,,standardowych'' sposobów budowy interfejsów aplikacji bazodanowych w modelu klient-serwer, dokonam teraz krótkiego (i z natury rzeczy bardzo subiektywnego) przeglądu narzędzi programistycznych, jakimi można się w tym celu posłużyć. Naturalnie większość z wymienionych poniżej języków i bibliotek nadaje się również do tworzenia programów CGI (pomijając biblioteki GUI).
Przegląd ten będzie rzecz jasna bardzo niepełny, w szczególności nie mogę tu w pełni uwzględnić narzędzi dostarczanych przez producentów komercyjnych baz danych, z którymi nie mam doświadczenia. Poza tym, wystąpi tu wyraźny ,,przechył'' na korzyść narzędzi używanych w środowiskach unixowych, i to narzędzi swobodnie dostępnych (darmowych) -- choć w aplikacjach komercyjnych zwykle jako stacje klienckie wykorzystuje się komputery PC pracujące pod MS Windows. Wszystkie pojawiające się poniżej uwagi zdające się mieć charakter ocen należy traktować jako bardzo mało zobowiązujące, często oparte są one na wiadomościach z drugiej ręki lub na dość powierzchownym oglądzie.
Należy uwzględnić dwa zadania należące do programu klienckiego: komunikację z serwerem baz danych, i obsługę interakcji z użytkownikiem (i prezentacji danych).
Programowanie w tych językach na ogół uważa się za niezbyt łatwe, szczególnie dotyczy to tworzenia graficznych interfejsów użytkownika (GUI). Za standardowe narzędzie do programowania GUI w środowiskach unixowych uważano dotąd bibliotekę Motif. Jest to produkt komercyjny, licencjonowany przez organizację The Open Group, dostarczany wraz z większością komercyjnych systemów unixowych (Sun, HP, SCO, itd.). Istnieje też niekomercyjna, niezależna implementacja funkcji Motifa pod nazwą Lesstif, nie do końca jednak (jak dotąd) zgodna z oryginałem. Tworzenie GUI za pomocą Motifa jest dość pracochłonne, istniejące narzędzia wspomagające ten proces są komercyjne i niełatwo dostępne. W ostatnim okresie, ze względu między innymi na wzrost znaczenia darmowych implementacji unixa (Linux, ale również np. FreeBSD), Motif wydaje się tracić na znaczeniu. Rośnie natomiast popularność alternatywnych bibliotek GUI, takich jak GTK lub Qt (ta ostatnia w C++). Oferują one (poza swobodną dostępnością, wraz z kodem źródłowym) nieco większą łatwość programowania, oraz dużą ilość przykładowych programów (niektóre z nich bardzo rozbudowane), których kod źródłowy można znaleźć w Internecie. Nie są jednak (szczególnie GTK) jeszcze w pełni dojrzałe i ustabilizowane -- dostępne funkcje i interfejsy mogą się zmieniać z wersji na wersję.
Jeżeli pożądana jest obsługa programu klienckiego z terminali alfanumerycznych (nie graficznych), to standardowym narzędziem do budowy programów z interfejsem pełnoekranowym jest biblioteka ncurses (patrz też tutaj).
Jeśli chodzi o obsługę komunikacji z RDBMS, to odpowiednie biblioteki istnieją zapewne dla większości produktów -- patrz np. MySQL C API.
Perl jest być może najbardziej popularnym językiem do tworzenia skryptów CGI. Jest to język interpretowany, o bogatych możliwościach przetwarzania danych tekstowych (i nie tylko), wyposażony w liczne biblioteki umożliwiające np. obsługę funkcji sieciowych z poziomu Perla (do tworzenia skryptów CGI nie jest to konieczne). Istnieją również moduły Perla umożliwiające obsługę komunikacji z szeregiem serwerów baz danych, w tym MySQL.
Nie brak też interfejsów umożliwiających tworzenie GUI z poziomu Perla, np. perl/Tk pozwala na korzystanie z funkcji biblioteki Tk, zazwyczaj używanej w połączeniu z językiem skryptowym Tcl, istnieją również (w różnym stopniu rozwinięte) interfejsy perl-Qt, perl-Gtk, ... korzystające z funkcji bibliotek GUI o odpowiednich nazwach. Szybkość i wydajność programów w Perlu jest na ogół zadowalająca; zastrzeżenia u niektórych budzi jego dość ,,eklektyczna'' składnia, umożliwiająca stosowanie wielu najrozmaitszych ,,stylów'' programowania (w tym całkiem nieczytelnych dla postronnych) -- ale inni uważają to z kolei za zaletę.
Stosowalność języka Perl nie jest ograniczona do systemów unixowych -- dostępna jest również (i szeroko wykorzystywana) implementacja dla Windows NT.
Tcl/Tk to tak naprawdę pakiet dwóch elementów -- język skryptowy Tcl, oraz biblioteka Tk do tworzenia interfejsów okienkowych. Niewątpliwą zaletą Tcl/Tk jest prostota składni i łatwość użycia: oferuje on zapewne najłatwiejszy sposób tworzenia niezbyt skomplikowanych programów wyposażonych w GUI, dostępny w systemach unixowych. Inną cechą jest łatwość wywoływania programów zewnętrznych i komunikacji z nimi z poziomu skryptu Tcl, oraz prosta integracja rozszerzeń które użytkownik może tworzyć w C, uzupełniając interpreter Tcl o potrzebne mu funkcje. Można korzystać z interpretera Tcl bez dołączania funkcji Tk, np. przy tworzeniu skryptów CGI.
Za słabość Tcl uważa się często również jego prostotę, a w szczególności brak bardziej złożonych struktur danych, panuje też opinia o jego słabej wydajności (chociaż w odniesieniu do bieżących wersji jest ona być może nie całkiem uzasadniona). Z naszego punktu widzenia wadą jest brak standardowych interfejsów komunikacji z systemami baz danych -- chociaż nie wydaje się trudne skorzystanie z możliwości integracji funkcji dopisanych w C z użyciem odpowiednich bibliotek.
Ogólnie można powiedzieć, że Tcl/Tk jest bardzo dobrym narzędziem do zadań nieco zbyt złożonych dla skryptu w shellu, lecz nie do budowy bardziej złożonych aplikacji. Istnieją wprawdzie przykłady całkiem zaawansowanych aplikacji zbudowanych na bazie Tcl/Tk, lecz na ogół korzystają one z niestandardowych rozszerzeń (np. obiektowych). Warto dodać, że istnieje implementacja Tcl/Tk dla MS Windows (oraz dla Apple Macintosh), a skrypty są w dużej mierze przenośne pomiędzy platformami.
Python jest niezwykle ciekawym interpretowanym językiem programowania, o cechach obiektowych, czytelnej składni, zadowalającej wydajności, bogactwie złożonych typów danych (tablice asocjatywne zwane tu ,,słownikami'', klasy z dziedziczeniem, ...), wyposażonym w zestaw bibliotek o możliwościach zbliżonych do Perla. Wśród tych bibliotek są również moduły zapewniające komunikację z szeregiem RDBMS, w tym z MySQL. Python istnieje też w wersjach na MS Windows i Apple Macintosh. Zdaniem autora jest to niewątpliwie język zasługujący na szerszą popularyzację. Ciekawostką jest fakt, że poza standardową implementacją interpretera w języku C istnieje również implementacja w języku Java (JPython).
Za słabą (jak dotychczas) stronę Pythona uważam stan integracji z bibliotekami GUI; standardem w środowisku programistów z niego korzystających jest Tkinter, zestaw klas GUI zbudowany na bazie Tcl/Tk -- ta wielowarstwowość ma wyraźnie ujemny wpływ na wydajność tych narzędzi. Sytuacja ta jednak szybko ulega zmianie -- rozwijane są interfejsy Pythona np. do biblioteki Gtk, nie są to jednak już dziś w pełni dojrzałe narzędzia.
Być może kogoś zdziwi, że niezwykle modny od paru lat język (i środowisko programistyczne) Java nie znalazł się w tym omówieniu na wyższej pozycji. Na pewno wynika to głównie ze skrzywionej optyki i uprzedzeń autora, który na codzień korzysta niemal wyłącznie z systemu Linux -- a implementacje Javy dla Linuxa nie działają jednak jak dotąd w sposób zadowalający (choć działają).
Java jest językiem obiektowym o dobrze przemyślanej składni, oraz całym środowiskiem programistycznym, którego główną cechą ma być pełna przenośność programów, osiągnięta dzięki ich kompilowaniu do niezależnych od platformy (sprzętowej i systemowej) kodów bajtowych, interpretowanych w czasie uruchomienia przez tzw. maszynę wirtualną. Nie jest więc to język skryptowy, lecz szczególny rodzaj języka kompilowanego. Wyposażony jest on w standardowe narzędzia do budowy GUI (wpierw była to biblioteka AWT, obecnie tzw. Java Foundation Classes/ Swing), istnieje też standardowy interfejs komunikacji z bazami danych (JDBC).
Java zawdzięcza swój rozgłos po części tzw. appletom, dekorującym liczne strony WWW animacjami i elementami interaktywnymi. Jest to możliwe dzięki temu, że popularne przeglądarki WWW (Nestcape i MSIE) zintegrowane są z wirtualnymi maszynami Javy i potrafią interpretować applety (które wysyłane są przez serwery WWW w postaci kodów bajtowych, w plikach o nazwie *.class). Jednak głównym zastosowaniem Javy ma być budowa samodzielnych aplikacji, działających poza środowiskiem przeglądarki. Nie należy też mylić Javy z Javascriptem -- jest to język interpretowany wprowadzony przez Netscape, w zamierzeniu również głównie do ,,dekorowania'' stron WWW. Kod Javascriptu jest jednak zagnieżdżany w tekście stron WWW, w postaci źródłowej i jest to typowy język interpretowany (lecz również o charakterze obiektowym).
Nie zamierzam nikogo odwodzić od prób tworzenia aplikacji w języku Java. Wydaje mi się jednak, że trudność programowania jest zbliżona do C++, wydajność jest na ogół słaba (choć silnie zależy to od platformy, tj. od implementacji maszyny wirtualnej), a przenośność -- mająca być główną zaletą Javy -- nie została jak dotąd w pełni zrealizowana. Należy się liczyć z niezgodnościami programów uruchomionych na określonej wersji platformy Javy z innymi wersjami tejże. W niedalekiej przyszłości ocena ta może jednak stać się całkiem nieaktualna (zakładając nawet, że jest ona słuszna dziś).
Jak już podkreślono, przegląd ten jest zdecydowanie niepełny -- nawet uwzględniając brak wiedzy i uprzedzenia autora, co jest przyczyną braku omówienia takich popularnych narzędzi jak Borland Delphi czy MS Visual Basic. Istnieje zadziwiające bogactwo mniej szeroko znanych języków programowania, zarówno o bogatej tradycji (różne warianty Lispa, Pascal, Smalltalk,...) jak i niedawno powstałych i obecnie rozwijanych, co do których przydatności w tworzeniu aplikacji bazodanowych w środowiskach unixowych nie potrafię się wypowiedzieć.
Chciałbym jedynie na koniec wspomnieć o bardzo mało jak dotąd znanym języku Pike. Jest on interesujący nie tyle (czy nie tylko) ze względu na swoje cechy rozważane w oderwaniu, lecz jako język implementacji doskonałego produktu jakim jest w mojej opinii serwer WWW Roxen Challenger. Pike jest to język interpretowany o cechach obiektowych, o składni zbliżonej do C++ (lecz znacznie prostszej). Dostępny jest bezpłatnie (licencja GPL), posiada zestaw podstawowych bibliotek, w tym biblioteki komunikacji z najpopularniejszymi RDBMS, i wydaje się charakteryzować bardzo dobrą jak na język interpretowany wydajnością. Niestety brak jak dotąd dokończonego interfejsu do bibliotek GUI. Istnieje jednak możliwość zagnieżdżania skryptów Pike w kodzie HTML stron WWW obsługiwanych przez serwer Roxen -- który ponadto posiada również moduł pozwalający na wpisywanie instrukcji SQL wprost do kodu HTML, zapewniając obsługę komunikacji z serwerem bazy danych. W połączeniu z możliwościami Roxena interpretacji makroinstrukcji dotyczących np. formatowania i ,,dekoracji'' stron WWW, wygląda to na bardzo obiecujące narzędzie. Ze względu na wydajność (sprawdzoną na przykładzie dość rozbudowanej aplikacji jaką jest Roxen), ,,łatwą'' składnię oraz dobrze przemyślane struktury danych, sądzę że Pike może okazać się bardzo godnym uwagi narzędziem, zarówno do tworzenia skryptów CGI (choć korzystanie z Roxen w dużej mierze czyni programy CGI zbędnymi), jak i do ogólniejszych zadań programistycznych.